package roomserver import ( "context" "encoding/json" "fmt" "strings" ) // resolveRemoteAlias asks the server an alias belongs to what it points // at. Remote aliases are never cached: the owning server may move one at // any time, and a stale answer would send a join to the wrong room. func (r *API) resolveRemoteAlias(ctx context.Context, alias string) (ResolvedAlias, error) { if err := r.requireFederation(fmt.Sprintf("%s belongs to another server, and resolving a remote alias", alias)); err != nil { return ResolvedAlias{}, err } _, server, _ := strings.Cut(alias[1:], ":") resp, err := r.remote.QueryDirectory(ctx, server, alias) if err != nil { err = remoteError(server, err) if isNotFound(err) { return ResolvedAlias{}, fmt.Errorf("%w: %s", ErrNoSuchAlias, alias) } return ResolvedAlias{}, err } if resp.RoomID == "" { return ResolvedAlias{}, fmt.Errorf("%w: %s answered for %s without a room ID", ErrRemote, server, alias) } servers := resp.Servers if len(servers) == 0 { servers = []string{server} } return ResolvedAlias{RoomID: resp.RoomID, Servers: servers}, nil } // remotePublicRooms reads another server's public room directory. func (r *API) remotePublicRooms(ctx context.Context, req PublicRoomsRequest) (PublicRoomsResponse, error) { if err := r.requireFederation("reading the room directory of " + req.Server); err != nil { return PublicRoomsResponse{}, err } raw, err := r.remote.PublicRooms(ctx, req.Server, req.Limit, req.Since, req.Search) if err != nil { return PublicRoomsResponse{}, remoteError(req.Server, err) } var resp PublicRoomsResponse if err := json.Unmarshal(raw, &resp); err != nil { return PublicRoomsResponse{}, fmt.Errorf("%w: %s sent an unreadable directory: %v", ErrRemote, req.Server, err) } if resp.Chunk == nil { resp.Chunk = []PublicRoom{} } return resp, nil }