【m】消息接收发送

This commit is contained in:
2026-04-11 00:03:30 +08:00
parent e9b7070219
commit 59d4105ed3
29 changed files with 258 additions and 834 deletions

2
.gitignore vendored
View File

@@ -74,3 +74,5 @@ xosmoRes
HybridCLRData HybridCLRData
ARMazModuleData/Modules ARMazModuleData/Modules
ARMazModuleData/Packages ARMazModuleData/Packages
WebApp/node_modules
WebApp/build

View File

@@ -1,11 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Answer = /** @class */ (function () {
function Answer(sdp, datetime) {
this.sdp = sdp;
this.datetime = datetime;
}
return Answer;
}());
exports.default = Answer;
//# sourceMappingURL=answer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/class/answer.ts"],"names":[],"mappings":";;AAAA;IAGE,gBAAY,GAAW,EAAE,QAAgB;QACvC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IACH,aAAC;AAAD,CAAC,AAPD,IAOC"}

View File

@@ -1,13 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Candidate = /** @class */ (function () {
function Candidate(candidate, sdpMLineIndex, sdpMid, datetime) {
this.candidate = candidate;
this.sdpMLineIndex = sdpMLineIndex;
this.sdpMid = sdpMid;
this.datetime = datetime;
}
return Candidate;
}());
exports.default = Candidate;
//# sourceMappingURL=candidate.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"candidate.js","sourceRoot":"","sources":["../../src/class/candidate.ts"],"names":[],"mappings":";;AAAA;IAKE,mBAAY,SAAiB,EAAE,aAAqB,EAAE,MAAc,EAAE,QAAgB;QACpF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IACH,gBAAC;AAAD,CAAC,AAXD,IAWC"}

View File

