mirror of
https://github.com/jech/galene.git
synced 2024-11-22 08:35:57 +01:00
Timestamp chat messages.
This commit is contained in:
parent
480922268e
commit
3bd9a1db4e
6 changed files with 89 additions and 11 deletions
|
@ -63,6 +63,7 @@ func IceConfiguration() webrtc.Configuration {
|
||||||
type ChatHistoryEntry struct {
|
type ChatHistoryEntry struct {
|
||||||
Id string
|
Id string
|
||||||
User string
|
User string
|
||||||
|
Time uint64
|
||||||
Kind string
|
Kind string
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
@ -393,7 +394,7 @@ func (g *Group) ClearChatHistory() {
|
||||||
g.history = nil
|
g.history = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) AddToChatHistory(id, user, kind, value string) {
|
func (g *Group) AddToChatHistory(id, user string, time uint64, kind, value string) {
|
||||||
g.mu.Lock()
|
g.mu.Lock()
|
||||||
defer g.mu.Unlock()
|
defer g.mu.Unlock()
|
||||||
|
|
||||||
|
@ -402,7 +403,7 @@ func (g *Group) AddToChatHistory(id, user, kind, value string) {
|
||||||
g.history = g.history[:len(g.history)-1]
|
g.history = g.history[:len(g.history)-1]
|
||||||
}
|
}
|
||||||
g.history = append(g.history,
|
g.history = append(g.history,
|
||||||
ChatHistoryEntry{Id: id, User: user, Kind: kind, Value: value},
|
ChatHistoryEntry{Id: id, User: user, Time: time, Kind: kind, Value: value},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,7 @@ type clientMessage struct {
|
||||||
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"`
|
||||||
|
Time uint64 `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"`
|
||||||
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
|
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
|
||||||
|
@ -149,6 +150,20 @@ type clientMessage struct {
|
||||||
Request rateMap `json:"request,omitempty"`
|
Request rateMap `json:"request,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fromJSTime(tm uint64) time.Time {
|
||||||
|
if tm == 0 {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
type closeMessage struct {
|
type closeMessage struct {
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
@ -714,6 +729,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
|
||||||
Type: "chat",
|
Type: "chat",
|
||||||
Id: m.Id,
|
Id: m.Id,
|
||||||
Username: m.User,
|
Username: m.User,
|
||||||
|
Time: m.Time,
|
||||||
Value: m.Value,
|
Value: m.Value,
|
||||||
Kind: m.Kind,
|
Kind: m.Kind,
|
||||||
})
|
})
|
||||||
|
@ -984,12 +1000,23 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
log.Printf("ICE: %v", err)
|
log.Printf("ICE: %v", err)
|
||||||
}
|
}
|
||||||
case "chat":
|
case "chat":
|
||||||
c.group.AddToChatHistory(m.Id, m.Username, m.Kind, m.Value)
|
tm := toJSTime(time.Now())
|
||||||
|
c.group.AddToChatHistory(
|
||||||
|
m.Id, m.Username, tm, m.Kind, m.Value,
|
||||||
|
)
|
||||||
|
mm := clientMessage{
|
||||||
|
Type: "chat",
|
||||||
|
Id: m.Id,
|
||||||
|
Username: m.Username,
|
||||||
|
Time: tm,
|
||||||
|
Kind: m.Kind,
|
||||||
|
Value: m.Value,
|
||||||
|
}
|
||||||
clients := c.group.GetClients(nil)
|
clients := c.group.GetClients(nil)
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
cc, ok := cc.(*webClient)
|
cc, ok := cc.(*webClient)
|
||||||
if ok {
|
if ok {
|
||||||
cc.write(m)
|
cc.write(mm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "groupaction":
|
case "groupaction":
|
||||||
|
|
22
rtpconn/webclient_test.go
Normal file
22
rtpconn/webclient_test.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package rtpconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJSTime(t *testing.T) {
|
||||||
|
tm := time.Now()
|
||||||
|
js := toJSTime(tm)
|
||||||
|
tm2 := fromJSTime(js)
|
||||||
|
js2 := toJSTime(tm2)
|
||||||
|
|
||||||
|
if js != js2 {
|
||||||
|
t.Errorf("%v != %v", js, js2)
|
||||||
|
}
|
||||||
|
|
||||||
|
delta := tm.Sub(tm2)
|
||||||
|
if delta < -time.Millisecond/2 || delta > time.Millisecond/2 {
|
||||||
|
t.Errorf("Delta %v, %v, %v", delta, tm, tm2)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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, kind: string, message: string) => void}
|
* @type {(this: ServerConnection, id: string, username: string, time: number, kind: string, message: string) => void}
|
||||||
*/
|
*/
|
||||||
this.onchat = null;
|
this.onchat = null;
|
||||||
/**
|
/**
|
||||||
|
@ -284,7 +284,9 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
break;
|
break;
|
||||||
case 'chat':
|
case 'chat':
|
||||||
if(sc.onchat)
|
if(sc.onchat)
|
||||||
sc.onchat.call(sc, m.id, m.username, m.kind, m.value);
|
sc.onchat.call(
|
||||||
|
sc, m.id, m.username, m.time, m.kind, m.value,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'clearchat':
|
case 'clearchat':
|
||||||
if(sc.onclearchat)
|
if(sc.onclearchat)
|
||||||
|
|
|
@ -321,12 +321,16 @@ textarea.form-reply {
|
||||||
color: #202035;
|
color: #202035;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-user {
|
.message-header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-time {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.message-me-asterisk, .message-me-user {
|
.message-me-asterisk, .message-me-user {
|
||||||
margin-right: 0.33em;
|
margin-right: 0.33em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1211,6 +1211,18 @@ function formatLines(lines) {
|
||||||
return elt;
|
return elt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} time
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function formatTime(time) {
|
||||||
|
let delta = Date.now() - time;
|
||||||
|
let date = new Date(time);
|
||||||
|
if(delta >= 0)
|
||||||
|
return date.toTimeString().slice(null, 8);
|
||||||
|
return date.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} lastMessage
|
* @typedef {Object} lastMessage
|
||||||
* @property {string} [nick]
|
* @property {string} [nick]
|
||||||
|
@ -1223,10 +1235,11 @@ let lastMessage = {};
|
||||||
/**
|
/**
|
||||||
* @param {string} peerId
|
* @param {string} peerId
|
||||||
* @param {string} nick
|
* @param {string} nick
|
||||||
|
* @param {number} time
|
||||||
* @param {string} kind
|
* @param {string} kind
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
function addToChatbox(peerId, nick, kind, message){
|
function addToChatbox(peerId, 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');
|
||||||
|
@ -1241,10 +1254,19 @@ function addToChatbox(peerId, nick, kind, message){
|
||||||
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) {
|
||||||
let user = document.createElement('p');
|
let header = document.createElement('p');
|
||||||
|
let user = document.createElement('span');
|
||||||
user.textContent = nick;
|
user.textContent = nick;
|
||||||
user.classList.add('message-user');
|
user.classList.add('message-user');
|
||||||
container.appendChild(user);
|
header.appendChild(user);
|
||||||
|
if(time) {
|
||||||
|
let tm = document.createElement('span');
|
||||||
|
tm.textContent = formatTime(time);
|
||||||
|
tm.classList.add('message-time');
|
||||||
|
header.appendChild(tm);
|
||||||
|
}
|
||||||
|
header.classList.add('message-header');
|
||||||
|
container.appendChild(header);
|
||||||
}
|
}
|
||||||
p.classList.add('message-content');
|
p.classList.add('message-content');
|
||||||
container.appendChild(p);
|
container.appendChild(p);
|
||||||
|
@ -1365,7 +1387,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, null, s);
|
addToChatbox(null, null, Date.now(), null, s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let parsed = parseCommand(rest);
|
let parsed = parseCommand(rest);
|
||||||
|
|
Loading…
Reference in a new issue