feat: add message storage and fetching api #21
3 changed files with 37 additions and 19 deletions
|
@ -94,6 +94,16 @@ app.post("/post/create", [
|
|||
app.get("/channel/:channel/messages", [
|
||||
param("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 })
|
||||
], authenticateEndpoint(async (req, res) => {
|
||||
if (!config.policies.allowSavingMessages) {
|
||||
// TODO: hack
|
||||
res.status(200).json({
|
||||
error: false,
|
||||
message: "SUCCESS_CHANNEL_MESSAGES_FETCHED",
|
||||
channelMessages: []
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
res.status(400).json({ error: true, message: "ERROR_REQUEST_INVALID_DATA", errors: errors.array() });
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const websockets = require("ws");
|
||||
const uuid = require("uuid");
|
||||
const { v4 } = require("uuid");
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const { policies, gatewayPingInterval, gatewayPingCheckInterval, clientFacingPingInterval } = require("../../../config");
|
||||
const { experiments } = require("../../../experiments");
|
||||
|
@ -18,21 +19,21 @@ const wsCloseCodes = {
|
|||
NOT_AUTHORIZED: [4006, "Not authorized"],
|
||||
FLOODING: [4007, "Flooding"],
|
||||
NO_PING: [4008, "No ping"],
|
||||
UNSUPPORTED_ATTRIBUTE: [4009, "Unsupported attribute."],
|
||||
};
|
||||
|
||||
const attributes = {
|
||||
PRESENCE_UPDATES: "PRESENCE_UPDATES",
|
||||
SAVE_MESSAGES: "SAVE_MESSAGES"
|
||||
};
|
||||
|
||||
const supportedAttributes = [attributes.PRESENCE_UPDATES, attributes.SAVE_MESSAGES];
|
||||
const supportedAttributes = [attributes.PRESENCE_UPDATES];
|
||||
|
||||
class GatewaySession {
|
||||
constructor() {
|
||||
this.authenticated = false;
|
||||
this.user = null;
|
||||
this.token = null;
|
||||
this.sessionId = uuid.v4();
|
||||
this.sessionId = v4();
|
||||
this.attributes = [];
|
||||
|
||||
// Specific to websocket sessions
|
||||
|
@ -110,7 +111,7 @@ class GatewayHandler {
|
|||
|
||||
const session = new GatewaySession();
|
||||
session.setWebsocketClient(ws);
|
||||
session.send("HELLO", { pingInterval: clientFacingPingInterval });
|
||||
session.send("HELLO", { pingInterval: clientFacingPingInterval, supportedAttributes });
|
||||
return session;
|
||||
}
|
||||
|
||||
|
@ -177,8 +178,9 @@ class GatewayHandler {
|
|||
|
||||
if (data.attributes) {
|
||||
if (!Array.isArray(data.attributes) || data.attributes.length > 8) return {error: wsCloseCodes.PAYLOAD_ERROR};
|
||||
for (let i = 0; i < data.attributes; i++) {
|
||||
if (!supportedAttributes.includes(data[i])) return {error: wsCloseCodes.PAYLOAD_ERROR};
|
||||
for (let i = 0; i < data.attributes.length; i++) {
|
||||
if (!supportedAttributes.includes(data.attributes[i]))
|
||||
return {error: wsCloseCodes.UNSUPPORTED_ATTRIBUTE};
|
||||
}
|
||||
session.attributes = data.attributes;
|
||||
}
|
||||
|
@ -232,7 +234,20 @@ class GatewayHandler {
|
|||
// Check if the user is in that channel before broadcasting the message
|
||||
if (!session.channels.includes(data.channel._id)) return {error: wsCloseCodes.NOT_AUTHORIZED};
|
||||
|
||||
this.eachInChannel({channelId: data.channel._id}, ({ session: remoteSession }) => {
|
||||
this.eachInChannel({channelId: data.channel._id}, async ({ session: remoteSession }) => {
|
||||
let id;
|
||||
if (policies.allowSavingMessages) {
|
||||
const message = await Message.create({
|
||||
author: session.user._id,
|
||||
channel: data.channel._id,
|
||||
content: messageContent,
|
||||
createdAt: new Date().getTime()
|
||||
});
|
||||
id = message._id;
|
||||
} else {
|
||||
id = new mongoose.Types.ObjectId();
|
||||
}
|
||||
|
||||
remoteSession.send("EVENT_CREATE_MESSAGE", {
|
||||
content: messageContent,
|
||||
channel: {
|
||||
|
@ -242,18 +257,9 @@ class GatewayHandler {
|
|||
_id: session.user._id,
|
||||
username: session.user.username
|
||||
},
|
||||
_id: uuid.v4()
|
||||
_id: id
|
||||
});
|
||||
});
|
||||
|
||||
if (session.hasAttribute(attributes.SAVE_MESSAGES)) {
|
||||
await Message.create({
|
||||
author: session.user._id,
|
||||
channel: data.channel._id,
|
||||
content: messageContent,
|
||||
createdAt: new Date().getTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ module.exports = {
|
|||
allowAccountCreation: true,
|
||||
allowLogin: true,
|
||||
allowGatewayConnection: true,
|
||||
// The policy below will make all messages sent over the gateway to be in plain text saved to the database.
|
||||
// This is experimental and dangerous, and, as such, should generally not be used.
|
||||
allowSavingMessages: true,
|
||||
perUserMaxGatewayConnections: 4
|
||||
},
|
||||
/*
|
||||
|
@ -35,7 +38,6 @@ module.exports = {
|
|||
gatewayPingInterval: 15000,
|
||||
gatewayPingCheckInterval: 4500,
|
||||
clientFacingPingInterval: 14750,
|
||||
unsafeStoreMessages: false,
|
||||
bcryptRounds: 10,
|
||||
roleMap: {
|
||||
"BANNED": 0,
|
||||
|
|
Reference in a new issue