@@ -1,372 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.postCandidate = exports.postAnswer = exports.postOffer = exports.deleteConnection = exports.createConnection = exports.deleteSession = exports.createSession = exports.getCandidate = exports.getAnswer = exports.getOffer = exports.getConnection = exports.getAll = exports.checkSessionId = exports.reset = void 0;
var offer_1 = require("./offer");
var answer_1 = require("./answer");
var candidate_1 = require("./candidate");
var uuid_1 = require("uuid");
var Disconnection = /** @class */ (function () {
function Disconnection(id, datetime) {
this.id = id;
this.datetime = datetime;
}
return Disconnection;
}());
var TimeoutRequestedTime = 10000; // 10sec
var isPrivate;
// [{sessonId:[connectionId,...]}]
var clients = new Map();
// [{sessonId:Date}]
var lastRequestedTime = new Map();
// [{connectionId:[sessionId1, sessionId2]}]
var connectionPair = new Map(); // key = connectionId
// [{sessionId:[{connectionId:Offer},...]}]
var offers = new Map(); // key = sessionId
// [{sessionId:[{connectionId:Answer},...]}]
var answers = new Map(); // key = sessionId
// [{sessionId:[{connectionId:Candidate},...]}]
var candidates = new Map(); // key = sessionId
// [{sessionId:[Disconnection,...]}]
var disconnections = new Map(); // key = sessionId
function getOrCreateConnectionIds(sessionId) {
var connectionIds = null;
if (!clients.has(sessionId)) {
connectionIds = new Set();
clients.set(sessionId, connectionIds);
}
connectionIds = clients.get(sessionId);
return connectionIds;
}
function reset(mode) {
isPrivate = mode == "private";
clients.clear();
connectionPair.clear();
offers.clear();
answers.clear();
candidates.clear();
disconnections.clear();
}
exports.reset = reset;
function checkSessionId(req, res, next) {
if (req.url === '/') {
next();
return;
}
var id = req.header('session-id');
if (!clients.has(id)) {
res.sendStatus(404);
return;
}
lastRequestedTime.set(id, Date.now());
next();
}
exports.checkSessionId = checkSessionId;
function _deleteConnection(sessionId, connectionId, datetime) {
clients.get(sessionId).delete(connectionId);
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
var otherSessionId = pair[0] == sessionId ? pair[1] : pair[0];
if (otherSessionId) {
if (clients.has(otherSessionId)) {
clients.get(otherSessionId).delete(connectionId);
var array1 = disconnections.get(otherSessionId);
array1.push(new Disconnection(connectionId, datetime));
}
}
}
}
else {
disconnections.forEach(function (array, id) {
if (id == sessionId)
return;
array.push(new Disconnection(connectionId, datetime));
});
}
connectionPair.delete(connectionId);
offers.get(sessionId).delete(connectionId);
answers.get(sessionId).delete(connectionId);
candidates.get(sessionId).delete(connectionId);
var array2 = disconnections.get(sessionId);
array2.push(new Disconnection(connectionId, datetime));
}
function _deleteSession(sessionId) {
if (clients.has(sessionId)) {
for (var _i = 0, _a = Array.from(clients.get(sessionId)); _i < _a.length; _i++) {
var connectionId = _a[_i];
_deleteConnection(sessionId, connectionId, Date.now());
}
}
offers.delete(sessionId);
answers.delete(sessionId);
candidates.delete(sessionId);
clients.delete(sessionId);
disconnections.delete(sessionId);
}
function _checkForTimedOutSessions() {
for (var _i = 0, _a = Array.from(clients.keys()); _i < _a.length; _i++) {
var sessionId = _a[_i];
if (!lastRequestedTime.has(sessionId))
continue;
if (lastRequestedTime.get(sessionId) > Date.now() - TimeoutRequestedTime)
continue;
_deleteSession(sessionId);
console.log("deleted sessionId:".concat(sessionId, " by timeout."));
}
}
function _getConnection(sessionId) {
_checkForTimedOutSessions();
return Array.from(clients.get(sessionId));
}
function _getDisconnection(sessionId, fromTime) {
_checkForTimedOutSessions();
var arrayDisconnections = [];
if (disconnections.size != 0 && disconnections.has(sessionId)) {
arrayDisconnections = disconnections.get(sessionId);
}
if (fromTime > 0) {
arrayDisconnections = arrayDisconnections.filter(function (v) { return v.datetime >= fromTime; });
}
return arrayDisconnections;
}
function _getOffer(sessionId, fromTime) {
var arrayOffers = [];
if (offers.size != 0) {
if (isPrivate) {
if (offers.has(sessionId)) {
arrayOffers = Array.from(offers.get(sessionId));
}
}
else {
var otherSessionMap = Array.from(offers).filter(function (x) { return x[0] != sessionId; });
arrayOffers = [].concat.apply([], Array.from(otherSessionMap, function (x) { return Array.from(x[1], function (y) { return [y[0], y[1]]; }); }));
}
}
if (fromTime > 0) {
arrayOffers = arrayOffers.filter(function (v) { return v[1].datetime >= fromTime; });
}
return arrayOffers;
}
function _getAnswer(sessionId, fromTime) {
var arrayAnswers = [];
if (answers.size != 0 && answers.has(sessionId)) {
arrayAnswers = Array.from(answers.get(sessionId));
}
if (fromTime > 0) {
arrayAnswers = arrayAnswers.filter(function (v) { return v[1].datetime >= fromTime; });
}
return arrayAnswers;
}
function _getCandidate(sessionId, fromTime) {
var connectionIds = Array.from(clients.get(sessionId));
var arr = [];
for (var _i = 0, connectionIds_1 = connectionIds; _i < connectionIds_1.length; _i++) {
var connectionId = connectionIds_1[_i];
var pair = connectionPair.get(connectionId);
if (pair == null) {
continue;
}
var otherSessionId = sessionId === pair[0] ? pair[1] : pair[0];
if (!candidates.get(otherSessionId) || !candidates.get(otherSessionId).get(connectionId)) {
continue;
}
var arrayCandidates = candidates.get(otherSessionId).get(connectionId)
.filter(function (v) { return v.datetime >= fromTime; });
if (arrayCandidates.length === 0) {
continue;
}
for (var _a = 0, arrayCandidates_1 = arrayCandidates; _a < arrayCandidates_1.length; _a++) {
var candidate = arrayCandidates_1[_a];
arr.push([connectionId, candidate]);
}
}
return arr;
}
function getAnswer(req, res) {
// get `fromtime` parameter from request query
var fromTime = req.query.fromtime ? Number(req.query.fromtime) : 0;
var sessionId = req.header('session-id');
var answers = _getAnswer(sessionId, fromTime);
res.json({ answers: answers.map(function (v) { return ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime }); }) });
}
exports.getAnswer = getAnswer;
function getConnection(req, res) {
// get `fromtime` parameter from request query
var sessionId = req.header('session-id');
var connections = _getConnection(sessionId);
res.json({ connections: connections.map(function (v) { return ({ connectionId: v, type: "connect", datetime: Date.now() }); }) });
}
exports.getConnection = getConnection;
function getOffer(req, res) {
// get `fromtime` parameter from request query
var fromTime = req.query.fromtime ? Number(req.query.fromtime) : 0;
var sessionId = req.header('session-id');
var offers = _getOffer(sessionId, fromTime);
res.json({ offers: offers.map(function (v) { return ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime }); }) });
}
exports.getOffer = getOffer;
function getCandidate(req, res) {
// get `fromtime` parameter from request query
var fromTime = req.query.fromtime ? Number(req.query.fromtime) : 0;
var sessionId = req.header('session-id');
var candidates = _getCandidate(sessionId, fromTime);
res.json({ candidates: candidates.map(function (v) { return ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime }); }) });
}
exports.getCandidate = getCandidate;
function getAll(req, res) {
var fromTime = req.query.fromtime ? Number(req.query.fromtime) : 0;
var sessionId = req.header('session-id');
var connections = _getConnection(sessionId);
var offers = _getOffer(sessionId, fromTime);
var answers = _getAnswer(sessionId, fromTime);
var candidates = _getCandidate(sessionId, fromTime);
var disconnections = _getDisconnection(sessionId, fromTime);
var datetime = lastRequestedTime.get(sessionId);
var array = [];
array = array.concat(connections.map(function (v) { return ({ connectionId: v, type: "connect", datetime: datetime }); }));
array = array.concat(offers.map(function (v) { return ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime }); }));
array = array.concat(answers.map(function (v) { return ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime }); }));
array = array.concat(candidates.map(function (v) { return ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime }); }));
array = array.concat(disconnections.map(function (v) { return ({ connectionId: v.id, type: "disconnect", datetime: v.datetime }); }));
array.sort(function (a, b) { return a.datetime - b.datetime; });
res.json({ messages: array, datetime: datetime });
}
exports.getAll = getAll;
function createSession(req, res) {
var sessionId = typeof req === "string" ? req : (0, uuid_1.v4)();
clients.set(sessionId, new Set());
offers.set(sessionId, new Map());
answers.set(sessionId, new Map());
candidates.set(sessionId, new Map());
disconnections.set(sessionId, []);
res.json({ sessionId: sessionId });
}
exports.createSession = createSession;
function deleteSession(req, res) {
var id = req.header('session-id');
_deleteSession(id);
res.sendStatus(200);
}
exports.deleteSession = deleteSession;
function createConnection(req, res) {
var sessionId = req.header('session-id');
var connectionId = req.body.connectionId;
var datetime = lastRequestedTime.get(sessionId);
if (connectionId == null) {
res.status(400).send({ error: new Error("connectionId is required") });
return;
}
var polite = true;
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
if (pair[0] != null && pair[1] != null) {
var err = new Error("".concat(connectionId, ": This connection id is already used."));
console.log(err);
res.status(400).send({ error: err });
return;
}
else if (pair[0] != null) {
connectionPair.set(connectionId, [pair[0], sessionId]);
var map = getOrCreateConnectionIds(pair[0]);
map.add(connectionId);
}
}
else {
connectionPair.set(connectionId, [sessionId, null]);
polite = false;
}
}
var connectionIds = getOrCreateConnectionIds(sessionId);
connectionIds.add(connectionId);
res.json({ connectionId: connectionId, polite: polite, type: "connect", datetime: datetime });
}
exports.createConnection = createConnection;
function deleteConnection(req, res) {
var sessionId = req.header('session-id');
var connectionId = req.body.connectionId;
var datetime = lastRequestedTime.get(sessionId);
_deleteConnection(sessionId, connectionId, datetime);
res.json({ connectionId: connectionId });
}
exports.deleteConnection = deleteConnection;
function postOffer(req, res) {
var sessionId = req.header('session-id');
var connectionId = req.body.connectionId;
var datetime = lastRequestedTime.get(sessionId);
var keySessionId = null;
var polite = false;
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
keySessionId = pair[0] == sessionId ? pair[1] : pair[0];
if (keySessionId != null) {
polite = true;
var map_1 = offers.get(keySessionId);
map_1.set(connectionId, new offer_1.default(req.body.sdp, datetime, polite));
}
}
res.sendStatus(200);
return;
}
if (!connectionPair.has(connectionId)) {
connectionPair.set(connectionId, [sessionId, null]);
}
keySessionId = sessionId;
var map = offers.get(keySessionId);
map.set(connectionId, new offer_1.default(req.body.sdp, datetime, polite));
res.sendStatus(200);
}
exports.postOffer = postOffer;
function postAnswer(req, res) {
var sessionId = req.header('session-id');
var connectionId = req.body.connectionId;
var datetime = lastRequestedTime.get(sessionId);
var connectionIds = getOrCreateConnectionIds(sessionId);
connectionIds.add(connectionId);
if (!connectionPair.has(connectionId)) {
res.sendStatus(200);
return;
}
// add connectionPair
var pair = connectionPair.get(connectionId);
var otherSessionId = pair[0] == sessionId ? pair[1] : pair[0];
if (!clients.has(otherSessionId)) {
// already deleted
res.sendStatus(200);
return;
}
if (!isPrivate) {
connectionPair.set(connectionId, [otherSessionId, sessionId]);
}
var map = answers.get(otherSessionId);
map.set(connectionId, new answer_1.default(req.body.sdp, datetime));
// update datetime for candidates
var mapCandidates = candidates.get(otherSessionId);
if (mapCandidates) {
var arrayCandidates = mapCandidates.get(connectionId);
if (arrayCandidates) {
for (var _i = 0, arrayCandidates_2 = arrayCandidates; _i < arrayCandidates_2.length; _i++) {
var candidate = arrayCandidates_2[_i];
candidate.datetime = datetime;
}
}
}
res.sendStatus(200);
}
exports.postAnswer = postAnswer;
function postCandidate(req, res) {
var sessionId = req.header('session-id');
var connectionId = req.body.connectionId;
var datetime = lastRequestedTime.get(sessionId);
var map = candidates.get(sessionId);
if (!map.has(connectionId)) {
map.set(connectionId, []);
}
var arr = map.get(connectionId);
var candidate = new candidate_1.default(req.body.candidate, req.body.sdpMLineIndex, req.body.sdpMid, datetime);
arr.push(candidate);
res.sendStatus(200);
}
exports.postCandidate = postCandidate;
//# sourceMappingURL=httphandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Offer = /** @class */ (function () {
function Offer(sdp, datetime, polite) {
this.sdp = sdp;
this.datetime = datetime;
this.polite = polite;
}
return Offer;
}());
exports.default = Offer;
//# sourceMappingURL=offer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"offer.js","sourceRoot":"","sources":["../../src/class/offer.ts"],"names":[],"mappings":";;AAAA;IAIE,eAAY,GAAW,EAAE,QAAgB,EAAE,MAAe;QACxD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IACH,YAAC;AAAD,CAAC,AATD,IASC"}

