Răsfoiți Sursa

webapi: replace IsSubscribedTo string params with EventType

Mike 4 zile în urmă
părinte
comite
0c1d344ca0

+ 11 - 11
server/webapi/aim_handler.go

@@ -233,7 +233,7 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 	// outgoing IMs, prompting recipients to send typing notifications
 	// back. This must run after FeedbagService.Use, which otherwise
 	// overwrites the flag from stored prefs the web user may not have set.
-	instance.Session().SetTypingEventsEnabled(slices.Contains(events, "typing"))
+	instance.Session().SetTypingEventsEnabled(slices.Contains(events, string(EventTypeTyping)))
 
 	instance.SetSignonComplete()
 
@@ -415,23 +415,23 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 	// iterated with it, so the server fixes their order and each is queued once.
 	// myInfo and presence render the identity badge from the same payload and the
 	// client subscribes to both, which a per-subscription loop would queue twice.
-	if slices.Contains(events, "myInfo") || slices.Contains(events, "presence") {
+	if slices.Contains(events, string(EventTypeMyInfo)) || slices.Contains(events, string(EventTypePresence)) {
 		myInfoData := buildMyInfo(screenName, "online", myIconURL, myMoodURL)
 		myInfoData.StatusMsg = sessionStatusMsg(session.OSCARSession)
 		myInfoData.OnlineTime = time.Now().Unix()
 		myInfoData.MemberSince = time.Now().Unix() - 86400*30 // 30 days ago
-		session.EventQueue.Push(EventTypeMyInfo, myInfoData)
+		session.PushEvent(EventTypeMyInfo, myInfoData)
 	}
 
-	if slices.Contains(events, "conversation") {
-		session.EventQueue.Push(EventTypeConversation,
+	if slices.Contains(events, string(EventTypeConversation)) {
+		session.PushEvent(EventTypeConversation,
 			ConversationEventData("list", nil))
 	}
 
 	if slices.Contains(events, string(EventTypeService)) {
 		svcPayload := newServiceData()
 		data.Events.Service = svcPayload
-		session.EventQueue.Push(EventTypeService, svcPayload)
+		session.PushEvent(EventTypeService, svcPayload)
 	}
 
 	// The remaining seeds also populate the response payload, so they stay keyed off
@@ -448,7 +448,7 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 			}
 			blPayload := &BuddyListData{Groups: buddyGroups}
 			data.Events.BuddyList = blPayload
-			session.EventQueue.Push(EventTypeBuddyList, blPayload)
+			session.PushEvent(EventTypeBuddyList, blPayload)
 		case EventTypePreference:
 			// Seed the client with effective preference values: the user's stored
 			// prefs where set, and the server-side spec defaults otherwise. The
@@ -463,7 +463,7 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 				prefPayload = effectiveBuddyPrefs(item.TLVList)
 			}
 			data.Events.Preference = prefPayload
-			session.EventQueue.Push(EventTypePreference, prefPayload)
+			session.PushEvent(EventTypePreference, prefPayload)
 		case EventTypePermitDeny:
 			// The client keeps its privacy state solely in the model this event
 			// populates. Both the block/unblock menu action and the "blocked"
@@ -476,7 +476,7 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 				pdPayload = pdd
 			}
 			data.Events.PermitDeny = pdPayload
-			session.EventQueue.Push(EventTypePermitDeny, pdPayload)
+			session.PushEvent(EventTypePermitDeny, pdPayload)
 		}
 	}
 
