add optimistic_id field for messages, allowing us to show our own messages from other clients

This commit is contained in:
hippoz 2022-08-20 00:12:27 +03:00
parent 8b9679b93d
commit 34f945b7f4
Signed by: hippoz
GPG key ID: 7C52899193467641
5 changed files with 38 additions and 13 deletions

View file

@ -60,7 +60,8 @@
messageInput = ""; messageInput = "";
const res = await request("POST", apiRoute(`channels/${channel.id}/messages`), true, { const res = await request("POST", apiRoute(`channels/${channel.id}/messages`), true, {
content: optimisticMessage.content content: optimisticMessage.content,
optimistic_id: optimisticMessageId
}); });
if (res.success && res.ok) { if (res.success && res.ok) {

View file

@ -162,6 +162,15 @@ class MessageStore extends Store {
} }
addMessage(message) { addMessage(message) {
if (message.optimistic_id) {
const index = this.value.findIndex(e => e.id === message.optimistic_id);
if (index !== -1) {
this.value[index] = message;
this.updated();
return;
}
}
this.value.push(message); this.value.push(message);
// only dispatch update if collectOldMessages didn't // only dispatch update if collectOldMessages didn't
if (!this.collectOldMessages()) { if (!this.collectOldMessages()) {
@ -255,10 +264,6 @@ class MessagesStoreProvider {
this.storeByChannel = new Map(); this.storeByChannel = new Map();
gateway.subscribe(GatewayEventType.MessageCreate, (message) => { gateway.subscribe(GatewayEventType.MessageCreate, (message) => {
// we currently don't care about our own messages
if (gateway.user && message.author_id === gateway.user.id)
return;
const store = this.getStoreOrNull(message.channel_id); const store = this.getStoreOrNull(message.channel_id);
if (store) if (store)
store.addMessage(message); store.addMessage(message);

View file

@ -67,13 +67,17 @@ function clientUnsubscribeAll(ws: WebSocket) {
ws.state.dispatchChannels = new Set(); ws.state.dispatchChannels = new Set();
} }
export function dispatch(channel: string, message: GatewayPayload) { export function dispatch(channel: string, message: GatewayPayload | ((ws: WebSocket) => GatewayPayload)) {
const members = dispatchChannels.get(channel); const members = dispatchChannels.get(channel);
if (!members) return; if (!members) return;
members.forEach(e => { members.forEach(e => {
if (e.state.ready) { if (e.state.ready) {
e.send(JSON.stringify(message)); let data = message;
if (typeof message === "function") {
data = message(e);
}
e.send(JSON.stringify(data));
} }
}); });
} }

View file

@ -173,12 +173,14 @@ router.post(
authenticateRoute(), authenticateRoute(),
param("id").isNumeric(), param("id").isNumeric(),
body("content").isLength({ min: 1, max: 4000 }), body("content").isLength({ min: 1, max: 4000 }),
body("optimistic_id").optional().isNumeric(),
async (req, res) => { async (req, res) => {
const validationErrors = validationResult(req); const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) { if (!validationErrors.isEmpty()) {
return res.status(400).json({ ...errors.INVALID_DATA, errors: validationErrors.array() }); return res.status(400).json({ ...errors.INVALID_DATA, errors: validationErrors.array() });
} }
const optimisticId = parseInt(req.body.optimistic_id);
const channelId = parseInt(req.params.id); const channelId = parseInt(req.params.id);
const { content } = req.body; const { content } = req.body;
const authorId = req.user.id; const authorId = req.user.id;
@ -191,7 +193,7 @@ router.post(
}); });
} }
const returnObject = { let returnObject: any = {
id: result.rows[0].id, id: result.rows[0].id,
content, content,
channel_id: channelId, channel_id: channelId,
@ -200,9 +202,22 @@ router.post(
created_at: createdAt created_at: createdAt
}; };
dispatch(`channel:${channelId}`, { dispatch(`channel:${channelId}`, (ws) => {
let payload: any = returnObject;
if (ws.state && ws.state.user && ws.state.user.id === req.user.id && optimisticId) {
payload = {
...payload,
optimistic_id: optimisticId
}
returnObject = {
...returnObject,
optimistic_id: optimisticId
};
}
return {
t: GatewayPayloadType.MessageCreate, t: GatewayPayloadType.MessageCreate,
d: returnObject d: payload
};
}); });
return res.status(201).send(returnObject); return res.status(201).send(returnObject);