View File

@@ -1,3 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=options.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/class/options.ts"],"names":[],"mappings":""}

View File

@@ -1,141 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onCandidate = exports.onAnswer = exports.onOffer = exports.onDisconnect = exports.onConnect = exports.remove = exports.add = exports.reset = void 0;
var offer_1 = require("./offer");
var answer_1 = require("./answer");
var candidate_1 = require("./candidate");
var isPrivate;
// [{sessonId:[connectionId,...]}]
var clients = new Map();
// [{connectionId:[sessionId1, sessionId2]}]
var connectionPair = new Map();
function getOrCreateConnectionIds(session) {
var connectionIds = null;
if (!clients.has(session)) {
connectionIds = new Set();
clients.set(session, connectionIds);
}
connectionIds = clients.get(session);
return connectionIds;
}
function reset(mode) {
isPrivate = mode == "private";
}
exports.reset = reset;
function add(ws) {
clients.set(ws, new Set());
}
exports.add = add;
function remove(ws) {
var connectionIds = clients.get(ws);
connectionIds.forEach(function (connectionId) {
var pair = connectionPair.get(connectionId);
if (pair) {
var otherSessionWs = pair[0] == ws ? pair[1] : pair[0];
if (otherSessionWs) {
otherSessionWs.send(JSON.stringify({ type: "disconnect", connectionId: connectionId }));
}
}
connectionPair.delete(connectionId);
});
clients.delete(ws);
}
exports.remove = remove;
function onConnect(ws, connectionId) {
var polite = true;
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
if (pair[0] != null && pair[1] != null) {
ws.send(JSON.stringify({ type: "error", message: "".concat(connectionId, ": This connection id is already used.") }));
return;
}
else if (pair[0] != null) {
connectionPair.set(connectionId, [pair[0], ws]);
}
}
else {
connectionPair.set(connectionId, [ws, null]);
polite = false;
}
}
var connectionIds = getOrCreateConnectionIds(ws);
connectionIds.add(connectionId);
ws.send(JSON.stringify({ type: "connect", connectionId: connectionId, polite: polite }));
}
exports.onConnect = onConnect;
function onDisconnect(ws, connectionId) {
var connectionIds = clients.get(ws);
connectionIds.delete(connectionId);
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
var otherSessionWs = pair[0] == ws ? pair[1] : pair[0];
if (otherSessionWs) {
otherSessionWs.send(JSON.stringify({ type: "disconnect", connectionId: connectionId }));
}
}
connectionPair.delete(connectionId);
ws.send(JSON.stringify({ type: "disconnect", connectionId: connectionId }));
}
exports.onDisconnect = onDisconnect;
function onOffer(ws, message) {
var connectionId = message.connectionId;
var newOffer = new offer_1.default(message.sdp, Date.now(), false);
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
var otherSessionWs = pair[0] == ws ? pair[1] : pair[0];
if (otherSessionWs) {
newOffer.polite = true;
otherSessionWs.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer }));
}
}
return;
}
connectionPair.set(connectionId, [ws, null]);
clients.forEach(function (_v, k) {
if (k == ws) {
return;
}
k.send(JSON.stringify({ from: connectionId, to: "", type: "offer", data: newOffer }));
});
}
exports.onOffer = onOffer;
function onAnswer(ws, message) {
var connectionId = message.connectionId;
var connectionIds = getOrCreateConnectionIds(ws);
connectionIds.add(connectionId);
var newAnswer = new answer_1.default(message.sdp, Date.now());
if (!connectionPair.has(connectionId)) {
return;
}
var pair = connectionPair.get(connectionId);
var otherSessionWs = pair[0] == ws ? pair[1] : pair[0];
if (!isPrivate) {
connectionPair.set(connectionId, [otherSessionWs, ws]);
}
otherSessionWs.send(JSON.stringify({ from: connectionId, to: "", type: "answer", data: newAnswer }));
}
exports.onAnswer = onAnswer;
function onCandidate(ws, message) {
var connectionId = message.connectionId;
var candidate = new candidate_1.default(message.candidate, message.sdpMLineIndex, message.sdpMid, Date.now());
if (isPrivate) {
if (connectionPair.has(connectionId)) {
var pair = connectionPair.get(connectionId);
var otherSessionWs = pair[0] == ws ? pair[1] : pair[0];
if (otherSessionWs) {
otherSessionWs.send(JSON.stringify({ from: connectionId, to: "", type: "candidate", data: candidate }));
}
}
return;
}
clients.forEach(function (_v, k) {
if (k === ws) {
return;
}
k.send(JSON.stringify({ from: connectionId, to: "", type: "candidate", data: candidate }));
});
}
exports.onCandidate = onCandidate;
//# sourceMappingURL=websockethandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,99 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RenderStreaming = void 0;
var commander_1 = require("commander");
var https = require("https");
var fs = require("fs");
var os = require("os");
var server_1 = require("./server");
var websocket_1 = require("./websocket");
var RenderStreaming = /** @class */ (function () {
function RenderStreaming(options) {
var _this = this;
this.options = options;
this.app = (0, server_1.createServer)(this.options);
if (this.options.secure) {
this.server = https.createServer({
key: fs.readFileSync(options.keyfile),
cert: fs.readFileSync(options.certfile),
}, this.app).listen(this.options.port, function () {
var port = _this.server.address().port;
var addresses = _this.getIPAddress();
for (var _i = 0, addresses_1 = addresses; _i < addresses_1.length; _i++) {
var address = addresses_1[_i];
console.log("https://".concat(address, ":").concat(port));
}
});
}
else {
this.server = this.app.listen(this.options.port, function () {
var port = _this.server.address().port;
var addresses = _this.getIPAddress();
for (var _i = 0, addresses_2 = addresses; _i < addresses_2.length; _i++) {
var address = addresses_2[_i];
console.log("http://".concat(address, ":").concat(port));
}
});
}
if (this.options.type == 'http') {
console.log("Use http polling for signaling server.");
}
else if (this.options.type != 'websocket') {
console.log("signaling type should be set \"websocket\" or \"http\". ".concat(this.options.type, " is not supported."));
console.log("Changing signaling type to websocket.");
this.options.type = 'websocket';
}
if (this.options.type == 'websocket') {
console.log("Use websocket for signaling server ws://".concat(this.getIPAddress()[0]));
//Start Websocket Signaling server
new websocket_1.default(this.server, this.options.mode);
}
console.log("start as ".concat(this.options.mode, " mode"));
}
RenderStreaming.run = function (argv) {
var program = new commander_1.Command();
var readOptions = function () {
if (Array.isArray(argv)) {
program
.usage('[options] <apps...>')
.option('-p, --port <n>', 'Port to start the server on.', process.env.PORT || "80")
.option('-s, --secure', 'Enable HTTPS (you need server.key and server.cert).', process.env.SECURE || false)
.option('-k, --keyfile <path>', 'https key file.', process.env.KEYFILE || 'server.key')
.option('-c, --certfile <path>', 'https cert file.', process.env.CERTFILE || 'server.cert')
.option('-t, --type <type>', 'Type of signaling protocol, Choose websocket or http.', process.env.TYPE || 'websocket')
.option('-m, --mode <type>', 'Choose Communication mode public or private.', process.env.MODE || 'public')
.option('-l, --logging <type>', 'Choose http logging type combined, dev, short, tiny or none.', process.env.LOGGING || 'dev')
.parse(argv);
var option = program.opts();
return {
port: option.port,
secure: option.secure == undefined ? false : option.secure,
keyfile: option.keyfile,
certfile: option.certfile,
type: option.type == undefined ? 'websocket' : option.type,
mode: option.mode,
logging: option.logging,
};
}
};
var options = readOptions();
return new RenderStreaming(options);
};
RenderStreaming.prototype.getIPAddress = function () {
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family === 'IPv4') {
addresses.push(address.address);
}
}
}
return addresses;
};
return RenderStreaming;
}());
exports.RenderStreaming = RenderStreaming;
RenderStreaming.run(process.argv);
//# sourceMappingURL=index.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}

