Add implementation of room alias methods

This commit is contained in:
nxshock 2019-08-06 20:28:39 +05:00
parent febdc5f31f
commit 4de7078f42
7 changed files with 142 additions and 3 deletions

View File

@ -89,9 +89,9 @@ Implemented from [Client-Server API](https://matrix.org/docs/spec/client_server/
### [10.2 Room aliases](https://matrix.org/docs/spec/client_server/latest#room-aliases)
- [ ] [10.2.1 PUT /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-directory-room-roomalias)
- [ ] [10.2.2 GET /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-directory-room-roomalias)
- [ ] [10.2.3 DELETE /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#delete-matrix-client-r0-directory-room-roomalias)
- [x] [10.2.1 PUT /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-directory-room-roomalias)
- [x] [10.2.2 GET /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-directory-room-roomalias)
- [x] [10.2.3 DELETE /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/latest#delete-matrix-client-r0-directory-room-roomalias)
### [10.4 Room membership](https://matrix.org/docs/spec/client_server/latest#room-membership)

View File

@ -18,6 +18,7 @@ type Backend interface {
Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err models.ApiError)
PublicRooms(filter string) []Room
ValidateUsernameFunc() func(string) error
GetRoomByAlias(string) Room
}
type Room interface {
@ -53,4 +54,6 @@ type User interface {
Invite(Room, User) models.ApiError
AddFilter(filterID string, filter common.Filter)
GetFilterByID(filterID string) *common.Filter
AddRoomAlias(Room, string) models.ApiError
DeleteRoomAlias(string) models.ApiError
}

View File

@ -17,6 +17,7 @@ import (
type Backend struct {
data map[string]internal.User
rooms map[string]internal.Room
roomAliases map[string]internal.Room
hostname string
validateUsernameFunc func(string) error // TODO: create ability to redefine validation func
mutex sync.RWMutex
@ -31,6 +32,7 @@ func NewBackend(hostname string) *Backend {
hostname: hostname,
validateUsernameFunc: defaultValidationUsernameFunc,
rooms: make(map[string]internal.Room),
roomAliases: make(map[string]internal.Room),
data: make(map[string]internal.User)}
}
@ -148,6 +150,20 @@ func (backend *Backend) PublicRooms(filter string) []internal.Room {
return rooms
}
func (backend *Backend) GetRoomByAlias(alias string) internal.Room {
backend.mutex.RLock()
defer backend.mutex.RUnlock()
alias = strings.TrimPrefix(alias, "#") // TODO: create strip alias func
alias = strings.TrimSuffix(alias, ":"+backend.hostname)
if room, exists := backend.roomAliases[alias]; exists {
return room
}
return nil
}
func (backend *Backend) ValidateUsernameFunc() func(string) error {
backend.mutex.RLock()
defer backend.mutex.RUnlock()

View File

@ -1,6 +1,7 @@
package memory
import (
"fmt"
"sync"
"time"
@ -278,6 +279,41 @@ func (user *User) JoinRoom(room internal.Room) models.ApiError {
return nil
}
func (user *User) AddRoomAlias(room internal.Room, alias string) models.ApiError {
user.backend.mutex.Lock()
defer user.backend.mutex.Unlock()
if room.Creator().ID() != user.ID() {
return models.NewError(models.M_FORBIDDEN, "only room creator can add room alias") // TODO: make room admins can use this method
}
if _, exists := user.backend.roomAliases[alias]; exists {
return models.NewError(models.M_UNKNOWN, fmt.Sprintf("room alias #%s:%s already exists", alias, user.backend.hostname))
}
user.backend.roomAliases[alias] = room
return nil
}
func (user *User) DeleteRoomAlias(alias string) models.ApiError {
user.backend.mutex.Lock()
defer user.backend.mutex.Unlock()
room := user.backend.GetRoomByAlias(alias)
if room == nil {
return models.NewError(models.M_NOT_FOUND, "room not found")
}
if room.Creator().ID() != user.ID() {
return models.NewError(models.M_FORBIDDEN, "only room creator can delete room alias") // TODO: make room admins can use this method
}
delete(user.backend.roomAliases, alias)
return nil
}
func (user *User) AddFilter(filterID string, filter common.Filter) {
user.mutex.Lock()
defer user.mutex.Unlock()

View File

@ -22,6 +22,7 @@ import (
"github.com/signaller-matrix/signaller/internal/models/publicrooms"
"github.com/signaller-matrix/signaller/internal/models/register"
"github.com/signaller-matrix/signaller/internal/models/registeravailable"
"github.com/signaller-matrix/signaller/internal/models/roomalias"
mSync "github.com/signaller-matrix/signaller/internal/models/sync"
"github.com/signaller-matrix/signaller/internal/models/versions"
"github.com/signaller-matrix/signaller/internal/models/whoami"
@ -538,6 +539,76 @@ func publicRoomsHandler(w http.ResponseWriter, r *http.Request) {
sendJsonResponse(w, http.StatusOK, response)
}
// https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-directory-room-roomalias
// https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-directory-room-roomalias
// https://matrix.org/docs/spec/client_server/latest#delete-matrix-client-r0-directory-room-roomalias
func roomAliasHandler(w http.ResponseWriter, r *http.Request) {
roomAlias := mux.Vars(r)["roomAlias"] // TODO: add validation of room alias
var user User
if r.Method == http.MethodPut || r.Method == http.MethodDelete {
token := getTokenFromResponse(r)
if token == "" {
errorResponse(w, models.M_FORBIDDEN, http.StatusForbidden, "")
return
}
user = currServer.Backend.GetUserByToken(token)
if user == nil {
errorResponse(w, models.M_UNKNOWN_TOKEN, http.StatusBadRequest, "")
return
}
}
var request roomalias.Request
err := getRequest(r, &request)
if err != nil {
errorResponse(w, models.M_BAD_JSON, http.StatusBadRequest, err.Error())
return
}
var response interface{}
switch r.Method {
case http.MethodGet:
room := currServer.Backend.GetRoomByAlias(roomAlias)
if room == nil {
errorResponse(w, models.M_NOT_FOUND, http.StatusNotFound, "room not found")
return
}
response = roomalias.ResponseGet{
RoomID: room.ID(),
Servers: []string{currServer.Address}}
case http.MethodPut:
room := currServer.Backend.GetRoomByID(request.RoomID)
if room == nil {
errorResponse(w, models.M_NOT_FOUND, http.StatusNotFound, "room not found")
return
}
err := user.AddRoomAlias(room, roomAlias)
if err != nil {
errorResponse(w, err, http.StatusConflict, "") // TODO: check http code
return
}
response = struct{}{}
case http.MethodDelete:
err := user.DeleteRoomAlias(roomAlias)
if err != nil {
errorResponse(w, err, http.StatusConflict, "") // TODO: check http code
return
}
response = struct{}{}
}
sendJsonResponse(w, http.StatusOK, response)
}
func sendJsonResponse(w http.ResponseWriter, httpStatus int, data interface{}) error {
b, err := json.Marshal(data)
if err != nil {

View File

@ -0,0 +1,12 @@
package roomalias
// Merged PUT and GET requests
type Request struct {
RoomID string `json:"room_id"` // The room ID to set.
RoomAlias string `json:"roomAlias"` // The room alias.
}
type ResponseGet struct {
RoomID string `json:"room_id"` // The room ID for this room alias.
Servers []string `json:"servers"` // A list of servers that are aware of this room alias.
}

View File

@ -42,6 +42,7 @@ func NewServer(port int) (*Server, error) {
router.HandleFunc("/_matrix/client/r0/publicRooms", publicRoomsHandler)
router.HandleFunc("/_matrix/client/r0/user/{userId}/filter/{filterID}", GetFilterHandler).Methods("GET")
router.HandleFunc("/_matrix/client/r0/user/{userId}/filter", AddFilterHandler).Methods("POST")
router.HandleFunc("/_matrix/client/r0/directory/room/{roomAlias}", roomAliasHandler).Methods(http.MethodPut, http.MethodGet, http.MethodDelete)
router.HandleFunc("/", RootHandler)