diff --git a/back/services/schedule.ts b/back/services/schedule.ts index 2eefb87d..8f7073c2 100644 --- a/back/services/schedule.ts +++ b/back/services/schedule.ts @@ -1,5 +1,6 @@ import { Service, Inject } from 'typedi'; import winston from 'winston'; +import { Connection } from 'sockjs'; import nodeSchedule from 'node-schedule'; import { ChildProcessWithoutNullStreams } from 'child_process'; import { @@ -33,6 +34,7 @@ export interface TaskCallbacks { ) => Promise; onLog?: (message: string) => Promise; onError?: (message: string) => Promise; + onMessage?:(cb:(msg:string,conn:Connection)=>void)=>void; } @Service() @@ -120,6 +122,10 @@ export default class ScheduleService { ); resolve({ ...others, pid: cp.pid, code }); }); + + callbacks.onMessage?.((msg:string,conn:Connection)=>{ + cp.stdin.write(JSON.parse(msg).message) + }) } catch (error) { this.logger.error( '[panel][执行任务失败] 命令: %s, 错误信息: %j', diff --git a/back/services/script.ts b/back/services/script.ts index d7551084..92d1d70f 100644 --- a/back/services/script.ts +++ b/back/services/script.ts @@ -1,4 +1,5 @@ import { Service, Inject } from 'typedi'; +import { Connection } from 'sockjs'; import winston from 'winston'; import path, { join } from 'path'; import SockService from './sock'; @@ -22,6 +23,7 @@ export default class ScriptService { return { onEnd: async (cp, endTime, diff) => { await rmPath(filePath); + this.sockService.removeAllListeners('message') }, onError: async (message: string) => { this.sockService.sendMessage({ @@ -35,6 +37,10 @@ export default class ScriptService { message, }); }, + onMessage:(cb:(msg:string,conn:Connection)=>void)=>{ + this.sockService.off('message',cb) + this.sockService.on('message',cb) + }, }; } diff --git a/back/services/sock.ts b/back/services/sock.ts index b09a43bb..a9c6d166 100644 --- a/back/services/sock.ts +++ b/back/services/sock.ts @@ -2,12 +2,15 @@ import { Service, Inject } from 'typedi'; import winston from 'winston'; import { Connection } from 'sockjs'; import { SockMessage } from '../data/sock'; +import EventEmitter from 'events'; @Service() -export default class SockService { +export default class SockService extends EventEmitter{ private clients: Connection[] = []; - constructor(@Inject('logger') private logger: winston.Logger) { } + constructor(@Inject('logger') private logger: winston.Logger) { + super() + } public getClients() { return this.clients; @@ -16,11 +19,17 @@ export default class SockService { public addClient(conn: Connection) { if (this.clients.indexOf(conn) === -1) { this.clients.push(conn); + + conn.on('data',(msg:string)=>{ + this.emit('message',msg,conn) + }); } } public removeClient(conn: Connection) { const index = this.clients.indexOf(conn); + conn.removeAllListeners('data') + if (index !== -1) { this.clients.splice(index, 1); } diff --git a/src/locales/en-US.json b/src/locales/en-US.json index f0d3aeba..12d4687c 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -486,5 +486,7 @@ "NPM 镜像源": "NPM Mirror Source", "PyPI 镜像源": "PyPI Mirror Source", "alpine linux 镜像源": "Alpine Linux Mirror Source", - "如果恢复失败,可进入容器执行": "If recovery fails, you can enter the container and execute" + "如果恢复失败,可进入容器执行": "If recovery fails, you can enter the container and execute", + "终端输入": "terminal input", + "发送": "send" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index c7f67d6d..90fdb32c 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -486,5 +486,7 @@ "NPM 镜像源": "NPM 镜像源", "PyPI 镜像源": "PyPI 镜像源", "alpine linux 镜像源": "alpine linux 镜像源", - "如果恢复失败,可进入容器执行": "如果恢复失败,可进入容器执行" + "如果恢复失败,可进入容器执行": "如果恢复失败,可进入容器执行", + "终端输入": "终端输入", + "发送": "发送" } diff --git a/src/pages/script/editModal.tsx b/src/pages/script/editModal.tsx index ef7d4eea..97c04e4e 100644 --- a/src/pages/script/editModal.tsx +++ b/src/pages/script/editModal.tsx @@ -6,7 +6,7 @@ import React, { useCallback, useReducer, } from 'react'; -import { Drawer, Button, Tabs, Badge, Select, TreeSelect } from 'antd'; +import { Drawer, Button, Tabs, Badge, Select, TreeSelect, Input } from 'antd'; import { request } from '@/utils/http'; import config from '@/utils/config'; import SplitPane from 'react-split-pane'; @@ -41,6 +41,7 @@ const EditModal = ({ const [settingModalVisible, setSettingModalVisible] = useState(false); const [log, setLog] = useState(''); + const [raw, setRaw] = useState('') const { theme } = useTheme(); const editorRef = useRef(null); const [isRunning, setIsRunning] = useState(false); @@ -124,6 +125,12 @@ const EditModal = ({ setLog((p) => `${p}${_message}`); }, []); + const send=()=>{ + const ws = WebSocketManager.getInstance(); + ws.send({ type:'terminalInput', message:raw }) + setRaw('') + } + useEffect(() => { const ws = WebSocketManager.getInstance(); ws.subscribe('manuallyRunScript', handleMessage); @@ -253,6 +260,12 @@ const EditModal = ({ padding: '0 15px', }} > +
+ { + setRaw(e.target.value) + }}> + +
{log} diff --git a/src/utils/type.ts b/src/utils/type.ts index ab13e686..1e5db608 100644 --- a/src/utils/type.ts +++ b/src/utils/type.ts @@ -7,4 +7,5 @@ export type SockMessageType = | 'runSubscriptionEnd' | 'reloadSystem' | 'updateNodeMirror' - | 'updateLinuxMirror'; + | 'updateLinuxMirror' + | 'terminalInput';