Create-CC-Shop/server.js
2026-01-28 22:44:28 +01:00

199 lines
4.6 KiB
JavaScript

const express = require("express");
const http = require("http");
const WebSocket = require("ws");
const env = require("dotenv").config().parsed;
const mariadb = require("mariadb");
const pool = mariadb.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
ssl: true, // try with and without
});
const app = express();
const PORT = env.PORT;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
async function upsertItemsForShop(shopId, items) {
if (!items.length) return;
const placeholders = items.map(() => "(?, ?, ?)").join(", ");
const values = items.flatMap((i) => [
shopId,
i.item_name,
Number(i.stock) || 0,
]);
const sql = `
INSERT INTO Item (shopId, item_name, stock)
VALUES ${placeholders}
ON DUPLICATE KEY UPDATE stock = VALUES(stock)
`;
await pool.query(sql, values);
}
async function zeroMissingItems(shopId, items) {
const names = items.map((i) => i.item_name);
items;
if (names.length === 0) {
await pool.query(`UPDATE Item SET stock = 0 WHERE shopId = ?`, [shopId]);
return;
}
const sql = `
UPDATE Item
SET stock = 0
WHERE shopId = ?
AND item_name NOT IN (?)
`;
await pool.query(sql, [shopId, names]);
}
async function zeroAllItemsForShop(shopId) {
await pool.query(`UPDATE Item SET stock = 0 WHERE shopId = ?`, [shopId]);
}
// Create HTTP server & WebSocket server
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// Helper to send JSON to a ws client
function sendJSON(ws, obj) {
try {
ws.send(JSON.stringify(obj));
} catch (err) {
// ignore send errors for now
}
}
wss.on("connection", (ws) => {
const clientId =
Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
ws._clientId = clientId;
ws._shopId = null;
console.log("Client connected:", clientId);
sendJSON(ws, { type: "welcome", id: clientId });
ws.on("message", async (raw) => {
let parsed;
try {
parsed = JSON.parse(raw.toString());
} catch {
return;
}
parsed.shopId = Number(parsed.id);
if (parsed && Array.isArray(parsed.items) && parsed.shopId != null) {
const shopId = Number(parsed.shopId);
ws._shopId = shopId;
const items = parsed.items.map((i) => ({
item_name: String(i.name),
stock: Number(i.count) || 0,
}));
try {
// 1. Upsert received items
await upsertItemsForShop(shopId, items);
// 2. Set missing items to 0 (ONLY this shop)
await zeroMissingItems(shopId, items);
console.log(`Updated shop ${shopId} (${items.length} items)`);
} catch (err) {
console.error("DB error:", err.message);
}
}
// ---- broadcast logic unchanged ----
if (parsed?.type && parsed.type !== "items") {
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(parsed));
}
});
}
});
ws.on("close", async () => {
console.log("Client disconnected:", clientId);
if (ws._shopId != null) {
try {
await zeroAllItemsForShop(ws._shopId);
console.log(`Shop ${ws._shopId} set to 0 stock`);
} catch (err) {
console.error("DB error on close:", err.message);
}
}
});
ws.on("error", (err) => {
console.log("WebSocket error:", err.message);
});
});
app.post("/api/send", (req, res) => {
const { shopId, address, items } = req.body;
// Basic validation
if (
typeof shopId !== "number" ||
typeof address !== "string" ||
!Array.isArray(items)
) {
return res.status(400).json({
ok: false,
error: "Invalid parameters",
});
}
for (const item of items) {
if (typeof item.id !== "string" || typeof item.quantity !== "number") {
return res.status(400).json({
ok: false,
error: "Invalid item format",
});
}
}
// Build request payload
const request = {
type: "request",
to: shopId,
address,
items: items.map((item) => ({
name: item.id,
_requestCount: item.quantity,
})),
};
// Send via WebSocket
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(request));
console.log("Sent request to client:", client._clientId);
}
});
return res.status(200).json({
ok: true,
message: "Items sent successfully",
data: request,
});
});
server.listen(PORT, () => {
console.log(`🚀 Server listening on http://localhost:${PORT}`);
});