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

test and document RateParamsQueryHandler

Mike 2 лет назад
Родитель
Сommit
eb09016dca
3 измененных файлов с 162 добавлено и 59 удалено
  1. 72 59
      handler/oservice.go
  2. 67 0
      handler/oservice_test.go
  3. 23 0
      oscar/snacs.go

+ 72 - 59
handler/oservice.go

@@ -35,72 +35,85 @@ func (s OServiceService) ClientVersionsHandler(_ context.Context, frame oscar.SN
 	}
 }
 
+// RateParamsQueryHandler returns SNAC rate limits.
+// The purpose of this method is to provide information about rate limits that can be
+// enforced on the server side. The response consists of two main parts: rate classes and
+// rate groups. Rate classes define limits based on specific parameters, while rate groups
+// associate these limits with relevant SNAC types.
+//
+// Note: The current implementation does not enforce server-side rate limiting. Instead,
+// the provided values inform the client about the recommended client-side rate limits.
+//
+// The response only contains rate limits for sending Instant Messages (IMs)
+// and chat messages. More refined limits may be added in the future if/when server
+// rate limiting is implemented.
+//
+// Parameters:
+//   - _ (context.Context): The context is not used in this method.
+//   - inFrame (oscar.SNACFrame): The input SNAC frame containing the request details.
+//
+// Returns:
+//
+//	oscar.SNACMessage: The SNAC message containing rate limits.
 func (s OServiceService) RateParamsQueryHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
