mirror of
https://github.com/jech/galene.git
synced 2024-11-22 08:35:57 +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
|
||||
to all users:
|
||||
|
||||
- `/msg user text`: sends a private message;
|
||||
- `/me text`: sends a chat message starting with the sender's username;
|
||||
- `/leave`: equivalent to clicking the *Disconnect* button.
|
||||
- `/set var val`: sets the value of a configuration variable without any
|
||||
|
|
|
@ -141,6 +141,7 @@ type clientMessage struct {
|
|||
Type string `json:"type"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
Dest string `json:"dest,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Permissions group.ClientPermissions `json:"permissions,omitempty"`
|
||||
|
@ -158,14 +159,14 @@ func fromJSTime(tm uint64) time.Time {
|
|||
if tm == 0 {
|
||||
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 {
|
||||
if tm.Before(time.Unix(0, 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 {
|
||||
|
@ -292,7 +293,7 @@ func addDownConn(c *webClient, id string, remote conn.Up) (*rtpDownConnection, e
|
|||
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()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
|
@ -1048,24 +1049,39 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
|||
}
|
||||
case "chat":
|
||||
tm := toJSTime(time.Now())
|
||||
if m.Dest == "" {
|
||||
c.group.AddToChatHistory(
|
||||
m.Id, m.Username, tm, m.Kind, m.Value,
|
||||
)
|
||||
}
|
||||
mm := clientMessage{
|
||||
Type: "chat",
|
||||
Id: m.Id,
|
||||
Dest: m.Dest,
|
||||
Username: m.Username,
|
||||
Time: tm,
|
||||
Kind: m.Kind,
|
||||
Value: m.Value,
|
||||
}
|
||||
if m.Dest == "" {
|
||||
clients := c.group.GetClients(nil)
|
||||
for _, cc := range clients {
|
||||
cc, ok := cc.(*webClient)
|
||||
ccc, ok := cc.(*webClient)
|
||||
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":
|
||||
switch m.Kind {
|
||||
case "clearchat":
|
||||
|
|
|
@ -124,7 +124,7 @@ function ServerConnection() {
|
|||
/**
|
||||
* 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;
|
||||
/**
|
||||
|
@ -148,6 +148,7 @@ function ServerConnection() {
|
|||
* @property {string} type
|
||||
* @property {string} [kind]
|
||||
* @property {string} [id]
|
||||
* @property {string} [dest]
|
||||
* @property {string} [username]
|
||||
* @property {string} [password]
|
||||
* @property {Object<string,boolean>} [permissions]
|
||||
|
@ -285,7 +286,7 @@ ServerConnection.prototype.connect = async function(url) {
|
|||
case 'chat':
|
||||
if(sc.onchat)
|
||||
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;
|
||||
case 'clearchat':
|
||||
|
@ -428,10 +429,11 @@ ServerConnection.prototype.newUpStream = function(id) {
|
|||
* @param {string} kind - The kind of message, either "" or "me".
|
||||
* @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({
|
||||
type: 'chat',
|
||||
id: this.id,
|
||||
dest: dest,
|
||||
username: username,
|
||||
kind: kind,
|
||||
value: message,
|
||||
|
|
|
@ -297,6 +297,15 @@ textarea.form-reply {
|
|||
background: #ececec;
|
||||
}
|
||||
|
||||
.message-private {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.message-private .message-header:after {
|
||||
content: "(private)";
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.message-system {
|
||||
font-size: 10px;
|
||||
background: #ececec;
|
||||
|
|
|
@ -1227,6 +1227,7 @@ function formatTime(time) {
|
|||
* @typedef {Object} lastMessage
|
||||
* @property {string} [nick]
|
||||
* @property {string} [peerId]
|
||||
* @property {string} [dest]
|
||||
*/
|
||||
|
||||
/** @type {lastMessage} */
|
||||
|
@ -1239,7 +1240,7 @@ let lastMessage = {};
|
|||
* @param {string} kind
|
||||
* @param {string} message
|
||||
*/
|
||||
function addToChatbox(peerId, nick, time, kind, message){
|
||||
function addToChatbox(peerId, dest, nick, time, kind, message) {
|
||||
let userpass = getUserPass();
|
||||
let row = document.createElement('div');
|
||||
row.classList.add('message-row');
|
||||
|
@ -1248,12 +1249,16 @@ function addToChatbox(peerId, nick, time, kind, message){
|
|||
row.appendChild(container);
|
||||
if(!peerId)
|
||||
container.classList.add('message-system');
|
||||
else if(userpass.username === nick) {
|
||||
if(userpass.username === nick)
|
||||
container.classList.add('message-sender');
|
||||
}
|
||||
if(dest)
|
||||
container.classList.add('message-private');
|
||||
|
||||
if(kind !== 'me') {
|
||||
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 user = document.createElement('span');
|
||||
user.textContent = nick;
|
||||
|
@ -1272,6 +1277,7 @@ function addToChatbox(peerId, nick, time, kind, message){
|
|||
container.appendChild(p);
|
||||
lastMessage.nick = nick;
|
||||
lastMessage.peerId = peerId;
|
||||
lastMessage.dest = (dest || null);
|
||||
} else {
|
||||
let asterisk = document.createElement('span');
|
||||
asterisk.textContent = '*';
|
||||
|
@ -1288,8 +1294,7 @@ function addToChatbox(peerId, nick, time, kind, message){
|
|||
container.appendChild(user);
|
||||
container.appendChild(content);
|
||||
container.classList.add('message-me');
|
||||
delete(lastMessage.nick);
|
||||
delete(lastMessage.peerId);
|
||||
lastMessage = {};
|
||||
}
|
||||
|
||||
let box = document.getElementById('box');
|
||||
|
@ -1387,7 +1392,7 @@ function handleInput() {
|
|||
let s = "";
|
||||
for(let key in settings)
|
||||
s = s + `${key}: ${JSON.stringify(settings[key])}\n`
|
||||
addToChatbox(null, null, Date.now(), null, s);
|
||||
addToChatbox(null, null, null, Date.now(), null, s);
|
||||
return;
|
||||
}
|
||||
let parsed = parseCommand(rest);
|
||||
|
@ -1424,15 +1429,12 @@ function handleInput() {
|
|||
}
|
||||
serverConnection.groupAction(cmd.slice(1));
|
||||
return;
|
||||
case '/msg':
|
||||
case '/op':
|
||||
case '/unop':
|
||||
case '/kick':
|
||||
case '/present':
|
||||
case '/unpresent': {
|
||||
if(!serverConnection.permissions.op) {
|
||||
displayError("You're not an operator");
|
||||
return;
|
||||
}
|
||||
let parsed = parseCommand(rest);
|
||||
let id;
|
||||
if(parsed[0] in users) {
|
||||
|
@ -1449,7 +1451,18 @@ function handleInput() {
|
|||
displayError('Unknown user ' + parsed[0]);
|
||||
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]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
@ -1474,7 +1487,7 @@ function handleInput() {
|
|||
}
|
||||
|
||||
try {
|
||||
serverConnection.chat(username, me ? 'me' : '', message);
|
||||
serverConnection.chat(username, me ? 'me' : '', '', message);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
displayError(e);
|
||||
|
|
Loading…
Reference in a new issue