Explorar el Código

encapsulate buddyBroadcaster

Mike hace 2 años
padre
commit
79e5f48a10

+ 1 - 1
.mockery.yaml

@@ -89,6 +89,6 @@ packages:
       CookieBaker:
         config:
           filename: "mock_cookie_baker_test.go"
-      BuddyBroadcaster:
+      buddyBroadcaster:
         config:
           filename: "mock_buddy_broadcaster_test.go"

+ 16 - 20
cmd/server/main.go

@@ -52,16 +52,16 @@ func main() {
 	}()
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "BOS")
+		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore)
+		bartService := foodgroup.NewBARTService(logger, feedbagStore, sessionManager, feedbagStore, adjListBuddyListStore)
 		buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore)
-		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, buddyService)
-		bartService := foodgroup.NewBARTService(logger, feedbagStore, buddyService)
-		oServiceService := foodgroup.NewOServiceServiceForBOS(cfg, sessionManager, adjListBuddyListStore, logger, cookieBaker, buddyService, chatRegistry)
-		locateService := foodgroup.NewLocateService(sessionManager, feedbagStore, feedbagStore, buddyService)
 		newChatSessMgr := func() foodgroup.SessionManager { return state.NewInMemorySessionManager(logger) }
 		chatNavService := foodgroup.NewChatNavService(logger, chatRegistry, state.NewChatRoom, newChatSessMgr)
-		feedbagService := foodgroup.NewFeedbagService(logger, sessionManager, feedbagStore, feedbagStore, buddyService)
-		icbmService := foodgroup.NewICBMService(sessionManager, feedbagStore, buddyService)
+		feedbagService := foodgroup.NewFeedbagService(logger, sessionManager, feedbagStore, feedbagStore, adjListBuddyListStore)
 		foodgroupService := foodgroup.NewPermitDenyService()
+		icbmService := foodgroup.NewICBMService(sessionManager, feedbagStore, adjListBuddyListStore)
+		locateService := foodgroup.NewLocateService(sessionManager, feedbagStore, feedbagStore, adjListBuddyListStore)
+		oServiceService := foodgroup.NewOServiceServiceForBOS(cfg, sessionManager, adjListBuddyListStore, logger, cookieBaker, chatRegistry, feedbagStore)
 
 		oscar.BOSServer{
 			AuthService: authService,
@@ -86,10 +86,9 @@ func main() {
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "CHAT")
 		sessionManager := state.NewInMemorySessionManager(logger)
-		buddyService := foodgroup.NewBuddyService(nil, feedbagStore, adjListBuddyListStore)
-		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, buddyService)
+		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore)
 		chatService := foodgroup.NewChatService(chatRegistry)
-		oServiceService := foodgroup.NewOServiceServiceForChat(cfg, logger, buddyService, chatRegistry)
+		oServiceService := foodgroup.NewOServiceServiceForChat(cfg, logger, chatRegistry, sessionManager, adjListBuddyListStore, feedbagStore)
 
 		oscar.ChatServer{
 			AuthService: authService,
@@ -106,11 +105,10 @@ func main() {
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "CHAT_NAV")
 		sessionManager := state.NewInMemorySessionManager(logger)
-		buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore)
-		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, buddyService)
-		oServiceService := foodgroup.NewOServiceServiceForChatNav(cfg, logger, buddyService)
+		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore)
 		newChatSessMgr := func() foodgroup.SessionManager { return state.NewInMemorySessionManager(logger) }
 		chatNavService := foodgroup.NewChatNavService(logger, chatRegistry, state.NewChatRoom, newChatSessMgr)