View File

@@ -1,35 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.log = exports.LogLevel = void 0;
var isDebug = true;
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["info"] = 0] = "info";
LogLevel[LogLevel["log"] = 1] = "log";
LogLevel[LogLevel["warn"] = 2] = "warn";
LogLevel[LogLevel["error"] = 3] = "error";
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
function log(level) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (isDebug) {
switch (level) {
case LogLevel.log:
console.log.apply(console, args);
break;
case LogLevel.info:
console.info.apply(console, args);
break;
case LogLevel.warn:
console.warn.apply(console, args);
break;
case LogLevel.error:
console.error.apply(console, args);
break;
}
}
}
exports.log = log;
//# sourceMappingURL=log.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":";;;AAAA,IAAM,OAAO,GAAG,IAAI,CAAC;AAErB,IAAY,QAKX;AALD,WAAY,QAAQ;IAClB,uCAAI,CAAA;IACJ,qCAAG,CAAA;IACH,uCAAI,CAAA;IACJ,yCAAK,CAAA;AACP,CAAC,EALW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAKnB;AAED,SAAgB,GAAG,CAAC,KAAe;IAAE,cAAc;SAAd,UAAc,EAAd,qBAAc,EAAd,IAAc;QAAd,6BAAc;;IACjD,IAAI,OAAO,EAAE;QACX,QAAQ,KAAK,EAAE;YACb,KAAK,QAAQ,CAAC,GAAG;gBACf,OAAO,CAAC,GAAG,OAAX,OAAO,EAAQ,IAAI,EAAE;gBACrB,MAAM;YACR,KAAK,QAAQ,CAAC,IAAI;gBAChB,OAAO,CAAC,IAAI,OAAZ,OAAO,EAAS,IAAI,EAAE;gBACtB,MAAM;YACR,KAAK,QAAQ,CAAC,IAAI;gBAChB,OAAO,CAAC,IAAI,OAAZ,OAAO,EAAS,IAAI,EAAE;gBACtB,MAAM;YACR,KAAK,QAAQ,CAAC,KAAK;gBACjB,OAAO,CAAC,KAAK,OAAb,OAAO,EAAU,IAAI,EAAE;gBACvB,MAAM;SACT;KACF;AACH,CAAC;AAjBD,kBAiBC"}

