Extractor.watch()
This commit is contained in:
		| @ -1,8 +1,15 @@ | ||||
| import { logger } from "./common"; | ||||
| import { Actions } from "../common"; | ||||
| import { messageSubscribers } from "./messaging"; | ||||
|  | ||||
| export class Caches { | ||||
|     private _state: string = ""; | ||||
|     constructor() { } | ||||
|     constructor() { | ||||
|         messageSubscribers.addListener(Actions.UPLOAD_STATE, (request, sender, sendResponse) => { | ||||
|             sendResponse('recieved!'); | ||||
|             this.setState(request.fileName, request.state) | ||||
|         }); | ||||
|     } | ||||
|     get state(): string { | ||||
|         let s = this._state; | ||||
|         this._state = ""; | ||||
|  | ||||
| @ -54,11 +54,22 @@ export class Extractor { | ||||
|     start() { | ||||
|         return this._startTasks(0); | ||||
|     } | ||||
|     stop() { | ||||
|     stop(id?: number) { | ||||
|         if (id !== undefined) { | ||||
|             id = this._checkTaskId(id); | ||||
|             if (id < 0) return; | ||||
|             this._tasks[id].stop(); | ||||
|             return; | ||||
|         } | ||||
|         for (let i = 0; i < this._tasks.length; i++) { | ||||
|             this._tasks[i].stop(); | ||||
|         } | ||||
|     } | ||||
|     watch(id: number) { | ||||
|         id = this._checkTaskId(id); | ||||
|         if (id < 0) return; | ||||
|         this._tasks[id].watch(); | ||||
|     } | ||||
|     /** | ||||
|      * restart from specified task, but don't restart the previous tasks. | ||||
|      * @param {number} from where to restart the tasks, begins with 0 | ||||
| @ -138,7 +149,7 @@ ${exResults.toString(50) || "- Empty -"} | ||||
|             saveFile(exResults.toString(), "text/csv"); | ||||
|         } | ||||
|     } | ||||
|     _checkTaskId(id: number, defaultId: number) { | ||||
|     _checkTaskId(id: number, defaultId?: number) { | ||||
|         if (!this._tasks.length) { | ||||
|             logger.info("No task found."); | ||||
|             return -1; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { Request, Actions } from "../common"; | ||||
| import { getTabByID } from "./actions"; | ||||
| import { caches, logger } from "./common"; | ||||
| import { logger } from "./common"; | ||||
|  | ||||
| /** | ||||
|  *  Sending a message to target tab repeatedly until the response is not undefined. | ||||
| @ -78,14 +78,41 @@ export function sendMessage<T>( | ||||
|     }); | ||||
| } | ||||
|  | ||||
| chrome.runtime.onMessage.addListener(function (request: Request, sender, sendResponse) { | ||||
|     switch (request.action) { | ||||
|         case Actions.UPLOAD_STATE: | ||||
|             sendResponse('recieved!'); | ||||
|             caches.setState(request.fileName, request.state) | ||||
|             break; | ||||
|         default: | ||||
|             sendResponse("Request not supported."); | ||||
|             break; | ||||
| export type ActionSubscriber = (request: Request, sender: chrome.runtime.MessageSender, sendResponse: (response?: any) => void) => void | Promise<void>; | ||||
| class MessageSubscribers { | ||||
|     private listeners: { [key: number]: ActionSubscriber[] } = {}; | ||||
|     addListener(action: Actions, subscriber: ActionSubscriber) { | ||||
|         this.listeners[action] || (this.listeners[action] = []); | ||||
|         this.listeners[action].push(subscriber); | ||||
|     } | ||||
|     removeListener(action: Actions, subscriber: ActionSubscriber) { | ||||
|         this.listeners[action] || (this.listeners[action] = []); | ||||
|         for (let i = 0; i < this.listeners[action].length; i++) { | ||||
|             if (this.listeners[action][i] == subscriber) { | ||||
|                 this.listeners[action].splice(i, 1); | ||||
|                 i--; | ||||
|             } | ||||
|         } | ||||
|         logger.debug(`${this.listeners[action].length} subscriber(s) remained for action ${Actions[action]}`); | ||||
|     } | ||||
|     getListeners(action: Actions): ActionSubscriber[] { | ||||
|         return this.listeners[action] | ||||
|     } | ||||
| } | ||||
| export const messageSubscribers = new MessageSubscribers(); | ||||
|  | ||||
| chrome.runtime.onMessage.addListener(function (request: Request, sender, sendResponse) { | ||||
|     let subscribers = messageSubscribers.getListeners(request.action); | ||||
|     if (!subscribers || !subscribers.length) { | ||||
|         sendResponse("Request not supported."); | ||||
|         return; | ||||
|     } | ||||
|     let promises: Promise<any>[] = []; | ||||
|     for (let subscriber of subscribers) { | ||||
|         let p = subscriber(request, sender, sendResponse); | ||||
|         if (p instanceof Promise) promises.push(p); | ||||
|     } | ||||
|     if (promises.length) | ||||
|         return Promise.all(promises); | ||||
|     return; | ||||
| }); | ||||
|  | ||||
| @ -2,6 +2,9 @@ import { parseUrls } from "./tools"; | ||||
| import { queryUrl, redirectTab, scrollToBottom, extractTabData } from "./actions"; | ||||
| import { testArgs, signitures } from "./signiture"; | ||||
| import { ExtractResult } from "./result"; | ||||
| import { messageSubscribers, ActionSubscriber } from "./messaging"; | ||||
| import { Actions } from "../common"; | ||||
| import { logger } from "./common"; | ||||
|  | ||||
| export class Task { | ||||
|     private _data: { [key: string]: string[][] } = {}; | ||||
| @ -46,12 +49,22 @@ export class Task { | ||||
|         return this._fieldSelectors; | ||||
|     } | ||||
|     clean(): Task { | ||||
|         this.stop(); | ||||
|         this._data = {}; | ||||
|         this._data_keys = []; | ||||
|         return this; | ||||
|     } | ||||
|     stop() { | ||||
|         this._running = false; | ||||
|         messageSubscribers.removeListener(Actions.REPORT_NEW_PAGE, this.listener); | ||||
|     } | ||||
|     watch() { | ||||
|         if (this._running) { | ||||
|             logger.info("The task is running. Please wait..."); | ||||
|             return; | ||||
|         } | ||||
|         this._running = true; | ||||
|         messageSubscribers.addListener(Actions.REPORT_NEW_PAGE, this.listener); | ||||
|     } | ||||
|     async execute(tab: chrome.tabs.Tab, upstreamData?: ExtractResult): Promise<void> { | ||||
|         if (!tab) return Promise.reject("No tab to execute the task."); | ||||
| @ -65,35 +78,26 @@ export class Task { | ||||
|                 urls = [await queryUrl(tab)]; | ||||
|             } | ||||
|         } | ||||
|         let saveResult = (results, key) => { | ||||
|             this._data[key] = results; | ||||
|             this._data_keys.push(key); | ||||
|         } | ||||
|         let runningCheck = (fn: () => Promise<any>): Promise<any> => { | ||||
|             if (!this._running) return Promise.reject("The task is stopped by user."); | ||||
|             return fn(); | ||||
|         } | ||||
|         return urls.reduce((p, url, i) => p.then( | ||||
|             results => { | ||||
|                 if (i > 0 && results instanceof Array) { | ||||
|                     let lastURL = urls[i - 1]; | ||||
|                     saveResult(results, lastURL); | ||||
|                     this.saveResult(results, lastURL); | ||||
|                 } | ||||
|                 if (this._data[url]) return; | ||||
|  | ||||
|                 let pms: Promise<any> = runningCheck(() => redirectTab(tab, url)); | ||||
|                 if (this._options["scrollToBottom"]) { | ||||
|                     pms = pms.then(() => runningCheck(() => scrollToBottom(tab))); | ||||
|                 } | ||||
|                 return pms.then( | ||||
|                     () => runningCheck(() => extractTabData(tab, this._itemsSelector, this._fieldSelectors)) | ||||
|                 ); | ||||
|                 let pms: Promise<any> = this.runningCheck(() => redirectTab(tab, url)); | ||||
|                 return pms | ||||
|                     .then(() => this.makeOptionalTasks(tab)) | ||||
|                     .then( | ||||
|                         () => this.runningCheck(() => extractTabData(tab, this._itemsSelector, this._fieldSelectors)) | ||||
|                     ); | ||||
|             } | ||||
|         ), Promise.resolve<string[][]>(null)).then( | ||||
|             results => { | ||||
|                 if (results && results.length) { | ||||
|                     let lastURL = urls[urls.length - 1]; | ||||
|                     saveResult(results, lastURL); | ||||
|                     this.saveResult(results, lastURL); | ||||
|                     this._running = false; | ||||
|                 } | ||||
|             } | ||||
| @ -104,4 +108,38 @@ export class Task { | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|     private listener: ActionSubscriber = (request, sender, sendResponse) => { | ||||
|         sendResponse('recieved!'); | ||||
|         let pm = this.makeOptionalTasks(sender.tab); | ||||
|         return pm.then( | ||||
|             () => extractTabData(sender.tab, this._itemsSelector, this._fieldSelectors) | ||||
|         ).then( | ||||
|             results => { | ||||
|                 if (results && results.length) { | ||||
|                     this.saveResult(results, sender.tab.url); | ||||
|                 } | ||||
|             } | ||||
|         ).catch( | ||||
|             e => logger.error(e) | ||||
|         ) | ||||
|     } | ||||
|     private makeOptionalTasks(tab: chrome.tabs.Tab): Promise<any> { | ||||
|         let pm: Promise<any>; | ||||
|         if (this._options["scrollToBottom"]) { | ||||
|             pm = this.runningCheck(() => scrollToBottom(tab)); | ||||
|         } | ||||
|         return pm; | ||||
|     } | ||||
|     private runningCheck(fn: () => Promise<any>): Promise<any> { | ||||
|         if (!this._running) return Promise.reject("The task is stopped by user."); | ||||
|         return fn(); | ||||
|     } | ||||
|     private saveResult(results, key) { | ||||
|         if (this._data[key] === undefined) { | ||||
|             // do not add keys again | ||||
|             this._data_keys.push(key); | ||||
|         } | ||||
|         this._data[key] = results; | ||||
|         logger.info(`${results.length} items found.`) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user