Make models.ApiError interface, not struct

This commit is contained in:
nxshock 2019-08-03 11:46:57 +05:00
parent a2ebc64065
commit 87144ee37d
9 changed files with 151 additions and 121 deletions

View File

@ -9,12 +9,12 @@ import (
) )
type Backend interface { type Backend interface {
Register(username, password, device string) (user User, token string, err *models.ApiError) Register(username, password, device string) (user User, token string, err models.ApiError)
Login(username, password, device string) (user User, token string, err *models.ApiError) Login(username, password, device string) (user User, token string, err models.ApiError)
GetUserByToken(token string) (user User) GetUserByToken(token string) (user User)
GetUserByName(userName string) User GetUserByName(userName string) User
GetRoomByID(id string) Room GetRoomByID(id string) Room
Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err *models.ApiError) Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err models.ApiError)
PublicRooms() []Room PublicRooms() []Room
} }
@ -37,15 +37,15 @@ type User interface {
Name() string Name() string
ID() string ID() string
Password() string Password() string
CreateRoom(request createroom.Request) (Room, *models.ApiError) CreateRoom(request createroom.Request) (Room, models.ApiError)
LeaveRoom(room Room) *models.ApiError LeaveRoom(room Room) models.ApiError
SetTopic(room Room, topic string) *models.ApiError SetTopic(room Room, topic string) models.ApiError
SendMessage(room Room, text string) *models.ApiError SendMessage(room Room, text string) models.ApiError
JoinedRooms() []Room JoinedRooms() []Room
ChangePassword(newPassword string) ChangePassword(newPassword string)
Devices() []devices.Device Devices() []devices.Device
SetRoomVisibility(Room, createroom.VisibilityType) *models.ApiError SetRoomVisibility(Room, createroom.VisibilityType) models.ApiError
Logout(token string) Logout(token string)
LogoutAll() LogoutAll()
JoinRoom(Room) *models.ApiError JoinRoom(Room) models.ApiError
} }

View File

