// ── Admin · Rust · NPCs: the handlers (docs/runicnpc/PLAN.md stage 4) ────── // // Thin: the model decides, and a refusal it throws carries its own status and // sentence. Every write is logged in core's activity log, a placement's too, // because a placement puts armed NPCs in the world. const core = require('../../core') const npcs = require('../../model/npcs/npcs.model') const npcSync = require('../../npcSync') const log = core.logger('npcs') const by = (req) => (req.user ? req.user.id : null) /** A model refusal answers with its own status; anything else is ours to log. */ function fail(res, err, what) { if (err instanceof npcs.NpcError) return res.status(err.status).json({ message: err.message }) log.error(`failed to ${what}`, { error: err.message }) return res.status(500).json({ message: `Failed to ${what}` }) } async function describe(req, res) { try { res.json(await npcs.describe()) } catch (err) { fail(res, err, 'read the NPC profiles') } } async function create(req, res) { try { const profile = await npcs.create(req.body || {}, by(req)) await core.activity.log({ req, action: 'rust.npcs.profile.create', detail: { id: profile.id, name: profile.name } }) res.status(201).json(profile) } catch (err) { fail(res, err, 'save the NPC profile') } } async function update(req, res) { try { const profile = await npcs.update(Number(req.params.pid), req.body || {}) await core.activity.log({ req, action: 'rust.npcs.profile.update', detail: { id: profile.id, name: profile.name } }) res.json(profile) } catch (err) { fail(res, err, 'save the NPC profile') } } async function remove(req, res) { try { await npcs.remove(Number(req.params.pid)) await core.activity.log({ req, action: 'rust.npcs.profile.delete', detail: { id: Number(req.params.pid) } }) res.json({ ok: true }) } catch (err) { fail(res, err, 'delete the NPC profile') } } async function restore(req, res) { try { const profile = await npcs.restore(Number(req.params.pid)) await core.activity.log({ req, action: 'rust.npcs.profile.restore', detail: { id: profile.id, name: profile.name } }) res.json(profile) } catch (err) { fail(res, err, 'restore the NPC profile') } } async function push(req, res) { try { const [result] = await npcSync.tick({ force: req.params.id }) if (!result) return res.status(404).json({ message: 'No such server, or it is switched off' }) await core.activity.log({ req, action: 'rust.npcs.push', detail: { server: req.params.id, outcome: result.outcome } }) res.json(result) } catch (err) { fail(res, err, 'push the NPC profiles') } } async function listPlacements(req, res) { try { res.json(await npcs.listPlacements(req.params.id)) } catch (err) { fail(res, err, 'read the placements') } } async function addPlacement(req, res) { try { const placed = await npcs.addPlacement(req.params.id, req.body || {}) await core.activity.log({ req, action: 'rust.npcs.placement.add', detail: { server: req.params.id, id: placed.id, profile: req.body.profile, position: placed.position } }) res.status(201).json(placed) } catch (err) { fail(res, err, 'place the NPCs') } } async function setPlacement(req, res) { try { const out = await npcs.setPlacement(req.params.id, req.params.placement, req.body || {}) await core.activity.log({ req, action: 'rust.npcs.placement.update', detail: { server: req.params.id, id: req.params.placement } }) res.json(out) } catch (err) { fail(res, err, 'change the placement') } } async function removePlacement(req, res) { try { await npcs.removePlacement(req.params.id, req.params.placement) await core.activity.log({ req, action: 'rust.npcs.placement.delete', detail: { server: req.params.id, id: req.params.placement } }) res.json({ ok: true }) } catch (err) { fail(res, err, 'remove the placement') } } async function renamePlacement(req, res) { try { const out = await npcs.renamePlacement(req.params.id, req.params.placement, req.body.to) await core.activity.log({ req, action: 'rust.npcs.placement.rename', detail: { server: req.params.id, from: req.params.placement, to: req.body.to } }) res.json({ id: out.id || req.body.to, previous: req.params.placement }) } catch (err) { fail(res, err, 'rename the placement') } } async function respawnPlacement(req, res) { try { const out = await npcs.respawnPlacement(req.params.id, req.params.placement) await core.activity.log({ req, action: 'rust.npcs.placement.respawn', detail: { server: req.params.id, id: req.params.placement } }) res.json({ id: req.params.placement, respawned: Number(out.respawned) || 0 }) } catch (err) { fail(res, err, 'respawn the placement') } } module.exports = { describe, create, update, remove, restore, push, listPlacements, addPlacement, setPlacement, removePlacement, renamePlacement, respawnPlacement, }