+		oServiceService := foodgroup.NewOServiceServiceForChatNav(cfg, logger, sessionManager, adjListBuddyListStore, feedbagStore)
 
 		oscar.BOSServer{
 			AuthService: authService,
@@ -128,9 +126,8 @@ func main() {
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "ALERT")
 		sessionManager := state.NewInMemorySessionManager(logger)
-		buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore)
-		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, buddyService)
-		oServiceService := foodgroup.NewOServiceServiceForAlert(cfg, logger, buddyService)
+		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore)
+		oServiceService := foodgroup.NewOServiceServiceForAlert(cfg, logger, sessionManager, adjListBuddyListStore, feedbagStore)
 
 		oscar.BOSServer{
 			AuthService: authService,
@@ -148,10 +145,9 @@ func main() {
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "BART")
 		sessionManager := state.NewInMemorySessionManager(logger)
-		buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore)
-		bartService := foodgroup.NewBARTService(logger, feedbagStore, buddyService)
-		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, buddyService)
-		oServiceService := foodgroup.NewOServiceServiceForBART(cfg, logger, buddyService)
+		bartService := foodgroup.NewBARTService(logger, feedbagStore, sessionManager, feedbagStore, adjListBuddyListStore)
+		authService := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, sessionManager, feedbagStore)
+		oServiceService := foodgroup.NewOServiceServiceForBART(cfg, logger, sessionManager, adjListBuddyListStore, feedbagStore)
 
 		oscar.BOSServer{
 			AuthService: authService,
@@ -168,7 +164,7 @@ func main() {
 	}(logger)
 	go func(logger *slog.Logger) {
 		logger = logger.With("svc", "AUTH")
-		authHandler := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, nil)
+		authHandler := foodgroup.NewAuthService(cfg, sessionManager, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker, nil, nil)
 
 		oscar.AuthServer{
 			AuthService: authHandler,

+ 1 - 1
config/settings.env

@@ -46,5 +46,5 @@ export LOG_LEVEL=info
 # clients, a private IP address (e.g. 192.168..) or hostname should suffice. For
 # clients connecting over the Internet, specify your public IP address and
 # ensure that TCP ports 5190-5194 are open on your firewall.
-export OSCAR_HOST=127.0.0.1
+export OSCAR_HOST=192.168.68.61
 

+ 5 - 4
foodgroup/auth.go

@@ -22,16 +22,17 @@ func NewAuthService(
 	chatRegistry ChatRegistry,
 	legacyBuddyListManager LegacyBuddyListManager,
 	cookieBaker CookieBaker,
-	buddyUpdateBroadcaster BuddyBroadcaster,
+	messageRelayer MessageRelayer,
+	feedbagManager FeedbagManager,
 ) *AuthService {
 	return &AuthService{
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		chatRegistry:           chatRegistry,
 		config:                 cfg,
+		cookieBaker:            cookieBaker,
 		legacyBuddyListManager: legacyBuddyListManager,
 		sessionManager:         sessionManager,
 		userManager:            userManager,
-		cookieBaker:            cookieBaker,
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
 	}
 }
 
@@ -39,7 +40,7 @@ func NewAuthService(
 // supports both FLAP (AIM v1.0-v3.0) and BUCP (AIM v3.5-v5.9) authentication
 // modes.
 type AuthService struct {
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	chatRegistry           ChatRegistry
 	config                 config.Config
 	cookieBaker            CookieBaker

+ 7 - 6
foodgroup/auth_test.go

@@ -969,7 +969,7 @@ func TestAuthService_RegisterChatSession_HappyPath(t *testing.T) {
 		Crack(authCookie).
 		Return(chatCookieBuf.Bytes(), nil)
 
-	svc := NewAuthService(config.Config{}, nil, userManager, chatRegistry, nil, cookieBaker, nil)
+	svc := NewAuthService(config.Config{}, nil, userManager, chatRegistry, nil, cookieBaker, nil, nil)
 
 	have, err := svc.RegisterChatSession(authCookie)
 	assert.NoError(t, err)
@@ -998,7 +998,7 @@ func TestAuthService_RegisterChatSession_ChatNotFound(t *testing.T) {
 		Crack(authCookie).
 		Return(loginCookie.Bytes(), nil)
 
-	svc := NewAuthService(config.Config{}, nil, nil, chatRegistry, nil, cookieBaker, nil)
+	svc := NewAuthService(config.Config{}, nil, nil, chatRegistry, nil, cookieBaker, nil, nil)
 
 	_, err := svc.RegisterChatSession(authCookie)
 	assert.ErrorIs(t, err, state.ErrChatRoomNotFound)
@@ -1024,7 +1024,7 @@ func TestAuthService_RegisterBOSSession_HappyPath(t *testing.T) {
 		User(sess.IdentScreenName()).
 		Return(&state.User{DisplayScreenName: sess.DisplayScreenName()}, nil)
 
-	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieBaker, nil)
+	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieBaker, nil, nil)
 
 	have, err := svc.RegisterBOSSession(authCookie)
 	assert.NoError(t, err)
@@ -1051,7 +1051,7 @@ func TestAuthService_RegisterBOSSession_SessionNotFound(t *testing.T) {
 		User(sess.IdentScreenName()).
 		Return(&state.User{DisplayScreenName: sess.DisplayScreenName()}, nil)
 
-	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieBaker, nil)
+	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieBaker, nil, nil)
 
 	have, err := svc.RegisterBOSSession(authCookie)
 	assert.NoError(t, err)
@@ -1193,7 +1193,7 @@ func TestAuthService_SignoutChat(t *testing.T) {
 
 			cookieBaker := newMockCookieBaker(t)
 
-			svc := NewAuthService(config.Config{}, nil, nil, chatRegistry, nil, cookieBaker, nil)
+			svc := NewAuthService(config.Config{}, nil, nil, chatRegistry, nil, cookieBaker, nil, nil)
 
 			err := svc.SignoutChat(nil, tt.userSession)
 			assert.ErrorIs(t, err, tt.wantErr)
@@ -1262,7 +1262,8 @@ func TestAuthService_Signout(t *testing.T) {
 					})).
 					Return(nil)
 			}
-			svc := NewAuthService(config.Config{}, sessionManager, nil, nil, legacyBuddyListManager, nil, buddyUpdateBroadcaster)
+			svc := NewAuthService(config.Config{}, sessionManager, nil, nil, legacyBuddyListManager, nil, nil, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 
 			err := svc.Signout(nil, tt.userSession)
 			assert.ErrorIs(t, err, tt.wantErr)

+ 3 - 3
foodgroup/bart.go

@@ -22,17 +22,17 @@ var blankGIF = []byte{
 // errKnownIconsOnly indicates that a non-known buddy icon was requested
 var errKnownIconsOnly = errors.New("can only satisfy requests for known icons")
 
-func NewBARTService(logger *slog.Logger, bartManager BARTManager, buddyUpdateBroadcaster BuddyBroadcaster) BARTService {
+func NewBARTService(logger *slog.Logger, bartManager BARTManager, messageRelayer MessageRelayer, feedbagManager FeedbagManager, legacyBuddyListManager LegacyBuddyListManager) BARTService {
 	return BARTService{
 		bartManager:            bartManager,
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		logger:                 logger,
 	}
 }
 
 type BARTService struct {
 	bartManager            BARTManager
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	logger                 *slog.Logger
 }
 

+ 3 - 2
foodgroup/bart_test.go

@@ -91,7 +91,8 @@ func TestBARTService_UpsertItem(t *testing.T) {
 					})).
 					Return(nil)
 			}
-			svc := NewBARTService(slog.Default(), bartManager, buddyUpdateBroadcaster)
+			svc := NewBARTService(slog.Default(), bartManager, nil, nil, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 
 			output, err := svc.UpsertItem(nil, tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x10_0x02_BARTUploadQuery))
@@ -236,7 +237,7 @@ func TestBARTService_RetrieveItem(t *testing.T) {
 					Return(params.result, nil)
 			}
 
-			svc := NewBARTService(slog.Default(), bartManager, nil)
+			svc := NewBARTService(slog.Default(), bartManager, nil, nil, nil)
 
 			output, err := svc.RetrieveItem(nil, tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x10_0x04_BARTDownloadQuery))

+ 3 - 3
foodgroup/feedbag.go

@@ -18,11 +18,11 @@ func NewFeedbagService(
 	messageRelayer MessageRelayer,
 	feedbagManager FeedbagManager,
 	bartManager BARTManager,
-	buddyUpdateBroadcaster BuddyBroadcaster,
+	legacyBuddyListManager LegacyBuddyListManager,
 ) FeedbagService {
 	return FeedbagService{
 		bartManager:            bartManager,
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		feedbagManager:         feedbagManager,
 		logger:                 logger,
 		messageRelayer:         messageRelayer,
@@ -33,7 +33,7 @@ func NewFeedbagService(
 // handles buddy list management.
 type FeedbagService struct {
 	bartManager            BARTManager
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	feedbagManager         FeedbagManager
 	logger                 *slog.Logger
 	messageRelayer         MessageRelayer

+ 4 - 2
foodgroup/feedbag_test.go

@@ -1049,7 +1049,8 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 						}))
 			}
 
-			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, bartManager, buddyUpdateBroadcaster)
+			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, bartManager, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 			output, err := svc.UpsertItem(nil, tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x13_0x08_FeedbagInsertItem).Items)
 			assert.NoError(t, err)
@@ -1432,7 +1433,8 @@ func TestFeedbagService_Use(t *testing.T) {
 					Return(nil)
 			}
 
-			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, nil, buddyUpdateBroadcast)
+			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, nil, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcast
 
 			haveErr := svc.Use(nil, tt.sess)
 			assert.ErrorIs(t, tt.wantErr, haveErr)

+ 3 - 3
foodgroup/icbm.go

@@ -16,10 +16,10 @@ const (
 func NewICBMService(
 	messageRelayer MessageRelayer,
 	feedbagManager FeedbagManager,
-	buddyUpdateBroadcaster BuddyBroadcaster,
+	legacyBuddyListManager LegacyBuddyListManager,
 ) *ICBMService {
 	return &ICBMService{
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		feedbagManager:         feedbagManager,
 		messageRelayer:         messageRelayer,
 	}
@@ -29,7 +29,7 @@ func NewICBMService(
 // responsible for sending and receiving instant messages and associated
 // functionality such as warning, typing events, etc.
 type ICBMService struct {
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	feedbagManager         FeedbagManager
 	messageRelayer         MessageRelayer
 }

+ 2 - 1
foodgroup/icbm_test.go

@@ -627,7 +627,8 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			// send input SNAC
 			//
 			senderSession := newTestSession(tc.senderSession.DisplayScreenName())
-			svc := NewICBMService(messageRelayer, feedbagManager, buddyUpdateBroadcaster)
+			svc := NewICBMService(messageRelayer, feedbagManager, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 			outputSNAC, err := svc.EvilRequest(nil, senderSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest))
 			assert.NoError(t, err)

+ 3 - 3
foodgroup/locate.go

@@ -24,10 +24,10 @@ func NewLocateService(
 	messageRelayer MessageRelayer,
 	feedbagManager FeedbagManager,
 	profileManager ProfileManager,
-	buddyUpdateBroadcaster BuddyBroadcaster,
+	legacyBuddyListManager LegacyBuddyListManager,
 ) LocateService {
 	return LocateService{
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		feedbagManager:         feedbagManager,
 		profileManager:         profileManager,
 		sessionManager:         messageRelayer,
@@ -38,7 +38,7 @@ func NewLocateService(
 // responsible for user profiles, user info lookups, directory information, and
 // keyword lookups.
 type LocateService struct {
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	feedbagManager         FeedbagManager
 	profileManager         ProfileManager
 	sessionManager         MessageRelayer

+ 2 - 1
foodgroup/locate_test.go

@@ -470,7 +470,8 @@ func TestLocateService_SetInfo(t *testing.T) {
 					})).
 					Return(nil)
 			}
-			svc := NewLocateService(nil, nil, profileManager, buddyUpdateBroadcaster)
+			svc := NewLocateService(nil, nil, profileManager, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 			assert.Equal(t, tt.wantErr, svc.SetInfo(nil, tt.userSession, tt.inBody))
 		})
 	}

+ 36 - 11
foodgroup/oservice.go

@@ -17,7 +17,7 @@ import (
 // OServiceService provides functionality for the OService food group, which
 // provides an assortment of services useful across multiple food groups.
 type OServiceService struct {
-	buddyUpdateBroadcaster BuddyBroadcaster
+	buddyUpdateBroadcaster buddyBroadcaster
 	cfg                    config.Config
 	logger                 *slog.Logger
 	foodGroups             []uint16
@@ -513,8 +513,8 @@ func NewOServiceServiceForBOS(
 	legacyBuddyListManager LegacyBuddyListManager,
 	logger *slog.Logger,
 	cookieIssuer CookieBaker,
-	buddyUpdateBroadcaster BuddyBroadcaster,
 	cr *state.ChatRegistry,
+	feedbagManager FeedbagManager,
 ) *OServiceServiceForBOS {
 	return &OServiceServiceForBOS{
 		chatRegistry:           cr,
@@ -522,7 +522,7 @@ func NewOServiceServiceForBOS(
 		legacyBuddyListManager: legacyBuddyListManager,
 		messageRelayer:         messageRelayer,
 		OServiceService: OServiceService{
-			buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+			buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 			cfg:                    cfg,
 			logger:                 logger,
 			foodGroups: []uint16{
@@ -717,11 +717,18 @@ func (s OServiceServiceForBOS) ClientOnline(ctx context.Context, _ wire.SNAC_0x0
 }
 
 // NewOServiceServiceForChat creates a new instance of NewOServiceServiceForChat.
-func NewOServiceServiceForChat(cfg config.Config, logger *slog.Logger, buddyUpdateBroadcaster BuddyBroadcaster, cr *state.ChatRegistry) *OServiceServiceForChat {
+func NewOServiceServiceForChat(
+	cfg config.Config,
+	logger *slog.Logger,
+	cr *state.ChatRegistry,
+	messageRelayer MessageRelayer,
+	legacyBuddyListManager LegacyBuddyListManager,
+	feedbagManager FeedbagManager,
+) *OServiceServiceForChat {
 	return &OServiceServiceForChat{
 		chatRegistry: cr,
 		OServiceService: OServiceService{
-			buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+			buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 			cfg:                    cfg,
 			logger:                 logger,
 			foodGroups: []uint16{
@@ -757,9 +764,15 @@ func (s OServiceServiceForChat) ClientOnline(ctx context.Context, _ wire.SNAC_0x
 
 // NewOServiceServiceForChatNav creates a new instance of OServiceService for
 // ChatNav.
-func NewOServiceServiceForChatNav(cfg config.Config, logger *slog.Logger, buddyUpdateBroadcaster BuddyBroadcaster) *OServiceService {
+func NewOServiceServiceForChatNav(
+	cfg config.Config,
+	logger *slog.Logger,
+	messageRelayer MessageRelayer,
+	legacyBuddyListManager LegacyBuddyListManager,
+	feedbagManager FeedbagManager,
+) *OServiceService {
 	return &OServiceService{
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		cfg:                    cfg,
 		logger:                 logger,
 		foodGroups: []uint16{
@@ -771,9 +784,15 @@ func NewOServiceServiceForChatNav(cfg config.Config, logger *slog.Logger, buddyU
 
 // NewOServiceServiceForAlert creates a new instance of OServiceService for the Alert
 // server.
-func NewOServiceServiceForAlert(cfg config.Config, logger *slog.Logger, buddyUpdateBroadcaster BuddyBroadcaster) *OServiceService {
+func NewOServiceServiceForAlert(
+	cfg config.Config,
+	logger *slog.Logger,
+	messageRelayer MessageRelayer,
+	legacyBuddyListManager LegacyBuddyListManager,
+	feedbagManager FeedbagManager,
+) *OServiceService {
 	return &OServiceService{
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		cfg:                    cfg,
 		logger:                 logger,
 		foodGroups: []uint16{
@@ -785,9 +804,15 @@ func NewOServiceServiceForAlert(cfg config.Config, logger *slog.Logger, buddyUpd
 
 // NewOServiceServiceForBART creates a new instance of OServiceService for the
 // BART server.
-func NewOServiceServiceForBART(cfg config.Config, logger *slog.Logger, buddyUpdateBroadcaster BuddyBroadcaster) *OServiceService {
+func NewOServiceServiceForBART(
+	cfg config.Config,
+	logger *slog.Logger,
+	messageRelayer MessageRelayer,
+	legacyBuddyListManager LegacyBuddyListManager,
+	feedbagManager FeedbagManager,
+) *OServiceService {
 	return &OServiceService{
-		buddyUpdateBroadcaster: buddyUpdateBroadcaster,
+		buddyUpdateBroadcaster: NewBuddyService(messageRelayer, feedbagManager, legacyBuddyListManager),
 		cfg:                    cfg,
 		logger:                 logger,
 		foodGroups: []uint16{

+ 7 - 6
foodgroup/oservice_test.go

@@ -259,7 +259,7 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) {
 			//
 			// send input SNAC
 			//
-			svc := NewOServiceServiceForBOS(tc.cfg, nil, nil, slog.Default(), cookieIssuer, nil, chatRegistry)
+			svc := NewOServiceServiceForBOS(tc.cfg, nil, nil, slog.Default(), cookieIssuer, chatRegistry, nil)
 
 			outputSNAC, err := svc.ServiceRequest(nil, tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x01_0x04_OServiceServiceRequest))
@@ -1364,7 +1364,7 @@ func TestOServiceServiceForBOS_OServiceHostOnline(t *testing.T) {
 }
 
 func TestOServiceServiceForChat_OServiceHostOnline(t *testing.T) {
-	svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, nil)
+	svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -1641,7 +1641,8 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 					Return(p.err)
 			}
 
-			svc := NewOServiceServiceForBOS(config.Config{}, messageRelayer, legacyBuddyListManager, slog.Default(), nil, buddyUpdateBroadcaster, nil)
+			svc := NewOServiceServiceForBOS(config.Config{}, messageRelayer, legacyBuddyListManager, slog.Default(), nil, nil, nil)
+			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 			haveErr := svc.ClientOnline(nil, tt.bodyIn, tt.sess)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
 		})
@@ -1772,7 +1773,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 			chatRegistry := state.NewChatRegistry()
 			chatRegistry.Register(chatRoom, chatMessageRelayer)
 
-			svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, chatRegistry)
+			svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), chatRegistry, nil, nil, nil)
 
 			haveErr := svc.ClientOnline(nil, wire.SNAC_0x01_0x02_OServiceClientOnline{}, tt.joiningChatter)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
@@ -1781,7 +1782,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 }
 
 func TestOServiceServiceForChatNav_HostOnline(t *testing.T) {
-	svc := NewOServiceServiceForChatNav(config.Config{}, slog.Default(), nil)
+	svc := NewOServiceServiceForChatNav(config.Config{}, slog.Default(), nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -1801,7 +1802,7 @@ func TestOServiceServiceForChatNav_HostOnline(t *testing.T) {
 }
 
 func TestOServiceServiceForAlert_HostOnline(t *testing.T) {
-	svc := NewOServiceServiceForAlert(config.Config{}, slog.Default(), nil)
+	svc := NewOServiceServiceForAlert(config.Config{}, slog.Default(), nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{

+ 5 - 5
foodgroup/test_helpers.go

@@ -289,7 +289,7 @@ type cookieIssuerParams []struct {
 }
 
 // buddyBroadcasterParams is a helper struct that contains mock parameters for
-// BuddyBroadcaster methods
+// buddyBroadcaster methods
 type buddyBroadcasterParams struct {
 	broadcastBuddyArrivedParams
 	broadcastBuddyDepartedParams
@@ -298,21 +298,21 @@ type buddyBroadcasterParams struct {
 }
 
 // broadcastBuddyArrivedParams is the list of parameters passed at the mock
-// BuddyBroadcaster.BroadcastBuddyArrived call site
+// buddyBroadcaster.BroadcastBuddyArrived call site
 type broadcastBuddyArrivedParams []struct {
 	screenName state.IdentScreenName
 	err        error
 }
 
 // broadcastBuddyDepartedParams is the list of parameters passed at the mock
-// BuddyBroadcaster.BroadcastBuddyDeparted call site
+// buddyBroadcaster.BroadcastBuddyDeparted call site
 type broadcastBuddyDepartedParams []struct {
 	screenName state.IdentScreenName
 	err        error
 }
 
 // unicastBuddyArrivedParams is the list of parameters passed at the mock
-// BuddyBroadcaster.UnicastBuddyArrived call site
+// buddyBroadcaster.UnicastBuddyArrived call site
 type unicastBuddyArrivedParams []struct {
 	from state.IdentScreenName
 	to   state.IdentScreenName
@@ -320,7 +320,7 @@ type unicastBuddyArrivedParams []struct {
 }
 
 // unicastBuddyDepartedParams is the list of parameters passed at the mock
-// BuddyBroadcaster.UnicastBuddyDeparted call site
+// buddyBroadcaster.UnicastBuddyDeparted call site
 type unicastBuddyDepartedParams []struct {
 	from state.IdentScreenName
 	to   state.IdentScreenName

+ 1 - 1
foodgroup/types.go

@@ -118,7 +118,7 @@ type CookieBaker interface {
 	Issue(data []byte) ([]byte, error)
 }
 
-type BuddyBroadcaster interface {
+type buddyBroadcaster interface {
 	BroadcastBuddyArrived(ctx context.Context, sess *state.Session) error
 	BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error
 	UnicastBuddyArrived(ctx context.Context, from *state.Session, to *state.Session) error