diff --git a/historyKeeper.js b/historyKeeper.js index 10137dd06..170de6233 100644 --- a/historyKeeper.js +++ b/historyKeeper.js @@ -400,6 +400,11 @@ module.exports.create = function (cfg) { * writes messages to the store */ const onChannelMessage = function (ctx, channel, msgStruct) { + // TODO our usage of 'channel' here looks prone to errors + // we only use it for its 'id', but it can contain other stuff + // also, we're using this RPC from both the RPC and Netflux-server + // we should probably just change this to expect a channel id directly + // don't store messages if the channel id indicates that it's an ephemeral message if (!channel.id || channel.id.length === EPHEMERAL_CHANNEL_LENGTH) { return; } @@ -986,7 +991,6 @@ module.exports.create = function (cfg) { onChannelCleared(ctx, msg[4]); } - // FIXME METADATA CHANGE if (msg[3] === 'SET_METADATA') { // or whatever we call the RPC???? // make sure we update our cache of metadata // or at least invalidate it and force other mechanisms to recompute its state @@ -994,6 +998,12 @@ module.exports.create = function (cfg) { onChannelMetadataChanged(ctx, msg[4].channel, output[1]); } + // unauthenticated RPC calls have a different message format + if (msg[0] === "WRITE_PRIVATE_MESSAGE" && output) { + historyKeeperBroadcast(ctx, output.channel, output.message); + } + + // finally, send a response to the client that sent the RPC sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'MSG', user.id, JSON.stringify([parsed[0]].concat(output))]); }); } catch (e) { diff --git a/rpc.js b/rpc.js index 6ab004865..437e9222d 100644 --- a/rpc.js +++ b/rpc.js @@ -1547,6 +1547,57 @@ var isNewChannel = function (Env, channel, cb) { }); }; +/* writePrivateMessage + allows users to anonymously send a message to the channel + prevents their netflux-id from being stored in history + and from being broadcast to anyone that might currently be in the channel + + Otherwise behaves the same as sending to a channel +*/ +var writePrivateMessage = function (Env, args, nfwssCtx, cb) { + var channelId = args[0]; + var msg = args[1]; + + // don't bother handling empty messages + if (!msg) { return void cb("INVALID_MESSAGE"); } + + // don't support anything except regular channels + if (!isValidId(channelId) || channelId.length !== 32) { + return void cb("INVALID_CHAN"); + } + + // We expect a modern netflux-websocket-server instance + // if this API isn't here everything will fall apart anyway + if (!(nfwssCtx && nfwssCtx.historyKeeper && typeof(nfwssCtx.historyKeeper.onChannelMessage) === 'function')) { + return void cb("NOT_IMPLEMENTED"); + } + + // historyKeeper expects something with an 'id' attribute + // it will fail unless you provide it, but it doesn't need anything else + var channelStruct = { + id: channelId, + }; + + // construct a message to store and broadcast + var fullMessage = [ + 0, // idk + null, // normally the netflux id, null isn't rejected, and it distinguishes messages written in this way + "MSG", // indicate that this is a MSG + channelId, // channel id + msg // the actual message content. Generally a string + ]; + + // store the message and do everything else that is typically done when going through historyKeeper + nfwssCtx.historyKeeper.onChannelMessage(nfwssCtx, channelStruct, fullMessage); + + // call back with the message and the target channel. + // historyKeeper will take care of broadcasting it if anyone is in the channel + cb(void 0, { + channel: channelId, + message: fullMessage + }); +}; + var getDiskUsage = function (Env, cb) { var data = {}; nThen(function (waitFor) { @@ -1646,6 +1697,7 @@ var isUnauthenticatedCall = function (call) { 'IS_NEW_CHANNEL', 'GET_HISTORY_OFFSET', 'GET_DELETED_PADS', + 'WRITE_PRIVATE_MESSAGE', ].indexOf(call) !== -1; }; @@ -1813,6 +1865,10 @@ RPC.create = function ( return void isNewChannel(Env, msg[1], function (e, isNew) { respond(e, [null, isNew, null]); }); + case 'WRITE_PRIVATE_MESSAGE': + return void writePrivateMessage(Env, msg[1], nfwssCtx, function (e, output) { + respond(e, output); + }); default: Log.warn("UNSUPPORTED_RPC_CALL", msg); return respond('UNSUPPORTED_RPC_CALL', msg);