@ -29,12 +29,12 @@ func NewBackend(hostname string) *Backend {
data: make(map[string]internal.User)} data: make(map[string]internal.User)}
} }
func (backend *Backend) Register(username, password, device string) (user internal.User, token string, err *models.ApiError) { func (backend *Backend) Register(username, password, device string) (user internal.User, token string, err models.ApiError) {
backend.mutex.Lock() backend.mutex.Lock()
if _, ok := backend.data[username]; ok { if _, ok := backend.data[username]; ok {
backend.mutex.Unlock() backend.mutex.Unlock()
return nil, "", internal.NewError(models.M_USER_IN_USE, "trying to register a user ID which has been taken") return nil, "", models.NewError(models.M_USER_IN_USE, "trying to register a user ID which has been taken")
} }
user = &User{ user = &User{
@ -49,17 +49,17 @@ func (backend *Backend) Register(username, password, device string) (user intern
return backend.Login(username, password, device) return backend.Login(username, password, device)
} }
func (backend *Backend) Login(username, password, device string) (user internal.User, token string, err *models.ApiError) { func (backend *Backend) Login(username, password, device string) (user internal.User, token string, err models.ApiError) {
backend.mutex.Lock() backend.mutex.Lock()
defer backend.mutex.Unlock() defer backend.mutex.Unlock()
user, ok := backend.data[username] user, ok := backend.data[username]
if !ok { if !ok {
return nil, "", internal.NewError(models.M_FORBIDDEN, "wrong username") return nil, "", models.NewError(models.M_FORBIDDEN, "wrong username")
} }
if user.Password() != password { if user.Password() != password {
return nil, "", internal.NewError(models.M_FORBIDDEN, "wrong password") return nil, "", models.NewError(models.M_FORBIDDEN, "wrong password")
} }
token = newToken(defaultTokenSize) token = newToken(defaultTokenSize)
@ -69,7 +69,7 @@ func (backend *Backend) Login(username, password, device string) (user internal.
return user, token, nil return user, token, nil
} }
func (backend *Backend) Sync(token string, request mSync.SyncRequest) (response *mSync.SyncReply, err *models.ApiError) { func (backend *Backend) Sync(token string, request mSync.SyncRequest) (response *mSync.SyncReply, err models.ApiError) {
backend.mutex.Lock() backend.mutex.Lock()
defer backend.mutex.Unlock() defer backend.mutex.Unlock()

View File

@ -18,7 +18,7 @@ func TestRegisterUser(t *testing.T) {
) )
user, token, err := backend.Register(username, password, device) user, token, err := backend.Register(username, password, device)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, username, user.Name()) assert.Equal(t, username, user.Name())
assert.Equal(t, password, user.Password()) assert.Equal(t, password, user.Password())
assert.NotEmpty(t, token) assert.NotEmpty(t, token)
@ -32,7 +32,7 @@ func TestRegisterUserWithAlreadyTakenName(t *testing.T) {
) )
_, _, err := backend.Register(userName, "", "") _, _, err := backend.Register(userName, "", "")
assert.Nil(t, err) assert.NoError(t, err)
_, _, err = backend.Register(userName, "", "") _, _, err = backend.Register(userName, "", "")
assert.NotNil(t, err) assert.NotNil(t, err)
@ -47,10 +47,10 @@ func TestLogin(t *testing.T) {
) )
_, _, err := backend.Register(userName, password, "") _, _, err := backend.Register(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
_, token, err := backend.Login(userName, password, "") _, token, err := backend.Login(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotZero(t, token) assert.NotZero(t, token)
} }
@ -63,7 +63,7 @@ func TestLoginWithWrongCredentials(t *testing.T) {
) )
_, _, err := backend.Register(userName, password, "") _, _, err := backend.Register(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
_, _, err = backend.Login(userName, "wrong password", "") _, _, err = backend.Login(userName, "wrong password", "")
assert.NotNil(t, err) assert.NotNil(t, err)
@ -81,10 +81,10 @@ func TestLogout(t *testing.T) {
) )
user, _, err := backend.Register(userName, password, "") user, _, err := backend.Register(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
_, token, err := backend.Login(userName, password, "") _, token, err := backend.Login(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotZero(t, token) assert.NotZero(t, token)
user.Logout(token) user.Logout(token)
@ -96,7 +96,7 @@ func TestGetRoomByID(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, token, err := backend.Register("user", "", "") user, token, err := backend.Register("user", "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, user) assert.NotNil(t, user)
assert.NotEmpty(t, token) assert.NotEmpty(t, token)
@ -105,7 +105,7 @@ func TestGetRoomByID(t *testing.T) {
Name: "room1"} Name: "room1"}
room, err := user.CreateRoom(request) room, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, room) assert.NotNil(t, room)
assert.Equal(t, room.ID(), backend.GetRoomByID(room.ID()).ID()) assert.Equal(t, room.ID(), backend.GetRoomByID(room.ID()).ID())
@ -122,7 +122,7 @@ func TestGetUserByName(t *testing.T) {
) )
user, token, err := backend.Register(userName, "", "") user, token, err := backend.Register(userName, "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, user) assert.NotNil(t, user)
assert.NotEmpty(t, token) assert.NotEmpty(t, token)
@ -141,7 +141,7 @@ func TestPublicRooms(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user1, _, err := backend.Register("user1", "", "") user1, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, user1) assert.NotNil(t, user1)
// Create first room // Create first room
@ -151,7 +151,7 @@ func TestPublicRooms(t *testing.T) {
Preset: createroom.PublicChat} Preset: createroom.PublicChat}
room1, err := user1.CreateRoom(request) room1, err := user1.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, room1) assert.NotNil(t, room1)
// Create second room // Create second room
@ -161,16 +161,16 @@ func TestPublicRooms(t *testing.T) {
Preset: createroom.PublicChat} Preset: createroom.PublicChat}
room2, err := user1.CreateRoom(request) room2, err := user1.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, room2) assert.NotNil(t, room2)
// Make room2 has 2 users // Make room2 has 2 users
user2, _, err := backend.Register("user2", "", "") user2, _, err := backend.Register("user2", "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, user2) assert.NotNil(t, user2)
err = user2.JoinRoom(room2) err = user2.JoinRoom(room2)
assert.Nil(t, err) assert.NoError(t, err)
rooms := backend.PublicRooms() rooms := backend.PublicRooms()
assert.Len(t, rooms, 2) assert.Len(t, rooms, 2)

View File

@ -12,7 +12,7 @@ func TestCreateRoom(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, _, err := backend.Register("user1", "", "") user, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
@ -20,7 +20,7 @@ func TestCreateRoom(t *testing.T) {
Topic: "topic"} Topic: "topic"}
room, err := user.CreateRoom(request) room, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, request.RoomAliasName, room.AliasName()) assert.Equal(t, request.RoomAliasName, room.AliasName())
assert.Equal(t, request.Name, room.Name()) assert.Equal(t, request.Name, room.Name())
assert.Equal(t, request.Topic, room.Topic()) assert.Equal(t, request.Topic, room.Topic())
@ -40,7 +40,7 @@ func TestCreateAlreadyExistingRoom(t *testing.T) {
Topic: "topic"} Topic: "topic"}
_, err := user.CreateRoom(request) _, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
_, err = user.CreateRoom(request) _, err = user.CreateRoom(request)
assert.NotNil(t, err) assert.NotNil(t, err)
@ -60,7 +60,7 @@ func TestSetRoomTopic(t *testing.T) {
var newTopic = "new topic" var newTopic = "new topic"
err := user.SetTopic(room, newTopic) err := user.SetTopic(room, newTopic)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, newTopic, room.Topic()) assert.Equal(t, newTopic, room.Topic())
assert.Equal(t, 5, len(room.Events())) // TODO: check start event count assert.Equal(t, 5, len(room.Events())) // TODO: check start event count
} }
@ -109,7 +109,7 @@ func TestRoomUserCount(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user1, _, err := backend.Register("user1", "", "") user1, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
@ -117,7 +117,7 @@ func TestRoomUserCount(t *testing.T) {
Topic: "topic"} Topic: "topic"}
room, err := user1.CreateRoom(request) room, err := user1.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.Len(t, room.Users(), 1) assert.Len(t, room.Users(), 1)
// TODO: add join another user test // TODO: add join another user test