View File

@@ -1,42 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createServer = void 0;
var express = require("express");
var path = require("path");
var fs = require("fs");
var morgan = require("morgan");
var signaling_1 = require("./signaling");
var log_1 = require("./log");
var httphandler_1 = require("./class/httphandler");
var cors = require('cors');
var createServer = function (config) {
var app = express();
(0, httphandler_1.reset)(config.mode);
// logging http access
if (config.logging != "none") {
app.use(morgan(config.logging));
}
// const signal = require('./signaling');
app.use(cors({ origin: '*' }));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/config', function (req, res) { return res.json({ useWebSocket: config.type == 'websocket', startupMode: config.mode, logging: config.logging }); });
app.use('/signaling', signaling_1.default);
app.use(express.static(path.join(__dirname, '../client/public')));
app.use('/module', express.static(path.join(__dirname, '../client/src')));
app.get('/', function (req, res) {
var indexPagePath = path.join(__dirname, '../client/public/index.html');
fs.access(indexPagePath, function (err) {
if (err) {
(0, log_1.log)(log_1.LogLevel.warn, "Can't find file ' ".concat(indexPagePath));
res.status(404).send("Can't find file ".concat(indexPagePath));
}
else {
res.sendFile(indexPagePath);
}
});
});
return app;
};
exports.createServer = createServer;
//# sourceMappingURL=server.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;AAAA,iCAAmC;AACnC,2BAA6B;AAC7B,uBAAyB;AACzB,+BAAiC;AACjC,yCAAoC;AACpC,6BAAsC;AAEtC,mDAA2D;AAE3D,IAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtB,IAAM,YAAY,GAAG,UAAC,MAAe;IAC1C,IAAM,GAAG,GAAwB,OAAO,EAAE,CAAC;IAC3C,IAAA,mBAAY,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,sBAAsB;IACtB,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,EAAE;QAC5B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;KACjC;IACD,yCAAyC;IACzC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,GAAG,EAAC,CAAC,CAAC,CAAC;IAC7B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,UAAC,GAAG,EAAE,GAAG,IAAK,OAAA,GAAG,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,IAAI,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,EAAzG,CAAyG,CAAC,CAAC;IAC5I,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,mBAAS,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAClE,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1E,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,UAAC,GAAG,EAAE,GAAG;QACpB,IAAM,aAAa,GAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,6BAA6B,CAAC,CAAC;QAClF,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,UAAC,GAAG;YAC3B,IAAI,GAAG,EAAE;gBACP,IAAA,SAAG,EAAC,cAAQ,CAAC,IAAI,EAAE,4BAAqB,aAAa,CAAE,CAAC,CAAC;gBACzD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0BAAmB,aAAa,CAAE,CAAC,CAAC;aAC1D;iBAAM;gBACL,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;aAC7B;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AA3BW,QAAA,YAAY,gBA2BvB"}