-	frameOut := oscar.SNACFrame{
-		FoodGroup: oscar.OService,
-		SubGroup:  oscar.OServiceRateParamsReply,
-		RequestID: inFrame.RequestID,
-	}
-	bodyOut := oscar.SNAC_0x01_0x07_OServiceRateParamsReply{
-		RateClasses: []struct {
-			ID              uint16
-			WindowSize      uint32
-			ClearLevel      uint32
-			AlertLevel      uint32
-			LimitLevel      uint32
-			DisconnectLevel uint32
-			CurrentLevel    uint32
-			MaxLevel        uint32
-			LastTime        uint32 // protocol v2 only
-			CurrentState    uint8  // protocol v2 only
-		}{
-			{
-				ID:              0x0001,
-				WindowSize:      0x00000050,
-				ClearLevel:      0x000009C4,
-				AlertLevel:      0x000007D0,
-				LimitLevel:      0x000005DC,
-				DisconnectLevel: 0x00000320,
-				CurrentLevel:    0x00000D69,
-				MaxLevel:        0x00001770,
-				LastTime:        0x00000000,
-				CurrentState:    0x00,
-			},
+	return oscar.SNACMessage{
+		Frame: oscar.SNACFrame{
+			FoodGroup: oscar.OService,
+			SubGroup:  oscar.OServiceRateParamsReply,
+			RequestID: inFrame.RequestID,
 		},
-		RateGroups: []struct {
-			ID    uint16
-			Pairs []struct {
-				FoodGroup uint16
-				SubGroup  uint16
-			} `count_prefix:"uint16"`
-		}{
-			{
-				ID: 1,
-				Pairs: []struct {
+		Body: oscar.SNAC_0x01_0x07_OServiceRateParamsReply{
+			RateClasses: []struct {
+				ID              uint16
+				WindowSize      uint32
+				ClearLevel      uint32
+				AlertLevel      uint32
+				LimitLevel      uint32
+				DisconnectLevel uint32
+				CurrentLevel    uint32
+				MaxLevel        uint32
+				LastTime        uint32
+				CurrentState    uint8
+			}{
+				{
+					ID:              0x01,
+					WindowSize:      0x0050,
+					ClearLevel:      0x09C4,
+					AlertLevel:      0x07D0,
+					LimitLevel:      0x05DC,
+					DisconnectLevel: 0x0320,
+					CurrentLevel:    0x0D69,
+					MaxLevel:        0x1770,
+					LastTime:        0x0000,
+					CurrentState:    0x0,
+				},
+			},
+			RateGroups: []struct {
+				ID    uint16
+				Pairs []struct {
 					FoodGroup uint16
 					SubGroup  uint16
-				}{},
+				} `count_prefix:"uint16"`
+			}{
+				{
+					ID: 1,
+					Pairs: []struct {
+						FoodGroup uint16
+						SubGroup  uint16
+					}{
+						{
+							FoodGroup: oscar.ICBM,
+							SubGroup:  oscar.ICBMChannelMsgToHost,
+						},
+						{
+							FoodGroup: oscar.Chat,
+							SubGroup:  oscar.ChatChannelMsgToHost,
+						},
+					},
+				},
 			},
 		},
 	}
-
-	for i := uint16(0); i < 24; i++ { // for each food group
-		for j := uint16(0); j < 32; j++ { // for each subgroup
-			bodyOut.RateGroups[0].Pairs = append(bodyOut.RateGroups[0].Pairs,
-				struct {
-					FoodGroup uint16
-					SubGroup  uint16
-				}{
-					FoodGroup: i,
-					SubGroup:  j,
-				})
-		}
-	}
-
-	return oscar.SNACMessage{
-		Frame: frameOut,
-		Body:  bodyOut,
-	}
 }
 
 func (s OServiceService) UserInfoQueryHandler(ctx context.Context, sess *state.Session, inFrame oscar.SNACFrame) oscar.SNACMessage {

+ 67 - 0
handler/oservice_test.go

@@ -320,3 +320,70 @@ func TestSetUserInfoFieldsHandler(t *testing.T) {
 		})
 	}
 }
+
+func TestOServiceService_RateParamsQueryHandler(t *testing.T) {
+
+	svc := OServiceService{}
+
+	have := svc.RateParamsQueryHandler(nil, oscar.SNACFrame{RequestID: 1234})
+	want := oscar.SNACMessage{
+		Frame: oscar.SNACFrame{
+			FoodGroup: oscar.OService,
+			SubGroup:  oscar.OServiceRateParamsReply,
+			RequestID: 1234,
+		},
+		Body: oscar.SNAC_0x01_0x07_OServiceRateParamsReply{
+			RateClasses: []struct {
+				ID              uint16
+				WindowSize      uint32
+				ClearLevel      uint32
+				AlertLevel      uint32
+				LimitLevel      uint32
+				DisconnectLevel uint32
+				CurrentLevel    uint32
+				MaxLevel        uint32
+				LastTime        uint32
+				CurrentState    uint8
+			}{
+				{
+					ID:              0x0001,
+					WindowSize:      0x00000050,
+					ClearLevel:      0x000009C4,
+					AlertLevel:      0x000007D0,
+					LimitLevel:      0x000005DC,
+					DisconnectLevel: 0x00000320,
+					CurrentLevel:    0x00000D69,
+					MaxLevel:        0x00001770,
+					LastTime:        0x00000000,
+					CurrentState:    0x00,
+				},
+			},
+			RateGroups: []struct {
+				ID    uint16
+				Pairs []struct {
+					FoodGroup uint16
+					SubGroup  uint16
+				} `count_prefix:"uint16"`
+			}{
+				{
+					ID: 1,
+					Pairs: []struct {
+						FoodGroup uint16
+						SubGroup  uint16
+					}{
+						{
+							FoodGroup: oscar.ICBM,
+							SubGroup:  oscar.ICBMChannelMsgToHost,
+						},
+						{
+							FoodGroup: oscar.Chat,
+							SubGroup:  oscar.ChatChannelMsgToHost,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	assert.Equal(t, want, have)
+}

+ 23 - 0
oscar/snacs.go

@@ -148,6 +148,29 @@ type SNAC_0x01_0x05_OServiceServiceResponse struct {
 	TLVRestBlock
 }
 
+//	SNAC_0x01_0x07_OServiceRateParamsReply contains rate limits for rate classes and groups.
+//
+// Rate Classes:
+//   - ID: Unique identifier for the rate class.
+//   - WindowSize: The number of previously sent commands included in calculating
+//     the current "rate average."
+//   - ClearLevel: The threshold the average must reach to clear a rate limit.
+//   - AlertLevel: The threshold for triggering an alert that tells the client
+//     that it's getting close to the limit.
+//   - LimitLevel: SNACs will be dropped if the rate falls below this value.
+//   - DisconnectLevel: Server will disconnect if the rate falls below this value.
+//   - CurrentLevel: The current value for the class; higher values are preferable.
+//     Represents the current "rate average," resembling a moving average of the
+//     times between each of the last WindowSize commands.
+//   - MaxLevel: The maximum rate value; if the current value surpasses this,
+//     it should be reset. The upper limit for a rate average.
+//   - LastTime: Time elapsed since the last message was received by the server.
+//   - CurrentState: Indicates whether the server is dropping SNACs for this rate class.
+//
+// Rate Groups:
+//   - ID: Unique identifier for the rate group.
+//   - Pairs: List of SNAC types associated with the rate group, including FoodGroup
+//     (e.g., oscar.ICBM) and SubGroup (e.g., oscar.ICBMChannelMsgToHost).
 type SNAC_0x01_0x07_OServiceRateParamsReply struct {
 	RateClasses []struct {
 		ID              uint16