mirror of
https://github.com/jech/galene.git
synced 2024-11-09 18:25:58 +01:00
Implement user statuses.
The server now maintains a set of statuses for each user that are not interpreted by the server but communicated to the other members of the group using 'user' messages.
This commit is contained in:
parent
f0a39fca48
commit
3ba2394be7
7 changed files with 87 additions and 15 deletions
|
@ -118,7 +118,8 @@ users a `user` message:
|
||||||
kind: 'add' or 'change' or 'delete',
|
kind: 'add' or 'change' or 'delete',
|
||||||
id: id,
|
id: id,
|
||||||
username: username,
|
username: username,
|
||||||
permissions: permissions
|
permissions: permissions,
|
||||||
|
status: status
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -277,8 +278,8 @@ A user action requests that the server act upon a user.
|
||||||
value: value
|
value: value
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Currently defined kinds include `op`, `unop`, `present`, `unpresent`, and
|
Currently defined kinds include `op`, `unop`, `present`, `unpresent`,
|
||||||
`kick`.
|
`kick` and `setstatus`.
|
||||||
|
|
||||||
Finally, a group action requests that the server act on the current group.
|
Finally, a group action requests that the server act on the current group.
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,11 @@ func (client *Client) Permissions() group.ClientPermissions {
|
||||||
return group.ClientPermissions{}
|
return group.ClientPermissions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) PushClient(id, username string, permissions group.ClientPermissions, kind string) error {
|
func (client *Client) Status() map[string]interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) PushClient(id, username string, permissions group.ClientPermissions, status map[string]interface{}, kind string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,9 @@ type Client interface {
|
||||||
Challengeable
|
Challengeable
|
||||||
Permissions() ClientPermissions
|
Permissions() ClientPermissions
|
||||||
SetPermissions(ClientPermissions)
|
SetPermissions(ClientPermissions)
|
||||||
|
Status() map[string]interface{}
|
||||||
OverridePermissions(*Group) bool
|
OverridePermissions(*Group) bool
|
||||||
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
|
||||||
PushClient(id, username string, permissions ClientPermissions, kind string) error
|
PushClient(id, username string, permissions ClientPermissions, status map[string]interface{}, kind string) error
|
||||||
Kick(id, user, message string) error
|
Kick(id, user, message string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,10 +488,14 @@ func AddClient(group string, c Client) (*Group, error) {
|
||||||
id := c.Id()
|
id := c.Id()
|
||||||
u := c.Username()
|
u := c.Username()
|
||||||
p := c.Permissions()
|
p := c.Permissions()
|
||||||
c.PushClient(c.Id(), u, p, "add")
|
s := c.Status()
|
||||||
|
c.PushClient(c.Id(), u, p, s, "add")
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
c.PushClient(cc.Id(), cc.Username(), cc.Permissions(), "add")
|
c.PushClient(
|
||||||
cc.PushClient(id, u, p, "add")
|
cc.Id(), cc.Username(), cc.Permissions(), cc.Status(),
|
||||||
|
"add",
|
||||||
|
)
|
||||||
|
cc.PushClient(id, u, p, s, "add")
|
||||||
}
|
}
|
||||||
|
|
||||||
return g, nil
|
return g, nil
|
||||||
|
@ -537,7 +541,7 @@ func DelClient(c Client) {
|
||||||
|
|
||||||
go func(clients []Client) {
|
go func(clients []Client) {
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
cc.PushClient(c.Id(), c.Username(), c.Permissions(), "delete")
|
cc.PushClient(c.Id(), c.Username(), c.Permissions(), c.Status(), "delete")
|
||||||
}
|
}
|
||||||
}(clients)
|
}(clients)
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ type webClient struct {
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
permissions group.ClientPermissions
|
permissions group.ClientPermissions
|
||||||
|
status map[string]interface{}
|
||||||
requested map[string]uint32
|
requested map[string]uint32
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
writeCh chan interface{}
|
writeCh chan interface{}
|
||||||
|
@ -98,6 +99,10 @@ func (c *webClient) Permissions() group.ClientPermissions {
|
||||||
return c.permissions
|
return c.permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *webClient) Status() map[string]interface{} {
|
||||||
|
return c.status
|
||||||
|
}
|
||||||
|
|
||||||
func (c *webClient) SetPermissions(perms group.ClientPermissions) {
|
func (c *webClient) SetPermissions(perms group.ClientPermissions) {
|
||||||
c.permissions = perms
|
c.permissions = perms
|
||||||
}
|
}
|
||||||
|
@ -106,13 +111,14 @@ func (c *webClient) OverridePermissions(g *group.Group) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *webClient) PushClient(id, username string, permissions group.ClientPermissions, kind string) error {
|
func (c *webClient) PushClient(id, username string, permissions group.ClientPermissions, status map[string]interface{}, kind string) error {
|
||||||
return c.write(clientMessage{
|
return c.write(clientMessage{
|
||||||
Type: "user",
|
Type: "user",
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
Id: id,
|
Id: id,
|
||||||
Username: username,
|
Username: username,
|
||||||
Permissions: &permissions,
|
Permissions: &permissions,
|
||||||
|
Status: status,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +180,7 @@ type clientMessage struct {
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Privileged bool `json:"privileged,omitempty"`
|
Privileged bool `json:"privileged,omitempty"`
|
||||||
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
|
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
|
||||||
|
Status map[string]interface{} `json:"status,omitempty"`
|
||||||
Group string `json:"group,omitempty"`
|
Group string `json:"group,omitempty"`
|
||||||
Value interface{} `json:"value,omitempty"`
|
Value interface{} `json:"value,omitempty"`
|
||||||
NoEcho bool `json:"noecho,omitempty"`
|
NoEcho bool `json:"noecho,omitempty"`
|
||||||
|
@ -988,10 +995,11 @@ func handleAction(c *webClient, a interface{}) error {
|
||||||
}
|
}
|
||||||
id := c.Id()
|
id := c.Id()
|
||||||
user := c.Username()
|
user := c.Username()
|
||||||
|
s := c.Status()
|
||||||
clients := g.GetClients(nil)
|
clients := g.GetClients(nil)
|
||||||
go func(clients []group.Client) {
|
go func(clients []group.Client) {
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
cc.PushClient(id, user, perms, "change")
|
cc.PushClient(id, user, perms, s, "change")
|
||||||
}
|
}
|
||||||
}(clients)
|
}(clients)
|
||||||
case kickAction:
|
case kickAction:
|
||||||
|
@ -1042,6 +1050,7 @@ func leaveGroup(c *webClient) {
|
||||||
|
|
||||||
group.DelClient(c)
|
group.DelClient(c)
|
||||||
c.permissions = group.ClientPermissions{}
|
c.permissions = group.ClientPermissions{}
|
||||||
|
c.status = nil
|
||||||
c.requested = map[string]uint32{}
|
c.requested = map[string]uint32{}
|
||||||
c.group = nil
|
c.group = nil
|
||||||
}
|
}
|
||||||
|
@ -1454,6 +1463,36 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.error(err)
|
return c.error(err)
|
||||||
}
|
}
|
||||||
|
case "setstatus":
|
||||||
|
if m.Dest != c.Id() {
|
||||||
|
return c.error(group.UserError("not authorised"))
|
||||||
|
}
|
||||||
|
s, ok := m.Value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return c.error(group.UserError(
|
||||||
|
"Bad value in setstatus",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if c.status == nil {
|
||||||
|
c.status = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
for k, v := range s {
|
||||||
|
if v == nil {
|
||||||
|
delete(c.status, k)
|
||||||
|
} else {
|
||||||
|
c.status[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id := c.Id()
|
||||||
|
user := c.Username()
|
||||||
|
perms := c.Permissions()
|
||||||
|
status := c.Status()
|
||||||
|
go func(clients []group.Client) {
|
||||||
|
for _, cc := range clients {
|
||||||
|
cc.PushClient(id, user, perms, status,
|
||||||
|
"change")
|
||||||
|
}
|
||||||
|
}(g.GetClients(nil))
|
||||||
default:
|
default:
|
||||||
return group.ProtocolError("unknown user action")
|
return group.ProtocolError("unknown user action")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2365,6 +2365,24 @@ commands.wall = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
commands.raise = {
|
||||||
|
description: 'raise hand',
|
||||||
|
f: (c, r) => {
|
||||||
|
serverConnection.userAction(
|
||||||
|
"setstatus", serverConnection.id, {"raisehand": true},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.unraise = {
|
||||||
|
description: 'unraise hand',
|
||||||
|
f: (c, r) => {
|
||||||
|
serverConnection.userAction(
|
||||||
|
"setstatus", serverConnection.id, {"raisehand": null},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test loopback through a TURN relay.
|
* Test loopback through a TURN relay.
|
||||||
*
|
*
|
||||||
|
|
|
@ -64,6 +64,7 @@ function newLocalId() {
|
||||||
* @typedef {Object} user
|
* @typedef {Object} user
|
||||||
* @property {string} username
|
* @property {string} username
|
||||||
* @property {Object<string,boolean>} permissions
|
* @property {Object<string,boolean>} permissions
|
||||||
|
* @property {Object<string,any>} status
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,6 +206,7 @@ function ServerConnection() {
|
||||||
* @property {string} [password]
|
* @property {string} [password]
|
||||||
* @property {boolean} [privileged]
|
* @property {boolean} [privileged]
|
||||||
* @property {Object<string,boolean>} [permissions]
|
* @property {Object<string,boolean>} [permissions]
|
||||||
|
* @property {Object<string,any>} [status]
|
||||||
* @property {string} [group]
|
* @property {string} [group]
|
||||||
* @property {unknown} [value]
|
* @property {unknown} [value]
|
||||||
* @property {boolean} [noecho]
|
* @property {boolean} [noecho]
|
||||||
|
@ -342,7 +344,8 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
console.warn(`Duplicate user ${m.id} ${m.username}`);
|
console.warn(`Duplicate user ${m.id} ${m.username}`);
|
||||||
sc.users[m.id] = {
|
sc.users[m.id] = {
|
||||||
username: m.username,
|
username: m.username,
|
||||||
permissions: m.permissions,
|
permissions: m.permissions || {},
|
||||||
|
status: m.status || {},
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 'change':
|
case 'change':
|
||||||
|
@ -350,11 +353,13 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
console.warn(`Unknown user ${m.id} ${m.username}`);
|
console.warn(`Unknown user ${m.id} ${m.username}`);
|
||||||
sc.users[m.id] = {
|
sc.users[m.id] = {
|
||||||
username: m.username,
|
username: m.username,
|
||||||
permissions: m.permissions,
|
permissions: m.permissions || {},
|
||||||
|
status: m.status || {},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
sc.users[m.id].username = m.username;
|
sc.users[m.id].username = m.username;
|
||||||
sc.users[m.id].permissions = m.permissions;
|
sc.users[m.id].permissions = m.permissions || {};
|
||||||
|
sc.users[m.id].status = m.status || {};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
|
@ -562,7 +567,7 @@ ServerConnection.prototype.chat = function(kind, dest, value) {
|
||||||
*
|
*
|
||||||
* @param {string} kind - One of "op", "unop", "kick", "present", "unpresent".
|
* @param {string} kind - One of "op", "unop", "kick", "present", "unpresent".
|
||||||
* @param {string} dest - The id of the user to act upon.
|
* @param {string} dest - The id of the user to act upon.
|
||||||
* @param {string} [value] - An optional user-readable message.
|
* @param {any} [value] - An action-dependent parameter.
|
||||||
*/
|
*/
|
||||||
ServerConnection.prototype.userAction = function(kind, dest, value) {
|
ServerConnection.prototype.userAction = function(kind, dest, value) {
|
||||||
this.send({
|
this.send({
|
||||||
|
|
Loading…
Reference in a new issue