Просмотр исходного кода

issue #104 - toc: remove chat sessions on signoff

Mike 1 год назад
Родитель
Сommit
d977ed5fda
3 измененных файлов с 62 добавлено и 5 удалено
  1. 26 1
      server/toc/cmd_client.go
  2. 33 1
      server/toc/cmd_client_test.go
  3. 3 3
      server/toc/server.go

+ 26 - 1
server/toc/cmd_client.go

@@ -89,6 +89,24 @@ func (c *ChatRegistry) RetrieveSess(chatID int) *state.Session {
 	return c.sessions[chatID]
 }
 
+// RemoveSess removes a chat session.
+func (c *ChatRegistry) RemoveSess(chatID int) {
+	c.m.Lock()
+	defer c.m.Unlock()
+	delete(c.sessions, chatID)
+}
+
+// Sessions retrieves all the chat sessions.
+func (c *ChatRegistry) Sessions() []*state.Session {
+	c.m.RLock()
+	defer c.m.RUnlock()
+	sessions := make([]*state.Session, 0, len(c.sessions))
+	for _, s := range c.sessions {
+		sessions = append(sessions, s)
+	}
+	return sessions
+}
+
 // OSCARProxy acts as a bridge between TOC clients and the OSCAR server,
 // translating protocol messages between the two.
 //
@@ -582,6 +600,8 @@ func (s OSCARProxy) ChatLeave(ctx context.Context, chatRegistry *ChatRegistry, c
 
 	me.Close() // stop async server SNAC reply handler for this chat room
 
+	chatRegistry.RemoveSess(chatID)
+
 	return fmt.Sprintf("CHAT_LEFT:%d", chatID)
 }
 
@@ -1337,7 +1357,7 @@ func (s OSCARProxy) Signon(ctx context.Context, cmd []byte) (*state.Session, []s
 
 // Signout terminates a TOC session. It sends departure notifications to
 // buddies, de-registers buddy list and session.
-func (s OSCARProxy) Signout(ctx context.Context, me *state.Session) {
+func (s OSCARProxy) Signout(ctx context.Context, me *state.Session, chatRegistry *ChatRegistry) {
 	if err := s.BuddyService.BroadcastBuddyDeparted(ctx, me); err != nil {
 		s.Logger.ErrorContext(ctx, "error sending departure notifications", "err", err.Error())
 	}
@@ -1345,6 +1365,11 @@ func (s OSCARProxy) Signout(ctx context.Context, me *state.Session) {
 		s.Logger.ErrorContext(ctx, "error removing buddy list entry", "err", err.Error())
 	}
 	s.AuthService.Signout(ctx, me)
+
+	for _, sess := range chatRegistry.Sessions() {
+		s.AuthService.SignoutChat(ctx, sess)
+		sess.Close() // stop async server SNAC reply handler for this chat room
+	}
 }
 
 // newHTTPAuthToken creates a HMAC token for authenticating TOC HTTP requests

+ 33 - 1
server/toc/cmd_client_test.go

@@ -3287,6 +3287,8 @@ func TestOSCARProxy_Signout(t *testing.T) {
 		name string
 		// me is the TOC user session
 		me *state.Session
+		// givenChatRegistry is the chat registry passed to the function
+		chatRegistry *ChatRegistry
 		// mockParams is the list of params sent to mocks that satisfy this
 		// method's dependencies
 		mockParams mockParams
@@ -3294,6 +3296,19 @@ func TestOSCARProxy_Signout(t *testing.T) {
 		{
 			name: "successfully sign out",
 			me:   newTestSession("me"),
+			chatRegistry: func() *ChatRegistry {
+				cr := NewChatRegistry()
+
+				s1 := state.NewSession()
+				s1.SetIdentScreenName(state.NewIdentScreenName("me1"))
+				cr.RegisterSess(0, s1)
+
+				s2 := state.NewSession()
+				s2.SetIdentScreenName(state.NewIdentScreenName("me2"))
+				cr.RegisterSess(1, s2)
+
+				return cr
+			}(),
 			mockParams: mockParams{
 				buddyParams: buddyParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
@@ -3315,12 +3330,23 @@ func TestOSCARProxy_Signout(t *testing.T) {
 							me: state.NewIdentScreenName("me"),
 						},
 					},
+					signoutChatParams: signoutChatParams{
+						{
+							me: state.NewIdentScreenName("me1"),
+						},
+						{
+							me: state.NewIdentScreenName("me2"),
+						},
+					},
 				},
 			},
 		},
 		{
 			name: "sign out, receive error from buddy service",
 			me:   newTestSession("me"),
+			chatRegistry: func() *ChatRegistry {
+				return NewChatRegistry()
+			}(),
 			mockParams: mockParams{
 				buddyParams: buddyParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
@@ -3349,6 +3375,9 @@ func TestOSCARProxy_Signout(t *testing.T) {
 		{
 			name: "sign out, receive error from buddy list registry",
 			me:   newTestSession("me"),
+			chatRegistry: func() *ChatRegistry {
+				return NewChatRegistry()
+			}(),
 			mockParams: mockParams{
 				buddyParams: buddyParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
@@ -3398,6 +3427,9 @@ func TestOSCARProxy_Signout(t *testing.T) {
 			for _, params := range tc.mockParams.signoutParams {
 				authSvc.EXPECT().Signout(ctx, matchSession(params.me))
 			}
+			for _, params := range tc.mockParams.signoutChatParams {
+				authSvc.EXPECT().SignoutChat(ctx, matchSession(params.me))
+			}
 
 			svc := OSCARProxy{
 				AuthService:       authSvc,
@@ -3405,7 +3437,7 @@ func TestOSCARProxy_Signout(t *testing.T) {
 				BuddyService:      buddySvc,
 				Logger:            slog.Default(),
 			}
-			svc.Signout(ctx, tc.me)
+			svc.Signout(ctx, tc.me, tc.chatRegistry)
 		})
 	}
 }

+ 3 - 3
server/toc/server.go

@@ -186,7 +186,9 @@ func (rt Server) dispatchFLAP(ctx context.Context, conn net.Conn) error {
 
 	ctx = context.WithValue(ctx, "screenName", sessBOS.IdentScreenName())
 
-	defer rt.BOSProxy.Signout(ctx, sessBOS)
+	chatRegistry := NewChatRegistry()
+
+	defer rt.BOSProxy.Signout(ctx, sessBOS, chatRegistry)
 
 	// messages from TOC client
 	fromCh := make(chan wire.FLAPFrame, 1)
@@ -198,8 +200,6 @@ func (rt Server) dispatchFLAP(ctx context.Context, conn net.Conn) error {
 
 	g, gCtx := errgroup.WithContext(ctx)
 
-	chatRegistry := NewChatRegistry()
-
 	g.Go(func() error {
 		return rt.BOSProxy.RecvBOS(gCtx, sessBOS, chatRegistry, toCh)
 	})