@@ -493,7 +493,7 @@ func (h *AimHandler) StartSession(w http.ResponseWriter, r *http.Request) {
 	// name against the buddy list it holds, and the conversation list is rebuilt from
 	// scratch on the first "list" the client sees. Both of those events are queued in
 	// the loop above, so the drain has to come after it.
-	if slices.Contains(events, "offlineIM") {
+	if slices.Contains(events, string(EventTypeOfflineIM)) {
 		frame := wire.SNACFrame{
 			FoodGroup: wire.ICBM,
 			SubGroup:  wire.ICBMOfflineRetrieve,
@@ -865,7 +865,7 @@ func seedRateLimitAlert(session *Session, classID wire.RateLimitClassID) {
 		return
 	}
 
-	session.EventQueue.Push(EventTypeRateLimit, RateLimitEvent{
+	session.PushEvent(EventTypeRateLimit, RateLimitEvent{
 		Classes: []RateLimitClass{
 			{
 				ID:     int(classID),

+ 5 - 3
server/webapi/im_handler.go

@@ -220,9 +220,11 @@ func (h *MessagingHandler) pushSenderWebAPIEvents(sess *Session, recipient state
 		AutoResp:  autoResponse,
 		ISent:     true,
 	}
-	sess.EventQueue.Push(EventTypeSentIM, senderEventData)
-	if sess.IsSubscribedTo("conversation") {
-		sess.EventQueue.Push(EventTypeConversation, ConversationEventData("update", []ConversationEntryData{
+	if sess.IsSubscribedTo(EventTypeSentIM) {
+		sess.PushEvent(EventTypeSentIM, senderEventData)
+	}
+	if sess.IsSubscribedTo(EventTypeConversation) {
+		sess.PushEvent(EventTypeConversation, ConversationEventData("update", []ConversationEntryData{
 			ConversationEntry(recipientAimID, recipientDisplay, message, messageID, senderAimID, true, 0),
 		}))
 	}

+ 2 - 2
server/webapi/preference_handler.go

@@ -255,7 +255,7 @@ func (h *PreferenceHandler) SetPreferences(w http.ResponseWriter, r *http.Reques
 		// Notify the client's open windows via the event stream so display
 		// changes (e.g. bubbles/classic) take effect immediately without a
 		// browser refresh.
-		session.EventQueue.Push(EventTypePreference, applied)
+		session.PushEvent(EventTypePreference, applied)
 	}
 
 	h.Logger.DebugContext(ctx, "preferences updated",
@@ -559,7 +559,7 @@ func (h *PreferenceHandler) SetPermitDeny(w http.ResponseWriter, r *http.Request
 	// block/unblock menu label) only from the permitDeny event, and it sees no
 	// SNAC for the write it just made. Without this the block takes effect
 	// server-side but the UI keeps showing the buddy as unblocked.
-	session.EventQueue.Push(EventTypePermitDeny, pdd)
+	session.PushEvent(EventTypePermitDeny, pdd)
 
 	h.Logger.DebugContext(ctx, "permit/deny settings updated",
 		"screenName", session.ScreenName.String(),

+ 27 - 22
server/webapi/session.go

@@ -300,8 +300,13 @@ func (s *Session) Touch() {
 }
 
 // IsSubscribedTo checks if the session is subscribed to a specific event type.
-func (s *Session) IsSubscribedTo(eventType string) bool {
-	return slices.Contains(s.Events, eventType)
+func (s *Session) IsSubscribedTo(eventType EventType) bool {
+	return slices.Contains(s.Events, string(eventType))
+}
+
+// PushEvent queues an event for delivery to the web client.
+func (s *Session) PushEvent(eventType EventType, data any) {
+	s.EventQueue.Push(eventType, data)
 }
 
 // StartListeningToOSCARSession starts a goroutine that listens to the OSCAR session's
@@ -333,7 +338,7 @@ func (s *Session) StartListeningToOSCARSession() {
 				// A teardown this session started needs no event, and gets
 				// none: Close closes the queue before it closes the instance,
 				// so this Push is a no-op on that path.
-				s.EventQueue.Push(EventTypeSessionEnded, struct{}{})
+				s.PushEvent(EventTypeSessionEnded, struct{}{})
 				return
 			}
 		}
@@ -391,7 +396,7 @@ func (s *Session) handleOServiceMessage(msg wire.SNACMessage) {
 // translate this into a fresh myInfo. The away message is the one field read off
 // the session, since no user info block carries the text.
 func (s *Session) handleUserInfoUpdate(msg wire.SNACMessage) {
-	if !s.IsSubscribedTo("myInfo") && !s.IsSubscribedTo("presence") {
+	if !s.IsSubscribedTo(EventTypeMyInfo) && !s.IsSubscribedTo(EventTypePresence) {
 		return
 	}
 
@@ -417,7 +422,7 @@ func (s *Session) handleUserInfoUpdate(msg wire.SNACMessage) {
 	myInfo.AwayMsg = s.OSCARSession.Session().AwayMessage()
 	myInfo.StatusMsg = userStatusMsg(info)
 
-	s.EventQueue.Push(EventTypeMyInfo, myInfo)
+	s.PushEvent(EventTypeMyInfo, myInfo)
 }
 
 // handleRateLimitUpdate translates a rate limit status change — broadcast by the
@@ -449,7 +454,7 @@ func (s *Session) handleRateLimitUpdate(msg wire.SNACMessage) {
 		return
 	}
 
-	s.EventQueue.Push(EventTypeRateLimit, RateLimitEvent{
+	s.PushEvent(EventTypeRateLimit, RateLimitEvent{
 		Classes: []RateLimitClass{
 			{ID: int(body.Rate.ID), Status: status},
 		},
@@ -483,7 +488,7 @@ func (s *Session) handleIncomingIM(msg wire.SNACMessage) {
 	// Retrieval answers only the instance that asked, and StartSession asks only
 	// when the client subscribed to offlineIM, so a stamped message here is one
 	// this session requested. A live IM still needs the im subscription.
-	if !isOffline && !s.IsSubscribedTo("im") {
+	if !isOffline && !s.IsSubscribedTo(EventTypeIM) {
 		return
 	}
 
@@ -530,7 +535,7 @@ func (s *Session) handleIncomingIM(msg wire.SNACMessage) {
 		if friendly == "" {
 			friendly = partnerDisplay
 		}
-		s.EventQueue.Push(EventTypeOfflineIM, OfflineIMEvent{
+		s.PushEvent(EventTypeOfflineIM, OfflineIMEvent{
 			AimID:     partnerAimID,
 			Friendly:  friendly,
 			Message:   messageText,
@@ -555,7 +560,7 @@ func (s *Session) handleIncomingIM(msg wire.SNACMessage) {
 			source.OnlineTime = presence.OnlineTime
 		}
 
-		s.EventQueue.Push(EventTypeIM, IMEvent{
+		s.PushEvent(EventTypeIM, IMEvent{
 			Source:    source,
 			Message:   messageText,
 			MsgID:     msgID,
@@ -568,14 +573,14 @@ func (s *Session) handleIncomingIM(msg wire.SNACMessage) {
 			"to", s.ScreenName)
 	}
 
-	if s.IsSubscribedTo("conversation") {
+	if s.IsSubscribedTo(EventTypeConversation) {
 		// unread is 0 here, not 1, because the "im"/"offlineIM" event pushed above
 		// already causes the client to increment its own persisted per-buddy unread
 		// tally. The "Recent chats" badge is the sum of that persisted tally and
 		// this conversation's unreadCount, so sending 1 here would double-count
 		// the message (badge shows 2 for the first IM). Mirrors the sent-IM path,
 		// which also passes 0.
-		s.EventQueue.Push(EventTypeConversation, ConversationEventData("update", []ConversationEntryData{
+		s.PushEvent(EventTypeConversation, ConversationEventData("update", []ConversationEntryData{
 			ConversationEntry(
 				partnerAimID,
 				partnerDisplay,
@@ -593,7 +598,7 @@ func (s *Session) handleIncomingIM(msg wire.SNACMessage) {
 // could not handle a message already delivered to it — into a clientError event
 // for the sender. Only OSCAR clients raise this SNAC.
 func (s *Session) handleClientError(msg wire.SNACMessage) {
-	if !s.IsSubscribedTo("im") {
+	if !s.IsSubscribedTo(EventTypeIM) {
 		return
 	}
 
@@ -611,7 +616,7 @@ func (s *Session) handleClientError(msg wire.SNACMessage) {
 		channel = "data"
 	}
 
-	s.EventQueue.Push(EventTypeClientError, ClientErrorEvent{
+	s.PushEvent(EventTypeClientError, ClientErrorEvent{
 		Source: UserInfo{
 			AimID:     sender.String(),
 			DisplayID: body.ScreenName,
@@ -625,7 +630,7 @@ func (s *Session) handleClientError(msg wire.SNACMessage) {
 
 // handleTypingNotification handles typing notifications.
 func (s *Session) handleTypingNotification(msg wire.SNACMessage) {
-	if !s.IsSubscribedTo("typing") {
+	if !s.IsSubscribedTo(EventTypeTyping) {
 		return
 	}
 
@@ -650,7 +655,7 @@ func (s *Session) handleTypingNotification(msg wire.SNACMessage) {
 		TypingStatus: typingStatus,
 	}
 
-	s.EventQueue.Push(EventTypeTyping, typingEvent)
+	s.PushEvent(EventTypeTyping, typingEvent)
 }
 
 // handleBuddyMessage handles buddy/presence SNAC messages.
@@ -679,7 +684,7 @@ func (s *Session) handleBuddyArrived(msg wire.SNACMessage) {
 
 	s.setBuddyPresence(buddy, presence)
 
-	if !s.IsSubscribedTo("presence") {
+	if !s.IsSubscribedTo(EventTypePresence) {
 		return
 	}
 
@@ -705,7 +710,7 @@ func (s *Session) handleBuddyArrived(msg wire.SNACMessage) {
 		presenceEvent.BuddyIcon = s.BuddyIconURL(buddy, presence.IconHash)
 	}
 
-	s.EventQueue.Push(EventTypePresence, presenceEvent)
+	s.PushEvent(EventTypePresence, presenceEvent)
 }
 
 // bartIDs returns the BART items a user info block carries. They travel as a list
@@ -863,7 +868,7 @@ func (s *Session) handleBuddyDeparted(msg wire.SNACMessage) {
 	// Recorded before the subscription check, for the same reason as arrivals.
 	s.setBuddyOffline(buddy)
 
-	if !s.IsSubscribedTo("presence") {
+	if !s.IsSubscribedTo(EventTypePresence) {
 		return
 	}
 
@@ -876,7 +881,7 @@ func (s *Session) handleBuddyDeparted(msg wire.SNACMessage) {
 		UserType: userTypeFor(buddy),
 	}
 
-	s.EventQueue.Push(EventTypePresence, presenceEvent)
+	s.PushEvent(EventTypePresence, presenceEvent)
 }
 
 // feedbagResultAuthRequired is the per-item feedbag result meaning the target's ICQ
@@ -894,7 +899,7 @@ func (s *Session) refreshBuddyList() {
 		s.logger.Error("failed to refresh buddy list after feedbag change", "err", err)
 		return
 	}
-	s.EventQueue.Push(EventTypeBuddyList, payload)
+	s.PushEvent(EventTypeBuddyList, payload)
 }
 
 func (s *Session) handleFeedbagMessage(msg wire.SNACMessage) {
@@ -904,7 +909,7 @@ func (s *Session) handleFeedbagMessage(msg wire.SNACMessage) {
 	case wire.FeedbagStatus:
 		// Insert/update/delete below reach only a user's *other* instances, so this
 		// is the one notification a session gets for its own feedbag write.
-		if !s.IsSubscribedTo(string(EventTypeBuddyList)) {
+		if !s.IsSubscribedTo(EventTypeBuddyList) {
 			return
 		}
 		if body, ok := msg.Body.(wire.SNAC_0x13_0x0E_FeedbagStatus); ok {
@@ -950,7 +955,7 @@ func (s *Session) handleFeedbagMessage(msg wire.SNACMessage) {
 					if err != nil {
 						s.logger.Error("failed to refresh permit/deny after feedbag change", "err", err)
 					} else {
-						s.EventQueue.Push(EventTypePermitDeny, pdd)
+						s.PushEvent(EventTypePermitDeny, pdd)
 					}
 					break
 				}