mirror of
https://github.com/jech/galene.git
synced 2024-11-22 08:35:57 +01:00
Encode group location in the status.json file.
This commit is contained in:
parent
4bc873a574
commit
b55e531aa5
5 changed files with 67 additions and 34 deletions
|
@ -28,31 +28,33 @@ server to client direction.
|
||||||
|
|
||||||
## Before connecting
|
## Before connecting
|
||||||
|
|
||||||
Before it connects and joins a group, a client may perform an HTTP GET
|
The client needs to know the location of the group, the (user-visible) URL
|
||||||
request on the URL `/public-groups.json`. This yields a JSON array of
|
at which the group is found. This may be obtained either by explicit
|
||||||
objects, one for each group that has been marked public in its
|
configuration by the user, or by parsing the `/public-groups.json` file
|
||||||
configuration file. Each object has the following fields:
|
which may contain an array of group statuses (see below).
|
||||||
|
|
||||||
|
A client then performs an HTTP GET request on the file `.status.json` at
|
||||||
|
the group's location. This yields a single JSON object, which contains
|
||||||
|
the following fields:
|
||||||
|
|
||||||
- `name`: the group's name
|
- `name`: the group's name
|
||||||
- `displayName` (optional): a longer version of the name used for display;
|
- `location`: the group's location
|
||||||
- `description` (optional): a user-readable description.
|
- `endpoint`: the URL of the server's WebSocket endpoint
|
||||||
|
- `displayName`: a longer version of the name used for display;
|
||||||
|
- `description`: a user-readable description;
|
||||||
|
- `authServer`: the URL of the authentication server, if any;
|
||||||
|
- `authPortal`: the uRL of the authentication portal, if any;
|
||||||
- `locked`: true if the group is locked;
|
- `locked`: true if the group is locked;
|
||||||
- `clientCount`: the number of clients currently in the group.
|
- `clientCount`: the number of clients currently in the group.
|
||||||
|
|
||||||
If token-based authorisation is in use for the group, then the dictionary
|
All fields are optional except `name`, `location` and `endpoint`.
|
||||||
contains the following additional field:
|
|
||||||
|
|
||||||
- `authServer`: the URL of the authorisation server.
|
|
||||||
|
|
||||||
A client may also fetch the URL `/group/name/.status.json` to retrieve the
|
|
||||||
status of a single group. If the group has not been marked as public,
|
|
||||||
then the fields `locked` and `clientCount` are omitted.
|
|
||||||
|
|
||||||
## Connecting
|
## Connecting
|
||||||
|
|
||||||
The client connects to the websocket at `/ws`. Galene uses a symmetric,
|
The client connects to the websocket at the URL obtained at the previous
|
||||||
asynchronous protocol: there are no requests and responses, and most
|
step. Galene uses a symmetric, asynchronous protocol: there are no
|
||||||
messages may be sent by either peer.
|
requests and responses, and most messages may be sent by either peer.
|
||||||
|
|
||||||
## Message syntax
|
## Message syntax
|
||||||
|
|
||||||
|
|
|
@ -1177,6 +1177,7 @@ func (desc *Description) GetPermission(group string, creds ClientCredentials) (s
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint"`
|
||||||
DisplayName string `json:"displayName,omitempty"`
|
DisplayName string `json:"displayName,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
|
@ -1186,10 +1187,40 @@ type Status struct {
|
||||||
ClientCount *int `json:"clientCount,omitempty"`
|
ClientCount *int `json:"clientCount,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) Status(authentified bool, endpoint string) Status {
|
// Status returns a group's status.
|
||||||
|
// Base is the base URL for groups; if omitted, then both the Location and
|
||||||
|
// Endpoint members are omitted from the result.
|
||||||
|
func (g *Group) Status(authentified bool, base string) Status {
|
||||||
desc := g.Description()
|
desc := g.Description()
|
||||||
|
|
||||||
|
var location, endpoint string
|
||||||
|
if base != "" {
|
||||||
|
burl, err := url.Parse(base)
|
||||||
|
if err == nil {
|
||||||
|
wss := "wss"
|
||||||
|
if burl.Scheme == "http" {
|
||||||
|
wss = "ws"
|
||||||
|
}
|
||||||
|
l := url.URL{
|
||||||
|
Scheme: burl.Scheme,
|
||||||
|
Host: burl.Host,
|
||||||
|
Path: path.Join(burl.Path, g.name) + "/",
|
||||||
|
}
|
||||||
|
location = l.String()
|
||||||
|
e := url.URL{
|
||||||
|
Scheme: wss,
|
||||||
|
Host: burl.Host,
|
||||||
|
Path: "/ws",
|
||||||
|
}
|
||||||
|
endpoint = e.String()
|
||||||
|
} else {
|
||||||
|
log.Printf("Couldn't parse base URL %v", base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d := Status{
|
d := Status{
|
||||||
Name: g.name,
|
Name: g.name,
|
||||||
|
Location: location,
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
DisplayName: desc.DisplayName,
|
DisplayName: desc.DisplayName,
|
||||||
AuthServer: desc.AuthServer,
|
AuthServer: desc.AuthServer,
|
||||||
|
@ -1207,11 +1238,11 @@ func (g *Group) Status(authentified bool, endpoint string) Status {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPublic() []Status {
|
func GetPublic(base string) []Status {
|
||||||
gs := make([]Status, 0)
|
gs := make([]Status, 0)
|
||||||
Range(func(g *Group) bool {
|
Range(func(g *Group) bool {
|
||||||
if g.Description().Public {
|
if g.Description().Public {
|
||||||
gs = append(gs, g.Status(false, ""))
|
gs = append(gs, g.Status(false, base))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestGroup(t *testing.T) {
|
||||||
t.Errorf("Expected [], got %v", subs)
|
t.Errorf("Expected [], got %v", subs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if public := GetPublic(); len(public) != 1 || public[0].Name != "group/subgroup" {
|
if public := GetPublic(""); len(public) != 1 || public[0].Name != "group/subgroup" {
|
||||||
t.Errorf("Expected group/subgroup, got %v", public)
|
t.Errorf("Expected group/subgroup, got %v", public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ async function listPublicGroups() {
|
||||||
let td = document.createElement('td');
|
let td = document.createElement('td');
|
||||||
let a = document.createElement('a');
|
let a = document.createElement('a');
|
||||||
a.textContent = group.displayName || group.name;
|
a.textContent = group.displayName || group.name;
|
||||||
a.href = '/group/' + group.name + '/';
|
a.href = group.location;
|
||||||
td.appendChild(a);
|
td.appendChild(a);
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
let td2 = document.createElement('td');
|
let td2 = document.createElement('td');
|
||||||
|
|
|
@ -332,9 +332,18 @@ func groupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
serveFile(w, r, filepath.Join(StaticRoot, "galene.html"))
|
serveFile(w, r, filepath.Join(StaticRoot, "galene.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func groupBase(r *http.Request) string {
|
||||||
|
base := url.URL{
|
||||||
|
Scheme: r.URL.Scheme,
|
||||||
|
Host: r.Host,
|
||||||
|
Path: "/group/",
|
||||||
|
}
|
||||||
|
return base.String()
|
||||||
|
}
|
||||||
|
|
||||||
func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
|
func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
path := path.Dir(r.URL.Path)
|
pth := path.Dir(r.URL.Path)
|
||||||
name := parseGroupName("/group/", path)
|
name := parseGroupName("/group/", pth)
|
||||||
if name == "" {
|
if name == "" {
|
||||||
notFound(w)
|
notFound(w)
|
||||||
return
|
return
|
||||||
|
@ -351,16 +360,7 @@ func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := "wss"
|
d := g.Status(false, groupBase(r))
|
||||||
if Insecure {
|
|
||||||
scheme = "ws"
|
|
||||||
}
|
|
||||||
endpoint := url.URL{
|
|
||||||
Scheme: scheme,
|
|
||||||
Host: r.Host,
|
|
||||||
Path: "/ws",
|
|
||||||
}
|
|
||||||
d := g.Status(false, endpoint.String())
|
|
||||||
w.Header().Set("content-type", "application/json")
|
w.Header().Set("content-type", "application/json")
|
||||||
w.Header().Set("cache-control", "no-cache")
|
w.Header().Set("cache-control", "no-cache")
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ func publicHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g := group.GetPublic()
|
g := group.GetPublic(groupBase(r))
|
||||||
e := json.NewEncoder(w)
|
e := json.NewEncoder(w)
|
||||||
e.Encode(g)
|
e.Encode(g)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue