Commit d09c0f0a authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Make the value field of client messages carry arbitrary types.

parent 5e831ab5
...@@ -83,7 +83,7 @@ type ChatHistoryEntry struct { ...@@ -83,7 +83,7 @@ type ChatHistoryEntry struct {
User string User string
Time int64 Time int64
Kind string Kind string
Value string Value interface{}
} }
const ( const (
...@@ -620,7 +620,7 @@ func (g *Group) ClearChatHistory() { ...@@ -620,7 +620,7 @@ func (g *Group) ClearChatHistory() {
g.history = nil g.history = nil
} }
func (g *Group) AddToChatHistory(id, user string, time int64, kind, value string) { func (g *Group) AddToChatHistory(id, user string, time int64, kind string, value interface{}) {
g.mu.Lock() g.mu.Lock()
defer g.mu.Unlock() defer g.mu.Unlock()
......
...@@ -27,13 +27,12 @@ func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) { ...@@ -27,13 +27,12 @@ func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
code = websocket.CloseNormalClosure code = websocket.CloseNormalClosure
case group.ProtocolError: case group.ProtocolError:
code = websocket.CloseProtocolError code = websocket.CloseProtocolError
s := e.Error()
m = &clientMessage{ m = &clientMessage{
Type: "usermessage", Type: "usermessage",
Kind: "error", Kind: "error",
Dest: id, Dest: id,
Privileged: true, Privileged: true,
Value: &s, Value: e.Error(),
} }
text = e.Error() text = e.Error()
case group.UserError, group.KickError: case group.UserError, group.KickError:
...@@ -171,7 +170,7 @@ type clientMessage struct { ...@@ -171,7 +170,7 @@ type clientMessage struct {
Privileged bool `json:"privileged,omitempty"` Privileged bool `json:"privileged,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 interface{} `json:"value,omitempty"`
Time int64 `json:"time,omitempty"` Time int64 `json:"time,omitempty"`
Offer *webrtc.SessionDescription `json:"offer,omitempty"` Offer *webrtc.SessionDescription `json:"offer,omitempty"`
Answer *webrtc.SessionDescription `json:"answer,omitempty"` Answer *webrtc.SessionDescription `json:"answer,omitempty"`
...@@ -808,11 +807,10 @@ func clientLoop(c *webClient, ws *websocket.Conn) error { ...@@ -808,11 +807,10 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
} }
} }
case addLabelAction: case addLabelAction:
label := a.label
c.write(clientMessage{ c.write(clientMessage{
Type: "label", Type: "label",
Id: a.id, Id: a.id,
Value: &label, Value: a.label,
}) })
case pushConnsAction: case pushConnsAction:
g := c.group g := c.group
...@@ -1063,7 +1061,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1063,7 +1061,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Kind: "fail", Kind: "fail",
Group: m.Group, Group: m.Group,
Permissions: &group.ClientPermissions{}, Permissions: &group.ClientPermissions{},
Value: &s, Value: s,
}) })
} }
if redirect := g.Redirect(); redirect != "" { if redirect := g.Redirect(); redirect != "" {
...@@ -1074,7 +1072,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1074,7 +1072,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Kind: "redirect", Kind: "redirect",
Group: m.Group, Group: m.Group,
Permissions: &group.ClientPermissions{}, Permissions: &group.ClientPermissions{},
Value: &redirect, Value: redirect,
}) })
} }
c.group = g c.group = g
...@@ -1090,13 +1088,12 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1090,13 +1088,12 @@ func handleClientMessage(c *webClient, m clientMessage) error {
} }
h := c.group.GetChatHistory() h := c.group.GetChatHistory()
for _, m := range h { for _, m := range h {
message := m.Value
err := c.write(clientMessage{ err := c.write(clientMessage{
Type: "chat", Type: "chat",
Id: m.Id, Id: m.Id,
Username: m.User, Username: m.User,
Time: m.Time, Time: m.Time,
Value: &message, Value: m.Value,
Kind: m.Kind, Kind: m.Kind,
}) })
if err != nil { if err != nil {
...@@ -1184,12 +1181,9 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1184,12 +1181,9 @@ func handleClientMessage(c *webClient, m clientMessage) error {
tm := group.ToJSTime(time.Now()) tm := group.ToJSTime(time.Now())
if m.Type == "chat" { if m.Type == "chat" {
if m.Value == nil {
return group.ProtocolError("missing value")
}
if m.Dest == "" { if m.Dest == "" {
g.AddToChatHistory( g.AddToChatHistory(
m.Id, m.Username, tm, m.Kind, *m.Value, m.Id, m.Username, tm, m.Kind, m.Value,
) )
} }
} }
...@@ -1249,8 +1243,9 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1249,8 +1243,9 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(group.UserError("not authorised")) return c.error(group.UserError("not authorised"))
} }
message := "" message := ""
if m.Value != nil { v, ok := m.Value.(string)
message = *m.Value if ok {
message = v
} }
g.SetLocked(m.Kind == "lock", message) g.SetLocked(m.Kind == "lock", message)
case "record": case "record":
...@@ -1299,7 +1294,7 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1299,7 +1294,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Dest: c.id, Dest: c.id,
Username: "Server", Username: "Server",
Time: group.ToJSTime(time.Now()), Time: group.ToJSTime(time.Now()),
Value: &s, Value: s,
}) })
default: default:
return group.ProtocolError("unknown group action") return group.ProtocolError("unknown group action")
...@@ -1329,8 +1324,9 @@ func handleClientMessage(c *webClient, m clientMessage) error { ...@@ -1329,8 +1324,9 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(group.UserError("not authorised")) return c.error(group.UserError("not authorised"))
} }
message := "" message := ""
if m.Value != nil { v, ok := m.Value.(string)
message = *m.Value if ok {
message = v
} }
err := kickClient(g, m.Id, m.Username, m.Dest, message) err := kickClient(g, m.Id, m.Username, m.Dest, message)
if err != nil { if err != nil {
...@@ -1420,7 +1416,7 @@ func (c *webClient) Warn(oponly bool, message string) error { ...@@ -1420,7 +1416,7 @@ func (c *webClient) Warn(oponly bool, message string) error {
Kind: "warning", Kind: "warning",
Dest: c.id, Dest: c.id,
Privileged: true, Privileged: true,
Value: &message, Value: message,
}) })
} }
...@@ -1456,13 +1452,12 @@ func (c *webClient) close(data []byte) error { ...@@ -1456,13 +1452,12 @@ func (c *webClient) close(data []byte) error {
func errorMessage(id string, err error) *clientMessage { func errorMessage(id string, err error) *clientMessage {
switch e := err.(type) { switch e := err.(type) {
case group.UserError: case group.UserError:
message := e.Error()
return &clientMessage{ return &clientMessage{
Type: "usermessage", Type: "usermessage",
Kind: "error", Kind: "error",
Dest: id, Dest: id,
Privileged: true, Privileged: true,
Value: &message, Value: e.Error(),
} }
case group.KickError: case group.KickError:
message := e.Message message := e.Message
...@@ -1476,7 +1471,7 @@ func errorMessage(id string, err error) *clientMessage { ...@@ -1476,7 +1471,7 @@ func errorMessage(id string, err error) *clientMessage {
Username: e.Username, Username: e.Username,
Dest: id, Dest: id,
Privileged: true, Privileged: true,
Value: &message, Value: message,
} }
default: default:
return nil return nil
......
...@@ -1549,6 +1549,43 @@ async function gotJoined(kind, group, perms, message) { ...@@ -1549,6 +1549,43 @@ async function gotJoined(kind, group, perms, message) {
} }
} }
/**
* @param {string} id
* @param {string} dest
* @param {string} username
* @param {number} time
* @param {boolean} privileged
* @param {string} kind
* @param {unknown} message
*/
function gotUserMessage(id, dest, username, time, privileged, kind, message) {
switch(kind) {
case 'error':
case 'warning':
case 'info':
let from = id ? (username || 'Anonymous') : 'The Server';
if(privileged)
displayError(`${from} said: ${message}`, kind);
else
console.error(`Got unprivileged message of kind ${kind}`);
break;
case 'mute':
console.log(id, dest, username);
if(privileged) {
setLocalMute(true, true);
let by = username ? ' by ' + username : '';
displayWarning(`You have been muted${by}`);
} else {
console.error(`Got unprivileged message of kind ${kind}`);
}
break;
default:
console.warn(`Got unknown user message ${kind}`);
break;
}
};
const urlRegexp = /https?:\/\/[-a-zA-Z0-9@:%/._\\+~#&()=?]+[-a-zA-Z0-9@:%/_\\+~#&()=]/g; const urlRegexp = /https?:\/\/[-a-zA-Z0-9@:%/._\\+~#&()=?]+[-a-zA-Z0-9@:%/_\\+~#&()=]/g;
/** /**
...@@ -1622,7 +1659,7 @@ let lastMessage = {}; ...@@ -1622,7 +1659,7 @@ let lastMessage = {};
* @param {string} nick * @param {string} nick
* @param {number} time * @param {number} time
* @param {string} kind * @param {string} kind
* @param {string} message * @param {unknown} message
*/ */
function addToChatbox(peerId, dest, nick, time, privileged, kind, message) { function addToChatbox(peerId, dest, nick, time, privileged, kind, message) {
let userpass = getUserPass(); let userpass = getUserPass();
...@@ -1641,7 +1678,7 @@ function addToChatbox(peerId, dest, nick, time, privileged, kind, message) { ...@@ -1641,7 +1678,7 @@ function addToChatbox(peerId, dest, nick, time, privileged, kind, message) {
container.classList.add('message-private'); container.classList.add('message-private');
if(kind !== 'me') { if(kind !== 'me') {
let p = formatLines(message.split('\n')); let p = formatLines(message.toString().split('\n'));
let doHeader = true; let doHeader = true;
if(!peerId && !dest && !nick) { if(!peerId && !dest && !nick) {
doHeader = false; doHeader = false;
...@@ -1689,7 +1726,7 @@ function addToChatbox(peerId, dest, nick, time, privileged, kind, message) { ...@@ -1689,7 +1726,7 @@ function addToChatbox(peerId, dest, nick, time, privileged, kind, message) {
user.textContent = nick || '(anon)'; user.textContent = nick || '(anon)';
user.classList.add('message-me-user'); user.classList.add('message-me-user');
let content = document.createElement('span'); let content = document.createElement('span');
formatLine(message).forEach(elt => { formatLine(message.toString()).forEach(elt => {
content.appendChild(elt); content.appendChild(elt);
}); });
content.classList.add('message-me-content'); content.classList.add('message-me-content');
...@@ -2300,32 +2337,8 @@ async function serverConnect() { ...@@ -2300,32 +2337,8 @@ async function serverConnect() {
serverConnection.onjoined = gotJoined; serverConnection.onjoined = gotJoined;
serverConnection.onchat = addToChatbox; serverConnection.onchat = addToChatbox;
serverConnection.onclearchat = clearChat; serverConnection.onclearchat = clearChat;
serverConnection.onusermessage = function(id, dest, username, time, privileged, kind, message) { serverConnection.onusermessage = gotUserMessage;
switch(kind) {
case 'error':
case 'warning':
case 'info':
let from = id ? (username || 'Anonymous') : 'The Server';
if(privileged)
displayError(`${from} said: ${message}`, kind);
else
console.error(`Got unprivileged message of kind ${kind}`);
break;
case 'mute':
console.log(id, dest, username);
if(privileged) {
setLocalMute(true, true);
let by = username ? ' by ' + username : '';
displayWarning(`You have been muted${by}`);
} else {
console.error(`Got unprivileged 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);
......
...@@ -142,7 +142,7 @@ function ServerConnection() { ...@@ -142,7 +142,7 @@ 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, privileged: boolean, kind: string, message: string) => void} * @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, privileged: boolean, kind: string, message: unknown) => void}
*/ */
this.onchat = null; this.onchat = null;
/** /**
...@@ -154,7 +154,7 @@ function ServerConnection() { ...@@ -154,7 +154,7 @@ function ServerConnection() {
* 'id' is non-null, 'privileged' indicates whether the message was * 'id' is non-null, 'privileged' indicates whether the message was
* sent by an operator. * sent by an operator.
* *
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, privileged: boolean, kind: string, message: string) => void} * @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, privileged: boolean, kind: string, message: unknown) => void}
*/ */
this.onusermessage = null; this.onusermessage = null;
/** /**
...@@ -177,7 +177,7 @@ function ServerConnection() { ...@@ -177,7 +177,7 @@ function ServerConnection() {
* @property {boolean} [privileged] * @property {boolean} [privileged]
* @property {Object<string,boolean>} [permissions] * @property {Object<string,boolean>} [permissions]
* @property {string} [group] * @property {string} [group]
* @property {string} [value] * @property {unknown} [value]
* @property {RTCSessionDescriptionInit} [offer] * @property {RTCSessionDescriptionInit} [offer]
* @property {RTCSessionDescriptionInit} [answer] * @property {RTCSessionDescriptionInit} [answer]
* @property {RTCIceCandidate} [candidate] * @property {RTCIceCandidate} [candidate]
......
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