add ws interface with receive or send message & image

This commit is contained in:
2025-03-28 21:49:03 +08:00
parent ea948e017a
commit be60ddd92c
3 changed files with 234 additions and 77 deletions

283
chat.js
View File

@@ -4,8 +4,10 @@ const http = require('http');
const fs = require('fs');
const { once } = require("node:events");
const dateformat = require('@matteo.collina/dateformat');
const WebSocket = require('ws');
const logger = client.logger
const steamUser = client.steamUser
fs.mkdir("./logs", { recursive: true }, (err) => {
if (err) {
@@ -25,33 +27,64 @@ async function sendMsg(req, res) {
console.log(requests)
client.steamUser.chat.sendFriendMessage(requests.id, requests.msg, (err, response) => {
if (err) {
console.log(err);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error\n');
return;
}
res.statusCode = 200;
let [err, response] = sendFriendMessage(requests.id, requests.msg);
if (err) {
console.log(err);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Success\n');
res.end('Internal Server Error\n');
return;
}
getUserInfo(client.steamUser.steamID).then((sender) => {
fs.appendFile("./logs/chat.jsonl", JSON.stringify({
date: dateToString(response.server_timestamp),
echo: true,
id: requests.id,
name: sender.player_name,
message: response.modified_message,
ordinal: response.ordinal,
}) + "\n", (e) => {
if (e) {
logger.error("an error occurred while writing chat log file: " + e);
}
});
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Success\n');
logSendMsg(requests.id, response);
}
function sendFriendMessage(uid, msg) {
return new Promise((resolve, reject) => {
client.steamUser.chat.sendFriendMessage(uid, msg, (err, response) => {
if (err) {
resolve([err, response]);
return
}
client.getUserInfo(client.steamUser.steamID).then((sender) => {
fs.appendFile("./logs/chat.jsonl", JSON.stringify({
date: dateToString(response.server_timestamp),
echo: true,
id: uid,
name: sender.player_name,
message: response.modified_message,
ordinal: response.ordinal,
}) + "\n", (e) => {
if (e) {
logger.error("an error occurred while writing chat log file: " + e);
}
});
})
resolve([err, response]);
})
});
}
function logSendMsg(uid, response) {
client.getUserInfo(client.steamUser.steamID).then((sender) => {
fs.appendFile("./logs/chat.jsonl", JSON.stringify({
date: dateToString(response.server_timestamp),
echo: true,
id: uid,
name: sender.player_name,
message: response.modified_message,
ordinal: response.ordinal,
}) + "\n", (e) => {
if (e) {
logger.error("an error occurred while writing chat log file: " + e);
}
});
})
}
@@ -65,58 +98,53 @@ async function sendImg(req, res) {
let requests = JSON.parse(body);
if (requests.img) {
console.log({
id: requests.id,
img: requests.img.length,
});
} else {
console.log(requests);
res.setHeader('Content-Type', 'text/plain');
let err = await sendImageToUser(requests.id, requests.img, requests.url);
if (err) {
const { code = 500, message = "Internal Server Error" } = err;
res.statusCode = code;
res.end(message + '\n');
return
}
if (requests.url) {
img = await readUrlAsBuffer(requests.url)
} else if (requests.img) {
img = Buffer.from(requests.img, 'base64');
} else {
res.statusCode = 400;
res.setHeader('Content-Type', 'text/plain');
res.end('Bad Request\n');
return;
}
client.steamCommunity.sendImageToUser(requests.id, img, function (err, imageUrl) {
if (err) {
logger.error("an error occurred while sending image: ", err);
client.steamUser.webLogOn();
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error\n');
return
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Success\n');
});
res.statusCode = 200;
res.end('Success\n');
}
const server = http.createServer(async (req, res) => {
try {
if (req.url == "/img") {
await sendImg(req, res);
function sendImageToUser(uid, img, url) {
return new Promise(async (resolve, reject) => {
if (img) {
console.log({
uid: uid,
img: img.length,
});
} else {
await sendMsg(req, res);
console.log({
uid: uid,
url: url,
});
}
} catch (e) {
console.error("An error occurred while processing the request: ", e);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error\n');
}
});
if (url) {
img = await readUrlAsBuffer(url)
} else if (img) {
img = Buffer.from(img, 'base64');
} else {
resolve({ code: 400, message: "Bad Request" });
return;
}
client.steamCommunity.sendImageToUser(uid, img, function (err, imageUrl) {
if (err) {
logger.error("an error occurred while sending image: ", err);
client.steamUser.webLogOn();
resolve({});
return
}
resolve();
});
})
}
async function readUrlAsBuffer(url) {
try {
@@ -142,11 +170,116 @@ function dateToString(date) {
return dateformat(date, "yyyy-mm-dd HH:MM:ss.l");
}
async function getUserInfo(steamID) {
return client.getUserInfo(steamID, (ignore) => {
async function handleHttp(req, res) {
try {
if (req.url == "/img") {
await sendImg(req, res);
} else {
await sendMsg(req, res);
}
} catch (e) {
console.error("An error occurred while processing the request: ", e);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error\n');
}
}
function handleWs(ws) {
console.log('WebSocket connection established.');
ws.on('message', (message) => {
let data;
try {
data = JSON.parse(message);
} catch {
ws.close(1003, 'Invalid JSON');
return;
}
logger.info('Received message:', data);
switch (data.type) {
case "msg":
sendFriendMessage(data.id, data.msg).then(([err, response]) => {
if (err) {
return;
}
onSteamMessage({
server_timestamp: response.server_timestamp,
steamid_friend: data.id,
message: response.modified_message,
ordinal: response.ordinal,
}, true);
});
break;
case "img":
sendImageToUser(data.id, data.img, data.url);
break
}
});
ws.on('close', () => {
logger.info('WebSocket connection closed.');
});
ws.on('error', (err) => {
logger.error('WebSocket error:', err);
});
}
server.listen(3000, '0.0.0.0', () => {
console.log('Server running at http://0.0.0.0:3000/');
async function messageToJson(message, echo) {
let friendId = message.steamid_friend
if (typeof friendId !== 'string') {
friendId = friendId.getSteamID64();
}
let sender = await client.getUserInfo(echo ? steamUser.steamID : friendId, (ignore) => { });
return JSON.stringify({
date: dateToString(message.server_timestamp),
echo: echo,
id: friendId,
name: sender.player_name,
message: message.message,
ordinal: message.ordinal,
})
}
async function onSteamMessage(message, echo) {
let messageEncoded = await messageToJson(message, echo);
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(messageEncoded);
}
});
}
client.steamLoginPromise.then(() => {
steamUser.chat.on("friendMessage", (message) => {
// noinspection JSIgnoredPromiseFromCall
onSteamMessage(message, false);
});
steamUser.chat.on("friendMessageEcho", (message) => {
// noinspection JSIgnoredPromiseFromCall
onSteamMessage(message, true);
});
try {
const server = http.createServer(handleHttp);
// 创建 WebSocket 服务器,并限制路径为 /ws
globalThis.wss = new WebSocket.Server({ server, path: '/ws' });
wss.on('connection', handleWs);
server.listen(3000, '0.0.0.0', () => {
console.log('Server running at http://0.0.0.0:3000/');
console.log('WebSocket server is also running.');
});
} catch (err) {
console.error('Error during initialization:', err);
}
});

24
package-lock.json generated
View File

@@ -14,7 +14,8 @@
"steam-totp": "^2.1.2",
"steam-user": "^5.0.8",
"steamcommunity": "^3.48.2",
"winston": "^3.12.0"
"winston": "^3.12.0",
"ws": "^8.18.1"
}
},
"node_modules/@bbob/parser": {
@@ -1506,6 +1507,27 @@
"node": ">= 12.0.0"
}
},
"node_modules/ws": {
"version": "8.18.1",
"resolved": "https://mvn.tursom.cn:20080/repository/npm/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",

View File

@@ -2,6 +2,7 @@
"name": "steam-chat",
"version": "1.0.0",
"description": "",
"type": "commonjs",
"main": "logger.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
@@ -15,6 +16,7 @@
"steam-totp": "^2.1.2",
"steam-user": "^5.0.8",
"steamcommunity": "^3.48.2",
"winston": "^3.12.0"
"winston": "^3.12.0",
"ws": "^8.18.1"
}
}