190 lines
4.3 KiB
JavaScript
190 lines
4.3 KiB
JavaScript
const express = require("express");
|
|
const http = require("http");
|
|
const WebSocket = require("ws");
|
|
const pool = require("./db");
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3100;
|
|
|
|
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}`);
|
|
});
|