通讯操作
This commit is contained in:
parent
9876c1cbcb
commit
c4b47d117c
@ -1,6 +1,6 @@
|
|||||||
export function sendMessage(action: string, params?: any): Promise<any> {
|
export function sendMessage(action: string, data?: any): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.runtime.sendMessage({ action, data: params }, (res) => {
|
chrome.runtime.sendMessage({ action, data }, (res) => {
|
||||||
if (res.code) {
|
if (res.code) {
|
||||||
console.error(res);
|
console.error(res);
|
||||||
reject(res.message);
|
reject(res.message);
|
||||||
@ -11,10 +11,10 @@ export function sendMessage(action: string, params?: any): Promise<any> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function connect(action: string, params?: any): Promise<chrome.runtime.Port> {
|
export function connect(action: string, data?: any): Promise<chrome.runtime.Port> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const port = chrome.runtime.connect();
|
const port = chrome.runtime.connect();
|
||||||
port.postMessage({ action, data: params });
|
port.postMessage({ action, data });
|
||||||
resolve(port);
|
resolve(port);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,20 @@ import EventEmitter from "eventemitter3";
|
|||||||
import { connect } from "./client";
|
import { connect } from "./client";
|
||||||
import { ApiFunction, Server } from "./server";
|
import { ApiFunction, Server } from "./server";
|
||||||
|
|
||||||
|
export type SubscribeCallback = (message: any) => void;
|
||||||
|
|
||||||
export class Broker {
|
export class Broker {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
// 订阅
|
// 订阅
|
||||||
async subscribe(topic: string, handler: (message: any) => void) {
|
async subscribe(topic: string, handler: SubscribeCallback): Promise<chrome.runtime.Port> {
|
||||||
const con = await connect("messageQueue", { action: "subscribe", topic });
|
const con = await connect("messageQueue", { action: "subscribe", topic });
|
||||||
con.onMessage.addListener((msg: { action: string; topic: string; message: any }) => {
|
con.onMessage.addListener((msg: { action: string; topic: string; message: any }) => {
|
||||||
if (msg.action === "message") {
|
if (msg.action === "message") {
|
||||||
handler(msg.message);
|
handler(msg.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发布
|
// 发布
|
||||||
|
99
packages/message/window_message.ts
Normal file
99
packages/message/window_message.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
// 通过 window.postMessage/onmessage 实现通信
|
||||||
|
|
||||||
|
import EventEmitter from "eventemitter3";
|
||||||
|
|
||||||
|
// 消息体
|
||||||
|
export type WindowMessageBody = {
|
||||||
|
messageId: string; // 消息id
|
||||||
|
type: "sendMessage" | "respMessage" | "connect"; // 消息类型
|
||||||
|
data: any; // 消息数据
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WindowMessage {
|
||||||
|
EE: EventEmitter = new EventEmitter();
|
||||||
|
|
||||||
|
// source: Window 消息来源
|
||||||
|
// target: Window 消息目标
|
||||||
|
constructor(
|
||||||
|
private source: Window,
|
||||||
|
private target: Window
|
||||||
|
) {
|
||||||
|
// 监听消息
|
||||||
|
this.source.addEventListener("message", (e) => {
|
||||||
|
if (e.source === this.target) {
|
||||||
|
this.messageHandle(e.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
messageHandle(data: WindowMessageBody) {
|
||||||
|
// 处理消息
|
||||||
|
if (data.type === "sendMessage") {
|
||||||
|
// 接收到消息
|
||||||
|
this.EE.emit("message", data.data, (resp: any) => {
|
||||||
|
// 发送响应消息
|
||||||
|
const body: WindowMessageBody = {
|
||||||
|
messageId: data.messageId,
|
||||||
|
type: "respMessage",
|
||||||
|
data: resp,
|
||||||
|
};
|
||||||
|
this.target.postMessage(body, "*");
|
||||||
|
});
|
||||||
|
} else if (data.type === "respMessage") {
|
||||||
|
// 接收到响应消息
|
||||||
|
this.EE.emit("response:" + data.messageId, data);
|
||||||
|
} else if (data.type === "connect") {
|
||||||
|
this.EE.emit("connect", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||||
|
} else if (data.type === "disconnect") {
|
||||||
|
this.EE.emit("disconnect", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||||
|
} else if (data.type === "connectMessage") {
|
||||||
|
this.EE.emit("connectMessage", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onConnect(callback: (data: any, con: WindowMessageConnect) => void) {
|
||||||
|
this.EE.addListener("connect", callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(action: string, data?: any): Promise<WindowMessageConnect> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const body: WindowMessageBody = {
|
||||||
|
messageId: uuidv4(),
|
||||||
|
type: "connect",
|
||||||
|
data: { action, data },
|
||||||
|
};
|
||||||
|
this.target.postMessage(body, "*");
|
||||||
|
resolve(new WindowMessageConnect(body.messageId, this.EE, this.target));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(callback: (data: any, sendResponse: (data: any) => void) => void) {
|
||||||
|
this.EE.addListener("message", callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(action: string, data?: any): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const body: WindowMessageBody = {
|
||||||
|
messageId: uuidv4(),
|
||||||
|
type: "sendMessage",
|
||||||
|
data: { action, data },
|
||||||
|
};
|
||||||
|
const callback = (body: WindowMessageBody) => {
|
||||||
|
this.EE.removeListener("response:" + body.messageId, callback);
|
||||||
|
resolve(body.data);
|
||||||
|
};
|
||||||
|
this.EE.addListener("response:" + body.messageId, callback);
|
||||||
|
this.target.postMessage(body, "*");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WindowMessageConnect {
|
||||||
|
constructor(
|
||||||
|
private messageId: string,
|
||||||
|
private EE: EventEmitter,
|
||||||
|
private target: Window
|
||||||
|
) {}
|
||||||
|
}
|
@ -9,20 +9,15 @@ export const SCRIPT_TYPE_NORMAL: SCRIPT_TYPE = 1;
|
|||||||
export const SCRIPT_TYPE_CRONTAB: SCRIPT_TYPE = 2;
|
export const SCRIPT_TYPE_CRONTAB: SCRIPT_TYPE = 2;
|
||||||
export const SCRIPT_TYPE_BACKGROUND: SCRIPT_TYPE = 3;
|
export const SCRIPT_TYPE_BACKGROUND: SCRIPT_TYPE = 3;
|
||||||
|
|
||||||
export type SCRIPT_STATUS = 1 | 2 | 3 | 4;
|
export type SCRIPT_STATUS = 1 | 2;
|
||||||
|
|
||||||
export const SCRIPT_STATUS_ENABLE: SCRIPT_STATUS = 1;
|
export const SCRIPT_STATUS_ENABLE: SCRIPT_STATUS = 1;
|
||||||
export const SCRIPT_STATUS_DISABLE: SCRIPT_STATUS = 2;
|
export const SCRIPT_STATUS_DISABLE: SCRIPT_STATUS = 2;
|
||||||
// 弃用
|
|
||||||
export const SCRIPT_STATUS_ERROR: SCRIPT_STATUS = 3;
|
|
||||||
export const SCRIPT_STATUS_DELETE: SCRIPT_STATUS = 4;
|
|
||||||
|
|
||||||
export type SCRIPT_RUN_STATUS = "running" | "complete" | "error" | "retry";
|
export type SCRIPT_RUN_STATUS = "running" | "complete" | "error";
|
||||||
export const SCRIPT_RUN_STATUS_RUNNING: SCRIPT_RUN_STATUS = "running";
|
export const SCRIPT_RUN_STATUS_RUNNING: SCRIPT_RUN_STATUS = "running";
|
||||||
export const SCRIPT_RUN_STATUS_COMPLETE: SCRIPT_RUN_STATUS = "complete";
|
export const SCRIPT_RUN_STATUS_COMPLETE: SCRIPT_RUN_STATUS = "complete";
|
||||||
export const SCRIPT_RUN_STATUS_ERROR: SCRIPT_RUN_STATUS = "error";
|
export const SCRIPT_RUN_STATUS_ERROR: SCRIPT_RUN_STATUS = "error";
|
||||||
// 弃用
|
|
||||||
export const SCRIPT_RUN_STATUS_RETRY: SCRIPT_RUN_STATUS = "retry";
|
|
||||||
|
|
||||||
export type Metadata = { [key: string]: string[] };
|
export type Metadata = { [key: string]: string[] };
|
||||||
|
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import { Server } from "@Packages/message/server";
|
import { Server } from "@Packages/message/server";
|
||||||
|
import { ScriptService } from "./script";
|
||||||
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
|
|
||||||
// offscreen环境的管理器
|
// offscreen环境的管理器
|
||||||
export class OffscreenManager {
|
export class OffscreenManager {
|
||||||
private api: Server = new Server("offscreen");
|
private api: Server = new Server("offscreen");
|
||||||
|
|
||||||
|
private mq: MessageQueue = new MessageQueue(this.api);
|
||||||
|
|
||||||
initManager() {
|
initManager() {
|
||||||
// 监听消息
|
// 监听消息
|
||||||
|
const group = this.api.group("serviceWorker");
|
||||||
|
const script = new ScriptService(group.group("script"), this.mq);
|
||||||
|
script.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/app/service/offscreen/script.ts
Normal file
20
src/app/service/offscreen/script.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import LoggerCore from "@App/app/logger/core";
|
||||||
|
import Logger from "@App/app/logger/logger";
|
||||||
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
|
import { Group } from "@Packages/message/server";
|
||||||
|
|
||||||
|
export class ScriptService {
|
||||||
|
logger: Logger;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private group: Group,
|
||||||
|
private mq: MessageQueue
|
||||||
|
) {
|
||||||
|
this.logger = LoggerCore.logger().with({ service: "script" });
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// 初始化, 执行所有的后台脚本, 设置定时脚本计时器
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { Script } from "@App/app/repo/scripts";
|
import { Script } from "@App/app/repo/scripts";
|
||||||
import { Client } from "@Packages/message/client";
|
import { Client } from "@Packages/message/client";
|
||||||
import { InstallSource } from ".";
|
import { InstallSource } from ".";
|
||||||
|
import { Broker } from "@Packages/message/message_queue";
|
||||||
|
|
||||||
export class ScriptClient extends Client {
|
export class ScriptClient extends Client {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -12,7 +13,26 @@ export class ScriptClient extends Client {
|
|||||||
return this.do("getInstallInfo", uuid);
|
return this.do("getInstallInfo", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
installScript(script: Script, upsertBy: InstallSource = "user") {
|
install(script: Script, upsertBy: InstallSource = "user") {
|
||||||
return this.do("installScript", { script, upsertBy });
|
return this.do("install", { script, upsertBy });
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(uuid: string) {
|
||||||
|
return this.do("delete", uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
enable(uuid: string, enable: boolean) {
|
||||||
|
return this.do("enable", { uuid, enable });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function subscribeScriptInstall(
|
||||||
|
border: Broker,
|
||||||
|
callback: (message: { script: Script; update: boolean }) => void
|
||||||
|
) {
|
||||||
|
return border.subscribe("installScript", callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function subscribeScriptDelete(border: Broker, callback: (message: { uuid: string }) => void) {
|
||||||
|
return border.subscribe("deleteScript", callback);
|
||||||
|
}
|
||||||
|
@ -6,7 +6,14 @@ import LoggerCore from "@App/app/logger/core";
|
|||||||
import Cache from "@App/app/cache";
|
import Cache from "@App/app/cache";
|
||||||
import CacheKey from "@App/app/cache_key";
|
import CacheKey from "@App/app/cache_key";
|
||||||
import { openInCurrentTab } from "@App/pkg/utils/utils";
|
import { openInCurrentTab } from "@App/pkg/utils/utils";
|
||||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
import {
|
||||||
|
Script,
|
||||||
|
SCRIPT_RUN_STATUS_COMPLETE,
|
||||||
|
SCRIPT_RUN_STATUS_RUNNING,
|
||||||
|
SCRIPT_STATUS_DISABLE,
|
||||||
|
SCRIPT_STATUS_ENABLE,
|
||||||
|
ScriptDAO,
|
||||||
|
} from "@App/app/repo/scripts";
|
||||||
import { MessageQueue } from "@Packages/message/message_queue";
|
import { MessageQueue } from "@Packages/message/message_queue";
|
||||||
import { InstallSource } from ".";
|
import { InstallSource } from ".";
|
||||||
|
|
||||||
@ -145,11 +152,13 @@ export class ScriptService {
|
|||||||
version: script.metadata.version[0],
|
version: script.metadata.version[0],
|
||||||
upsertBy,
|
upsertBy,
|
||||||
});
|
});
|
||||||
|
let update = false;
|
||||||
const dao = new ScriptDAO();
|
const dao = new ScriptDAO();
|
||||||
// 判断是否已经安装
|
// 判断是否已经安装
|
||||||
const oldScript = await dao.findByUUID(script.uuid);
|
const oldScript = await dao.findByUUID(script.uuid);
|
||||||
if (oldScript) {
|
if (oldScript) {
|
||||||
// 执行更新逻辑
|
// 执行更新逻辑
|
||||||
|
update = true;
|
||||||
script.selfMetadata = oldScript.selfMetadata;
|
script.selfMetadata = oldScript.selfMetadata;
|
||||||
}
|
}
|
||||||
return dao
|
return dao
|
||||||
@ -157,7 +166,7 @@ export class ScriptService {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info("install success");
|
logger.info("install success");
|
||||||
// 广播一下
|
// 广播一下
|
||||||
this.mq.publish("installScript", script);
|
this.mq.publish("installScript", { script, update });
|
||||||
return {};
|
return {};
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@ -166,10 +175,54 @@ export class ScriptService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteScript(uuid: string) {
|
||||||
|
const logger = this.logger.with({ uuid });
|
||||||
|
const dao = new ScriptDAO();
|
||||||
|
const script = await dao.findByUUID(uuid);
|
||||||
|
if (!script) {
|
||||||
|
logger.error("script not found");
|
||||||
|
throw new Error("script not found");
|
||||||
|
}
|
||||||
|
return dao
|
||||||
|
.delete(uuid)
|
||||||
|
.then(() => {
|
||||||
|
logger.info("delete success");
|
||||||
|
this.mq.publish("deleteScript", { uuid });
|
||||||
|
return {};
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
logger.error("delete error", Logger.E(e));
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async enableScript(param: { uuid: string; enable: boolean }) {
|
||||||
|
const logger = this.logger.with({ uuid: param.uuid, enable: param.enable });
|
||||||
|
const dao = new ScriptDAO();
|
||||||
|
const script = await dao.findByUUID(param.uuid);
|
||||||
|
if (!script) {
|
||||||
|
logger.error("script not found");
|
||||||
|
throw new Error("script not found");
|
||||||
|
}
|
||||||
|
return dao
|
||||||
|
.update(param.uuid, { status: param.enable ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE })
|
||||||
|
.then(() => {
|
||||||
|
logger.info("enable success");
|
||||||
|
this.mq.publish("enableScript", { uuid: param.uuid, enable: param.enable });
|
||||||
|
return {};
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
logger.error("enable error", Logger.E(e));
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.listenerScriptInstall();
|
this.listenerScriptInstall();
|
||||||
|
|
||||||
this.group.on("getInstallInfo", this.getInstallInfo);
|
this.group.on("getInstallInfo", this.getInstallInfo);
|
||||||
this.group.on("installScript", this.installScript.bind(this));
|
this.group.on("install", this.installScript.bind(this));
|
||||||
|
this.group.on("delete", this.deleteScript.bind(this));
|
||||||
|
this.group.on("enable", this.enableScript.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ function App() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new ScriptClient()
|
new ScriptClient()
|
||||||
.installScript(upsertScript as Script)
|
.install(upsertScript as Script)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
Message.success(t("install.update_success")!);
|
Message.success(t("install.update_success")!);
|
||||||
|
@ -68,10 +68,21 @@ import CloudScriptPlan from "@App/pages/components/CloudScriptPlan";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { nextTime, semTime } from "@App/pkg/utils/utils";
|
import { nextTime, semTime } from "@App/pkg/utils/utils";
|
||||||
import { i18nName } from "@App/locales/locales";
|
import { i18nName } from "@App/locales/locales";
|
||||||
import { ListHomeRender, ScriptIcons } from "./utils";
|
import { getValues, ListHomeRender, ScriptIcons } from "./utils";
|
||||||
import { useAppDispatch, useAppSelector } from "@App/store/hooks";
|
import { useAppDispatch, useAppSelector } from "@App/store/hooks";
|
||||||
import { fetchScriptList, selectScripts } from "@App/store/features/script";
|
import {
|
||||||
|
deleteScript,
|
||||||
|
requestEnableScript,
|
||||||
|
fetchAndSortScriptList,
|
||||||
|
requestDeleteScript,
|
||||||
|
ScriptLoading,
|
||||||
|
selectScripts,
|
||||||
|
sortScript,
|
||||||
|
upsertScript,
|
||||||
|
} from "@App/store/features/script";
|
||||||
import { selectScriptListColumnWidth } from "@App/store/features/setting";
|
import { selectScriptListColumnWidth } from "@App/store/features/setting";
|
||||||
|
import { Broker } from "@Packages/message/message_queue";
|
||||||
|
import { subscribeScriptDelete, subscribeScriptInstall } from "@App/app/service/service_worker/client";
|
||||||
|
|
||||||
type ListType = Script & { loading?: boolean };
|
type ListType = Script & { loading?: boolean };
|
||||||
|
|
||||||
@ -87,7 +98,7 @@ function ScriptList() {
|
|||||||
const scriptListColumnWidth = useAppSelector(selectScriptListColumnWidth);
|
const scriptListColumnWidth = useAppSelector(selectScriptListColumnWidth);
|
||||||
const inputRef = useRef<RefInputType>(null);
|
const inputRef = useRef<RefInputType>(null);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const openUserConfig = parseInt(useSearchParams()[0].get("userConfig") || "", 10);
|
const openUserConfig = useSearchParams()[0].get("userConfig") || "";
|
||||||
const [showAction, setShowAction] = useState(false);
|
const [showAction, setShowAction] = useState(false);
|
||||||
const [action, setAction] = useState("");
|
const [action, setAction] = useState("");
|
||||||
const [select, setSelect] = useState<Script[]>([]);
|
const [select, setSelect] = useState<Script[]>([]);
|
||||||
@ -96,9 +107,24 @@ function ScriptList() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchScriptList());
|
dispatch(fetchAndSortScriptList());
|
||||||
// 监听脚本安装/运行
|
// 监听脚本安装/运行
|
||||||
// Monitor script running status
|
const border = new Broker();
|
||||||
|
const subCon: chrome.runtime.Port[] = [];
|
||||||
|
|
||||||
|
subscribeScriptInstall(border, (message) => {
|
||||||
|
dispatch(upsertScript(message.script));
|
||||||
|
}).then((con) => subCon.push(con));
|
||||||
|
|
||||||
|
subscribeScriptDelete(border, (message) => {
|
||||||
|
dispatch(deleteScript(message.uuid));
|
||||||
|
}).then((con) => subCon.push(con));
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subCon.forEach((con) => {
|
||||||
|
con.disconnect();
|
||||||
|
});
|
||||||
|
};
|
||||||
// const channel = runtimeCtrl.watchRunStatus();
|
// const channel = runtimeCtrl.watchRunStatus();
|
||||||
// channel.setHandler(([id, status]: any) => {
|
// channel.setHandler(([id, status]: any) => {
|
||||||
// setScriptList((list) => {
|
// setScriptList((list) => {
|
||||||
@ -123,6 +149,9 @@ function ScriptList() {
|
|||||||
key: "#",
|
key: "#",
|
||||||
sorter: (a, b) => a.sort - b.sort,
|
sorter: (a, b) => a.sort - b.sort,
|
||||||
render(col) {
|
render(col) {
|
||||||
|
if (col < 0) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
return col + 1;
|
return col + 1;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -146,34 +175,14 @@ function ScriptList() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
onFilter: (value, row) => row.status === value,
|
onFilter: (value, row) => row.status === value,
|
||||||
render: (col, item: ListType) => {
|
render: (col, item: ScriptLoading) => {
|
||||||
return (
|
return (
|
||||||
<Switch
|
<Switch
|
||||||
checked={item.status === SCRIPT_STATUS_ENABLE}
|
checked={item.status === SCRIPT_STATUS_ENABLE}
|
||||||
loading={item.loading}
|
loading={item.enableLoading}
|
||||||
disabled={item.loading}
|
disabled={item.enableLoading}
|
||||||
onChange={(checked) => {
|
onChange={(checked) => {
|
||||||
// setScriptList((list) => {
|
dispatch(requestEnableScript({ uuid: item.uuid, enable: checked }));
|
||||||
// const index = list.findIndex((script) => script.id === item.id);
|
|
||||||
// list[index].loading = true;
|
|
||||||
// let p: Promise<any>;
|
|
||||||
// if (checked) {
|
|
||||||
// p = scriptCtrl.enable(item.id).then(() => {
|
|
||||||
// list[index].status = SCRIPT_STATUS_ENABLE;
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// p = scriptCtrl.disable(item.id).then(() => {
|
|
||||||
// list[index].status = SCRIPT_STATUS_DISABLE;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// p.catch((err) => {
|
|
||||||
// Message.error(err);
|
|
||||||
// }).finally(() => {
|
|
||||||
// list[index].loading = false;
|
|
||||||
// setScriptList([...list]);
|
|
||||||
// });
|
|
||||||
// return list;
|
|
||||||
// });
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -466,7 +475,7 @@ function ScriptList() {
|
|||||||
dataIndex: "action",
|
dataIndex: "action",
|
||||||
key: "action",
|
key: "action",
|
||||||
width: 160,
|
width: 160,
|
||||||
render(col, item: Script) {
|
render(col, item: ScriptLoading) {
|
||||||
return (
|
return (
|
||||||
<Button.Group>
|
<Button.Group>
|
||||||
<Link to={`/script/editor/${item.uuid}`}>
|
<Link to={`/script/editor/${item.uuid}`}>
|
||||||
@ -482,18 +491,13 @@ function ScriptList() {
|
|||||||
title={t("confirm_delete_script")}
|
title={t("confirm_delete_script")}
|
||||||
icon={<RiDeleteBin5Fill />}
|
icon={<RiDeleteBin5Fill />}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
// setScriptList((list) => {
|
dispatch(requestDeleteScript(item.uuid));
|
||||||
// return list.filter((i) => i.id !== item.id);
|
|
||||||
// });
|
|
||||||
// scriptCtrl.delete(item.id).catch((e) => {
|
|
||||||
// Message.error(`${t("delete_failed")}: ${e}`);
|
|
||||||
// });
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<RiDeleteBin5Fill />}
|
icon={<RiDeleteBin5Fill />}
|
||||||
onClick={() => {}}
|
loading={item.actionLoading}
|
||||||
style={{
|
style={{
|
||||||
color: "var(--color-text-2)",
|
color: "var(--color-text-2)",
|
||||||
}}
|
}}
|
||||||
@ -504,26 +508,29 @@ function ScriptList() {
|
|||||||
type="text"
|
type="text"
|
||||||
icon={<RiSettings3Fill />}
|
icon={<RiSettings3Fill />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Get value
|
getValues(item).then((newValues) => {
|
||||||
// getValues(item).then((newValues) => {
|
setUserConfig({
|
||||||
// setUserConfig({
|
userConfig: { ...item.config! },
|
||||||
// userConfig: { ...item.config! },
|
script: item,
|
||||||
// script: item,
|
values: newValues,
|
||||||
// values: newValues,
|
});
|
||||||
// });
|
});
|
||||||
// });
|
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
color: "var(--color-text-2)",
|
color: "var(--color-text-2)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{item.type !== SCRIPT_TYPE_NORMAL &&
|
{item.type !== SCRIPT_TYPE_NORMAL && (
|
||||||
(item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? (
|
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<RiStopFill />}
|
icon={item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? <RiStopFill /> : <RiPlayFill />}
|
||||||
|
loading={item.actionLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
if (item.runStatus === SCRIPT_RUN_STATUS_RUNNING) {
|
||||||
|
// Stop script
|
||||||
|
}
|
||||||
|
console.log(item.runStatus);
|
||||||
// Stop script
|
// Stop script
|
||||||
// Message.loading({
|
// Message.loading({
|
||||||
// id: "script-stop",
|
// id: "script-stop",
|
||||||
@ -540,37 +547,7 @@ function ScriptList() {
|
|||||||
color: "var(--color-text-2)",
|
color: "var(--color-text-2)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
)}
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<RiPlayFill />}
|
|
||||||
onClick={async () => {
|
|
||||||
// Start script
|
|
||||||
// Message.loading({
|
|
||||||
// id: "script-run",
|
|
||||||
// content: t("starting_script"),
|
|
||||||
// });
|
|
||||||
// await runtimeCtrl.startScript(item.id);
|
|
||||||
// Message.success({
|
|
||||||
// id: "script-run",
|
|
||||||
// content: t("script_started"),
|
|
||||||
// duration: 3000,
|
|
||||||
// });
|
|
||||||
// setScriptList((list) => {
|
|
||||||
// for (let i = 0; i < list.length; i += 1) {
|
|
||||||
// if (list[i].id === item.id) {
|
|
||||||
// list[i].runStatus = SCRIPT_RUN_STATUS_RUNNING;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return [...list];
|
|
||||||
// });
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: "var(--color-text-2)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{item.metadata.cloudcat && (
|
{item.metadata.cloudcat && (
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
@ -591,28 +568,20 @@ function ScriptList() {
|
|||||||
|
|
||||||
const [newColumns, setNewColumns] = useState<ColumnProps[]>([]);
|
const [newColumns, setNewColumns] = useState<ColumnProps[]>([]);
|
||||||
|
|
||||||
// 设置列和排序
|
// 设置列和判断是否打开用户配置
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// const dao = new ScriptDAO();
|
if (openUserConfig) {
|
||||||
// dao.table
|
const script = scriptList.find((item) => item.uuid === openUserConfig);
|
||||||
// .orderBy("sort")
|
if (script && script.config) {
|
||||||
// .toArray()
|
getValues(script).then((values) => {
|
||||||
// .then(async (scripts) => {
|
setUserConfig({
|
||||||
// // Sort when a new script is added (-1)
|
script,
|
||||||
// scriptListSort(scripts);
|
userConfig: script.config!,
|
||||||
// // Open user config panel
|
values: values,
|
||||||
// if (openUserConfig) {
|
});
|
||||||
// const script = scripts.find((item) => item.id === openUserConfig);
|
});
|
||||||
// if (script && script.config) {
|
}
|
||||||
// setUserConfig({
|
}
|
||||||
// script,
|
|
||||||
// userConfig: script.config,
|
|
||||||
// values: await getValues(script),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// setScriptList(scripts);
|
|
||||||
// });
|
|
||||||
setNewColumns(
|
setNewColumns(
|
||||||
columns.map((item) => {
|
columns.map((item) => {
|
||||||
item.width = scriptListColumnWidth[item.key!] ?? item.width;
|
item.width = scriptListColumnWidth[item.key!] ?? item.width;
|
||||||
@ -640,24 +609,21 @@ function ScriptList() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (active.id !== over.id) {
|
if (active.id !== over.id) {
|
||||||
// setScriptList((items) => {
|
console.log(active);
|
||||||
// let oldIndex = 0;
|
let oldIndex = 0;
|
||||||
// let newIndex = 0;
|
let newIndex = 0;
|
||||||
// items.forEach((item, index) => {
|
scriptList.forEach((item, index) => {
|
||||||
// if (item.id === active.id) {
|
if (item.uuid === active.id) {
|
||||||
// oldIndex = index;
|
oldIndex = index;
|
||||||
// } else if (item.id === over.id) {
|
} else if (item.uuid === over.id) {
|
||||||
// newIndex = index;
|
newIndex = index;
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// const newItems = arrayMove(items, oldIndex, newIndex);
|
dispatch(sortScript({ uuid: active.id as string, newIndex, oldIndex }));
|
||||||
// scriptListSort(newItems);
|
|
||||||
// return newItems;
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SortableContext items={scriptList} strategy={verticalListSortingStrategy}>
|
<SortableContext items={scriptList.map((s) => ({ ...s, id: s.uuid }))} strategy={verticalListSortingStrategy}>
|
||||||
<table ref={ref} {...props} />
|
<table ref={ref} {...props} />
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
@ -970,7 +936,7 @@ function ScriptList() {
|
|||||||
<Table
|
<Table
|
||||||
className="arco-drag-table-container"
|
className="arco-drag-table-container"
|
||||||
components={components}
|
components={components}
|
||||||
rowKey="id"
|
rowKey="uuid"
|
||||||
tableLayoutFixed
|
tableLayoutFixed
|
||||||
columns={dealColumns}
|
columns={dealColumns}
|
||||||
data={scriptList}
|
data={scriptList}
|
||||||
|
@ -148,7 +148,7 @@ export function ListHomeRender({ script }: { script: Script }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getValues(script: Script) {
|
export function getValues(script: Script) {
|
||||||
return {};
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ScriptIconsProps = {
|
export type ScriptIconsProps = {
|
||||||
|
@ -1,3 +1,23 @@
|
|||||||
function main() {}
|
import LoggerCore from "./app/logger/core";
|
||||||
|
import DBWriter from "./app/logger/db_writer";
|
||||||
|
import MessageWriter from "./app/logger/message_writer";
|
||||||
|
import { LoggerDAO } from "./app/repo/logger";
|
||||||
|
import { OffscreenManager } from "./app/service/offscreen";
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
// 建立与offscreen页面的连接
|
||||||
|
|
||||||
|
// 初始化日志组件
|
||||||
|
const loggerCore = new LoggerCore({
|
||||||
|
debug: process.env.NODE_ENV === "development",
|
||||||
|
writer: new MessageWriter(connectSandbox),
|
||||||
|
labels: { env: "sandbox" },
|
||||||
|
});
|
||||||
|
loggerCore.logger().debug("offscreen start");
|
||||||
|
|
||||||
|
// 初始化管理器
|
||||||
|
const manager = new OffscreenManager();
|
||||||
|
manager.initManager();
|
||||||
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
@ -1,31 +1,99 @@
|
|||||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
import { createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { createAppSlice } from "../hooks";
|
import { createAppSlice } from "../hooks";
|
||||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
import { Script, SCRIPT_STATUS_DISABLE, SCRIPT_STATUS_ENABLE, ScriptDAO } from "@App/app/repo/scripts";
|
||||||
|
import { arrayMove } from "@dnd-kit/sortable";
|
||||||
|
import { ScriptClient } from "@App/app/service/service_worker/client";
|
||||||
|
|
||||||
export const fetchScriptList = createAsyncThunk("script/fetchScriptList", () => {
|
export const fetchAndSortScriptList = createAsyncThunk("script/fetchScriptList", async () => {
|
||||||
return new ScriptDAO().all();
|
// 排序
|
||||||
|
const dao = new ScriptDAO();
|
||||||
|
const scripts = await dao.all();
|
||||||
|
scripts.sort((a, b) => a.sort - b.sort);
|
||||||
|
for (let i = 0; i < scripts.length; i += 1) {
|
||||||
|
if (scripts[i].sort !== i) {
|
||||||
|
dao.update(scripts[i].uuid, { sort: i });
|
||||||
|
scripts[i].sort = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scripts;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const requestEnableScript = createAsyncThunk(
|
||||||
|
"script/enableScript",
|
||||||
|
(param: { uuid: string; enable: boolean }) => {
|
||||||
|
return new ScriptClient().enable(param.uuid, param.enable);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const requestDeleteScript = createAsyncThunk("script/deleteScript", async (uuid: string) => {
|
||||||
|
return new ScriptClient().delete(uuid);
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ScriptLoading = Script & { enableLoading?: boolean; actionLoading?: boolean };
|
||||||
|
|
||||||
|
const updateScript = (scripts: ScriptLoading[], uuid: string, update: (s: ScriptLoading) => void) => {
|
||||||
|
const script = scripts.find((s) => s.uuid === uuid);
|
||||||
|
if (script) {
|
||||||
|
update(script);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const scriptSlice = createAppSlice({
|
export const scriptSlice = createAppSlice({
|
||||||
name: "script",
|
name: "script",
|
||||||
initialState: {
|
initialState: {
|
||||||
scripts: [] as Script[],
|
scripts: [] as ScriptLoading[],
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
upsertScript: (state, action: PayloadAction<Script>) => {
|
||||||
|
const script = state.scripts.find((s) => s.uuid === action.payload.uuid);
|
||||||
|
if (script) {
|
||||||
|
Object.assign(script, action.payload);
|
||||||
|
} else {
|
||||||
|
// 放到第一
|
||||||
|
state.scripts.splice(0, 0, action.payload);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteScript: (state, action: PayloadAction<string>) => {
|
||||||
|
state.scripts = state.scripts.filter((s) => s.uuid !== action.payload);
|
||||||
|
},
|
||||||
|
sortScript: (state, action: PayloadAction<{ uuid: string; newIndex: number; oldIndex: number }>) => {
|
||||||
|
const dao = new ScriptDAO();
|
||||||
|
const newItems = arrayMove(state.scripts, action.payload.oldIndex, action.payload.newIndex);
|
||||||
|
for (let i = 0; i < state.scripts.length; i += 1) {
|
||||||
|
if (newItems[i].sort !== i) {
|
||||||
|
dao.update(newItems[i].uuid, { sort: i });
|
||||||
|
newItems[i].sort = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.scripts = newItems;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
reducers: {},
|
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(fetchScriptList.fulfilled, (state, action) => {
|
builder
|
||||||
const newScripts: Script[] = [];
|
.addCase(fetchAndSortScriptList.fulfilled, (state, action) => {
|
||||||
action.payload.forEach((item) => {
|
state.scripts = action.payload;
|
||||||
newScripts.push(item);
|
})
|
||||||
});
|
.addCase(requestEnableScript.fulfilled, (state, action) => {
|
||||||
state.scripts = newScripts;
|
updateScript(state.scripts, action.meta.arg.uuid, (script) => {
|
||||||
|
script.enableLoading = false;
|
||||||
|
script.status = action.meta.arg.enable ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE;
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.addCase(requestEnableScript.pending, (state, action) =>
|
||||||
|
updateScript(state.scripts, action.meta.arg.uuid, (s) => (s.enableLoading = true))
|
||||||
|
)
|
||||||
|
.addCase(requestDeleteScript.fulfilled, (state, action) => {
|
||||||
|
state.scripts = state.scripts.filter((s) => s.uuid !== action.meta.arg);
|
||||||
|
})
|
||||||
|
.addCase(requestDeleteScript.pending, (state, action) =>
|
||||||
|
updateScript(state.scripts, action.meta.arg, (s) => (s.actionLoading = true))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
selectors: {
|
selectors: {
|
||||||
selectScripts: (state) => state.scripts,
|
selectScripts: (state) => state.scripts,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// export const {} = scriptSlice.actions;
|
export const { sortScript, upsertScript, deleteScript } = scriptSlice.actions;
|
||||||
|
|
||||||
export const { selectScripts } = scriptSlice.selectors;
|
export const { selectScripts } = scriptSlice.selectors;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user