View File

@@ -1,20 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var express = require("express");
var handler = require("./class/httphandler");
var router = express.Router();
router.use(handler.checkSessionId);
router.get('/connection', handler.getConnection);
router.get('/offer', handler.getOffer);
router.get('/answer', handler.getAnswer);
router.get('/candidate', handler.getCandidate);
router.get('', handler.getAll);
router.put('', handler.createSession);
router.delete('', handler.deleteSession);
router.put('/connection', handler.createConnection);
router.delete('/connection', handler.deleteConnection);
router.post('/offer', handler.postOffer);
router.post('/answer', handler.postAnswer);
router.post('/candidate', handler.postCandidate);
exports.default = router;
//# sourceMappingURL=signaling.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"signaling.js","sourceRoot":"","sources":["../src/signaling.ts"],"names":[],"mappings":";;AAAA,iCAAmC;AACnC,6CAA8C;AAE9C,IAAM,MAAM,GAAmB,OAAO,CAAC,MAAM,EAAE,CAAC;AAChD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;AACnC,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;AACjD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AACvC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;AACzC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;AAC/C,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AAC/B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;AACzC,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;AACpD,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;AACvD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;AACzC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;AAEjD,kBAAe,MAAM,CAAC"}

View File

@@ -1,53 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var websocket = require("ws");
var handler = require("./class/websockethandler");
var WSSignaling = /** @class */ (function () {
function WSSignaling(server, mode) {
var _this = this;
this.server = server;
this.wss = new websocket.Server({ server: server });
handler.reset(mode);
this.wss.on('connection', function (ws) {
handler.add(ws);
ws.onclose = function () {
handler.remove(ws);
};
ws.onmessage = function (event) {
// type: connect, disconnect JSON Schema
// connectionId: connect or disconnect connectionId
// type: offer, answer, candidate JSON Schema
// from: from connection id
// to: to connection id
// data: any message data structure
var msg = JSON.parse(event.data);
if (!msg || !_this) {
return;
}
console.log(msg);
switch (msg.type) {
case "connect":
handler.onConnect(ws, msg.connectionId);
break;
case "disconnect":
handler.onDisconnect(ws, msg.connectionId);
break;
case "offer":
handler.onOffer(ws, msg.data);
break;
case "answer":
handler.onAnswer(ws, msg.data);
break;
case "candidate":
handler.onCandidate(ws, msg.data);
break;
default:
break;
}
};
});
}
return WSSignaling;
}());
exports.default = WSSignaling;
//# sourceMappingURL=websocket.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":";;AAAA,8BAAgC;AAEhC,kDAAoD;AAEpD;IAIE,qBAAY,MAAc,EAAE,IAAY;QAAxC,iBAmDC;QAlDC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,QAAA,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEpB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,UAAC,EAAa;YAEtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEhB,EAAE,CAAC,OAAO,GAAG;gBACX,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC,CAAC;YAEF,EAAE,CAAC,SAAS,GAAG,UAAC,KAAmB;gBAEjC,wCAAwC;gBACxC,mDAAmD;gBAEnD,6CAA6C;gBAC7C,2BAA2B;gBAC3B,uBAAuB;gBACvB,mCAAmC;gBAEnC,IAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAI,EAAE;oBACjB,OAAO;iBACR;gBAED,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEjB,QAAQ,GAAG,CAAC,IAAI,EAAE;oBAChB,KAAK,SAAS;wBACZ,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;wBACxC,MAAM;oBACR,KAAK,YAAY;wBACf,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;wBAC3C,MAAM;oBACR,KAAK,OAAO;wBACV,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;wBAC9B,MAAM;oBACR,KAAK,QAAQ;wBACX,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;wBAC/B,MAAM;oBACR,KAAK,WAAW;wBACd,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;wBAClC,MAAM;oBACR;wBACE,MAAM;iBACT;YACH,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IACH,kBAAC;AAAD,CAAC,AAxDD,IAwDC"}

View File

@@ -76,9 +76,9 @@ export function handleChatMessage(data) {
const messageType = isImage ? 'file' : 'text'; const messageType = isImage ? 'file' : 'text';
// 显示通知 // 显示通知
if (!message.isSelf) { if (!data.isSelf) {
const content = isImage ? '[图片]' : message.content; const content = isImage ? '[图片]' : data.content;
showNotification(`${message.senderName}: ${content.substring(0, 20)}${content.length > 20 ? '...' : ''}`); showNotification(`${data.senderName}: ${content.substring(0, 20)}${content.length > 20 ? '...' : ''}`);
} }
} }

