fix(chat): the review's gaps — owner hand-over, live group lines, names, scroll, one tab's sound, uploads on disk, a chat button without the pet
- A group whose creator left or was deleted passes to its longest-standing member (ensureOwner), so it can still be managed. - Group changes (added / removed / renamed / left) are sent live as chat_message and never count as unread, here or on the server. - A disabled account is still named in old chats (people carries `disabled`) and never offered for a new one; a deleted one reads 'Deleted user' instead of '?'. - Load older keeps the message being read in place. - With several tabs open only the first to see a message plays its sound / system notification (agenthub.chat.notified). - The people list is read again on New chat and on every room change. - Uploads go to <data dir>/chat/.incoming/ (multer disk storage) and are renamed into place — never held in memory; a refused one is removed. - With the pet hidden, a chat button in the bottom-right corner (ChatDock, server mode) opens the same window, unread count and new-message card included.
This commit is contained in:
+23
-6
@@ -48,12 +48,17 @@ function tell(type, data, to) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Multipart `files` + `body`, in memory, within the chat's limits. */
|
||||
/** Multipart `files` + `body`, written to disk (never held whole in memory), within the chat's limits. */
|
||||
function upload(req, res, next) {
|
||||
if (!req.is("multipart/form-data")) return next();
|
||||
const multer = require("multer");
|
||||
multer({
|
||||
storage: multer.memoryStorage(),
|
||||
storage: multer.diskStorage({
|
||||
destination: (_req, _file, cb) => cb(null, chat.incomingDir()),
|
||||
// A name of ours; the browser's goes only into the database.
|
||||
filename: (_req, _file, cb) =>
|
||||
cb(null, require("node:crypto").randomBytes(16).toString("hex")),
|
||||
}),
|
||||
limits: { fileSize: chat.MAX_FILE_BYTES, files: chat.MAX_FILES },
|
||||
}).array("files")(req, res, (e) => {
|
||||
if (!e) return next();
|
||||
@@ -98,12 +103,14 @@ router.patch(
|
||||
sameOriginGuard,
|
||||
handle((me, req, res) => {
|
||||
const b = req.body || {};
|
||||
const { room, notify } = chat.updateGroup(me, req.params.id, {
|
||||
const { room, notify, lines } = chat.updateGroup(me, req.params.id, {
|
||||
name: b.name,
|
||||
add: b.add,
|
||||
remove: b.remove,
|
||||
});
|
||||
tell("chat_room", { roomId: room.id }, notify);
|
||||
// The "X added Y" lines, live in every open view.
|
||||
for (const message of lines) tell("chat_message", { roomId: room.id, message }, room.members);
|
||||
res.json({ room });
|
||||
})
|
||||
);
|
||||
@@ -112,8 +119,11 @@ router.post(
|
||||
"/rooms/:id/leave",
|
||||
sameOriginGuard,
|
||||
handle((me, req, res) => {
|
||||
const { notify } = chat.leaveGroup(me, req.params.id);
|
||||
const { notify, lines } = chat.leaveGroup(me, req.params.id);
|
||||
tell("chat_room", { roomId: Number(req.params.id) }, notify);
|
||||
const stay = notify.filter((id) => id !== me);
|
||||
for (const message of lines)
|
||||
tell("chat_message", { roomId: Number(req.params.id), message }, stay);
|
||||
res.json({ ok: true });
|
||||
})
|
||||
);
|
||||
@@ -149,9 +159,16 @@ router.post("/rooms/:id/messages", sameOriginGuard, upload, (req, res) =>
|
||||
// multer reads names as latin1; browsers send UTF-8.
|
||||
name: Buffer.from(f.originalname, "latin1").toString("utf8"),
|
||||
type: f.mimetype,
|
||||
buffer: f.buffer,
|
||||
path: f.path,
|
||||
}));
|
||||
const { message, notify } = chat.post(me, req.params.id, { body: req.body?.body, files });
|
||||
let posted;
|
||||
try {
|
||||
posted = chat.post(me, req.params.id, { body: req.body?.body, files });
|
||||
} finally {
|
||||
// Moved into place on success; anything left over is a refused upload.
|
||||
for (const f of files) require("node:fs").rmSync(f.path, { force: true });
|
||||
}
|
||||
const { message, notify } = posted;
|
||||
tell("chat_message", { roomId: message.roomId, message }, notify);
|
||||
res.status(201).json({ message });
|
||||
})(req, res)
|
||||
|
||||
Reference in New Issue
Block a user