mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Implement private messages.
This commit is contained in:
parent
bd5cd7c1a2
commit
66dd71678e
5 changed files with 68 additions and 27 deletions
1
README
1
README
|
@ -138,6 +138,7 @@ Typing a line starting with a slash `/` in the chat dialogue causes
|
||||||
a command to be sent to the server. The following commands are available
|
a command to be sent to the server. The following commands are available
|
||||||
to all users:
|
to all users:
|
||||||
|
|
||||||
|
- `/msg user text`: sends a private message;
|
||||||
- `/me text`: sends a chat message starting with the sender's username;
|
- `/me text`: sends a chat message starting with the sender's username;
|
||||||
- `/leave`: equivalent to clicking the *Disconnect* button.
|
- `/leave`: equivalent to clicking the *Disconnect* button.
|
||||||
- `/set var val`: sets the value of a configuration variable without any
|
- `/set var val`: sets the value of a configuration variable without any
|
||||||
|
|
|
@ -141,6 +141,7 @@ type clientMessage struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
Id string `json:"id,omitempty"`
|
Id string `json:"id,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"`
|
||||||
Permissions group.ClientPermissions `json:"permissions,omitempty"`
|
Permissions group.ClientPermissions `json:"permissions,omitempty"`
|
||||||
|
@ -158,14 +159,14 @@ func fromJSTime(tm uint64) time.Time {
|
||||||
if tm == 0 {
|
if tm == 0 {
|
||||||
return time.Time{}
|
return time.Time{}
|
||||||
}
|
}
|
||||||
return time.Unix(int64(tm)/1000, (int64(tm)%1000) * 1000000)
|
return time.Unix(int64(tm)/1000, (int64(tm)%1000)*1000000)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toJSTime(tm time.Time) uint64 {
|
func toJSTime(tm time.Time) uint64 {
|
||||||
if tm.Before(time.Unix(0, 0)) {
|
if tm.Before(time.Unix(0, 0)) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return uint64((tm.Sub(time.Unix(0, 0)) + time.Millisecond / 2) / time.Millisecond)
|
return uint64((tm.Sub(time.Unix(0, 0)) + time.Millisecond/2) / time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
type closeMessage struct {
|
type closeMessage struct {
|
||||||
|
@ -292,7 +293,7 @@ func addDownConn(c *webClient, id string, remote conn.Up) (*rtpDownConnection, e
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDownConnHelper(c *webClient, conn *rtpDownConnection, remote conn.Up) (error) {
|
func addDownConnHelper(c *webClient, conn *rtpDownConnection, remote conn.Up) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
@ -1048,24 +1049,39 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
}
|
}
|
||||||
case "chat":
|
case "chat":
|
||||||
tm := toJSTime(time.Now())
|
tm := toJSTime(time.Now())
|
||||||
|
if m.Dest == "" {
|
||||||
c.group.AddToChatHistory(
|
c.group.AddToChatHistory(
|
||||||
m.Id, m.Username, tm, m.Kind, m.Value,
|
m.Id, m.Username, tm, m.Kind, m.Value,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
mm := clientMessage{
|
mm := clientMessage{
|
||||||
Type: "chat",
|
Type: "chat",
|
||||||
Id: m.Id,
|
Id: m.Id,
|
||||||
|
Dest: m.Dest,
|
||||||
Username: m.Username,
|
Username: m.Username,
|
||||||
Time: tm,
|
Time: tm,
|
||||||
Kind: m.Kind,
|
Kind: m.Kind,
|
||||||
Value: m.Value,
|
Value: m.Value,
|
||||||
}
|
}
|
||||||
|
if m.Dest == "" {
|
||||||
clients := c.group.GetClients(nil)
|
clients := c.group.GetClients(nil)
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
cc, ok := cc.(*webClient)
|
ccc, ok := cc.(*webClient)
|
||||||
if ok {
|
if ok {
|
||||||
cc.write(mm)
|
ccc.write(mm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cc := c.group.GetClient(m.Dest)
|
||||||
|
if cc == nil {
|
||||||
|
return c.error(group.UserError("user unknown"))
|
||||||
|
}
|
||||||
|
ccc, ok := cc.(*webClient)
|
||||||
|
if !ok {
|
||||||
|
return c.error(group.UserError("this user doesn't chat"))
|
||||||
|
}
|
||||||
|
ccc.write(mm)
|
||||||
|
}
|
||||||
case "groupaction":
|
case "groupaction":
|
||||||
switch m.Kind {
|
switch m.Kind {
|
||||||
case "clearchat":
|
case "clearchat":
|
||||||
|
|
|
@ -124,7 +124,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, username: string, time: number, kind: string, message: string) => void}
|
* @type {(this: ServerConnection, id: string, dest: string, username: string, time: number, kind: string, message: string) => void}
|
||||||
*/
|
*/
|
||||||
this.onchat = null;
|
this.onchat = null;
|
||||||
/**
|
/**
|
||||||
|
@ -148,6 +148,7 @@ function ServerConnection() {
|
||||||
* @property {string} type
|
* @property {string} type
|
||||||
* @property {string} [kind]
|
* @property {string} [kind]
|
||||||
* @property {string} [id]
|
* @property {string} [id]
|
||||||
|
* @property {string} [dest]
|
||||||
* @property {string} [username]
|
* @property {string} [username]
|
||||||
* @property {string} [password]
|
* @property {string} [password]
|
||||||
* @property {Object<string,boolean>} [permissions]
|
* @property {Object<string,boolean>} [permissions]
|
||||||
|
@ -285,7 +286,7 @@ 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.username, m.time, m.kind, m.value,
|
sc, m.id, m.dest, m.username, m.time, m.kind, m.value,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'clearchat':
|
case 'clearchat':
|
||||||
|
@ -428,10 +429,11 @@ ServerConnection.prototype.newUpStream = function(id) {
|
||||||
* @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} message - The text of the message.
|
||||||
*/
|
*/
|
||||||
ServerConnection.prototype.chat = function(username, kind, message) {
|
ServerConnection.prototype.chat = function(username, kind, dest, message) {
|
||||||
this.send({
|
this.send({
|
||||||
type: 'chat',
|
type: 'chat',
|
||||||
id: this.id,
|
id: this.id,
|
||||||
|
dest: dest,
|
||||||
username: username,
|
username: username,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
value: message,
|
value: message,
|
||||||
|
|
|
@ -297,6 +297,15 @@ textarea.form-reply {
|
||||||
background: #ececec;
|
background: #ececec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-private {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-private .message-header:after {
|
||||||
|
content: "(private)";
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.message-system {
|
.message-system {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
background: #ececec;
|
background: #ececec;
|
||||||
|
|
|
@ -1227,6 +1227,7 @@ function formatTime(time) {
|
||||||
* @typedef {Object} lastMessage
|
* @typedef {Object} lastMessage
|
||||||
* @property {string} [nick]
|
* @property {string} [nick]
|
||||||
* @property {string} [peerId]
|
* @property {string} [peerId]
|
||||||
|
* @property {string} [dest]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {lastMessage} */
|
/** @type {lastMessage} */
|
||||||
|
@ -1239,7 +1240,7 @@ let lastMessage = {};
|
||||||
* @param {string} kind
|
* @param {string} kind
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
function addToChatbox(peerId, nick, time, kind, message){
|
function addToChatbox(peerId, dest, nick, time, 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');
|
||||||
|
@ -1248,12 +1249,16 @@ function addToChatbox(peerId, nick, time, kind, message){
|
||||||
row.appendChild(container);
|
row.appendChild(container);
|
||||||
if(!peerId)
|
if(!peerId)
|
||||||
container.classList.add('message-system');
|
container.classList.add('message-system');
|
||||||
else if(userpass.username === nick) {
|
if(userpass.username === nick)
|
||||||
container.classList.add('message-sender');
|
container.classList.add('message-sender');
|
||||||
}
|
if(dest)
|
||||||
|
container.classList.add('message-private');
|
||||||
|
|
||||||
if(kind !== 'me') {
|
if(kind !== 'me') {
|
||||||
let p = formatLines(message.split('\n'));
|
let p = formatLines(message.split('\n'));
|
||||||
if (lastMessage.nick !== nick || lastMessage.peerId !== peerId) {
|
if(lastMessage.nick !== nick ||
|
||||||
|
lastMessage.peerId !== peerId ||
|
||||||
|
lastMessage.dest !== (dest || null)) {
|
||||||
let header = document.createElement('p');
|
let header = document.createElement('p');
|
||||||
let user = document.createElement('span');
|
let user = document.createElement('span');
|
||||||
user.textContent = nick;
|
user.textContent = nick;
|
||||||
|
@ -1272,6 +1277,7 @@ function addToChatbox(peerId, nick, time, kind, message){
|
||||||
container.appendChild(p);
|
container.appendChild(p);
|
||||||
lastMessage.nick = nick;
|
lastMessage.nick = nick;
|
||||||
lastMessage.peerId = peerId;
|
lastMessage.peerId = peerId;
|
||||||
|
lastMessage.dest = (dest || null);
|
||||||
} else {
|
} else {
|
||||||
let asterisk = document.createElement('span');
|
let asterisk = document.createElement('span');
|
||||||
asterisk.textContent = '*';
|
asterisk.textContent = '*';
|
||||||
|
@ -1288,8 +1294,7 @@ function addToChatbox(peerId, nick, time, kind, message){
|
||||||
container.appendChild(user);
|
container.appendChild(user);
|
||||||
container.appendChild(content);
|
container.appendChild(content);
|
||||||
container.classList.add('message-me');
|
container.classList.add('message-me');
|
||||||
delete(lastMessage.nick);
|
lastMessage = {};
|
||||||
delete(lastMessage.peerId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let box = document.getElementById('box');
|
let box = document.getElementById('box');
|
||||||
|
@ -1387,7 +1392,7 @@ function handleInput() {
|
||||||
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, Date.now(), null, s);
|
addToChatbox(null, null, null, Date.now(), null, s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let parsed = parseCommand(rest);
|
let parsed = parseCommand(rest);
|
||||||
|
@ -1424,15 +1429,12 @@ function handleInput() {
|
||||||
}
|
}
|
||||||
serverConnection.groupAction(cmd.slice(1));
|
serverConnection.groupAction(cmd.slice(1));
|
||||||
return;
|
return;
|
||||||
|
case '/msg':
|
||||||
case '/op':
|
case '/op':
|
||||||
case '/unop':
|
case '/unop':
|
||||||
case '/kick':
|
case '/kick':
|
||||||
case '/present':
|
case '/present':
|
||||||
case '/unpresent': {
|
case '/unpresent': {
|
||||||
if(!serverConnection.permissions.op) {
|
|
||||||
displayError("You're not an operator");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let parsed = parseCommand(rest);
|
let parsed = parseCommand(rest);
|
||||||
let id;
|
let id;
|
||||||
if(parsed[0] in users) {
|
if(parsed[0] in users) {
|
||||||
|
@ -1449,7 +1451,18 @@ function handleInput() {
|
||||||
displayError('Unknown user ' + parsed[0]);
|
displayError('Unknown user ' + parsed[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(cmd === '/msg') {
|
||||||
|
let username = getUsername();
|
||||||
|
if(!username) {
|
||||||
|
displayError("Sorry, you're anonymous, you cannot chat");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
serverConnection.chat(username, '', id, parsed[1]);
|
||||||
|
addToChatbox(serverConnection.id,
|
||||||
|
id, username, Date.now(), '', parsed[1]);
|
||||||
|
} else {
|
||||||
serverConnection.userAction(cmd.slice(1), id, parsed[1]);
|
serverConnection.userAction(cmd.slice(1), id, parsed[1]);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1474,7 +1487,7 @@ function handleInput() {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverConnection.chat(username, me ? 'me' : '', message);
|
serverConnection.chat(username, me ? 'me' : '', '', message);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
displayError(e);
|
displayError(e);
|
||||||
|
|
Loading…
Reference in a new issue