View File

@@ -234,10 +234,20 @@ class UIRenderer {
} }
if (this.elements.remoteStatus) { if (this.elements.remoteStatus) {
this.elements.remoteStatus.textContent = this.getStatusText(remoteUser.status); // 显示与黄框中一致的状态
if (!remoteUser.mediaState.audio) {
this.elements.remoteStatus.textContent = '静音中';
} else if (!remoteUser.mediaState.video) {
this.elements.remoteStatus.textContent = '视频关闭';
} else {
this.elements.remoteStatus.textContent = this.getStatusText(remoteUser.status);
}
} }
} }
// 同步更新侧边栏用户列表
this.renderUserList(this.stateManager.getState().session.localUser, remoteUser);
// 当远程视频关闭时显示占位符 // 当远程视频关闭时显示占位符
if (this.elements.remoteVideoPlaceholder) { if (this.elements.remoteVideoPlaceholder) {
const shouldShowPlaceholder = !remoteUser.mediaState.video; const shouldShowPlaceholder = !remoteUser.mediaState.video;
@@ -479,14 +489,15 @@ class UIRenderer {
// 计算通话成员总数 // 计算通话成员总数
let userCount = 1; // 至少有本地用户 let userCount = 1; // 至少有本地用户
if (remoteUser.status === 'online' || remoteUser.status === 'connecting') { if (remoteUser.status !== 'offline') {
userCount++; // 只有当远程用户在线或连接中时,增加计数 userCount++; // 如果远程用户在线,增加计数
} }
// 更新通话成员总数显示 // 更新通话成员总数显示
if (this.elements.userCountDisplay) { const userCountElement = this.elements.userList.closest('div').querySelector('h3.text-sm.font-medium.text-gray-400');
this.elements.userCountDisplay.textContent = `通话成员 (${userCount})`; if (userCountElement) {
} userCountElement.textContent = `通话成员 (${userCount})`;
}
// 渲染本地用户 // 渲染本地用户
const localUserElement = this.elements.userList.querySelector('[data-user-id="local"]'); const localUserElement = this.elements.userList.querySelector('[data-user-id="local"]');

View File

@@ -336,6 +336,13 @@ class CallStateManager {
this.state.session.status = 'ongoing'; this.state.session.status = 'ongoing';
this.notify({ type: 'CALL_STATUS_CHANGE', status: 'ongoing' }); this.notify({ type: 'CALL_STATUS_CHANGE', status: 'ongoing' });
// 连接建立后发送本地用户信息
this.sendMessage('user-info', {
id: this.state.session.localUser.id,
name: this.state.session.localUser.name,
avatar: this.state.session.localUser.avatar
});
if (this.state.localStream) { if (this.state.localStream) {
const tracks = this.state.localStream.getTracks(); // 获取本地媒体轨道 const tracks = this.state.localStream.getTracks(); // 获取本地媒体轨道
for (const track of tracks) { for (const track of tracks) {
@@ -383,6 +390,12 @@ class CallStateManager {
this.updateRemoteUserStatus('online'); this.updateRemoteUserStatus('online');
// 更新远程用户网络质量为好 // 更新远程用户网络质量为好
this.updateRemoteUserNetworkQuality('good'); this.updateRemoteUserNetworkQuality('good');
this.sendMessage('user-info', {
id: this.state.session.localUser.id,
name: this.state.session.localUser.name,
avatar: this.state.session.localUser.avatar
});
// 启动通话时长计时器 // 启动通话时长计时器
this.durationInterval = setInterval(() => { this.durationInterval = setInterval(() => {
this.state.session.duration++; this.state.session.duration++;
@@ -406,17 +419,39 @@ class CallStateManager {
if (data.type === 'chat-message') { if (data.type === 'chat-message') {
// 处理聊天 // 处理聊天
// 添加到列表并更新UI // 添加到列表并更新UI
chatMessage.handleChatMessage(data.message); chatMessage.handleChatMessage(data.message);
// 从消息中提取用户信息并更新remoteUser
if (data.message && data.message.senderId !== this.state.session.localUser.id) {
this.state.session.remoteUser = {
...this.state.session.remoteUser,
id: data.message.senderId,
name: data.message.senderName,
avatar: data.message.senderAvatar
};
this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState: this.state.session.remoteUser.mediaState });
}
} else if (data.type === 'media-state-changed') { } else if (data.type === 'media-state-changed') {
// 处理媒体状态变化 // 处理媒体状态变化
console.log('收到媒体状态变化:', data.data); console.log('收到媒体状态变化:', data.data);
// 更新远程用户的媒体状态 // 更新远程用户的媒体状态
this.updateRemoteMedia(data.data); this.updateRemoteMedia(data.data);
} else if (data.type === 'on-message') { } else if (data.type === 'user-info') {
// 处理用户信息更新
console.log('收到用户信息:', data.data);
if (data.data) {
this.state.session.remoteUser = {
...this.state.session.remoteUser,
id: data.data.id || this.state.session.remoteUser.id,
name: data.data.name || this.state.session.remoteUser.name,
avatar: data.data.avatar || this.state.session.remoteUser.avatar
};
this.notify({ type: 'REMOTE_MEDIA_CHANGE', mediaState: this.state.session.remoteUser.mediaState });
}
} }
}; };
// 启动WebRTC连接 // 启动WebRTC连接
await this.renderstreaming.start(); await this.renderstreaming.start();
await this.renderstreaming.createConnection(connectionId); await this.renderstreaming.createConnection(connectionId);
@@ -466,6 +501,21 @@ class CallStateManager {
this.state.session.status = 'ended'; this.state.session.status = 'ended';
this.notify({ type: 'CALL_ENDED' }); this.notify({ type: 'CALL_ENDED' });
} }
/**
* 发送消息
* @param {string} type - 消息类型
* @param {Object} data - 消息数据
*/
sendMessage(type, data) {
if (this.renderstreaming) {
this.renderstreaming.sendMessage({
type: type,
data: data
});
}
}
/** /**
* 设置编解码器偏好 * 设置编解码器偏好
*/ */

146
WebApp/package-lock.json generated
View File

@@ -15,6 +15,7 @@
"debug": "~4.3.4", "debug": "~4.3.4",
"express": "~4.18.1", "express": "~4.18.1",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "^2.1.1",
"swagger-jsdoc": "^6.2.1", "swagger-jsdoc": "^6.2.1",
"swagger-ui-express": "^4.5.0", "swagger-ui-express": "^4.5.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",
@@ -2289,6 +2290,11 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"node_modules/aproba": { "node_modules/aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -2653,8 +2659,18 @@
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
"dev": true },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
}, },
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
@@ -2895,6 +2911,33 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
}, },
"node_modules/concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"engines": [
"node >= 6.0"
],
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
}
},
"node_modules/concat-stream/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/console-control-strings": { "node_modules/console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -6244,6 +6287,24 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/multer": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz",
"integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.6.0",
"concat-stream": "^2.0.0",
"type-is": "^1.6.18"
},
"engines": {
"node": ">= 10.16.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/multistream": { "node_modules/multistream": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz",
@@ -7773,11 +7834,18 @@
"readable-stream": "^2.1.4" "readable-stream": "^2.1.4"
} }
}, },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"dependencies": { "dependencies": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@@ -8263,6 +8331,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.8.2", "version": "4.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
@@ -8334,8 +8407,7 @@
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"dev": true
}, },
"node_modules/utils-merge": { "node_modules/utils-merge": {
"version": "1.0.1", "version": "1.0.1",
@@ -10403,6 +10475,11 @@
"picomatch": "^2.0.4" "picomatch": "^2.0.4"
} }
}, },
"append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -10690,8 +10767,15 @@
"buffer-from": { "buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
"dev": true },
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"streamsearch": "^1.1.0"
}
}, },
"bytes": { "bytes": {
"version": "3.1.2", "version": "3.1.2",
@@ -10871,6 +10955,29 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
}, },
"concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
},
"dependencies": {
"readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -13408,6 +13515,17 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"multer": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz",
"integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^1.6.0",
"concat-stream": "^2.0.0",
"type-is": "^1.6.18"
}
},
"multistream": { "multistream": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz",
@@ -14573,11 +14691,15 @@
"readable-stream": "^2.1.4" "readable-stream": "^2.1.4"
} }
}, },
"streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": { "string_decoder": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": { "requires": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@@ -14912,6 +15034,11 @@
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
} }
}, },
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"typescript": { "typescript": {
"version": "4.8.2", "version": "4.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
@@ -14964,8 +15091,7 @@
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"dev": true
}, },
"utils-merge": { "utils-merge": {
"version": "1.0.1", "version": "1.0.1",

View File

@@ -19,6 +19,7 @@
"debug": "~4.3.4", "debug": "~4.3.4",
"express": "~4.18.1", "express": "~4.18.1",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "^2.1.1",
"swagger-jsdoc": "^6.2.1", "swagger-jsdoc": "^6.2.1",
"swagger-ui-express": "^4.5.0", "swagger-ui-express": "^4.5.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",

View File

@@ -9,6 +9,7 @@ import { reset as resetHandler }from './class/httphandler';
import { initSwagger } from './swagger'; import { initSwagger } from './swagger';
const cors = require('cors'); const cors = require('cors');
const multer = require('multer');
export const createServer = (config: Options): express.Express => { export const createServer = (config: Options): express.Express => {
const app: express.Express = express(); const app: express.Express = express();
@@ -39,5 +40,50 @@ export const createServer = (config: Options): express.Express => {
// 初始化Swagger // 初始化Swagger
initSwagger(app, config); initSwagger(app, config);
// 配置multer存储
const storage = multer.diskStorage({
destination: function (req: any, file: any, cb: (error: Error | null, destination: string) => void) {
// 确保上传目录存在
const uploadDir = path.join(__dirname, '../client/public/uploads/avatars');
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: function (req: any, file: any, cb: (error: Error | null, filename: string) => void) {
// 临时使用原始文件名稍后在API处理中重命名
cb(null, file.originalname);
}
});
const upload = multer({ storage: storage });
// 头像上传API
app.post('/api/upload/avatar', upload.single('avatar'), (req: any, res: express.Response) => {
if (!req.file) {
return res.status(400).json({ success: false, message: 'No file uploaded' });
}
const userId = req.body.userId || 'unknown';
const ext = path.extname(req.file.originalname);
const oldPath = req.file.path;
const newFilename = `${userId}${ext}`;
const newPath = path.join(path.dirname(oldPath), newFilename);
// 重命名文件
fs.rename(oldPath, newPath, (err) => {
if (err) {
console.error('Error renaming file:', err);
return res.status(500).json({ success: false, message: '文件重命名失败' });
}
const avatarUrl = `/uploads/avatars/${newFilename}`;
res.json({ success: true, avatarUrl: avatarUrl });
});
});
// 确保uploads目录可访问
app.use('/uploads', express.static(path.join(__dirname, '../client/public/uploads')));
return app; return app;
}; };