v0.3
This commit is contained in:
@@ -6,6 +6,18 @@ const path = require('path')
|
||||
|
||||
const app = express()
|
||||
const PORT = process.env.PORT || 3000
|
||||
|
||||
// SSE clients: Map<slug, Set<res>>
|
||||
const sseClients = new Map()
|
||||
|
||||
function broadcast(slug) {
|
||||
const bucket = sseClients.get(slug)
|
||||
if (!bucket) return
|
||||
const msg = `data: update\n\n`
|
||||
for (const res of bucket) {
|
||||
try { res.write(msg) } catch {}
|
||||
}
|
||||
}
|
||||
const DB_PATH = path.join(__dirname, 'colony.json')
|
||||
|
||||
function loadDB() {
|
||||
@@ -59,6 +71,24 @@ function publicGame(g) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Live updates (SSE) ---
|
||||
app.get('/api/games/:slug/live', (req, res) => {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'X-Accel-Buffering': 'no',
|
||||
})
|
||||
res.write('data: connected\n\n')
|
||||
const slug = req.params.slug
|
||||
if (!sseClients.has(slug)) sseClients.set(slug, new Set())
|
||||
sseClients.get(slug).add(res)
|
||||
req.on('close', () => {
|
||||
sseClients.get(slug)?.delete(res)
|
||||
if (sseClients.get(slug)?.size === 0) sseClients.delete(slug)
|
||||
})
|
||||
})
|
||||
|
||||
// --- Games ---
|
||||
app.get('/api/games', (req, res) => {
|
||||
const db = loadDB()
|
||||
@@ -120,7 +150,7 @@ app.put('/api/games/:slug', requirePassword, (req, res) => {
|
||||
game.end_title = end_title || ''
|
||||
game.end_description = end_description || ''
|
||||
game.end_mood = end_mood || ''
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.json(publicGame(game))
|
||||
})
|
||||
|
||||
@@ -159,7 +189,7 @@ app.post('/api/games/:slug/items', requirePassword, (req, res) => {
|
||||
}
|
||||
req.game.items = req.game.items || []
|
||||
req.game.items.push(item)
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.status(201).json(item)
|
||||
})
|
||||
|
||||
@@ -171,7 +201,7 @@ app.put('/api/games/:slug/items/:id', requirePassword, (req, res) => {
|
||||
if (!title || !date) return res.status(400).json({ error: 'title, date required' })
|
||||
const { env, env_layout } = req.body
|
||||
items[idx] = { ...items[idx], title, description: description || '', mood: mood || null, date, end_date: end_date || null, status: status || null, discipline: discipline || null, env: env || null, env_layout: env_layout || null }
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.json(items[idx])
|
||||
})
|
||||
|
||||
@@ -180,7 +210,7 @@ app.delete('/api/games/:slug/items/:id', requirePassword, (req, res) => {
|
||||
const idx = items.findIndex(i => i.id === req.params.id)
|
||||
if (idx === -1) return res.status(404).json({ error: 'Item not found' })
|
||||
items.splice(idx, 1)
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.json({ ok: true })
|
||||
})
|
||||
|
||||
@@ -200,12 +230,12 @@ app.post('/api/games/:slug/keywords', requirePassword, (req, res) => {
|
||||
const existing = req.game.keywords.find(k => k.term.toLowerCase() === term.toLowerCase())
|
||||
if (existing) {
|
||||
existing.definition = definition || ''
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
return res.json(existing)
|
||||
}
|
||||
const kw = { id: newId(), term, definition: definition || '', created_at: now() }
|
||||
req.game.keywords.push(kw)
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.status(201).json(kw)
|
||||
})
|
||||
|
||||
@@ -215,7 +245,7 @@ app.put('/api/games/:slug/keywords/:id', requirePassword, (req, res) => {
|
||||
if (idx === -1) return res.status(404).json({ error: 'Keyword not found' })
|
||||
const { term, definition } = req.body
|
||||
kws[idx] = { ...kws[idx], term: term || kws[idx].term, definition: definition || '' }
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.json(kws[idx])
|
||||
})
|
||||
|
||||
@@ -224,7 +254,7 @@ app.delete('/api/games/:slug/keywords/:id', requirePassword, (req, res) => {
|
||||
const idx = kws.findIndex(k => k.id === req.params.id)
|
||||
if (idx === -1) return res.status(404).json({ error: 'Keyword not found' })
|
||||
kws.splice(idx, 1)
|
||||
saveDB(req.db)
|
||||
saveDB(req.db); broadcast(req.params.slug)
|
||||
res.json({ ok: true })
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user