-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
125 lines (104 loc) · 3.49 KB
/
app.js
File metadata and controls
125 lines (104 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// app.js
const express = require("express");
const path = require("path");
const app = express();
app.use(express.json());
app.use(express.static(path.join(__dirname)));
// --- health check for tests ---
app.get("/health", (_req, res) => res.status(200).json({ ok: true }));
// --- in-memory inventory ---
let products = [
{ id: 1, name: "Laptop", stock: 5, maxThreshold: 20 },
{ id: 2, name: "Phone", stock: 10, maxThreshold: 30 },
{ id: 3, name: "Headphones", stock: 15, maxThreshold: 25 },
];
// list
app.get("/api/products", (_req, res) => res.json(products));
// add
app.post("/api/products", (req, res) => {
const { name, stock = 0, maxThreshold = 10 } = req.body || {};
if (!name || String(name).trim().length < 2) {
return res.status(400).json({ error: "name required (min 2 chars)" });
}
if (stock < 0)
return res.status(400).json({ error: "stock cannot be negative" });
const id = products.length ? products[products.length - 1].id + 1 : 1;
const p = {
id,
name: String(name).trim(),
stock: Number(stock),
maxThreshold: Number(maxThreshold),
};
products.push(p);
res.status(201).json(p);
});
// update (stock/threshold/name)
app.put("/api/products/:id", (req, res) => {
const id = Number(req.params.id);
const p = products.find((x) => x.id === id);
if (!p) return res.status(404).json({ error: "not found" });
const { name, stock, maxThreshold } = req.body || {};
if (name !== undefined && String(name).trim().length < 2)
return res.status(400).json({ error: "name too short" });
if (stock !== undefined && Number(stock) < 0)
return res.status(400).json({ error: "stock cannot be negative" });
if (maxThreshold !== undefined && Number(maxThreshold) < 0)
return res.status(400).json({ error: "maxThreshold cannot be negative" });
if (name !== undefined) p.name = String(name).trim();
if (stock !== undefined) p.stock = Number(stock);
if (maxThreshold !== undefined) p.maxThreshold = Number(maxThreshold);
res.json(p);
});
// delete
app.delete("/api/products/:id", (req, res) => {
const id = Number(req.params.id);
const before = products.length;
products = products.filter((x) => x.id !== id);
if (products.length === before)
return res.status(404).json({ error: "not found" });
res.status(204).end();
});
// --- Simulation engine ---
let simRunning = false;
let simTimer = null;
let nextRunAt = null;
function scheduleSimulation() {
if (!simRunning) return;
const delay = Math.floor(Math.random() * 1500) + 500; // 5–20 sec
nextRunAt = Date.now() + delay;
simTimer = setTimeout(() => {
runSimulation();
scheduleSimulation(); // reschedule next tick
}, delay);
}
function runSimulation() {
if (products.length === 0) return;
const p = products[Math.floor(Math.random() * products.length)];
const action = Math.random() > 0.5 ? "sale" : "purchase";
if (action === "sale" && p.stock > 0) {
p.stock -= 1;
} else if (action === "purchase" && p.stock < p.maxThreshold) {
p.stock += 1;
}
}
// start sim
app.post("/api/sim/start", (_req, res) => {
if (!simRunning) {
simRunning = true;
scheduleSimulation();
}
res.json({ running: simRunning, nextRunAt });
});
// stop sim
app.post("/api/sim/stop", (_req, res) => {
if (simTimer) clearTimeout(simTimer);
simRunning = false;
simTimer = null;
nextRunAt = null;
res.json({ running: simRunning });
});
// status
app.get("/api/sim/status", (_req, res) => {
res.json({ running: simRunning, nextRunAt, products });
});
module.exports = app;