Commit 6040d194 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Allow forwarding usermessages.

They now have the same format as chat messages; the only difference
is that they are not stored in the chat history.

Also adds userMessage method to ServerConnection.

Fix usermessages.
parent 60470cf8
...@@ -157,6 +157,7 @@ type clientMessage struct { ...@@ -157,6 +157,7 @@ type clientMessage struct {
Dest string `json:"dest,omitempty"` Dest string `json:"dest,omitempty"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Priviledged bool `json:"priviledged,omitempty"`
Permissions *group.ClientPermissions `json:"permissions,omitempty"` Permissions *group.ClientPermissions `json:"permissions,omitempty"`
Group string `json:"group,omitempty"` Group string `json:"group,omitempty"`
Value string `json:"value,omitempty"` Value string `json:"value,omitempty"`
...@@ -676,9 +677,11 @@ func StartClient(conn *websocket.Conn) (err error) { ...@@ -676,9 +677,11 @@ func StartClient(conn *websocket.Conn) (err error) {
m, e := errorToWSCloseMessage(err) m, e := errorToWSCloseMessage(err)
if m != "" { if m != "" {
c.write(clientMessage{ c.write(clientMessage{
Type: "usermessage", Type: "usermessage",
Kind: "error", Kind: "error",
Value: m, Dest: c.id,
Priviledged: true,
Value: m,
}) })
} }
c.close(e) c.close(e)
...@@ -1065,21 +1068,24 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1065,21 +1068,24 @@ func handleClientMessage(c *webClient, m clientMessage) error {
if err != nil { if err != nil {
log.Printf("ICE: %v", err) log.Printf("ICE: %v", err)
} }
case "chat": case "chat", "usermessage":
tm := group.ToJSTime(time.Now()) tm := group.ToJSTime(time.Now())
if m.Dest == "" { if m.Type == "chat" {
c.group.AddToChatHistory( if m.Dest == "" {
m.Id, m.Username, tm, m.Kind, m.Value, c.group.AddToChatHistory(
) m.Id, m.Username, tm, m.Kind, m.Value,
)
}
} }
mm := clientMessage{ mm := clientMessage{
Type: "chat", Type: m.Type,
Id: m.Id, Id: m.Id,
Dest: m.Dest, Dest: m.Dest,
Username: m.Username, Username: m.Username,
Time: tm, Priviledged: c.permissions.Op,
Kind: m.Kind, Time: tm,
Value: m.Value, Kind: m.Kind,
Value: m.Value,
} }
if m.Dest == "" { if m.Dest == "" {
clients := c.group.GetClients(nil) clients := c.group.GetClients(nil)
...@@ -1154,7 +1160,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1154,7 +1160,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
if !c.permissions.Op { if !c.permissions.Op {
return c.error(group.UserError("not authorised")) return c.error(group.UserError("not authorised"))
} }
err := setPermissions(c.group, m.Id, m.Kind) err := setPermissions(c.group, m.Dest, m.Kind)
if err != nil { if err != nil {
return c.error(err) return c.error(err)
} }
...@@ -1166,7 +1172,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1166,7 +1172,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
if message == "" { if message == "" {
message = "you have been kicked out" message = "you have been kicked out"
} }
err := kickClient(c.group, m.Id, message) err := kickClient(c.group, m.Dest, message)
if err != nil { if err != nil {
return c.error(err) return c.error(err)
} }
...@@ -1277,9 +1283,11 @@ func (c *webClient) error(err error) error { ...@@ -1277,9 +1283,11 @@ func (c *webClient) error(err error) error {
switch e := err.(type) { switch e := err.(type) {
case group.UserError: case group.UserError:
return c.write(clientMessage{ return c.write(clientMessage{
Type: "usermessage", Type: "usermessage",
Kind: "error", Kind: "error",
Value: string(e), Dest: c.id,
Priviledged: true,
Value: string(e),
}) })
default: default:
return err return err
......
...@@ -124,9 +124,21 @@ function ServerConnection() { ...@@ -124,9 +124,21 @@ function ServerConnection() {
/** /**
* onchat is called whenever a new chat message is received. * onchat is called whenever a new chat message is received.
* *
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, kind: string, message: string) => void} * @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, priviledged: boolean, kind: string, message: string) => void}
*/ */
this.onchat = null; this.onchat = null;
/**
* onusermessage is called when an application-specific message is
* received. Id is null when the message originated at the server,
* a user-id otherwise.
*
* 'kind' is typically one of 'error', 'warning', 'info' or 'mute'. If
* 'id' is non-null, 'priviledged' indicates whether the message was
* sent by an operator.
*
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, priviledged: boolean, kind: string, message: string) => void}
*/
this.onusermessage = null;
/** /**
* onclearchat is called whenever the server requests that the chat * onclearchat is called whenever the server requests that the chat
* be cleared. * be cleared.
...@@ -134,13 +146,6 @@ function ServerConnection() { ...@@ -134,13 +146,6 @@ function ServerConnection() {
* @type{(this: ServerConnection) => void} * @type{(this: ServerConnection) => void}
*/ */
this.onclearchat = null; this.onclearchat = null;
/**
* onusermessage is called when the server sends an error or warning
* message that should be displayed to the user.
*
* @type{(this: ServerConnection, kind: string, message: string) => void}
*/
this.onusermessage = null;
} }
/** /**
...@@ -151,6 +156,7 @@ function ServerConnection() { ...@@ -151,6 +156,7 @@ function ServerConnection() {
* @property {string} [dest] * @property {string} [dest]
* @property {string} [username] * @property {string} [username]
* @property {string} [password] * @property {string} [password]
* @property {boolean} [priviledged]
* @property {Object<string,boolean>} [permissions] * @property {Object<string,boolean>} [permissions]
* @property {string} [group] * @property {string} [group]
* @property {string} [value] * @property {string} [value]
...@@ -286,7 +292,15 @@ ServerConnection.prototype.connect = async function(url) { ...@@ -286,7 +292,15 @@ ServerConnection.prototype.connect = async function(url) {
case 'chat': case 'chat':
if(sc.onchat) if(sc.onchat)
sc.onchat.call( sc.onchat.call(
sc, m.id, m.dest, m.username, m.time, m.kind, m.value, sc, m.id, m.dest, m.username, m.time,
m.privileged, m.kind, m.value,
);
break;
case 'usermessage':
if(sc.onusermessage)
sc.onusermessage.call(
sc, m.id, m.dest, m.username, m.time,
m.priviledged, m.kind, m.value,
); );
break; break;
case 'clearchat': case 'clearchat':
...@@ -301,10 +315,6 @@ ServerConnection.prototype.connect = async function(url) { ...@@ -301,10 +315,6 @@ ServerConnection.prototype.connect = async function(url) {
case 'pong': case 'pong':
/* nothing */ /* nothing */
break; break;
case 'usermessage':
if(sc.onusermessage)
sc.onusermessage.call(sc, m.kind, m.value);
break;
default: default:
console.warn('Unexpected server message', m.type); console.warn('Unexpected server message', m.type);
return; return;
...@@ -422,48 +432,67 @@ ServerConnection.prototype.newUpStream = function(id) { ...@@ -422,48 +432,67 @@ ServerConnection.prototype.newUpStream = function(id) {
* chat sends a chat message to the server. The server will normally echo * chat sends a chat message to the server. The server will normally echo
* the message back to the client. * the message back to the client.
* *
* @param {string} username - The username of the sending user. * @param {string} username - The sender's username.
* @param {string} kind - The kind of message, either "" or "me". * @param {string} kind - The kind of message, either "" or "me".
* @param {string} message - The text of the message. * @param {string} dest - The id to send the message to, empty for broadcast.
* @param {string} value - The text of the message.
*/ */
ServerConnection.prototype.chat = function(username, kind, dest, message) { ServerConnection.prototype.chat = function(username, kind, dest, value) {
this.send({ this.send({
type: 'chat', type: 'chat',
id: this.id, id: this.id,
dest: dest, dest: dest,
username: username, username: username,
kind: kind, kind: kind,
value: message, value: value,
}); });
}; };
/** /**
* groupAction sends a request to act on the current group. * userAction sends a request to act on a user.
* *
* @param {string} kind - One of "clearchat", "lock", "unlock", "record or * @param {string} kind - One of "op", "unop", "kick", "present", "unpresent".
* "unrecord". * @param {string} dest - The id of the user to act upon.
* @param {string} [message] - An optional user-readable message. * @param {string} [value] - An optional user-readable message.
*/ */
ServerConnection.prototype.groupAction = function(kind, message) { ServerConnection.prototype.userAction = function(kind, dest, value) {
this.send({ this.send({
type: 'groupaction', type: 'useraction',
id: this.id,
dest: dest,
kind: kind, kind: kind,
value: message, value: value,
}); });
}; };
/** /**
* userAction sends a request to act on a user. * userMessage sends an application-specific message to a user.
* *
* @param {string} kind - One of "op", "unop", "kick", "present", "unpresent". * @param {string} kind - The kind of application-specific message.
* @param {string} id - The id of the user to act upon. * @param {string} dest - The id of the user to send the message to.
* @param {string} [value] - An optional parameter.
*/
ServerConnection.prototype.userMessage = function(kind, dest, value) {
this.send({
type: 'usermessage',
id: this.id,
dest: dest,
kind: kind,
value: value,
});
};
/**
* groupAction sends a request to act on the current group.
*
* @param {string} kind - One of "clearchat", "lock", "unlock", "record or
* "unrecord".
* @param {string} [message] - An optional user-readable message. * @param {string} [message] - An optional user-readable message.
*/ */
ServerConnection.prototype.userAction = function(kind, id, message) { ServerConnection.prototype.groupAction = function(kind, message) {
this.send({ this.send({
type: 'useraction', type: 'groupaction',
kind: kind, kind: kind,
id: id,
value: message, value: message,
}); });
}; };
......
...@@ -1483,7 +1483,7 @@ let lastMessage = {}; ...@@ -1483,7 +1483,7 @@ let lastMessage = {};
* @param {string} kind * @param {string} kind
* @param {string} message * @param {string} message
*/ */
function addToChatbox(peerId, dest, nick, time, kind, message) { function addToChatbox(peerId, dest, nick, time, priviledged, kind, message) {
let userpass = getUserPass(); let userpass = getUserPass();
let row = document.createElement('div'); let row = document.createElement('div');
row.classList.add('message-row'); row.classList.add('message-row');
...@@ -1608,7 +1608,7 @@ commands.help = { ...@@ -1608,7 +1608,7 @@ commands.help = {
let s = ''; let s = '';
for(let i = 0; i < cs.length; i++) for(let i = 0; i < cs.length; i++)
s = s + cs[i] + '\n'; s = s + cs[i] + '\n';
addToChatbox(null, null, null, Date.now(), null, s); addToChatbox(null, null, null, Date.now(), false, null, s);
} }
}; };
...@@ -1626,7 +1626,7 @@ commands.set = { ...@@ -1626,7 +1626,7 @@ commands.set = {
let s = ""; let s = "";
for(let key in settings) for(let key in settings)
s = s + `${key}: ${JSON.stringify(settings[key])}\n`; s = s + `${key}: ${JSON.stringify(settings[key])}\n`;
addToChatbox(null, null, null, Date.now(), null, s); addToChatbox(null, null, null, Date.now(), false, null, s);
return; return;
} }
let p = parseCommand(r); let p = parseCommand(r);
...@@ -1756,7 +1756,8 @@ commands.msg = { ...@@ -1756,7 +1756,8 @@ commands.msg = {
throw new Error(`Unknown user ${p[0]}`); throw new Error(`Unknown user ${p[0]}`);
let username = getUsername(); let username = getUsername();
serverConnection.chat(username, '', id, p[1]); serverConnection.chat(username, '', id, p[1]);
addToChatbox(serverConnection.id, id, username, Date.now(), '', p[1]); addToChatbox(serverConnection.id, id, username,
Date.now(), false, '', p[1]);
} }
}; };
...@@ -2089,12 +2090,22 @@ async function serverConnect() { ...@@ -2089,12 +2090,22 @@ async function serverConnect() {
serverConnection.onpermissions = gotPermissions; serverConnection.onpermissions = gotPermissions;
serverConnection.onchat = addToChatbox; serverConnection.onchat = addToChatbox;
serverConnection.onclearchat = clearChat; serverConnection.onclearchat = clearChat;
serverConnection.onusermessage = function(kind, message) { serverConnection.onusermessage = function(id, dest, username, time, priviledged, kind, message) {
if(kind === 'error') let from = id ? (username || 'Anonymous') : 'The Server';
displayError(`The server said: ${message}`); switch(kind) {
else case 'error':
displayWarning(`The server said: ${message}`); case 'warning':
} case 'info':
if(priviledged)
displayError(`${from} said: ${message}`, kind);
else
console.error(`Got unpriviledged message of kind ${kind}`);
break;
default:
console.warn(`Got unknown user message ${kind}`);
break;
}
};
let url = `ws${location.protocol === 'https:' ? 's' : ''}://${location.host}/ws`; let url = `ws${location.protocol === 'https:' ? 's' : ''}://${location.host}/ws`;
try { try {
await serverConnection.connect(url); await serverConnection.connect(url);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment