新增 直接与守护进程WS连接功能

This commit is contained in:
Suwings 2021-07-16 20:06:31 +08:00
parent b78e4e1a21
commit 415240b128
5 changed files with 96 additions and 10 deletions

View File

@ -1,7 +1,7 @@
/*
* @Author: Copyright(c) 2020 Suwings
* @Date: 2020-11-23 17:45:02
* @LastEditTime: 2021-07-15 22:50:51
* @LastEditTime: 2021-07-16 19:00:10
* @Description: Daemon service startup file
*/
@ -65,7 +65,13 @@ const io = new Server(httpServer, {
serveClient: false,
pingInterval: 3000,
pingTimeout: 5000,
cookie: false
cookie: false,
path: "/socket.io",
cors: {
origin: "*",
methods: ["GET", "POST"],
credentials: true
}
});
// 初始化应用实例系统 & 装载应用实例

View File

@ -1,7 +1,7 @@
/*
* @Author: Copyright(c) 2020 Suwings
* @Date: 2020-11-23 17:45:02
* @LastEditTime: 2021-06-21 18:12:27
* @LastEditTime: 2021-07-16 16:59:19
* @Description:
* @Projcet: MCSManager Daemon
* @License: MIT
@ -16,7 +16,9 @@ import RouterContext from "../entity/ctx";
// 权限认证中间件
routerApp.use((event, ctx, _, next) => {
const socket = ctx.socket;
// 除 auth 控制器是公开访问,其他控制器必须得到授权才可访问
// 放行所有数据流控制器
if (event.startsWith("stream")) return next();
// 除 auth 控制器是公开访问,其他业务控制器必须得到授权才可访问
if (event === "auth") return next();
if (!ctx.session) throw new Error("Session does not exist in authentication middleware.");
// 若未验证则阻止除 auth 事件外的所有事件
@ -53,7 +55,7 @@ routerApp.on("auth", (ctx, data) => {
});
// 登录成功后必须执行此函数
function loginSuccessful(ctx: RouterContext, data: any) {
function loginSuccessful(ctx: RouterContext, data: string) {
ctx.session.key = data;
ctx.session.login = true;
ctx.session.id = ctx.socket.id;

View File

@ -1,7 +1,7 @@
/*
* @Author: Copyright(c) 2020 Suwings
* @Date: 2020-11-23 17:45:02
* @LastEditTime: 2021-07-02 19:38:02
* @LastEditTime: 2021-07-16 20:06:11
* @Description:
* @Projcet: MCSManager Daemon
* @License: MIT
@ -23,6 +23,7 @@ InstanceSubsystem.on("data", (instanceUuid: string, text: string) => {
// 实例退出事件
InstanceSubsystem.on("exit", (obj: any) => {
// 警告,重构后的广播是不安全的
protocol.broadcast("instance/stopped", {
instanceUuid: obj.instanceUuid,
instanceName: obj.instanceName

View File

@ -0,0 +1,76 @@
/*
* @Author: Copyright(c) 2020 Suwings
* @Date: 2021-06-22 22:44:06
* @LastEditTime: 2021-07-16 19:25:05
* @Description:
* @Projcet: MCSManager Daemon
* @License: MIT
*/
import * as protocol from "../service/protocol";
import { routerApp } from "../service/router";
import { missionPassport } from "../service/mission_passport";
import InstanceSubsystem from "../service/system_instance";
import logger from '../service/log';
import SendCommand from '../entity/commands/cmd';
// 权限认证中间件
routerApp.use((event, ctx, data, next) => {
// 放行数据流身份验证路由
if (event === "stream/auth") return next();
// 检查数据流其他路由
if (event.startsWith("stream")) {
if (ctx.session.stream && ctx.session.stream.check === true) {
return next();
}
return protocol.error(ctx, "error", "权限不足,非法访问");
}
next();
});
// 可公开访问数据流身份验证路由
routerApp.on("stream/auth", (ctx, data) => {
try {
const password = data.password;
const mission = missionPassport.getMission(password, "stream_channel");
if (!mission) throw new Error("任务不存在");
// 实例UUID参数必须来自于任务参数不可直接使用
const instance = InstanceSubsystem.getInstance(mission.parameter.instanceUuid);
if (!instance) throw new Error("实例不存在");
// 加入数据流认证标识
logger.info(`会话 ${ctx.socket.id} ${ctx.socket.handshake.address} 数据流通道身份验证成功`);
ctx.session.stream = {
check: true,
instanceUuid: instance.instanceUuid
};
// 开始向此 Socket 转发输出流数据
InstanceSubsystem.forward(instance.instanceUuid, ctx.socket);
logger.info(`会话 ${ctx.socket.id} ${ctx.socket.handshake.address} 已与 ${instance.instanceUuid} 建立数据通道`);
// 注册断开时取消转发事件
ctx.socket.on("disconnect", () => {
InstanceSubsystem.stopForward(instance.instanceUuid, ctx.socket);
logger.info(`会话 ${ctx.socket.id} ${ctx.socket.handshake.address} 已与 ${instance.instanceUuid} 断开数据通道`);
});
protocol.response(ctx, true);
} catch (error) {
protocol.responseError(ctx, error);
}
});
// 列出指定实例工作目录的文件列表
routerApp.on("stream/input", (ctx, data) => {
try {
const command = data.command;
const instanceUuid = ctx.session.stream.instanceUuid;
const instance = InstanceSubsystem.getInstance(instanceUuid);
instance.exec(new SendCommand(command));
} catch (error) {
protocol.responseError(ctx, error);
}
});

View File

@ -1,7 +1,7 @@
/*
* @Author: Copyright(c) 2020 Suwings
* @Date: 2020-11-23 17:45:02
* @LastEditTime: 2021-07-16 15:28:47
* @LastEditTime: 2021-07-16 19:32:02
* @Description: Route navigator, used to analyze the Socket.io protocol and encapsulate and forward to a custom route
* @Projcet: MCSManager Daemon
* @License: MIT
@ -54,8 +54,8 @@ export function navigation(socket: Socket) {
// Register all middleware with Socket
for (const fn of routerApp.getMiddlewares()) {
socket.use((packet, next) => {
const protocol = packet[1];
if (!protocol) return logger.info(`session $(socket.id) request data protocol format is incorrect`);
const protocol = packet[1] as IPacket;
if (!protocol) return logger.info(`session ${socket.id} request data protocol format is incorrect`);
const ctx = new RouterContext(protocol.uuid, socket, session);
fn(packet[0], ctx, protocol.data, next);
});
@ -63,7 +63,7 @@ export function navigation(socket: Socket) {
// Register all events with Socket
for (const event of routerApp.eventNames()) {
socket.on(event, (protocol: IPacket) => {
if (!protocol) return logger.info(`session $(socket.id) request data protocol format is incorrect`);
if (!protocol) return logger.info(`session ${socket.id} request data protocol format is incorrect`);
const ctx = new RouterContext(protocol.uuid, socket, session, event.toString());
routerApp.emitRouter(event as string, ctx, protocol.data);
});
@ -78,5 +78,6 @@ import "../routers/passport_router";
import "../routers/Instance_router";
import "../routers/instance_event_router";
import "../routers/file_router";
import "../routers/stream_router";
logger.info(`Complete. Total routing controller ${routerApp.eventNames().length}, middleware ${routerApp.middlewares.length}.`);