View File

@ -33,10 +33,10 @@ func (user *User) Password() string {
return user.password return user.password
} }
func (user *User) CreateRoom(request createroom.Request) (internal.Room, *models.ApiError) { func (user *User) CreateRoom(request createroom.Request) (internal.Room, models.ApiError) {
for _, existingRoom := range user.backend.rooms { for _, existingRoom := range user.backend.rooms {
if existingRoom.AliasName() == request.RoomAliasName { // TODO: strip and check request room alias name before use if existingRoom.AliasName() == request.RoomAliasName { // TODO: strip and check request room alias name before use
return nil, internal.NewError(models.M_ROOM_IN_USE, "") return nil, models.NewError(models.M_ROOM_IN_USE, "")
} }
} }
@ -104,12 +104,12 @@ func (user *User) CreateRoom(request createroom.Request) (internal.Room, *models
return room, nil return room, nil
} }
func (user *User) SetTopic(room internal.Room, topic string) *models.ApiError { func (user *User) SetTopic(room internal.Room, topic string) models.ApiError {
room.(*Room).mutex.Lock() room.(*Room).mutex.Lock()
defer room.(*Room).mutex.Unlock() defer room.(*Room).mutex.Unlock()
if room.(*Room).creator.ID() != user.ID() { // TODO: currently only creator can change topic if room.(*Room).creator.ID() != user.ID() { // TODO: currently only creator can change topic
return internal.NewError(models.M_FORBIDDEN, "") return models.NewError(models.M_FORBIDDEN, "")
} }
room.(*Room).topic = topic room.(*Room).topic = topic
@ -122,7 +122,7 @@ func (user *User) SetTopic(room internal.Room, topic string) *models.ApiError {
return nil return nil
} }
func (user *User) LeaveRoom(room internal.Room) *models.ApiError { func (user *User) LeaveRoom(room internal.Room) models.ApiError {
room.(*Room).mutex.Lock() room.(*Room).mutex.Lock()
defer room.(*Room).mutex.Unlock() defer room.(*Room).mutex.Unlock()
@ -133,10 +133,10 @@ func (user *User) LeaveRoom(room internal.Room) *models.ApiError {
} }
} }
return internal.NewError(models.M_BAD_STATE, "you are not a member of group") // TODO: check error code return models.NewError(models.M_BAD_STATE, "you are not a member of group") // TODO: check error code
} }
func (user *User) SendMessage(room internal.Room, text string) *models.ApiError { func (user *User) SendMessage(room internal.Room, text string) models.ApiError {
room.(*Room).mutex.Lock() room.(*Room).mutex.Lock()
defer room.(*Room).mutex.Unlock() defer room.(*Room).mutex.Unlock()
@ -148,7 +148,7 @@ func (user *User) SendMessage(room internal.Room, text string) *models.ApiError
} }
if !userInRoom { if !userInRoom {
return internal.NewError(models.M_FORBIDDEN, "") return models.NewError(models.M_FORBIDDEN, "")
} }
room.(*Room).events = append(room.(*Room).events, RoomEvent{ room.(*Room).events = append(room.(*Room).events, RoomEvent{
@ -195,9 +195,9 @@ func (user *User) Devices() []devices.Device {
return result return result
} }
func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) *models.ApiError { func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) models.ApiError {
if user.ID() != room.Creator().ID() { if user.ID() != room.Creator().ID() {
return internal.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too return models.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too
} }
room.(*Room).mutex.Lock() room.(*Room).mutex.Lock()
@ -223,7 +223,7 @@ func (user *User) LogoutAll() {
user.Tokens = make(map[string]Token) user.Tokens = make(map[string]Token)
} }
func (user *User) JoinRoom(room internal.Room) *models.ApiError { func (user *User) JoinRoom(room internal.Room) models.ApiError {
memRoom := room.(*Room) memRoom := room.(*Room)
memRoom.mutex.Lock() memRoom.mutex.Lock()
@ -231,7 +231,7 @@ func (user *User) JoinRoom(room internal.Room) *models.ApiError {
for _, roomUser := range memRoom.joined { for _, roomUser := range memRoom.joined {
if roomUser.ID() == user.ID() { if roomUser.ID() == user.ID() {
return internal.NewError(models.M_BAD_STATE, "user already in room") // TODO: check code return models.NewError(models.M_BAD_STATE, "user already in room") // TODO: check code
} }
} }

View File

@ -19,7 +19,7 @@ func TestUserID(t *testing.T) {
backend := NewBackend(hostName) backend := NewBackend(hostName)
user, _, err := backend.Register(userName, "", "") user, _, err := backend.Register(userName, "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, expectedUserID, user.ID()) assert.Equal(t, expectedUserID, user.ID())
} }
@ -28,34 +28,34 @@ func TestUserMessage(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, _, err := backend.Register("user1", "", "") user, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
Name: "room1"} Name: "room1"}
room, err := user.CreateRoom(request) room, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
err = user.SendMessage(room, "hello") err = user.SendMessage(room, "hello")
assert.Nil(t, err) assert.NoError(t, err)
} }
func TestUserMessageInWrongRoom(t *testing.T) { func TestUserMessageInWrongRoom(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user1, _, err := backend.Register("user1", "", "") user1, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
Name: "room1"} Name: "room1"}
room, err := user1.CreateRoom(request) room, err := user1.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
user2, _, err := backend.Register("user2", "", "") user2, _, err := backend.Register("user2", "", "")
assert.Nil(t, err) assert.NoError(t, err)
err = user2.SendMessage(room, "hello") err = user2.SendMessage(room, "hello")
assert.NotNil(t, err) assert.NotNil(t, err)
@ -65,7 +65,7 @@ func TestGetUserByToken(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, token, err := backend.Register("user1", "", "") user, token, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotEmpty(t, token) assert.NotEmpty(t, token)
gotUser := backend.GetUserByToken(token) gotUser := backend.GetUserByToken(token)
@ -76,7 +76,7 @@ func TestGetUserByWrongToken(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
_, token, err := backend.Register("user1", "", "") _, token, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotEmpty(t, token) assert.NotEmpty(t, token)
gotUser := backend.GetUserByToken("wrong token") gotUser := backend.GetUserByToken("wrong token")
@ -92,10 +92,10 @@ func TestLogoutWithWrongToken(t *testing.T) {
) )
user, _, err := backend.Register(userName, password, "") user, _, err := backend.Register(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
_, token, err := backend.Login(userName, password, "") _, token, err := backend.Login(userName, password, "")
assert.Nil(t, err) assert.NoError(t, err)
assert.NotZero(t, token) assert.NotZero(t, token)
user.Logout("worng token") user.Logout("worng token")
@ -105,7 +105,7 @@ func TestJoinedRooms(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, _, err := backend.Register("user1", "", "") user, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
@ -113,7 +113,7 @@ func TestJoinedRooms(t *testing.T) {
Topic: "topic"} Topic: "topic"}
room, err := user.CreateRoom(request) room, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
rooms := user.JoinedRooms() rooms := user.JoinedRooms()
assert.Equal(t, []internal.Room{room}, rooms) assert.Equal(t, []internal.Room{room}, rooms)
@ -125,7 +125,7 @@ func TestNewPassword(t *testing.T) {
var newPassword = "new password" var newPassword = "new password"
user, _, err := backend.Register("user1", "old password", "") user, _, err := backend.Register("user1", "old password", "")
assert.Nil(t, err) assert.NoError(t, err)
user.ChangePassword(newPassword) user.ChangePassword(newPassword)
assert.Equal(t, newPassword, user.Password()) assert.Equal(t, newPassword, user.Password())
@ -137,7 +137,7 @@ func TestDevices(t *testing.T) {
var expectedDeviceID = "my device" var expectedDeviceID = "my device"
user, _, err := backend.Register("user1", "", expectedDeviceID) user, _, err := backend.Register("user1", "", expectedDeviceID)
assert.Nil(t, err) assert.NoError(t, err)
devices := user.Devices() devices := user.Devices()
assert.Len(t, devices, 1) assert.Len(t, devices, 1)
@ -148,7 +148,7 @@ func TestSetRoomVisibility(t *testing.T) {
backend := NewBackend("localhost") backend := NewBackend("localhost")
user, _, err := backend.Register("user1", "", "") user, _, err := backend.Register("user1", "", "")
assert.Nil(t, err) assert.NoError(t, err)
request := createroom.Request{ request := createroom.Request{
RoomAliasName: "room1", RoomAliasName: "room1",
@ -156,17 +156,17 @@ func TestSetRoomVisibility(t *testing.T) {
Visibility: createroom.VisibilityTypePrivate} Visibility: createroom.VisibilityTypePrivate}
room, err := user.CreateRoom(request) room, err := user.CreateRoom(request)
assert.Nil(t, err) assert.NoError(t, err)
assert.NotNil(t, room) assert.NotNil(t, room)
assert.Equal(t, createroom.VisibilityTypePrivate, room.Visibility()) assert.Equal(t, createroom.VisibilityTypePrivate, room.Visibility())
err = user.SetRoomVisibility(room, createroom.VisibilityTypePublic) err = user.SetRoomVisibility(room, createroom.VisibilityTypePublic)
assert.Nil(t, err) assert.NoError(t, err)
assert.Equal(t, createroom.VisibilityTypePublic, room.Visibility()) assert.Equal(t, createroom.VisibilityTypePublic, room.Visibility())
// TODO: Only owner can change room visibility // TODO: Only owner can change room visibility
notOwnerUser, _, err := backend.Register("user2", "", "") notOwnerUser, _, err := backend.Register("user2", "", "")
assert.Nil(t, err) assert.NoError(t, err)
err = notOwnerUser.SetRoomVisibility(room, createroom.VisibilityTypePrivate) err = notOwnerUser.SetRoomVisibility(room, createroom.VisibilityTypePrivate)
assert.NotNil(t, err) assert.NotNil(t, err)
@ -182,11 +182,11 @@ func TestLogoutAll(t *testing.T) {
) )
user, _, err := backend.Register(userName, password, "dev1") user, _, err := backend.Register(userName, password, "dev1")
assert.Nil(t, err) assert.NoError(t, err)
assert.Len(t, user.Devices(), 1) assert.Len(t, user.Devices(), 1)
_, _, err = backend.Login(userName, password, "dev2") _, _, err = backend.Login(userName, password, "dev2")
assert.Nil(t, err) assert.NoError(t, err)
assert.Len(t, user.Devices(), 2) assert.Len(t, user.Devices(), 2)
user.LogoutAll() user.LogoutAll()

View File

@ -6,21 +6,14 @@ import (
"github.com/nxshock/signaller/internal/models" "github.com/nxshock/signaller/internal/models"
) )
func errorResponse(w http.ResponseWriter, code models.ApiError, httpCode int, message string) { func errorResponse(w http.ResponseWriter, code models.ApiError, httpCode int, messageOverride string) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if message != "" {
code.Message = message
}
w.WriteHeader(httpCode) w.WriteHeader(httpCode)
if messageOverride != "" {
w.Write(models.NewError(code, messageOverride).JSON())
} else {
w.Write(code.JSON()) w.Write(code.JSON())
} }
func NewError(code models.ApiError, message string) *models.ApiError {
if message != "" {
code.Message = message
}
return &code
} }

View File

@ -68,7 +68,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
_, token, apiErr := currServer.Backend.Login(request.Identifier.User, request.Password, request.DeviceID) _, token, apiErr := currServer.Backend.Login(request.Identifier.User, request.Password, request.DeviceID)
if apiErr != nil { if apiErr != nil {
errorResponse(w, *apiErr, http.StatusForbidden, "") errorResponse(w, apiErr, http.StatusForbidden, "")
return return
} }
@ -110,7 +110,7 @@ func leaveRoomHandler(w http.ResponseWriter, r *http.Request) {
err := user.LeaveRoom(room) err := user.LeaveRoom(room)
if err != nil { if err != nil {
errorResponse(w, *err, http.StatusBadRequest, "") errorResponse(w, err, http.StatusBadRequest, "")
return return
} }
@ -185,7 +185,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
_, token, apiErr := currServer.Backend.Register(request.Username, request.Password, request.DeviceID) _, token, apiErr := currServer.Backend.Register(request.Username, request.Password, request.DeviceID)
if apiErr != nil { if apiErr != nil {
errorResponse(w, *apiErr, http.StatusBadRequest, "") errorResponse(w, apiErr, http.StatusBadRequest, "")
return return
} }

View File

@ -4,49 +4,86 @@ import (
"encoding/json" "encoding/json"
) )
type ApiError struct { type ApiError interface {
Code string `json:"errcode"` error
Message string `json:"error"` Code() string
Message() string
JSON() []byte
}
type apiError struct {
code string `json:"errcode"`
message string `json:"error"`
}
func (apiError *apiError) Error() string {
s := apiError.code
if apiError.message != "" {
s = s + ": " + apiError.message
}
return s
}
func (apiError *apiError) Code() string {
return apiError.code
}
func (apiError *apiError) Message() string {
return apiError.message
}
func (apiError *apiError) JSON() []byte {
b, _ := json.Marshal(apiError) // TODO: error handler?
return b
} }
var ( var (
// https://matrix.org/docs/spec/client_server/latest#api-standards // https://matrix.org/docs/spec/client_server/latest#api-standards
M_FORBIDDEN = ApiError{"M_FORBIDDEN", ""} // Forbidden access, e.g. joining a room without permission, failed login. M_FORBIDDEN = &apiError{"M_FORBIDDEN", ""} // Forbidden access, e.g. joining a room without permission, failed login.
M_UNKNOWN_TOKEN = ApiError{"M_UNKNOWN_TOKEN", ""} // The access token specified was not recognised. M_UNKNOWN_TOKEN = &apiError{"M_UNKNOWN_TOKEN", ""} // The access token specified was not recognised.
M_MISSING_TOKEN = ApiError{"M_MISSING_TOKEN", ""} // No access token was specified for the request. M_MISSING_TOKEN = &apiError{"M_MISSING_TOKEN", ""} // No access token was specified for the request.
M_BAD_JSON = ApiError{"M_BAD_JSON", ""} // Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. M_BAD_JSON = &apiError{"M_BAD_JSON", ""} // Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys.
M_NOT_JSON = ApiError{"M_NOT_JSON", ""} // Request did not contain valid JSON. M_NOT_JSON = &apiError{"M_NOT_JSON", ""} // Request did not contain valid JSON.
M_NOT_FOUND = ApiError{"M_NOT_FOUND", ""} // No resource was found for this request. M_NOT_FOUND = &apiError{"M_NOT_FOUND", ""} // No resource was found for this request.
M_LIMIT_EXCEEDED = ApiError{"M_LIMIT_EXCEEDED", ""} // Too many requests have been sent in a short period of time. Wait a while then try again. M_LIMIT_EXCEEDED = &apiError{"M_LIMIT_EXCEEDED", ""} // Too many requests have been sent in a short period of time. Wait a while then try again.
M_UNKNOWN = ApiError{"M_UNKNOWN", ""} // An unknown error has occurred. M_UNKNOWN = &apiError{"M_UNKNOWN", ""} // An unknown error has occurred.
M_UNRECOGNIZED = ApiError{"M_UNRECOGNIZED", ""} // The server did not understand the request. M_UNRECOGNIZED = &apiError{"M_UNRECOGNIZED", ""} // The server did not understand the request.
M_UNAUTHORIZED = ApiError{"M_UNAUTHORIZED", ""} // The request was not correctly authorized. Usually due to login failures. M_UNAUTHORIZED = &apiError{"M_UNAUTHORIZED", ""} // The request was not correctly authorized. Usually due to login failures.
M_USER_IN_USE = ApiError{"M_USER_IN_USE", ""} // Encountered when trying to register a user ID which has been taken. M_USER_IN_USE = &apiError{"M_USER_IN_USE", ""} // Encountered when trying to register a user ID which has been taken.
M_INVALID_USERNAME = ApiError{"M_INVALID_USERNAME", ""} // Encountered when trying to register a user ID which is not valid. M_INVALID_USERNAME = &apiError{"M_INVALID_USERNAME", ""} // Encountered when trying to register a user ID which is not valid.
M_ROOM_IN_USE = ApiError{"M_ROOM_IN_USE", ""} // Sent when the room alias given to the createRoom API is already in use. M_ROOM_IN_USE = &apiError{"M_ROOM_IN_USE", ""} // Sent when the room alias given to the createRoom API is already in use.
M_INVALID_ROOM_STATE = ApiError{"M_INVALID_ROOM_STATE", ""} // Sent when the initial state given to the createRoom API is invalid. M_INVALID_ROOM_STATE = &apiError{"M_INVALID_ROOM_STATE", ""} // Sent when the initial state given to the createRoom API is invalid.
M_THREEPID_IN_USE = ApiError{"M_THREEPID_IN_USE", ""} // Sent when a threepid given to an API cannot be used because the same threepid is already in use. M_THREEPID_IN_USE = &apiError{"M_THREEPID_IN_USE", ""} // Sent when a threepid given to an API cannot be used because the same threepid is already in use.
M_THREEPID_NOT_FOUND = ApiError{"M_THREEPID_NOT_FOUND", ""} // Sent when a threepid given to an API cannot be used because no record matching the threepid was found. M_THREEPID_NOT_FOUND = &apiError{"M_THREEPID_NOT_FOUND", ""} // Sent when a threepid given to an API cannot be used because no record matching the threepid was found.
M_THREEPID_AUTH_FAILED = ApiError{"M_THREEPID_AUTH_FAILED", ""} // Authentication could not be performed on the third party identifier. M_THREEPID_AUTH_FAILED = &apiError{"M_THREEPID_AUTH_FAILED", ""} // Authentication could not be performed on the third party identifier.
M_THREEPID_DENIED = ApiError{"M_THREEPID_DENIED", ""} // The server does not permit this third party identifier. This may happen if the server only permits, for example, email addresses from a particular domain. M_THREEPID_DENIED = &apiError{"M_THREEPID_DENIED", ""} // The server does not permit this third party identifier. This may happen if the server only permits, for example, email addresses from a particular domain.
M_SERVER_NOT_TRUSTED = ApiError{"M_SERVER_NOT_TRUSTED", ""} // The client's request used a third party server, eg. identity server, that this server does not trust. M_SERVER_NOT_TRUSTED = &apiError{"M_SERVER_NOT_TRUSTED", ""} // The client's request used a third party server, eg. identity server, that this server does not trust.
M_UNSUPPORTED_ROOM_VERSION = ApiError{"M_UNSUPPORTED_ROOM_VERSION", ""} // The client's request to create a room used a room version that the server does not support. M_UNSUPPORTED_ROOM_VERSION = &apiError{"M_UNSUPPORTED_ROOM_VERSION", ""} // The client's request to create a room used a room version that the server does not support.
M_INCOMPATIBLE_ROOM_VERSION = ApiError{"M_INCOMPATIBLE_ROOM_VERSION", ""} // The client attempted to join a room that has a version the server does not support. Inspect the room_version property of the error response for the room's version. M_INCOMPATIBLE_ROOM_VERSION = &apiError{"M_INCOMPATIBLE_ROOM_VERSION", ""} // The client attempted to join a room that has a version the server does not support. Inspect the room_version property of the error response for the room's version.
M_BAD_STATE = ApiError{"M_BAD_STATE", ""} // The state change requested cannot be performed, such as attempting to unban a user who is not banned. M_BAD_STATE = &apiError{"M_BAD_STATE", ""} // The state change requested cannot be performed, such as attempting to unban a user who is not banned.
M_GUEST_ACCESS_FORBIDDEN = ApiError{"M_GUEST_ACCESS_FORBIDDEN", ""} // The room or resource does not permit guests to access it. M_GUEST_ACCESS_FORBIDDEN = &apiError{"M_GUEST_ACCESS_FORBIDDEN", ""} // The room or resource does not permit guests to access it.
M_CAPTCHA_NEEDED = ApiError{"M_CAPTCHA_NEEDED", ""} // A Captcha is required to complete the request. M_CAPTCHA_NEEDED = &apiError{"M_CAPTCHA_NEEDED", ""} // A Captcha is required to complete the request.
M_CAPTCHA_INVALID = ApiError{"M_CAPTCHA_INVALID", ""} // The Captcha provided did not match what was expected. M_CAPTCHA_INVALID = &apiError{"M_CAPTCHA_INVALID", ""} // The Captcha provided did not match what was expected.
M_MISSING_PARAM = ApiError{"M_MISSING_PARAM", ""} // A required parameter was missing from the request. M_MISSING_PARAM = &apiError{"M_MISSING_PARAM", ""} // A required parameter was missing from the request.
M_INVALID_PARAM = ApiError{"M_INVALID_PARAM", ""} // A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. M_INVALID_PARAM = &apiError{"M_INVALID_PARAM", ""} // A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string.
M_TOO_LARGE = ApiError{"M_TOO_LARGE", ""} // The request or entity was too large. M_TOO_LARGE = &apiError{"M_TOO_LARGE", ""} // The request or entity was too large.
M_EXCLUSIVE = ApiError{"M_EXCLUSIVE", ""} // The resource being requested is reserved by an application service, or the application service making the request has not created the resource. M_EXCLUSIVE = &apiError{"M_EXCLUSIVE", ""} // The resource being requested is reserved by an application service, or the application service making the request has not created the resource.
M_RESOURCE_LIMIT_EXCEEDED = ApiError{"M_RESOURCE_LIMIT_EXCEEDED", ""} // The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: /sync, get account data, etc). M_RESOURCE_LIMIT_EXCEEDED = &apiError{"M_RESOURCE_LIMIT_EXCEEDED", ""} // The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: /sync, get account data, etc).
M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = ApiError{"M_CANNOT_LEAVE_SERVER_NOTICE_ROOM", ""} // The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = &apiError{"M_CANNOT_LEAVE_SERVER_NOTICE_ROOM", ""} // The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information.
) )
func (apiError ApiError) JSON() []byte { func NewError(err ApiError, messageOverride string) ApiError {
b, _ := json.Marshal(apiError) // TODO: error handler? newErr := &apiError{
return b code: err.Code(),
message: err.Message()}
if messageOverride != "" {
newErr.message = messageOverride
}
return newErr
} }