From 3a3bc85d6f3f94e6cc052f27d0374b166f8932e8 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 14 Jul 2024 00:06:27 -0400 Subject: [PATCH] issue #48 - fix chat in pidgin client This commit implements the following changes that makes Pidgin chat work: - chat detail level value must be "2" - set TLV 0xDA in chat room info - change the chat cookie to this format: %s-%s-%s, where the third %s is the chat room name. All chat room business logic is now consolidated in the state package. Co-authored-by: Josh Knight --- cmd/server/main.go | 4 +- foodgroup/auth_test.go | 10 +- foodgroup/chat.go | 8 +- foodgroup/chat_nav.go | 31 ++- foodgroup/chat_nav_test.go | 229 +++++++++------------ foodgroup/mock_chat_room_registry_test.go | 12 +- foodgroup/oservice.go | 2 +- foodgroup/oservice_test.go | 83 +++----- foodgroup/test_helpers.go | 2 +- foodgroup/types.go | 2 +- server/http/mgmt_api.go | 50 +++-- server/http/mgmt_api_test.go | 69 ++----- server/http/mock_chat_room_creator_test.go | 12 +- server/http/types.go | 2 +- state/chat.go | 91 +++++--- state/chat_test.go | 10 +- state/migrations/0006_chat_cookie.down.sql | 1 + state/migrations/0006_chat_cookie.up.sql | 2 + state/user_store.go | 47 +++-- state/user_store_test.go | 90 ++------ wire/snacs.go | 1 + 21 files changed, 324 insertions(+), 434 deletions(-) create mode 100644 state/migrations/0006_chat_cookie.down.sql create mode 100644 state/migrations/0006_chat_cookie.up.sql diff --git a/cmd/server/main.go b/cmd/server/main.go index b7df1ac0..fbca97ed 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -55,7 +55,7 @@ func main() { authService := foodgroup.NewAuthService(cfg, sessionManager, chatSessionManager, feedbagStore, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore, chatSessionManager, feedbagStore) bartService := foodgroup.NewBARTService(logger, feedbagStore, sessionManager, feedbagStore, adjListBuddyListStore) buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore) - chatNavService := foodgroup.NewChatNavService(logger, feedbagStore, state.NewChatRoom) + chatNavService := foodgroup.NewChatNavService(logger, feedbagStore) feedbagService := foodgroup.NewFeedbagService(logger, sessionManager, feedbagStore, feedbagStore, adjListBuddyListStore) foodgroupService := foodgroup.NewPermitDenyService() icbmService := foodgroup.NewICBMService(sessionManager, feedbagStore, adjListBuddyListStore) @@ -105,7 +105,7 @@ func main() { logger = logger.With("svc", "CHAT_NAV") sessionManager := state.NewInMemorySessionManager(logger) authService := foodgroup.NewAuthService(cfg, sessionManager, chatSessionManager, feedbagStore, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore, chatSessionManager, feedbagStore) - chatNavService := foodgroup.NewChatNavService(logger, feedbagStore, state.NewChatRoom) + chatNavService := foodgroup.NewChatNavService(logger, feedbagStore) oServiceService := foodgroup.NewOServiceServiceForChatNav(cfg, logger, sessionManager, adjListBuddyListStore, feedbagStore) oscar.BOSServer{ diff --git a/foodgroup/auth_test.go b/foodgroup/auth_test.go index f13693d5..215c4861 100644 --- a/foodgroup/auth_test.go +++ b/foodgroup/auth_test.go @@ -1056,8 +1056,6 @@ func TestAuthService_SignoutChat(t *testing.T) { name string // userSession is the session of the user signing out userSession *state.Session - // chatRoom is the chat room user is exiting - chatRoom state.ChatRoom // mockParams is the list of params sent to mocks that satisfy this // method's dependencies mockParams mockParams @@ -1065,9 +1063,6 @@ func TestAuthService_SignoutChat(t *testing.T) { { name: "user signs out of chat room, room is empty after user leaves", userSession: newTestSession("the-screen-name", sessOptCannedSignonTime, sessOptChatRoomCookie("the-chat-cookie")), - chatRoom: state.ChatRoom{ - Cookie: "the-chat-cookie", - }, mockParams: mockParams{ chatMessageRelayerParams: chatMessageRelayerParams{ chatRelayToAllExceptParams: chatRelayToAllExceptParams{ @@ -1104,9 +1099,6 @@ func TestAuthService_SignoutChat(t *testing.T) { { name: "user signs out of chat room, room is not empty after user leaves", userSession: newTestSession("the-screen-name", sessOptCannedSignonTime, sessOptChatRoomCookie("the-chat-cookie")), - chatRoom: state.ChatRoom{ - Cookie: "the-chat-cookie", - }, mockParams: mockParams{ chatMessageRelayerParams: chatMessageRelayerParams{ chatRelayToAllExceptParams: chatRelayToAllExceptParams{ @@ -1146,7 +1138,7 @@ func TestAuthService_SignoutChat(t *testing.T) { chatMessageRelayer := newMockChatMessageRelayer(t) for _, params := range tt.mockParams.chatRelayToAllExceptParams { chatMessageRelayer.EXPECT(). - RelayToAllExcept(nil, tt.chatRoom.Cookie, params.screenName, params.message) + RelayToAllExcept(nil, tt.userSession.ChatRoomCookie(), params.screenName, params.message) } sessionManager := newMockChatSessionRegistry(t) for _, params := range tt.mockParams.removeSessionParams { diff --git a/foodgroup/chat.go b/foodgroup/chat.go index 7120b76c..0c3225c9 100644 --- a/foodgroup/chat.go +++ b/foodgroup/chat.go @@ -121,10 +121,10 @@ func sendChatRoomInfoUpdate(ctx context.Context, sess *state.Session, chatMessag SubGroup: wire.ChatRoomInfoUpdate, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: room.Exchange, - Cookie: room.Cookie, - InstanceNumber: room.InstanceNumber, - DetailLevel: room.DetailLevel, + Exchange: room.Exchange(), + Cookie: room.Cookie(), + InstanceNumber: room.InstanceNumber(), + DetailLevel: room.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: room.TLVList(), }, diff --git a/foodgroup/chat_nav.go b/foodgroup/chat_nav.go index 823b1793..4eac9b30 100644 --- a/foodgroup/chat_nav.go +++ b/foodgroup/chat_nav.go @@ -32,11 +32,10 @@ var ( ) // NewChatNavService creates a new instance of NewChatNavService. -func NewChatNavService(logger *slog.Logger, chatRoomManager ChatRoomRegistry, fnNewChatRoom func() state.ChatRoom) *ChatNavService { +func NewChatNavService(logger *slog.Logger, chatRoomManager ChatRoomRegistry) *ChatNavService { return &ChatNavService{ logger: logger, chatRoomManager: chatRoomManager, - fnNewChatRoom: fnNewChatRoom, } } @@ -45,7 +44,6 @@ func NewChatNavService(logger *slog.Logger, chatRoomManager ChatRoomRegistry, fn type ChatNavService struct { logger *slog.Logger chatRoomManager ChatRoomRegistry - fnNewChatRoom func() state.ChatRoom } // RequestChatRights returns SNAC wire.ChatNavNavInfo, which contains chat @@ -102,14 +100,9 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNoMatch) } - room = s.fnNewChatRoom() - room.Creator = sess.IdentScreenName() - room.DetailLevel = inBody.DetailLevel - room.Exchange = inBody.Exchange - room.InstanceNumber = inBody.InstanceNumber - room.Name = name + room = state.NewChatRoom(name, sess.IdentScreenName(), inBody.Exchange) - if err := s.chatRoomManager.CreateChatRoom(room); err != nil { + if err := s.chatRoomManager.CreateChatRoom(&room); err != nil { return wire.SNACMessage{}, fmt.Errorf("%w: %w", errChatNavRoomCreateFailed, err) } break @@ -126,10 +119,10 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra TLVRestBlock: wire.TLVRestBlock{ TLVList: wire.TLVList{ wire.NewTLV(wire.ChatNavTLVRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: room.Exchange, - Cookie: room.Cookie, - InstanceNumber: room.InstanceNumber, - DetailLevel: room.DetailLevel, + Cookie: room.Cookie(), + Exchange: room.Exchange(), + DetailLevel: room.DetailLevel(), + InstanceNumber: room.InstanceNumber(), TLVBlock: wire.TLVBlock{ TLVList: room.TLVList(), }, @@ -153,7 +146,7 @@ func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFram return wire.SNACMessage{}, fmt.Errorf("%w: %w", state.ErrChatRoomNotFound, err) } - if room.Exchange != inBody.Exchange { + if room.Exchange() != inBody.Exchange { return wire.SNACMessage{}, errChatNavMismatchedExchange } @@ -167,10 +160,10 @@ func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFram TLVRestBlock: wire.TLVRestBlock{ TLVList: wire.TLVList{ wire.NewTLV(wire.ChatNavTLVRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: room.Exchange, - Cookie: room.Cookie, - InstanceNumber: room.InstanceNumber, - DetailLevel: room.DetailLevel, + Cookie: room.Cookie(), + Exchange: room.Exchange(), + DetailLevel: room.DetailLevel(), + InstanceNumber: room.InstanceNumber(), TLVBlock: wire.TLVBlock{ TLVList: room.TLVList(), }, diff --git a/foodgroup/chat_nav_test.go b/foodgroup/chat_nav_test.go index 2d6dc3c3..e3162df5 100644 --- a/foodgroup/chat_nav_test.go +++ b/foodgroup/chat_nav_test.go @@ -5,7 +5,6 @@ import ( "errors" "log/slog" "testing" - "time" "github.com/mk6i/retro-aim-server/state" "github.com/mk6i/retro-aim-server/wire" @@ -14,28 +13,12 @@ import ( ) func TestChatNavService_CreateRoom(t *testing.T) { - basicChatRoom := state.ChatRoom{ - Cookie: "dummy-cookie", - CreateTime: time.UnixMilli(0), - Creator: state.NewIdentScreenName("the-screen-name"), - DetailLevel: 3, - Exchange: 4, - InstanceNumber: 2, - Name: "the-chat-room-name", - } - publicChatRoom := state.ChatRoom{ - Cookie: "dummy-cookie", - CreateTime: time.UnixMilli(0), - Creator: state.NewIdentScreenName("the-screen-name"), - DetailLevel: 3, - Exchange: 5, - InstanceNumber: 2, - Name: "the-public-chat-room-name", - } + basicChatRoom := state.NewChatRoom("the-chat-room-name", state.NewIdentScreenName("the-screen-name"), state.PrivateExchange) + publicChatRoom := state.NewChatRoom("the-public-chat-room-name", state.NewIdentScreenName("the-screen-name"), state.PublicExchange) tests := []struct { name string - chatRoom state.ChatRoom + chatRoom *state.ChatRoom sess *state.Session inputSNAC wire.SNACMessage want wire.SNACMessage @@ -45,20 +28,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }{ { name: "create private room that already exists", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, + Exchange: basicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name()), }, }, }, @@ -75,10 +58,10 @@ func TestChatNavService_CreateRoom(t *testing.T) { wire.NewTLV( wire.ChatNavRequestRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, - Cookie: basicChatRoom.Cookie, - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + Exchange: basicChatRoom.Exchange(), + Cookie: basicChatRoom.Cookie(), + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: basicChatRoom.TLVList(), }, @@ -92,8 +75,8 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: basicChatRoom.Exchange, - name: basicChatRoom.Name, + exchange: basicChatRoom.Exchange(), + name: basicChatRoom.Name(), room: basicChatRoom, }, }, @@ -102,20 +85,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create private room that doesn't already exist", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, + Exchange: basicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name()), }, }, }, @@ -132,10 +115,10 @@ func TestChatNavService_CreateRoom(t *testing.T) { wire.NewTLV( wire.ChatNavRequestRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, - Cookie: basicChatRoom.Cookie, - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + Exchange: basicChatRoom.Exchange(), + Cookie: basicChatRoom.Cookie(), + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: basicChatRoom.TLVList(), }, @@ -149,14 +132,14 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: basicChatRoom.Exchange, - name: basicChatRoom.Name, + exchange: basicChatRoom.Exchange(), + name: basicChatRoom.Name(), err: state.ErrChatRoomNotFound, }, }, createChatRoomParams: createChatRoomParams{ { - room: basicChatRoom, + room: &basicChatRoom, }, }, }, @@ -167,20 +150,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create public room that already exists", - chatRoom: publicChatRoom, + chatRoom: &publicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: publicChatRoom.Exchange, + Exchange: publicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: publicChatRoom.InstanceNumber, - DetailLevel: publicChatRoom.DetailLevel, + InstanceNumber: publicChatRoom.InstanceNumber(), + DetailLevel: publicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name()), }, }, }, @@ -197,10 +180,10 @@ func TestChatNavService_CreateRoom(t *testing.T) { wire.NewTLV( wire.ChatNavRequestRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: publicChatRoom.Exchange, - Cookie: publicChatRoom.Cookie, - InstanceNumber: publicChatRoom.InstanceNumber, - DetailLevel: publicChatRoom.DetailLevel, + Exchange: publicChatRoom.Exchange(), + Cookie: publicChatRoom.Cookie(), + InstanceNumber: publicChatRoom.InstanceNumber(), + DetailLevel: publicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: publicChatRoom.TLVList(), }, @@ -214,8 +197,8 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: publicChatRoom.Exchange, - name: publicChatRoom.Name, + exchange: publicChatRoom.Exchange(), + name: publicChatRoom.Name(), room: publicChatRoom, }, }, @@ -224,20 +207,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create public room that does not exist", - chatRoom: publicChatRoom, + chatRoom: &publicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: publicChatRoom.Exchange, + Exchange: publicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: publicChatRoom.InstanceNumber, - DetailLevel: publicChatRoom.DetailLevel, + InstanceNumber: publicChatRoom.InstanceNumber(), + DetailLevel: publicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, publicChatRoom.Name()), }, }, }, @@ -256,8 +239,8 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: publicChatRoom.Exchange, - name: publicChatRoom.Name, + exchange: publicChatRoom.Exchange(), + name: publicChatRoom.Name(), err: state.ErrChatRoomNotFound, }, }, @@ -269,7 +252,7 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create room invalid exchange number", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ @@ -278,11 +261,11 @@ func TestChatNavService_CreateRoom(t *testing.T) { Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ Exchange: 1337, Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name()), }, }, }, @@ -300,17 +283,17 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "incoming create room missing name tlv", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, + Exchange: basicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{}, // intentionally empty for test }, @@ -321,20 +304,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create private room failed", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, + Exchange: basicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name()), }, }, }, @@ -345,14 +328,14 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: basicChatRoom.Exchange, - name: basicChatRoom.Name, + exchange: basicChatRoom.Exchange(), + name: basicChatRoom.Name(), err: state.ErrChatRoomNotFound, }, }, createChatRoomParams: createChatRoomParams{ { - room: basicChatRoom, + room: &basicChatRoom, err: errors.New("fake database error"), }, }, @@ -364,20 +347,20 @@ func TestChatNavService_CreateRoom(t *testing.T) { }, { name: "create private room failed unknown error", - chatRoom: basicChatRoom, + chatRoom: &basicChatRoom, sess: newTestSession("the-screen-name"), inputSNAC: wire.SNACMessage{ Frame: wire.SNACFrame{ RequestID: 1234, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: basicChatRoom.Exchange, + Exchange: basicChatRoom.Exchange(), Cookie: "create", // actual canned value sent by AIM client - InstanceNumber: basicChatRoom.InstanceNumber, - DetailLevel: basicChatRoom.DetailLevel, + InstanceNumber: basicChatRoom.InstanceNumber(), + DetailLevel: basicChatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: wire.TLVList{ - wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name), + wire.NewTLV(wire.ChatRoomTLVRoomName, basicChatRoom.Name()), }, }, }, @@ -388,8 +371,8 @@ func TestChatNavService_CreateRoom(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByNameParams: chatRoomByNameParams{ { - exchange: basicChatRoom.Exchange, - name: basicChatRoom.Name, + exchange: basicChatRoom.Exchange(), + name: basicChatRoom.Name(), err: errors.New("fake database error"), }, }, @@ -415,7 +398,7 @@ func TestChatNavService_CreateRoom(t *testing.T) { Return(params.err) } - svc := NewChatNavService(slog.Default(), chatRoomRegistry, tt.fnNewChatRoom) + svc := NewChatNavService(slog.Default(), chatRoomRegistry) outputSNAC, err := svc.CreateRoom(context.Background(), tt.sess, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate)) assert.ErrorIs(t, err, tt.wantErr) assert.Equal(t, tt.want, outputSNAC) @@ -424,6 +407,9 @@ func TestChatNavService_CreateRoom(t *testing.T) { } func TestChatNavService_RequestRoomInfo(t *testing.T) { + privateChatRoom := state.NewChatRoom("the-chat-room", state.NewIdentScreenName("the-user"), state.PrivateExchange) + publicChatRoom := state.NewChatRoom("the-chat-room", state.NewIdentScreenName("the-user"), state.PublicExchange) + tests := []struct { name string inputSNAC wire.SNACMessage @@ -439,7 +425,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { }, Body: wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{ Exchange: state.PrivateExchange, - Cookie: "the-chat-cookie", + Cookie: privateChatRoom.Cookie(), }, }, want: wire.SNACMessage{ @@ -452,12 +438,12 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { TLVRestBlock: wire.TLVRestBlock{ TLVList: wire.TLVList{ wire.NewTLV(0x04, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PrivateExchange, - InstanceNumber: 8, + Cookie: privateChatRoom.Cookie(), + DetailLevel: privateChatRoom.DetailLevel(), + Exchange: privateChatRoom.Exchange(), + InstanceNumber: privateChatRoom.InstanceNumber(), TLVBlock: wire.TLVBlock{ - TLVList: state.ChatRoom{Cookie: "the-chat-cookie"}.TLVList(), + TLVList: privateChatRoom.TLVList(), }, }), }, @@ -468,13 +454,8 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByCookieParams: chatRoomByCookieParams{ { - cookie: "the-chat-cookie", - room: state.ChatRoom{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PrivateExchange, - InstanceNumber: 8, - }, + cookie: privateChatRoom.Cookie(), + room: privateChatRoom, }, }, }, @@ -487,8 +468,8 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { RequestID: 1234, }, Body: wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{ - Exchange: state.PublicExchange, - Cookie: "the-chat-cookie", + Exchange: publicChatRoom.Exchange(), + Cookie: publicChatRoom.Cookie(), }, }, want: wire.SNACMessage{ @@ -501,12 +482,12 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { TLVRestBlock: wire.TLVRestBlock{ TLVList: wire.TLVList{ wire.NewTLV(0x04, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PublicExchange, - InstanceNumber: 8, + Cookie: publicChatRoom.Cookie(), + DetailLevel: publicChatRoom.DetailLevel(), + Exchange: publicChatRoom.Exchange(), + InstanceNumber: publicChatRoom.InstanceNumber(), TLVBlock: wire.TLVBlock{ - TLVList: state.ChatRoom{Cookie: "the-chat-cookie"}.TLVList(), + TLVList: publicChatRoom.TLVList(), }, }), }, @@ -517,13 +498,8 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByCookieParams: chatRoomByCookieParams{ { - cookie: "the-chat-cookie", - room: state.ChatRoom{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PublicExchange, - InstanceNumber: 8, - }, + cookie: publicChatRoom.Cookie(), + room: publicChatRoom, }, }, }, @@ -559,7 +535,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { }, Body: wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{ Exchange: state.PrivateExchange, - Cookie: "the-chat-cookie", + Cookie: privateChatRoom.Cookie(), }, }, want: wire.SNACMessage{}, @@ -568,13 +544,8 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByCookieParams: chatRoomByCookieParams{ { - cookie: "the-chat-cookie", - room: state.ChatRoom{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PublicExchange, - InstanceNumber: 8, - }, + cookie: privateChatRoom.Cookie(), + room: publicChatRoom, }, }, }, @@ -588,7 +559,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { }, Body: wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{ Exchange: state.PrivateExchange, - Cookie: "the-chat-cookie", + Cookie: privateChatRoom.Cookie(), }, }, want: wire.SNACMessage{}, @@ -597,14 +568,8 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByCookieParams: chatRoomByCookieParams{ { - cookie: "the-chat-cookie", - room: state.ChatRoom{ - Cookie: "the-chat-cookie", - DetailLevel: 2, - Exchange: state.PrivateExchange, - InstanceNumber: 8, - }, - err: state.ErrChatRoomNotFound, + cookie: privateChatRoom.Cookie(), + err: state.ErrChatRoomNotFound, }, }, }, @@ -620,7 +585,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { Return(params.room, params.err) } - svc := NewChatNavService(slog.Default(), chatRoomRegistry, nil) + svc := NewChatNavService(slog.Default(), chatRoomRegistry) got, err := svc.RequestRoomInfo(nil, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo)) assert.ErrorIs(t, err, tt.wantErr) @@ -633,7 +598,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) { } func TestChatNavService_RequestChatRights(t *testing.T) { - svc := NewChatNavService(nil, nil, nil) + svc := NewChatNavService(nil, nil) have := svc.RequestChatRights(nil, wire.SNACFrame{RequestID: 1234}) @@ -802,7 +767,7 @@ func TestChatNavService_ExchangeInfo(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - svc := NewChatNavService(slog.Default(), nil, nil) + svc := NewChatNavService(slog.Default(), nil) outputSNAC, err := svc.ExchangeInfo(context.Background(), tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x0D_0x03_ChatNavRequestExchangeInfo)) assert.ErrorIs(t, err, tt.wantErr) diff --git a/foodgroup/mock_chat_room_registry_test.go b/foodgroup/mock_chat_room_registry_test.go index e5b2bef7..72bd7490 100644 --- a/foodgroup/mock_chat_room_registry_test.go +++ b/foodgroup/mock_chat_room_registry_test.go @@ -134,7 +134,7 @@ func (_c *mockChatRoomRegistry_ChatRoomByName_Call) RunAndReturn(run func(uint16 } // CreateChatRoom provides a mock function with given fields: chatRoom -func (_m *mockChatRoomRegistry) CreateChatRoom(chatRoom state.ChatRoom) error { +func (_m *mockChatRoomRegistry) CreateChatRoom(chatRoom *state.ChatRoom) error { ret := _m.Called(chatRoom) if len(ret) == 0 { @@ -142,7 +142,7 @@ func (_m *mockChatRoomRegistry) CreateChatRoom(chatRoom state.ChatRoom) error { } var r0 error - if rf, ok := ret.Get(0).(func(state.ChatRoom) error); ok { + if rf, ok := ret.Get(0).(func(*state.ChatRoom) error); ok { r0 = rf(chatRoom) } else { r0 = ret.Error(0) @@ -157,14 +157,14 @@ type mockChatRoomRegistry_CreateChatRoom_Call struct { } // CreateChatRoom is a helper method to define mock.On call -// - chatRoom state.ChatRoom +// - chatRoom *state.ChatRoom func (_e *mockChatRoomRegistry_Expecter) CreateChatRoom(chatRoom interface{}) *mockChatRoomRegistry_CreateChatRoom_Call { return &mockChatRoomRegistry_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", chatRoom)} } -func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Run(run func(chatRoom state.ChatRoom)) *mockChatRoomRegistry_CreateChatRoom_Call { +func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Run(run func(chatRoom *state.ChatRoom)) *mockChatRoomRegistry_CreateChatRoom_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(state.ChatRoom)) + run(args[0].(*state.ChatRoom)) }) return _c } @@ -174,7 +174,7 @@ func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Return(_a0 error) *mockChatR return _c } -func (_c *mockChatRoomRegistry_CreateChatRoom_Call) RunAndReturn(run func(state.ChatRoom) error) *mockChatRoomRegistry_CreateChatRoom_Call { +func (_c *mockChatRoomRegistry_CreateChatRoom_Call) RunAndReturn(run func(*state.ChatRoom) error) *mockChatRoomRegistry_CreateChatRoom_Call { _c.Call.Return(run) return _c } diff --git a/foodgroup/oservice.go b/foodgroup/oservice.go index 981f1fd8..4bd5ee3a 100644 --- a/foodgroup/oservice.go +++ b/foodgroup/oservice.go @@ -670,7 +670,7 @@ func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.S } loginCookie := chatLoginCookie{ - ChatCookie: room.Cookie, + ChatCookie: room.Cookie(), ScreenName: sess.DisplayScreenName(), } buf := &bytes.Buffer{} diff --git a/foodgroup/oservice_test.go b/foodgroup/oservice_test.go index ed4d95de..35919f92 100644 --- a/foodgroup/oservice_test.go +++ b/foodgroup/oservice_test.go @@ -17,6 +17,8 @@ import ( ) func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) { + chatRoom := state.NewChatRoom("the-chat-room", state.NewIdentScreenName(""), state.PrivateExchange) + cases := []struct { // name is the unit test name name string @@ -200,9 +202,9 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) { TLVRestBlock: wire.TLVRestBlock{ TLVList: wire.TLVList{ wire.NewTLV(0x01, wire.SNAC_0x01_0x04_TLVRoomInfo{ - Exchange: 8, - Cookie: "the-chat-cookie", - InstanceNumber: 16, + Exchange: chatRoom.Exchange(), + Cookie: chatRoom.Cookie(), + InstanceNumber: chatRoom.InstanceNumber(), }), }, }, @@ -226,32 +228,27 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) { }, }, }, - mockParams: mockParams{ - chatRoomRegistryParams: chatRoomRegistryParams{ - chatRoomByCookieParams: chatRoomByCookieParams{ - { - cookie: "the-chat-cookie", - room: state.ChatRoom{ - CreateTime: time.UnixMilli(0), - DetailLevel: 4, - Exchange: 8, - Cookie: "the-chat-cookie", - InstanceNumber: 16, - Name: "my new chat", + mockParams: func() mockParams { + return mockParams{ + chatRoomRegistryParams: chatRoomRegistryParams{ + chatRoomByCookieParams: chatRoomByCookieParams{ + { + cookie: chatRoom.Cookie(), + room: chatRoom, }, }, }, - }, - cookieIssuerParams: cookieIssuerParams{ - { - data: []byte{ - 0x0F, 't', 'h', 'e', '-', 'c', 'h', 'a', 't', '-', 'c', 'o', 'o', 'k', 'i', 'e', - 0x10, 'u', 's', 'e', 'r', '_', 's', 'c', 'r', 'e', 'e', 'n', '_', 'n', 'a', 'm', 'e', + cookieIssuerParams: cookieIssuerParams{ + { + data: []byte{ + 0x11, '4', '-', '0', '-', 't', 'h', 'e', '-', 'c', 'h', 'a', 't', '-', 'r', 'o', 'o', 'm', + 0x10, 'u', 's', 'e', 'r', '_', 's', 'c', 'r', 'e', 'e', 'n', '_', 'n', 'a', 'm', 'e', + }, + cookie: []byte("the-auth-cookie"), }, - cookie: []byte("the-auth-cookie"), }, - }, - }, + } + }(), }, { name: "request info for connecting to non-existent chat room, return ErrChatRoomNotFound", @@ -1702,15 +1699,9 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) { } func TestOServiceServiceForChat_ClientOnline(t *testing.T) { - chatter1 := newTestSession("chatter-1", sessOptChatRoomCookie("the-cookie")) - chatter2 := newTestSession("chatter-2", sessOptChatRoomCookie("the-cookie")) - chatRoom := state.ChatRoom{ - Cookie: "the-cookie", - DetailLevel: 1, - Exchange: 2, - InstanceNumber: 3, - Name: "the-chat-room", - } + chatRoom := state.NewChatRoom("the-chat-room", state.NewIdentScreenName("creator"), state.PrivateExchange) + chatter1 := newTestSession("chatter-1", sessOptChatRoomCookie(chatRoom.Cookie())) + chatter2 := newTestSession("chatter-2", sessOptChatRoomCookie(chatRoom.Cookie())) tests := []struct { // name is the name of the test @@ -1734,7 +1725,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { chatRelayToAllExceptParams: chatRelayToAllExceptParams{ { screenName: state.NewIdentScreenName("chatter-1"), - cookie: "the-cookie", + cookie: chatRoom.Cookie(), message: wire.SNACMessage{ Frame: wire.SNACFrame{ FoodGroup: wire.Chat, @@ -1750,7 +1741,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { }, chatAllSessionsParams: chatAllSessionsParams{ { - cookie: "the-cookie", + cookie: chatRoom.Cookie(), sessions: []*state.Session{ chatter1, chatter2, @@ -1759,7 +1750,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { }, chatRelayToScreenNameParams: chatRelayToScreenNameParams{ { - cookie: "the-cookie", + cookie: chatRoom.Cookie(), screenName: chatter1.IdentScreenName(), message: wire.SNACMessage{ Frame: wire.SNACFrame{ @@ -1767,10 +1758,10 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { SubGroup: wire.ChatRoomInfoUpdate, }, Body: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{ - Exchange: chatRoom.Exchange, - Cookie: chatRoom.Cookie, - InstanceNumber: chatRoom.InstanceNumber, - DetailLevel: chatRoom.DetailLevel, + Exchange: chatRoom.Exchange(), + Cookie: chatRoom.Cookie(), + InstanceNumber: chatRoom.InstanceNumber(), + DetailLevel: chatRoom.DetailLevel(), TLVBlock: wire.TLVBlock{ TLVList: chatRoom.TLVList(), }, @@ -1778,7 +1769,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { }, }, { - cookie: "the-cookie", + cookie: chatRoom.Cookie(), screenName: chatter1.IdentScreenName(), message: wire.SNACMessage{ Frame: wire.SNACFrame{ @@ -1798,14 +1789,8 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) { chatRoomRegistryParams: chatRoomRegistryParams{ chatRoomByCookieParams: chatRoomByCookieParams{ { - cookie: "the-cookie", - room: state.ChatRoom{ - Cookie: "the-cookie", - DetailLevel: 1, - Exchange: 2, - InstanceNumber: 3, - Name: "the-chat-room", - }, + cookie: chatRoom.Cookie(), + room: chatRoom, }, }, }, diff --git a/foodgroup/test_helpers.go b/foodgroup/test_helpers.go index 9b702b52..557906d7 100644 --- a/foodgroup/test_helpers.go +++ b/foodgroup/test_helpers.go @@ -433,7 +433,7 @@ type chatRoomByNameParams []struct { // createChatRoomParams is the list of parameters passed at the mock // ChatRoomRegistry.CreateChatRoom call site type createChatRoomParams []struct { - room state.ChatRoom + room *state.ChatRoom err error } diff --git a/foodgroup/types.go b/foodgroup/types.go index 5500e088..c9c2d4ad 100644 --- a/foodgroup/types.go +++ b/foodgroup/types.go @@ -143,7 +143,7 @@ type ChatRoomRegistry interface { ChatRoomByName(exchange uint16, name string) (state.ChatRoom, error) // CreateChatRoom creates a new chat room. - CreateChatRoom(chatRoom state.ChatRoom) error + CreateChatRoom(chatRoom *state.ChatRoom) error } type BARTManager interface { diff --git a/server/http/mgmt_api.go b/server/http/mgmt_api.go index e1b72863..848f6885 100644 --- a/server/http/mgmt_api.go +++ b/server/http/mgmt_api.go @@ -44,7 +44,7 @@ func StartManagementAPI( sessionHandler(w, r, sessionRetriever) }) mux.HandleFunc("/chat/room/public", func(w http.ResponseWriter, r *http.Request) { - publicChatHandler(w, r, chatRoomRetriever, chatRoomCreator, chatSessionRetriever, state.NewChatRoom, logger) + publicChatHandler(w, r, chatRoomRetriever, chatRoomCreator, chatSessionRetriever, logger) }) mux.HandleFunc("/chat/room/private", func(w http.ResponseWriter, r *http.Request) { privateChatHandler(w, r, chatRoomRetriever, chatSessionRetriever, logger) @@ -93,7 +93,7 @@ func deleteUserHandler(w http.ResponseWriter, r *http.Request, manager UserManag } w.WriteHeader(http.StatusNoContent) - fmt.Fprintln(w, "User account successfully deleted.") + _, _ = fmt.Fprintln(w, "User account successfully deleted.") } func userPasswordHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, newUUID func() uuid.UUID, logger *slog.Logger) { @@ -225,7 +225,7 @@ func postUserHandler(w http.ResponseWriter, r *http.Request, userManager UserMan } w.WriteHeader(http.StatusCreated) - fmt.Fprintln(w, "User account created successfully.") + _, _ = fmt.Fprintln(w, "User account created successfully.") } func userFromBody(r *http.Request) (userWithPassword, error) { @@ -244,28 +244,28 @@ func loginHandler(w http.ResponseWriter, r *http.Request, userManager UserManage // No authentication header found w.WriteHeader(http.StatusUnauthorized) w.Header().Set("WWW-Authenticate", `Basic realm="User Login"`) - w.Write([]byte("401 Unauthorized\n")) + _, _ = w.Write([]byte("401 Unauthorized\n")) return } auth := strings.SplitN(authHeader, " ", 2) if len(auth) != 2 || auth[0] != "Basic" { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte("401 Unauthorized: Missing Basic prefix\n")) + _, _ = w.Write([]byte("401 Unauthorized: Missing Basic prefix\n")) return } payload, err := base64.StdEncoding.DecodeString(auth[1]) if err != nil { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte("401 Unauthorized: Invalid Base64 Encoding\n")) + _, _ = w.Write([]byte("401 Unauthorized: Invalid Base64 Encoding\n")) return } pair := strings.SplitN(string(payload), ":", 2) if len(pair) != 2 { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte("401 Unauthorized: Invalid Authentication Token\n")) + _, _ = w.Write([]byte("401 Unauthorized: Invalid Authentication Token\n")) return } @@ -274,27 +274,27 @@ func loginHandler(w http.ResponseWriter, r *http.Request, userManager UserManage user, err := userManager.User(username) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("500 InternalServerError\n")) + _, _ = w.Write([]byte("500 InternalServerError\n")) logger.Error("error getting user", "err", err.Error()) return } if user == nil || !user.ValidateHash(wire.StrongMD5PasswordHash(password, user.AuthKey)) { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte("401 Unauthorized: Invalid Credentials\n")) + _, _ = w.Write([]byte("401 Unauthorized: Invalid Credentials\n")) return } // Successfully authenticated w.WriteHeader(http.StatusOK) - w.Write([]byte("200 OK: Successfully Authenticated\n")) + _, _ = w.Write([]byte("200 OK: Successfully Authenticated\n")) } -func publicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomRetriever ChatRoomRetriever, chatRoomCreator ChatRoomCreator, chatSessionRetriever ChatSessionRetriever, newChatRoom func() state.ChatRoom, logger *slog.Logger) { +func publicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomRetriever ChatRoomRetriever, chatRoomCreator ChatRoomCreator, chatSessionRetriever ChatSessionRetriever, logger *slog.Logger) { switch r.Method { case http.MethodGet: getPublicChatHandler(w, r, chatRoomRetriever, chatSessionRetriever, logger) case http.MethodPost: - postPublicChatHandler(w, r, chatRoomCreator, newChatRoom, logger) + postPublicChatHandler(w, r, chatRoomCreator, logger) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } @@ -321,10 +321,10 @@ func getPublicChatHandler(w http.ResponseWriter, _ *http.Request, chatRoomRetrie out := make([]chatRoom, len(rooms)) for i, room := range rooms { - sessions := chatSessionRetriever.AllSessions(room.Cookie) + sessions := chatSessionRetriever.AllSessions(room.Cookie()) cr := chatRoom{ - CreateTime: room.CreateTime, - Name: room.Name, + CreateTime: room.CreateTime(), + Name: room.Name(), Participants: make([]userHandle, len(sessions)), URL: room.URL().String(), } @@ -345,7 +345,7 @@ func getPublicChatHandler(w http.ResponseWriter, _ *http.Request, chatRoomRetrie } // postPublicChatHandler handles the POST /chat/room/public endpoint. -func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreator ChatRoomCreator, newChatRoom func() state.ChatRoom, logger *slog.Logger) { +func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreator ChatRoomCreator, logger *slog.Logger) { input := chatRoomCreate{} if err := json.NewDecoder(r.Body).Decode(&input); err != nil { http.Error(w, "invalid input", http.StatusBadRequest) @@ -358,11 +358,9 @@ func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreat return } - cr := newChatRoom() - cr.Name = input.Name - cr.Exchange = state.PublicExchange + cr := state.NewChatRoom(input.Name, state.NewIdentScreenName("system"), state.PublicExchange) - err := chatRoomCreator.CreateChatRoom(cr) + err := chatRoomCreator.CreateChatRoom(&cr) switch { case errors.Is(err, state.ErrDupChatRoom): http.Error(w, "Chat room already exists.", http.StatusConflict) @@ -374,7 +372,7 @@ func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreat } w.WriteHeader(http.StatusCreated) - fmt.Fprintln(w, "Chat room created successfully.") + _, _ = fmt.Fprintln(w, "Chat room created successfully.") } // getPrivateChatHandler handles the GET /chat/room/private endpoint. @@ -389,11 +387,11 @@ func getPrivateChatHandler(w http.ResponseWriter, _ *http.Request, chatRoomRetri out := make([]chatRoom, len(rooms)) for i, room := range rooms { - sessions := chatSessionRetriever.AllSessions(room.Cookie) + sessions := chatSessionRetriever.AllSessions(room.Cookie()) cr := chatRoom{ - CreateTime: room.CreateTime, - CreatorID: room.Creator.String(), - Name: room.Name, + CreateTime: room.CreateTime(), + CreatorID: room.Creator().String(), + Name: room.Name(), Participants: make([]userHandle, len(sessions)), URL: room.URL().String(), } @@ -457,5 +455,5 @@ func postInstantMessageHandler(w http.ResponseWriter, r *http.Request, messageRe messageRelayer.RelayToScreenName(context.Background(), state.NewIdentScreenName(input.To), msg) w.WriteHeader(http.StatusOK) - fmt.Fprintln(w, "Message sent successfully.") + _, _ = fmt.Fprintln(w, "Message sent successfully.") } diff --git a/server/http/mgmt_api_test.go b/server/http/mgmt_api_test.go index 6ea6b2e9..3f7c7725 100644 --- a/server/http/mgmt_api_test.go +++ b/server/http/mgmt_api_test.go @@ -7,7 +7,6 @@ import ( "net/http/httptest" "strings" "testing" - "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -442,6 +441,9 @@ func TestPublicChatHandler_GET(t *testing.T) { result []*state.Session } + chatRoom1 := state.NewChatRoom("chat-room-1-name", state.NewIdentScreenName("chat-room-1-creator"), state.PublicExchange) + chatRoom2 := state.NewChatRoom("chat-room-2-name", state.NewIdentScreenName("chat-room-1-creator"), state.PublicExchange) + tt := []struct { name string allChatRoomsParams allChatRoomsParams @@ -455,37 +457,27 @@ func TestPublicChatHandler_GET(t *testing.T) { allChatRoomsParams: allChatRoomsParams{ exchange: state.PublicExchange, result: []state.ChatRoom{ - { - Cookie: "chat-room-1-cookie", - Creator: state.NewIdentScreenName("chat-room-1-creator"), - Name: "chat-room-1-name", - CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC), - }, - { - Cookie: "chat-room-2-cookie", - Creator: state.NewIdentScreenName("chat-room-2-creator"), - Name: "chat-room-2-name", - CreateTime: time.Date(2022, 01, 04, 6, 8, 1, 2, time.UTC), - }, + chatRoom1, + chatRoom2, }, }, allSessionsParams: []allSessionsParams{ { - cookie: "chat-room-1-cookie", + cookie: chatRoom1.Cookie(), result: []*state.Session{ fnNewSess("userA"), fnNewSess("userB"), }, }, { - cookie: "chat-room-2-cookie", + cookie: chatRoom2.Cookie(), result: []*state.Session{ fnNewSess("userC"), fnNewSess("userD"), }, }, }, - want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"2022-01-04T06:08:01.000000002Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`, + want: `[{"name":"chat-room-1-name","create_time":"0001-01-01T00:00:00Z","url":"aim:gochat?exchange=5\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"0001-01-01T00:00:00Z","url":"aim:gochat?exchange=5\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`, statusCode: http.StatusOK, }, { @@ -493,21 +485,16 @@ func TestPublicChatHandler_GET(t *testing.T) { allChatRoomsParams: allChatRoomsParams{ exchange: state.PublicExchange, result: []state.ChatRoom{ - { - Cookie: "chat-room-1-cookie", - Creator: state.NewIdentScreenName("chat-room-1-creator"), - Name: "chat-room-1-name", - CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC), - }, + chatRoom1, }, }, allSessionsParams: []allSessionsParams{ { - cookie: "chat-room-1-cookie", + cookie: chatRoom1.Cookie(), result: []*state.Session{}, }, }, - want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[]}]`, + want: `[{"name":"chat-room-1-name","create_time":"0001-01-01T00:00:00Z","url":"aim:gochat?exchange=5\u0026roomname=chat-room-1-name","participants":[]}]`, statusCode: http.StatusOK, }, { @@ -569,6 +556,9 @@ func TestPrivateChatHandler_GET(t *testing.T) { result []*state.Session } + chatRoom1 := state.NewChatRoom("chat-room-1-name", state.NewIdentScreenName("chat-room-1-creator"), state.PrivateExchange) + chatRoom2 := state.NewChatRoom("chat-room-2-name", state.NewIdentScreenName("chat-room-2-creator"), state.PrivateExchange) + tt := []struct { name string allChatRoomsParams allChatRoomsParams @@ -582,37 +572,27 @@ func TestPrivateChatHandler_GET(t *testing.T) { allChatRoomsParams: allChatRoomsParams{ exchange: state.PrivateExchange, result: []state.ChatRoom{ - { - Cookie: "chat-room-1-cookie", - Creator: state.NewIdentScreenName("chat-room-1-creator"), - Name: "chat-room-1-name", - CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC), - }, - { - Cookie: "chat-room-2-cookie", - Creator: state.NewIdentScreenName("chat-room-2-creator"), - Name: "chat-room-2-name", - CreateTime: time.Date(2022, 01, 04, 6, 8, 1, 2, time.UTC), - }, + chatRoom1, + chatRoom2, }, }, allSessionsParams: []allSessionsParams{ { - cookie: "chat-room-1-cookie", + cookie: chatRoom1.Cookie(), result: []*state.Session{ fnNewSess("userA"), fnNewSess("userB"), }, }, { - cookie: "chat-room-2-cookie", + cookie: chatRoom2.Cookie(), result: []*state.Session{ fnNewSess("userC"), fnNewSess("userD"), }, }, }, - want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"2022-01-04T06:08:01.000000002Z","creator_id":"chat-room-2-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`, + want: `[{"name":"chat-room-1-name","create_time":"0001-01-01T00:00:00Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=4\u0026roomname=chat-room-1-name","participants":[{"id":"usera","screen_name":"userA"},{"id":"userb","screen_name":"userB"}]},{"name":"chat-room-2-name","create_time":"0001-01-01T00:00:00Z","creator_id":"chat-room-2-creator","url":"aim:gochat?exchange=4\u0026roomname=chat-room-2-name","participants":[{"id":"userc","screen_name":"userC"},{"id":"userd","screen_name":"userD"}]}]`, statusCode: http.StatusOK, }, { @@ -620,21 +600,16 @@ func TestPrivateChatHandler_GET(t *testing.T) { allChatRoomsParams: allChatRoomsParams{ exchange: state.PrivateExchange, result: []state.ChatRoom{ - { - Cookie: "chat-room-1-cookie", - Creator: state.NewIdentScreenName("chat-room-1-creator"), - Name: "chat-room-1-name", - CreateTime: time.Date(2024, 06, 01, 1, 2, 3, 4, time.UTC), - }, + chatRoom1, }, }, allSessionsParams: []allSessionsParams{ { - cookie: "chat-room-1-cookie", + cookie: chatRoom1.Cookie(), result: []*state.Session{}, }, }, - want: `[{"name":"chat-room-1-name","create_time":"2024-06-01T01:02:03.000000004Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=0\u0026roomname=chat-room-1-name","participants":[]}]`, + want: `[{"name":"chat-room-1-name","create_time":"0001-01-01T00:00:00Z","creator_id":"chat-room-1-creator","url":"aim:gochat?exchange=4\u0026roomname=chat-room-1-name","participants":[]}]`, statusCode: http.StatusOK, }, { diff --git a/server/http/mock_chat_room_creator_test.go b/server/http/mock_chat_room_creator_test.go index ce249a1e..a3f426bd 100644 --- a/server/http/mock_chat_room_creator_test.go +++ b/server/http/mock_chat_room_creator_test.go @@ -21,7 +21,7 @@ func (_m *mockChatRoomCreator) EXPECT() *mockChatRoomCreator_Expecter { } // CreateChatRoom provides a mock function with given fields: chatRoom -func (_m *mockChatRoomCreator) CreateChatRoom(chatRoom state.ChatRoom) error { +func (_m *mockChatRoomCreator) CreateChatRoom(chatRoom *state.ChatRoom) error { ret := _m.Called(chatRoom) if len(ret) == 0 { @@ -29,7 +29,7 @@ func (_m *mockChatRoomCreator) CreateChatRoom(chatRoom state.ChatRoom) error { } var r0 error - if rf, ok := ret.Get(0).(func(state.ChatRoom) error); ok { + if rf, ok := ret.Get(0).(func(*state.ChatRoom) error); ok { r0 = rf(chatRoom) } else { r0 = ret.Error(0) @@ -44,14 +44,14 @@ type mockChatRoomCreator_CreateChatRoom_Call struct { } // CreateChatRoom is a helper method to define mock.On call -// - chatRoom state.ChatRoom +// - chatRoom *state.ChatRoom func (_e *mockChatRoomCreator_Expecter) CreateChatRoom(chatRoom interface{}) *mockChatRoomCreator_CreateChatRoom_Call { return &mockChatRoomCreator_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", chatRoom)} } -func (_c *mockChatRoomCreator_CreateChatRoom_Call) Run(run func(chatRoom state.ChatRoom)) *mockChatRoomCreator_CreateChatRoom_Call { +func (_c *mockChatRoomCreator_CreateChatRoom_Call) Run(run func(chatRoom *state.ChatRoom)) *mockChatRoomCreator_CreateChatRoom_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(state.ChatRoom)) + run(args[0].(*state.ChatRoom)) }) return _c } @@ -61,7 +61,7 @@ func (_c *mockChatRoomCreator_CreateChatRoom_Call) Return(_a0 error) *mockChatRo return _c } -func (_c *mockChatRoomCreator_CreateChatRoom_Call) RunAndReturn(run func(state.ChatRoom) error) *mockChatRoomCreator_CreateChatRoom_Call { +func (_c *mockChatRoomCreator_CreateChatRoom_Call) RunAndReturn(run func(*state.ChatRoom) error) *mockChatRoomCreator_CreateChatRoom_Call { _c.Call.Return(run) return _c } diff --git a/server/http/types.go b/server/http/types.go index 2cc7509f..bd0ac78b 100644 --- a/server/http/types.go +++ b/server/http/types.go @@ -13,7 +13,7 @@ type ChatRoomRetriever interface { } type ChatRoomCreator interface { - CreateChatRoom(chatRoom state.ChatRoom) error + CreateChatRoom(chatRoom *state.ChatRoom) error } type ChatSessionRetriever interface { diff --git a/state/chat.go b/state/chat.go index a5b88a6e..66b34596 100644 --- a/state/chat.go +++ b/state/chat.go @@ -7,8 +7,6 @@ import ( "time" "github.com/mk6i/retro-aim-server/wire" - - "github.com/google/uuid" ) const ( @@ -26,29 +24,69 @@ var ( ErrDupChatRoom = errors.New("chat room already exists") ) -// ChatRoom is the representation of a chat room's metadata. +// NewChatRoom creates a new ChatRoom instance. +func NewChatRoom(name string, creator IdentScreenName, exchange uint16) ChatRoom { + return ChatRoom{ + name: name, + creator: creator, + exchange: exchange, + } +} + +// ChatRoom represents of a chat room. type ChatRoom struct { - // Cookie is the unique chat room identifier. - Cookie string - // CreateTime indicates when the chat room was created. - CreateTime time.Time - // Creator is the screen name of the user who created the chat room. - Creator IdentScreenName - // DetailLevel is the detail level of the chat room. Unclear what this value means. - DetailLevel uint8 - // Exchange indicates which exchange the chatroom belongs to. Typically, a canned value. - Exchange uint16 - // InstanceNumber indicates which instance chatroom exists in. Typically, a canned value. - InstanceNumber uint16 - // Name is the name of the chat room. - Name string + createTime time.Time + creator IdentScreenName + exchange uint16 + name string +} + +// Creator returns the screen name of the user who created the chat room. +func (c ChatRoom) Creator() IdentScreenName { + return c.creator +} + +// Exchange returns which exchange the chat room belongs to. +func (c ChatRoom) Exchange() uint16 { + return c.exchange +} + +// Name returns the chat room name. +func (c ChatRoom) Name() string { + return c.name +} + +// InstanceNumber returns which instance chatroom exists in. Overflow chat +// rooms do not exist yet, so all chats happen in the same instance. +func (c ChatRoom) InstanceNumber() uint16 { + return 0 +} + +// CreateTime returns when the chat room was inserted in the database. +func (c ChatRoom) CreateTime() time.Time { + return c.createTime +} + +// DetailLevel returns the detail level of the chat room (whatever that means). +func (c ChatRoom) DetailLevel() uint8 { + return 0x02 // Pidgin 2.13.0 expects value 0x02 +} + +// Cookie returns the chat room unique identifier. +func (c ChatRoom) Cookie() string { + // According to Pidgin, the chat cookie is a 3-part identifier. The third + // segment is the chat name, which is shown explicitly in the Pidgin code. + // We can assume that the first two parts were the exchange and instance + // number. As of now, Pidgin is the only client that cares about the cookie + // format, and it only cares about the chat name segment. + return fmt.Sprintf("%d-%d-%s", c.exchange, c.InstanceNumber(), c.name) } // URL creates a URL that can be used to join a chat room. func (c ChatRoom) URL() *url.URL { v := url.Values{} - v.Set("roomname", c.Name) - v.Set("exchange", fmt.Sprintf("%d", c.Exchange)) + v.Set("roomname", c.name) + v.Set("exchange", fmt.Sprintf("%d", c.exchange)) return &url.URL{ Scheme: "aim", @@ -67,7 +105,7 @@ func (c ChatRoom) TLVList() []wire.TLV { // - 8 Occupant Peek Allowed // It's unclear what effect they actually have. wire.NewTLV(wire.ChatRoomTLVFlags, uint16(15)), - wire.NewTLV(wire.ChatRoomTLVCreateTime, uint32(c.CreateTime.Unix())), + wire.NewTLV(wire.ChatRoomTLVCreateTime, uint32(c.createTime.Unix())), wire.NewTLV(wire.ChatRoomTLVMaxMsgLen, uint16(1024)), wire.NewTLV(wire.ChatRoomTLVMaxOccupancy, uint16(100)), // From protocols/oscar/family_chatnav.c in lib purple, these are the @@ -77,15 +115,8 @@ func (c ChatRoom) TLVList() []wire.TLV { // - 2 exchange creation allowed // It's unclear what effect they actually have. wire.NewTLV(wire.ChatRoomTLVNavCreatePerms, uint8(2)), - wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, c.Name), - wire.NewTLV(wire.ChatRoomTLVRoomName, c.Name), - } -} - -// NewChatRoom creates new state.ChatRoom objects -func NewChatRoom() ChatRoom { - return ChatRoom{ - Cookie: uuid.New().String(), - CreateTime: time.Now().UTC(), + wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, c.name), + wire.NewTLV(wire.ChatRoomTLVRoomName, c.name), + wire.NewTLV(wire.ChatRoomTLVMaxMsgVisLen, uint16(1024)), } } diff --git a/state/chat_test.go b/state/chat_test.go index e3293a28..043634ca 100644 --- a/state/chat_test.go +++ b/state/chat_test.go @@ -9,18 +9,18 @@ import ( ) func TestChatRoom_TLVList(t *testing.T) { - room := NewChatRoom() - room.Name = "chat-room-name" + room := NewChatRoom("chat-room-name", NewIdentScreenName(""), PublicExchange) have := room.TLVList() want := []wire.TLV{ wire.NewTLV(wire.ChatRoomTLVFlags, uint16(15)), - wire.NewTLV(wire.ChatRoomTLVCreateTime, uint32(room.CreateTime.Unix())), + wire.NewTLV(wire.ChatRoomTLVCreateTime, uint32(room.createTime.Unix())), wire.NewTLV(wire.ChatRoomTLVMaxMsgLen, uint16(1024)), wire.NewTLV(wire.ChatRoomTLVMaxOccupancy, uint16(100)), wire.NewTLV(wire.ChatRoomTLVNavCreatePerms, uint8(2)), - wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, room.Name), - wire.NewTLV(wire.ChatRoomTLVRoomName, room.Name), + wire.NewTLV(wire.ChatRoomTLVFullyQualifiedName, room.name), + wire.NewTLV(wire.ChatRoomTLVRoomName, room.name), + wire.NewTLV(wire.ChatRoomTLVMaxMsgVisLen, uint16(1024)), } assert.Equal(t, want, have) diff --git a/state/migrations/0006_chat_cookie.down.sql b/state/migrations/0006_chat_cookie.down.sql new file mode 100644 index 00000000..8e552adc --- /dev/null +++ b/state/migrations/0006_chat_cookie.down.sql @@ -0,0 +1 @@ +-- nothing to do here \ No newline at end of file diff --git a/state/migrations/0006_chat_cookie.up.sql b/state/migrations/0006_chat_cookie.up.sql new file mode 100644 index 00000000..1a4ab5cf --- /dev/null +++ b/state/migrations/0006_chat_cookie.up.sql @@ -0,0 +1,2 @@ +UPDATE chatRoom +SET cookie = exchange || '-' || '0' || '-' || name; diff --git a/state/user_store.go b/state/user_store.go index 196d2272..141fdcb7 100644 --- a/state/user_store.go +++ b/state/user_store.go @@ -479,9 +479,7 @@ func (f SQLiteUserStore) BARTRetrieve(hash []byte) ([]byte, error) { // ChatRoomByCookie looks up a chat room by cookie. Returns // ErrChatRoomNotFound if the room does not exist for cookie. func (f SQLiteUserStore) ChatRoomByCookie(cookie string) (ChatRoom, error) { - chatRoom := ChatRoom{ - Cookie: cookie, - } + chatRoom := ChatRoom{} q := ` SELECT exchange, name, created, creator @@ -490,15 +488,15 @@ func (f SQLiteUserStore) ChatRoomByCookie(cookie string) (ChatRoom, error) { ` var creator string err := f.db.QueryRow(q, cookie).Scan( - &chatRoom.Exchange, - &chatRoom.Name, - &chatRoom.CreateTime, + &chatRoom.exchange, + &chatRoom.name, + &chatRoom.createTime, &creator, ) if errors.Is(err, sql.ErrNoRows) { err = ErrChatRoomNotFound } - chatRoom.Creator = NewIdentScreenName(creator) + chatRoom.creator = NewIdentScreenName(creator) return chatRoom, err } @@ -507,42 +505,43 @@ func (f SQLiteUserStore) ChatRoomByCookie(cookie string) (ChatRoom, error) { // ErrChatRoomNotFound if the room does not exist for exchange and name. func (f SQLiteUserStore) ChatRoomByName(exchange uint16, name string) (ChatRoom, error) { chatRoom := ChatRoom{ - Exchange: exchange, - Name: name, + exchange: exchange, + name: name, } q := ` - SELECT cookie, created, creator + SELECT created, creator FROM chatRoom WHERE exchange = ? AND name = ? ` var creator string err := f.db.QueryRow(q, exchange, name).Scan( - &chatRoom.Cookie, - &chatRoom.CreateTime, + &chatRoom.createTime, &creator, ) if errors.Is(err, sql.ErrNoRows) { err = ErrChatRoomNotFound } - chatRoom.Creator = NewIdentScreenName(creator) + chatRoom.creator = NewIdentScreenName(creator) return chatRoom, err } -// CreateChatRoom creates a new chat room. -func (f SQLiteUserStore) CreateChatRoom(chatRoom ChatRoom) error { +// CreateChatRoom creates a new chat room. It sets createTime on chatRoom to +// the current timestamp. +func (f SQLiteUserStore) CreateChatRoom(chatRoom *ChatRoom) error { + chatRoom.createTime = time.Now().UTC() q := ` INSERT INTO chatRoom (cookie, exchange, name, created, creator) VALUES (?, ?, ?, ?, ?) ` _, err := f.db.Exec( q, - chatRoom.Cookie, - chatRoom.Exchange, - chatRoom.Name, - chatRoom.CreateTime, - chatRoom.Creator.String(), + chatRoom.Cookie(), + chatRoom.Exchange(), + chatRoom.Name(), + chatRoom.createTime, + chatRoom.Creator().String(), ) if err != nil { @@ -558,7 +557,7 @@ func (f SQLiteUserStore) CreateChatRoom(chatRoom ChatRoom) error { func (f SQLiteUserStore) AllChatRooms(exchange uint16) ([]ChatRoom, error) { q := ` - SELECT cookie, created, creator, name + SELECT created, creator, name FROM chatRoom WHERE exchange = ? ORDER BY created ASC @@ -572,13 +571,13 @@ func (f SQLiteUserStore) AllChatRooms(exchange uint16) ([]ChatRoom, error) { var users []ChatRoom for rows.Next() { cr := ChatRoom{ - Exchange: exchange, + exchange: exchange, } var creator string - if err := rows.Scan(&cr.Cookie, &cr.CreateTime, &creator, &cr.Name); err != nil { + if err := rows.Scan(&cr.createTime, &creator, &cr.name); err != nil { return nil, err } - cr.Creator = NewIdentScreenName(creator) + cr.creator = NewIdentScreenName(creator) users = append(users, cr) } diff --git a/state/user_store_test.go b/state/user_store_test.go index 5e46f06b..31c427d2 100644 --- a/state/user_store_test.go +++ b/state/user_store_test.go @@ -691,15 +691,12 @@ func TestSQLiteUserStore_ChatRoomByCookie_RoomFound(t *testing.T) { userStore, err := NewSQLiteUserStore(testFile) assert.NoError(t, err) - chatRoom := NewChatRoom() - chatRoom.Exchange = 4 - chatRoom.Name = "my new chat room!" - chatRoom.Creator = NewIdentScreenName("the-screen-name") + chatRoom := NewChatRoom("my new chat room!", NewIdentScreenName("the-screen-name"), PrivateExchange) - err = userStore.CreateChatRoom(chatRoom) + err = userStore.CreateChatRoom(&chatRoom) assert.NoError(t, err) - gotRoom, err := userStore.ChatRoomByCookie(chatRoom.Cookie) + gotRoom, err := userStore.ChatRoomByCookie(chatRoom.Cookie()) assert.NoError(t, err) assert.Equal(t, chatRoom, gotRoom) } @@ -724,15 +721,12 @@ func TestSQLiteUserStore_ChatRoomByName_RoomFound(t *testing.T) { userStore, err := NewSQLiteUserStore(testFile) assert.NoError(t, err) - chatRoom := NewChatRoom() - chatRoom.Exchange = 4 - chatRoom.Name = "my new chat room!" - chatRoom.Creator = NewIdentScreenName("the-screen-name") + chatRoom := NewChatRoom("my new chat room!", NewIdentScreenName("the-screen-name"), PrivateExchange) - err = userStore.CreateChatRoom(chatRoom) + err = userStore.CreateChatRoom(&chatRoom) assert.NoError(t, err) - gotRoom, err := userStore.ChatRoomByName(chatRoom.Exchange, chatRoom.Name) + gotRoom, err := userStore.ChatRoomByName(chatRoom.Exchange(), chatRoom.Name()) assert.NoError(t, err) assert.Equal(t, chatRoom, gotRoom) } @@ -758,26 +752,16 @@ func TestSQLiteUserStore_AllChatRooms(t *testing.T) { assert.NoError(t, err) chatRooms := []ChatRoom{ - { - Cookie: "chat-room-1", - Exchange: 4, - Name: "chat room 1", - }, - { - Cookie: "chat-room-2", - Exchange: 4, - Name: "chat room 2", - }, - { - Cookie: "chat-room-3", - Exchange: 5, - Name: "chat room 3", - }, + NewChatRoom("chat room 1", NewIdentScreenName("creator"), PrivateExchange), + NewChatRoom("chat room 2", NewIdentScreenName("creator"), PrivateExchange), + NewChatRoom("chat room 3", NewIdentScreenName("creator"), PublicExchange), } - for _, room := range chatRooms { - err = userStore.CreateChatRoom(room) + for i := range chatRooms { + tBefore := (&chatRooms[i]).CreateTime() + err = userStore.CreateChatRoom(&chatRooms[i]) assert.NoError(t, err) + assert.True(t, chatRooms[i].CreateTime().After(tBefore)) } // public exchange @@ -802,46 +786,10 @@ func TestSQLiteUserStore_CreateChatRoom_ErrChatRoomExists(t *testing.T) { wantErr error }{ { - name: "create two rooms with same exchange/name, different cookie", - firstInsert: ChatRoom{ - Cookie: "chat-room-1", - Exchange: 4, - Name: "chat room 1", - }, - secondInsert: ChatRoom{ - Cookie: "chat-room-1-new", - Exchange: 4, - Name: "chat room 1", - }, - wantErr: ErrDupChatRoom, - }, - { - name: "create two rooms with different exchange/name, same cookie", - firstInsert: ChatRoom{ - Cookie: "chat-room", - Exchange: 5, - Name: "chat room 1", - }, - secondInsert: ChatRoom{ - Cookie: "chat-room", - Exchange: 4, - Name: "chat room 2", - }, - wantErr: ErrDupChatRoom, - }, - { - name: "create two rooms with different cookie/exchange, same name", - firstInsert: ChatRoom{ - Cookie: "chat-room-1", - Exchange: 5, - Name: "chat room", - }, - secondInsert: ChatRoom{ - Cookie: "chat-room-2", - Exchange: 4, - Name: "chat room", - }, - wantErr: nil, + name: "create two rooms with different cookie/exchange, same name", + firstInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PublicExchange), + secondInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PrivateExchange), + wantErr: nil, }, } @@ -854,10 +802,10 @@ func TestSQLiteUserStore_CreateChatRoom_ErrChatRoomExists(t *testing.T) { userStore, err := NewSQLiteUserStore(testFile) assert.NoError(t, err) - err = userStore.CreateChatRoom(tc.firstInsert) + err = userStore.CreateChatRoom(&tc.firstInsert) assert.NoError(t, err) - err = userStore.CreateChatRoom(tc.secondInsert) + err = userStore.CreateChatRoom(&tc.secondInsert) assert.ErrorIs(t, err, tc.wantErr) }) } diff --git a/wire/snacs.go b/wire/snacs.go index 18f461df..73119fc9 100644 --- a/wire/snacs.go +++ b/wire/snacs.go @@ -890,6 +890,7 @@ const ( ChatRoomTLVLang1 uint16 = 0xD7 ChatRoomTLVCharSet2 uint16 = 0xD8 ChatRoomTLVLang2 uint16 = 0xD9 + ChatRoomTLVMaxMsgVisLen uint16 = 0xDA ) type SNAC_0x0E_0x02_ChatRoomInfoUpdate struct {