From 978e14fb2b5edee6c2dd16ea3e00dcb0d4667d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=BD=E5=9F=B9=E8=80=85?= Date: Sun, 6 Jan 2019 22:19:07 +0800 Subject: [PATCH] feat: 1.0.0.5 alpha --- public/manifest.json | 2 +- src/background/config.ts | 4 +- src/background/controller.ts | 169 +++++------------ src/background/downloadHistory.ts | 88 +++++++++ src/background/index.ts | 6 +- src/background/service.ts | 82 ++++++++- src/content/index.ts | 21 ++- src/interface/common.ts | 53 +++++- src/options/components/Footer.vue | 14 +- .../views/settings/DownloadClients/Editor.vue | 172 ++++++++++++------ src/options/views/settings/Sites/Editor.vue | 13 ++ src/service/clientController.ts | 110 +++++++++++ 12 files changed, 527 insertions(+), 207 deletions(-) create mode 100644 src/background/downloadHistory.ts create mode 100644 src/service/clientController.ts diff --git a/public/manifest.json b/public/manifest.json index a9ca60665..afe24d105 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_manifest_appName__", "short_name": "__MSG_manifest_shortName__", - "version": "1.0.0.4", + "version": "1.0.0.5", "description": "__MSG_manifest_appDescription__", "manifest_version": 2, "default_locale": "zh_CN", diff --git a/src/background/config.ts b/src/background/config.ts index cf53fbf71..2854dd6a9 100644 --- a/src/background/config.ts +++ b/src/background/config.ts @@ -40,7 +40,9 @@ class Config { exceedSize: 10, search: { rows: 10 - } + }, + // 连接下载服务器超时时间(毫秒) + connectClientTimeout: 5000 }; /** diff --git a/src/background/controller.ts b/src/background/controller.ts index a3225a48d..44b853fa5 100644 --- a/src/background/controller.ts +++ b/src/background/controller.ts @@ -4,15 +4,15 @@ import { Site, SiteSchema, Dictionary, - EConfigKey, DownloadClient, EDownloadClientType, DownloadOptions, - DownloadResult -} from "../interface/common"; -import { APP } from "../service/api"; -import { filters as Filters } from "../service/filters"; -import localStorage from "../service/localStorage"; + DataResult, + EDataResultType +} from "@/interface/common"; +import { filters as Filters } from "@/service/filters"; +import { ClientController } from "@/service/clientController"; +import { DownloadHistory } from "./downloadHistory"; export default class Controller { public options: Options = { sites: [], @@ -23,13 +23,25 @@ export default class Controller { public defaultClientOptions: DownloadClient = {}; public siteDefaultClients: any = {}; public optionsTabId: number | undefined = 0; - public downloadHistory: any[] = []; + public downloadHistory: DownloadHistory = new DownloadHistory(); public clients: any = {}; - constructor(options: Options) { + public clientController: ClientController = new ClientController(); + public isInitialized: boolean = false; + + public init(options: Options) { + this.reset(options); + this.isInitialized = true; + } + + /** + * 重置并刷新配置 + * @param options + */ + public reset(options: Options) { this.options = options; + this.clientController.init(options); this.initDefaultClient(); - this.getDownloadHistory(); } /** @@ -165,13 +177,24 @@ export default class Controller { * 获取下载历史记录 */ public getDownloadHistory(): Promise { - return new Promise((resolve?: any, reject?: any) => { - let storage: localStorage = new localStorage(); - storage.get(EConfigKey.downloadHistory, (result: any) => { - this.downloadHistory = result || []; - resolve(this.downloadHistory); - }); - }); + return this.downloadHistory.load(); + } + + /** + * 保存下载记录 + * @param data 下载链接信息 + * @param host 站点域名 + * @param clientId 下载客户端ID + */ + private saveDownloadHistory( + data: any, + host: string = "", + clientId: string = "" + ) { + // 是否保存历史记录 + if (this.options.saveDownloadHistory) { + this.downloadHistory.add(data, host, clientId); + } } /** @@ -179,35 +202,14 @@ export default class Controller { * @param items 需要删除的列表 */ public removeDownloadHistory(items: any[]): Promise { - return new Promise((resolve?: any, reject?: any) => { - let storage: localStorage = new localStorage(); - storage.get(EConfigKey.downloadHistory, (result: any) => { - this.downloadHistory = result; - for (let index = this.downloadHistory.length - 1; index >= 0; index--) { - let item = this.downloadHistory[index]; - let findIndex = items.findIndex((_data: any) => { - return _data.data.url === item.data.url; - }); - if (findIndex >= 0) { - this.downloadHistory.splice(index, 1); - } - } - storage.set(EConfigKey.downloadHistory, this.downloadHistory); - resolve(this.downloadHistory); - }); - }); + return this.downloadHistory.remove(items); } /** * 清除下载记录 */ public clearDownloadHistory(): Promise { - return new Promise((resolve?: any, reject?: any) => { - let storage: localStorage = new localStorage(); - this.downloadHistory = []; - storage.set(EConfigKey.downloadHistory, this.downloadHistory); - resolve(this.downloadHistory); - }); + return this.downloadHistory.clear(); } /** @@ -278,44 +280,6 @@ export default class Controller { }); } - /** - * 保存下载记录 - * @param data 下载链接信息 - * @param host 站点域名 - * @param clientId 下载客户端ID - */ - private saveDownloadHistory( - data: any, - host: string = "", - clientId: string = "" - ) { - // 是否保存历史记录 - if (this.options.saveDownloadHistory) { - let storage: localStorage = new localStorage(); - let saveData = { - data, - clientId, - host, - time: new Date().getTime() - }; - if (!this.downloadHistory) { - this.getDownloadHistory().then((result: any) => { - this.downloadHistory = result; - this.downloadHistory.push(saveData); - storage.set(EConfigKey.downloadHistory, this.downloadHistory); - }); - } else { - let index = this.downloadHistory.findIndex((item: any) => { - return item.data.url === data.url; - }); - if (index === -1) { - this.downloadHistory.push(saveData); - storage.set(EConfigKey.downloadHistory, this.downloadHistory); - } - } - } - } - /** * 执行下载操作 * @param clientConfig @@ -397,8 +361,8 @@ export default class Controller { siteDefaultPath: string ): Promise { return new Promise((resolve?: any, reject?: any) => { - let result: DownloadResult = { - type: "success", + let result: DataResult = { + type: EDataResultType.success, msg: "种子已添加", success: true, data: data @@ -410,21 +374,21 @@ export default class Controller { if (data.id != undefined) { result.msg = data.name + " 已发送至 Transmission,编号:" + data.id; if (!siteDefaultPath) { - result.type = "info"; + result.type = EDataResultType.info; result.msg += ";但站点默认目录未配置,建议配置。"; } } else if (data.status) { switch (data.status) { // 重复的种子 case "duplicate": - result.type = "error"; + result.type = EDataResultType.error; result.success = false; result.msg = data.torrent.name + " 种子已存在!编号:" + data.torrent.id; break; case "error": - result.type = "error"; + result.type = EDataResultType.error; result.success = false; result.msg = "链接发送失败,请检查下载服务器是否可用。"; break; @@ -451,46 +415,7 @@ export default class Controller { * @param clientOptions 客户端配置 */ private getClient(clientOptions: any): Promise { - return new Promise((resolve?: any, reject?: any) => { - if (typeof clientOptions === "string") { - let clientId = clientOptions; - clientOptions = this.options.clients.find((item: DownloadClient) => { - return item.id === clientId; - }); - let client = this.clients[clientId]; - if (client) { - resolve({ client, options: clientOptions }); - return; - } - } - if ((window)[clientOptions.type] === undefined) { - // 加载初始化脚本 - APP.execScript({ - type: "file", - content: `clients/${clientOptions.type}/init.js` - }).then(() => { - let client: any; - eval(`client = new ${clientOptions.type}()`); - client.init({ - loginName: clientOptions.loginName, - loginPwd: clientOptions.loginPwd, - address: clientOptions.address - }); - this.clients[clientOptions.id] = client; - resolve({ client, options: clientOptions }); - }); - } else { - let client: any; - eval(`client = new ${clientOptions.type}()`); - client.init({ - loginName: clientOptions.loginName, - loginPwd: clientOptions.loginPwd, - address: clientOptions.address - }); - this.clients[clientOptions.id] = client; - resolve({ client, options: clientOptions }); - } - }); + return this.clientController.getClient(clientOptions); } /** diff --git a/src/background/downloadHistory.ts b/src/background/downloadHistory.ts new file mode 100644 index 000000000..16feebe46 --- /dev/null +++ b/src/background/downloadHistory.ts @@ -0,0 +1,88 @@ +import { EConfigKey } from "@/interface/common"; +import localStorage from "@/service/localStorage"; + +/** + * 下载历史记录操作类 + */ +export class DownloadHistory { + public items: any[] = []; + public storage: localStorage = new localStorage(); + + constructor() { + this.load(); + } + + /** + * 获取下载历史记录 + */ + public load(): Promise { + return new Promise((resolve?: any, reject?: any) => { + this.storage.get(EConfigKey.downloadHistory, (result: any) => { + this.items = result || []; + resolve(this.items); + }); + }); + } + + /** + * 保存下载记录 + * @param data 下载链接信息 + * @param host 站点域名 + * @param clientId 下载客户端ID + */ + public add(data: any, host: string = "", clientId: string = "") { + let saveData = { + data, + clientId, + host, + time: new Date().getTime() + }; + if (!this.items) { + this.load().then(() => { + this.items.push(saveData); + this.storage.set(EConfigKey.downloadHistory, this.items); + }); + } else { + let index = this.items.findIndex((item: any) => { + return item.data.url === data.url; + }); + if (index === -1) { + this.items.push(saveData); + this.storage.set(EConfigKey.downloadHistory, this.items); + } + } + } + + /** + * 删除下载历史记录 + * @param items 需要删除的列表 + */ + public remove(items: any[]): Promise { + return new Promise((resolve?: any, reject?: any) => { + this.load().then(() => { + for (let index = this.items.length - 1; index >= 0; index--) { + let item = this.items[index]; + let findIndex = items.findIndex((_data: any) => { + return _data.data.url === item.data.url; + }); + if (findIndex >= 0) { + this.items.splice(index, 1); + } + } + this.storage.set(EConfigKey.downloadHistory, this.items); + resolve(this.items); + }); + }); + } + + /** + * 清除下载记录 + */ + public clear(): Promise { + return new Promise((resolve?: any, reject?: any) => { + this.items = []; + this.storage.set(EConfigKey.downloadHistory, this.items); + resolve(this.items); + }); + } +} diff --git a/src/background/index.ts b/src/background/index.ts index 20aa6fe89..e7b1e5b1a 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -4,7 +4,7 @@ import { filters } from "../service/filters"; const PTService = new PTPlugin(); // 监听由活动页面发来的消息事件 -chrome.runtime.onMessage.addListener(function (request, sender, callback) { +chrome.runtime.onMessage.addListener(function(request, sender, callback) { PTService.requestMessage(request, sender) .then((result: any) => { callback && callback(result); @@ -25,8 +25,8 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { // return true; // }); - // 暴露到 window 对象 Object.assign(window, { - PTSevriceFilters: filters + PTSevriceFilters: filters, + PTBackgroundService: PTService }); diff --git a/src/background/service.ts b/src/background/service.ts index ecbc0bc2a..f443c1699 100644 --- a/src/background/service.ts +++ b/src/background/service.ts @@ -1,7 +1,14 @@ -import { EAction, Request, Options } from "../interface/common"; +import { + EAction, + Request, + Options, + EModule, + ELogEvent +} from "../interface/common"; import Config from "./config"; import Controller from "./controller"; +import { Logger } from "@/service/logger"; /** * PT 助手后台服务类 */ @@ -14,9 +21,14 @@ export default class PTPlugin { }; // 本地模式,用于本地快速调试 public localMode: boolean = false; - public controller: any; + public controller: Controller = new Controller(); + public logger: Logger = new Logger(); constructor(localMode: boolean = false) { + this.logger.add({ + module: EModule.background, + event: ELogEvent.init + }); this.localMode = localMode; this.readConfig().then(() => { this.init(); @@ -31,6 +43,14 @@ export default class PTPlugin { public requestMessage(request: Request, sender?: any): Promise { return new Promise((resolve?: any, reject?: any) => { let result: any; + if (request.action !== EAction.getSystemLogs) { + this.logger.add({ + module: EModule.background, + event: `${ELogEvent.requestMessage}.${request.action}`, + data: request.data + }); + } + switch (request.action) { // 读取参数 case EAction.readConfig: @@ -53,8 +73,8 @@ export default class PTPlugin { case EAction.saveConfig: this.config.save(request.data); this.options = request.data; - if (this.controller) { - this.controller.options = this.options; + if (this.controller.isInitialized) { + this.controller.reset(this.options); } break; @@ -131,7 +151,7 @@ export default class PTPlugin { break; case EAction.getSearchResult: - this.controller && + this.controller.isInitialized && this.controller .getSearchResult(request.data) .then((result: any) => { @@ -144,7 +164,7 @@ export default class PTPlugin { // 获取下载记录 case EAction.getDownloadHistory: - this.controller && + this.controller.isInitialized && this.controller .getDownloadHistory() .then((result: any) => { @@ -157,7 +177,7 @@ export default class PTPlugin { // 删除下载记录 case EAction.removeDownloadHistory: - this.controller && + this.controller.isInitialized && this.controller .removeDownloadHistory(request.data) .then((result: any) => { @@ -170,7 +190,7 @@ export default class PTPlugin { // 清除下载记录 case EAction.clearDownloadHistory: - this.controller && + this.controller.isInitialized && this.controller .clearDownloadHistory() .then((result: any) => { @@ -180,6 +200,50 @@ export default class PTPlugin { reject(result); }); break; + + case EAction.testClientConnectivity: + this.controller.clientController + .testClientConnectivity(request.data) + .then((result: any) => { + resolve(result); + }) + .catch((result: any) => { + reject(result); + }); + break; + + case EAction.getSystemLogs: + this.logger + .load() + .then((result: any) => { + resolve(result); + }) + .catch((result: any) => { + reject(result); + }); + break; + + case EAction.removeSystemLogs: + this.logger + .remove(request.data) + .then((result: any) => { + resolve(result); + }) + .catch((result: any) => { + reject(result); + }); + break; + + case EAction.clearSystemLogs: + this.logger + .clear() + .then((result: any) => { + resolve(result); + }) + .catch((result: any) => { + reject(result); + }); + break; } }); } @@ -190,7 +254,7 @@ export default class PTPlugin { this.options = result; resolve(result); if (!this.localMode) { - this.controller = new Controller(this.options); + this.controller.init(this.options); } }); }); diff --git a/src/content/index.ts b/src/content/index.ts index 09e2537f4..3a0a55da5 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -8,7 +8,8 @@ import { ButtonOption, NoticeOptions, EDownloadClientType, - ESizeUnit + ESizeUnit, + EDataResultType } from "../interface/common"; import { APP } from "../service/api"; import { filters } from "../service/filters"; @@ -366,7 +367,7 @@ class PTPContent { } delete options.msg; - return new (window)["NoticeJs"](options).show(); + return $(new (window)["NoticeJs"](options).show()); } /** @@ -477,10 +478,20 @@ class PTPContent { let data = JSON.parse(e.dataTransfer.getData("text/plain")); if (data) { if (data.url && this.pageApp) { - this.pageApp.call(EAction.downloadFromDroper, data).then(() => { - this.logo.removeClass("onLoading"); - }); + this.pageApp + .call(EAction.downloadFromDroper, data) + .then(() => { + this.logo.removeClass("onLoading"); + }) + .catch(() => { + this.logo.removeClass("onLoading"); + }); } else { + this.showNotice({ + type: EDataResultType.info, + msg: "当前页面不支持此操作", + timeout: 3 + }); this.logo.removeClass("onLoading"); } } diff --git a/src/interface/common.ts b/src/interface/common.ts index 51c89b86f..e74b08a35 100644 --- a/src/interface/common.ts +++ b/src/interface/common.ts @@ -81,6 +81,7 @@ export interface Options { system?: any; search?: SearchOptions | void; saveDownloadHistory?: boolean; + connectClientTimeout?: number; } export interface Plugin { @@ -100,6 +101,7 @@ export interface SiteSchema { searchPage?: string; searchResultType?: ESearchResultType; getSearchResultScript?: string; + securityKeyFields?: string[]; } /** @@ -119,6 +121,7 @@ export interface Site { defaultClientId?: string; plugins?: any[]; allowSearch?: boolean; + securityKeys?: object; } /** @@ -151,10 +154,18 @@ export enum EAction { getSearchResult = "getSearchResult", // 获取下载记录 getDownloadHistory = "getDownloadHistory", - // 删除下载记录 + // 删除指定的下载记录 removeDownloadHistory = "removeDownloadHistory", // 清除下载记录 - clearDownloadHistory = "clearDownloadHistory" + clearDownloadHistory = "clearDownloadHistory", + // 测试下载服务器是否可连接 + testClientConnectivity = "testClientConnectivity", + // 获取系统日志 + getSystemLogs = "getSystemLogs", + // 删除指定的系统日志 + removeSystemLogs = "removeSystemLogs", + // 清除系统日志 + clearSystemLogs = "clearSystemLogs" } export interface Request { @@ -181,7 +192,8 @@ export enum EStorageType { export enum EConfigKey { default = "PT-Plugin-Plus-Config", - downloadHistory = "PT-Plugin-Plus-downloadHistory" + downloadHistory = "PT-Plugin-Plus-downloadHistory", + systemLogs = "PT-Plugin-Plus-systemLogs" } /** @@ -195,12 +207,41 @@ export interface DownloadOptions { clientId?: string; } +export enum EDataResultType { + success = "success", + error = "error", + info = "info", + warning = "warning", + unknown = "unknown" +} /** - * 下载返回的结果 + * 调用数据返回的结果格式 */ -export interface DownloadResult { +export interface DataResult { + // 是否成功 success: boolean; + // 成功或失败消息 msg?: string; - type?: string; + // 类型 + type?: EDataResultType; + // 附加数据 + data?: any; +} + +export enum EModule { + background = "background", + content = "content" +} + +export enum ELogEvent { + init = "init", + requestMessage = "requestMessage" +} + +export interface LogItem { + module: string; + event?: string; data?: any; + id?: number | string; + time?: number; } diff --git a/src/options/components/Footer.vue b/src/options/components/Footer.vue index fcdc16f1d..1040514ec 100644 --- a/src/options/components/Footer.vue +++ b/src/options/components/Footer.vue @@ -1,11 +1,15 @@ diff --git a/src/options/views/settings/DownloadClients/Editor.vue b/src/options/views/settings/DownloadClients/Editor.vue index 5d66eaaf3..60a672992 100644 --- a/src/options/views/settings/DownloadClients/Editor.vue +++ b/src/options/views/settings/DownloadClients/Editor.vue @@ -1,59 +1,90 @@ diff --git a/src/options/views/settings/Sites/Editor.vue b/src/options/views/settings/Sites/Editor.vue index cfe41c900..b1b9a64a7 100644 --- a/src/options/views/settings/Sites/Editor.vue +++ b/src/options/views/settings/Sites/Editor.vue @@ -58,7 +58,20 @@ :type="showPasskey ? 'text' : 'password'" :append-icon="showPasskey ? 'visibility_off' : 'visibility'" @click:append="showPasskey = !showPasskey" + v-if="!site.securityKeys" > + + + { + return new Promise((resolve?: any, reject?: any) => { + if (typeof clientOptions === "string") { + let clientId = clientOptions; + clientOptions = this.options.clients.find((item: DownloadClient) => { + return item.id === clientId; + }); + let client = this.clients[clientId]; + if (client) { + resolve({ client, options: clientOptions }); + return; + } + } + if ((window)[clientOptions.type] === undefined) { + // 加载初始化脚本 + APP.execScript({ + type: "file", + content: `clients/${clientOptions.type}/init.js` + }).then(() => { + let client: any; + eval(`client = new ${clientOptions.type}()`); + client.init({ + loginName: clientOptions.loginName, + loginPwd: clientOptions.loginPwd, + address: clientOptions.address + }); + this.clients[clientOptions.id] = client; + resolve({ client, options: clientOptions }); + }); + } else { + let client: any; + eval(`client = new ${clientOptions.type}()`); + client.init({ + loginName: clientOptions.loginName, + loginPwd: clientOptions.loginPwd, + address: clientOptions.address + }); + this.clients[clientOptions.id] = client; + resolve({ client, options: clientOptions }); + } + }); + } + + /** + * 测试客户端是否可连接 + * @param options 参数 + */ + public testClientConnectivity(options: DownloadClient): Promise { + return new Promise((resolve?: any, reject?: any) => { + let dataResult: DataResult = { + type: EDataResultType.unknown, + success: false + }; + this.getClient(options).then((clientOptions: any) => { + clientOptions.client + .call(EAction.testClientConnectivity, options) + .then((result: boolean) => { + dataResult.success = result; + if (result) { + dataResult.type = EDataResultType.success; + } + resolve(dataResult); + }) + .catch((result: any) => { + dataResult.data = result; + dataResult.type = EDataResultType.error; + reject(dataResult); + }); + }); + }); + } +}