mirror of
https://github.com/jech/galene.git
synced 2024-12-22 15:25:48 +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 it connects and joins a group, a client may perform an HTTP GET
|
||||
request on the URL `/public-groups.json`. This yields a JSON array of
|
||||
objects, one for each group that has been marked public in its
|
||||
configuration file. Each object has the following fields:
|
||||
The client needs to know the location of the group, the (user-visible) URL
|
||||
at which the group is found. This may be obtained either by explicit
|
||||
configuration by the user, or by parsing the `/public-groups.json` file
|
||||
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
|
||||
- `displayName` (optional): a longer version of the name used for display;
|
||||
- `description` (optional): a user-readable description.
|
||||
- `location`: the group's location
|
||||
- `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;
|
||||
- `clientCount`: the number of clients currently in the group.
|
||||
|
||||
If token-based authorisation is in use for the group, then the dictionary
|
||||
contains the following additional field:
|
||||
All fields are optional except `name`, `location` and `endpoint`.
|
||||
|
||||
- `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
|
||||
|
||||
The client connects to the websocket at `/ws`. Galene uses a symmetric,
|
||||
asynchronous protocol: there are no requests and responses, and most
|
||||
messages may be sent by either peer.
|
||||
The client connects to the websocket at the URL obtained at the previous
|
||||
step. Galene uses a symmetric, asynchronous protocol: there are no
|
||||
requests and responses, and most messages may be sent by either peer.
|
||||
|
||||
## Message syntax
|
||||
|
||||
|
|
|
@ -1177,6 +1177,7 @@ func (desc *Description) GetPermission(group string, creds ClientCredentials) (s
|
|||
|
||||
type Status struct {
|
||||
Name string `json:"name"`
|
||||
Location string `json:"location"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
|
@ -1186,10 +1187,40 @@ type Status struct {
|
|||
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()
|
||||
|
||||
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{
|
||||
Name: g.name,
|
||||
Location: location,
|
||||
Endpoint: endpoint,
|
||||
DisplayName: desc.DisplayName,
|
||||
AuthServer: desc.AuthServer,
|
||||
|
@ -1207,11 +1238,11 @@ func (g *Group) Status(authentified bool, endpoint string) Status {
|
|||
return d
|
||||
}
|
||||
|
||||
func GetPublic() []Status {
|
||||
func GetPublic(base string) []Status {
|
||||
gs := make([]Status, 0)
|
||||
Range(func(g *Group) bool {
|
||||
if g.Description().Public {
|
||||
gs = append(gs, g.Status(false, ""))
|
||||
gs = append(gs, g.Status(false, base))
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
|
|
@ -42,7 +42,7 @@ func TestGroup(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ async function listPublicGroups() {
|
|||
let td = document.createElement('td');
|
||||
let a = document.createElement('a');
|
||||
a.textContent = group.displayName || group.name;
|
||||
a.href = '/group/' + group.name + '/';
|
||||
a.href = group.location;
|
||||
td.appendChild(a);
|
||||
tr.appendChild(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"))
|
||||
}
|
||||
|
||||
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) {
|
||||
path := path.Dir(r.URL.Path)
|
||||
name := parseGroupName("/group/", path)
|
||||
pth := path.Dir(r.URL.Path)
|
||||
name := parseGroupName("/group/", pth)
|
||||
if name == "" {
|
||||
notFound(w)
|
||||
return
|
||||
|
@ -351,16 +360,7 @@ func groupStatusHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
scheme := "wss"
|
||||
if Insecure {
|
||||
scheme = "ws"
|
||||
}
|
||||
endpoint := url.URL{
|
||||
Scheme: scheme,
|
||||
Host: r.Host,
|
||||
Path: "/ws",
|
||||
}
|
||||
d := g.Status(false, endpoint.String())
|
||||
d := g.Status(false, groupBase(r))
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.Header().Set("cache-control", "no-cache")
|
||||
|
||||
|
@ -380,7 +380,7 @@ func publicHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
g := group.GetPublic()
|
||||
g := group.GetPublic(groupBase(r))
|
||||
e := json.NewEncoder(w)
|
||||
e.Encode(g)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue