BackgroundWorkflowTriggers.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import browser from 'webextension-polyfill';
  2. import dayjs from 'dayjs';
  3. import { findTriggerBlock, parseJSON } from '@/utils/helper';
  4. import {
  5. registerCronJob,
  6. registerSpecificDay,
  7. registerWorkflowTrigger,
  8. } from '@/utils/workflowTrigger';
  9. import BackgroundUtils from './BackgroundUtils';
  10. import BackgroundWorkflowUtils from './BackgroundWorkflowUtils';
  11. async function executeWorkflow(workflowData, options) {
  12. if (workflowData.isDisabled) return;
  13. const isMV2 = browser.runtime.getManifest().manifest_version === 2;
  14. const context = workflowData.settings.execContext;
  15. if (isMV2 || context === 'background') {
  16. BackgroundWorkflowUtils.executeWorkflow(workflowData, options);
  17. return;
  18. }
  19. await BackgroundUtils.openDashboard('?fromBackground=true', false);
  20. await BackgroundUtils.sendMessageToDashboard('workflow:execute', {
  21. data: workflowData,
  22. options,
  23. });
  24. }
  25. class BackgroundWorkflowTriggers {
  26. static async visitWebTriggers(tabId, tabUrl, spa = false) {
  27. const { visitWebTriggers } = await browser.storage.local.get(
  28. 'visitWebTriggers'
  29. );
  30. if (!visitWebTriggers || visitWebTriggers.length === 0) return;
  31. const triggeredWorkflow = visitWebTriggers.find(
  32. ({ url, isRegex, supportSPA }) => {
  33. if (!url.trim() || (spa && !supportSPA)) return false;
  34. return tabUrl.match(isRegex ? new RegExp(url, 'g') : url);
  35. }
  36. );
  37. if (triggeredWorkflow) {
  38. let workflowId = triggeredWorkflow.id;
  39. if (triggeredWorkflow.id.startsWith('trigger')) {
  40. const { 1: triggerWorkflowId } = triggeredWorkflow.id.split(':');
  41. workflowId = triggerWorkflowId;
  42. }
  43. const workflowData = await BackgroundWorkflowUtils.getWorkflow(
  44. workflowId
  45. );
  46. if (workflowData) executeWorkflow(workflowData, { tabId });
  47. }
  48. }
  49. static async scheduleWorkflow({ name }) {
  50. try {
  51. let workflowId = name;
  52. let triggerId = null;
  53. if (name.startsWith('trigger')) {
  54. const { 1: triggerWorkflowId, 2: triggerItemId } = name.split(':');
  55. triggerId = triggerItemId;
  56. workflowId = triggerWorkflowId;
  57. }
  58. const currentWorkflow = await BackgroundWorkflowUtils.getWorkflow(
  59. workflowId
  60. );
  61. if (!currentWorkflow) return;
  62. let data = currentWorkflow.trigger;
  63. if (!data) {
  64. const drawflow =
  65. typeof currentWorkflow.drawflow === 'string'
  66. ? parseJSON(currentWorkflow.drawflow, {})
  67. : currentWorkflow.drawflow;
  68. const { data: triggerBlockData } = findTriggerBlock(drawflow) || {};
  69. data = triggerBlockData;
  70. }
  71. if (triggerId) {
  72. data = data.triggers.find((trigger) => trigger.id === triggerId);
  73. if (data) data = { ...data, ...data.data };
  74. }
  75. if (data && data.type === 'interval' && data.fixedDelay) {
  76. const { workflowStates } = await browser.storage.local.get(
  77. 'workflowStates'
  78. );
  79. const workflowState = (workflowStates || []).find(
  80. (item) => item.workflowId === workflowId
  81. );
  82. if (workflowState) {
  83. let { workflowQueue } = await browser.storage.local.get(
  84. 'workflowQueue'
  85. );
  86. workflowQueue = workflowQueue || [];
  87. if (!workflowQueue.includes(workflowId)) {
  88. (workflowQueue = workflowQueue || []).push(workflowId);
  89. await browser.storage.local.set({ workflowQueue });
  90. }
  91. return;
  92. }
  93. } else if (data && data.type === 'date') {
  94. const [hour, minute, second] = data.time.split(':');
  95. const date = dayjs(data.date)
  96. .hour(hour)
  97. .minute(minute)
  98. .second(second || 0);
  99. const isAfter = dayjs(Date.now() - 60 * 1000).isAfter(date);
  100. if (isAfter) return;
  101. }
  102. executeWorkflow(currentWorkflow);
  103. if (!data) return;
  104. if (['specific-day', 'cron-job'].includes(data.type)) {
  105. if (data.type === 'specific-day') {
  106. registerSpecificDay(name, data);
  107. } else {
  108. registerCronJob(name, data);
  109. }
  110. }
  111. } catch (error) {
  112. console.error(error);
  113. }
  114. }
  115. static async contextMenu({ parentMenuItemId, menuItemId, frameId }, tab) {
  116. try {
  117. if (parentMenuItemId !== 'automaContextMenu') return;
  118. const message = await browser.tabs.sendMessage(
  119. tab.id,
  120. {
  121. type: 'context-element',
  122. },
  123. { frameId }
  124. );
  125. let workflowId = menuItemId;
  126. if (menuItemId.startsWith('trigger')) {
  127. const { 1: triggerWorkflowId } = menuItemId.split(':');
  128. workflowId = triggerWorkflowId;
  129. }
  130. const workflowData = await BackgroundWorkflowUtils.getWorkflow(
  131. workflowId
  132. );
  133. executeWorkflow(workflowData, {
  134. data: {
  135. variables: message,
  136. },
  137. });
  138. } catch (error) {
  139. console.error(error);
  140. }
  141. }
  142. static async reRegisterTriggers(isStartup = false) {
  143. const { workflows, workflowHosts, teamWorkflows } =
  144. await browser.storage.local.get([
  145. 'workflows',
  146. 'workflowHosts',
  147. 'teamWorkflows',
  148. ]);
  149. const convertToArr = (value) =>
  150. Array.isArray(value) ? value : Object.values(value);
  151. const workflowsArr = convertToArr(workflows);
  152. if (workflowHosts) {
  153. workflowsArr.push(...convertToArr(workflowHosts));
  154. }
  155. if (teamWorkflows) {
  156. workflowsArr.push(
  157. ...BackgroundWorkflowUtils.flattenTeamWorkflows(teamWorkflows)
  158. );
  159. }
  160. for (const currWorkflow of workflowsArr) {
  161. // eslint-disable-next-line no-continue
  162. if (currWorkflow.isDisabled) continue;
  163. let triggerBlock = currWorkflow.trigger;
  164. if (!triggerBlock) {
  165. const flow =
  166. typeof currWorkflow.drawflow === 'string'
  167. ? parseJSON(currWorkflow.drawflow, {})
  168. : currWorkflow.drawflow;
  169. triggerBlock = findTriggerBlock(flow)?.data;
  170. }
  171. if (triggerBlock) {
  172. if (isStartup && triggerBlock.type === 'on-startup') {
  173. executeWorkflow(currWorkflow);
  174. } else {
  175. if (isStartup && triggerBlock.triggers) {
  176. for (const trigger of triggerBlock.triggers) {
  177. if (trigger.type === 'on-startup') {
  178. await BackgroundWorkflowUtils.executeWorkflow(currWorkflow);
  179. }
  180. }
  181. }
  182. await registerWorkflowTrigger(currWorkflow.id, {
  183. data: triggerBlock,
  184. });
  185. }
  186. }
  187. }
  188. }
  189. }
  190. export default BackgroundWorkflowTriggers;