机器人进房逻辑

This commit is contained in:
zhx 2026-06-23 14:01:53 +08:00
parent 535ca29fa7
commit f88347638e
8 changed files with 1860 additions and 1794 deletions

File diff suppressed because it is too large Load Diff

View File

@ -276,6 +276,8 @@ message AdminHumanRoomRobotCountryPool {
message AdminHumanRoomRobotCountryRule {
string country_code = 1;
int32 max_room_count = 2;
// allowed_owner_ids / owner_user_id
repeated string allowed_owner_ids = 3;
}
message AdminHumanRoomRobotConfig {

View File

@ -195,8 +195,9 @@ type HumanRoomRobotConfig struct {
}
type HumanRoomRobotCountryRule struct {
CountryCode string
MaxRoomCount int32
CountryCode string
MaxRoomCount int32
AllowedOwnerIDs []string
}
type UpdateHumanRoomRobotConfigRequest struct {
@ -762,8 +763,9 @@ func humanRoomRobotConfigFromProto(input *roomv1.AdminHumanRoomRobotConfig) Huma
}
for _, rule := range input.GetCountryRules() {
config.CountryRules = append(config.CountryRules, HumanRoomRobotCountryRule{
CountryCode: rule.GetCountryCode(),
MaxRoomCount: rule.GetMaxRoomCount(),
CountryCode: rule.GetCountryCode(),
MaxRoomCount: rule.GetMaxRoomCount(),
AllowedOwnerIDs: append([]string(nil), rule.GetAllowedOwnerIds()...),
})
}
return config
@ -800,8 +802,9 @@ func humanRoomRobotConfigToProto(input HumanRoomRobotConfig) *roomv1.AdminHumanR
}
for _, rule := range input.CountryRules {
out.CountryRules = append(out.CountryRules, &roomv1.AdminHumanRoomRobotCountryRule{
CountryCode: rule.CountryCode,
MaxRoomCount: rule.MaxRoomCount,
CountryCode: rule.CountryCode,
MaxRoomCount: rule.MaxRoomCount,
AllowedOwnerIds: append([]string(nil), rule.AllowedOwnerIDs...),
})
}
return out

View File

@ -71,7 +71,7 @@ func TestHumanRoomRobotAllowedOwnerIDsAcceptsCommaStringAndArray(t *testing.T) {
func TestHumanRoomRobotCountryRulesDecode(t *testing.T) {
var req updateHumanRoomRobotConfigRequest
if err := json.Unmarshal([]byte(`{"countryLimitEnabled":true,"countryRules":[{"countryCode":"sa","maxRoomCount":2}]}`), &req); err != nil {
if err := json.Unmarshal([]byte(`{"countryLimitEnabled":true,"countryRules":[{"countryCode":"sa","maxRoomCount":2,"allowedOwnerIds":"1001, 1002,,1001"}]}`), &req); err != nil {
t.Fatalf("unmarshal human room robot country rules failed: %v", err)
}
if !req.CountryLimitEnabled || len(req.CountryRules) != 1 {
@ -80,4 +80,7 @@ func TestHumanRoomRobotCountryRulesDecode(t *testing.T) {
if req.CountryRules[0].CountryCode != "sa" || req.CountryRules[0].MaxRoomCount != 2 {
t.Fatalf("country rule mismatch: %+v", req.CountryRules[0])
}
if got := normalizeStringList([]string(req.CountryRules[0].AllowedOwnerIDs)); !reflect.DeepEqual(got, []string{"1001", "1002"}) {
t.Fatalf("country rule allowed owner ids mismatch: %+v", got)
}
}

View File

@ -89,8 +89,9 @@ type HumanRoomRobotConfig struct {
}
type HumanRoomRobotCountryRule struct {
CountryCode string `json:"countryCode"`
MaxRoomCount int32 `json:"maxRoomCount"`
CountryCode string `json:"countryCode"`
MaxRoomCount int32 `json:"maxRoomCount"`
AllowedOwnerIDs flexibleCommaStringList `json:"allowedOwnerIds"`
}
func (s *Service) ListRobotRooms(ctx context.Context, query robotRoomListQuery) ([]RobotRoom, int64, error) {
@ -308,8 +309,9 @@ func humanRoomRobotCountryRulesToClient(values []HumanRoomRobotCountryRule) []ro
out := make([]roomclient.HumanRoomRobotCountryRule, 0, len(values))
for _, value := range values {
out = append(out, roomclient.HumanRoomRobotCountryRule{
CountryCode: strings.ToUpper(strings.TrimSpace(value.CountryCode)),
MaxRoomCount: value.MaxRoomCount,
CountryCode: strings.ToUpper(strings.TrimSpace(value.CountryCode)),
MaxRoomCount: value.MaxRoomCount,
AllowedOwnerIDs: normalizeStringList([]string(value.AllowedOwnerIDs)),
})
}
return out
@ -319,8 +321,9 @@ func humanRoomRobotCountryRulesFromClient(values []roomclient.HumanRoomRobotCoun
out := make([]HumanRoomRobotCountryRule, 0, len(values))
for _, value := range values {
out = append(out, HumanRoomRobotCountryRule{
CountryCode: value.CountryCode,
MaxRoomCount: value.MaxRoomCount,
CountryCode: value.CountryCode,
MaxRoomCount: value.MaxRoomCount,
AllowedOwnerIDs: flexibleCommaStringList(append([]string(nil), value.AllowedOwnerIDs...)),
})
}
return out

View File

@ -118,8 +118,8 @@ func (s *Service) scanHumanRoomRobotRuntimes(ctx context.Context) {
continue
}
}
// 限定房主 ID 只影响本轮候选房 SQL不额外读取 Room Cell 或 presence为空时保持原来的全房间扫描语义
rooms, err := s.repository.ListHumanRobotCandidateRooms(ctx, config.AppCode, countryCode, config.CandidateRoomMaxOnline, config.RoomTargetMaxOnline, 50, config.AllowedOwnerIDs)
// 国家行里的房主白名单只收窄当前国家的候选 SQL不额外读取 Room Cell旧的全局白名单只作为未配置国家行白名单时的兼容回退
rooms, err := s.repository.ListHumanRobotCandidateRooms(ctx, config.AppCode, countryCode, config.CandidateRoomMaxOnline, config.RoomTargetMaxOnline, 50, humanRoomRobotAllowedOwnersForCountry(config, countryCode))
if err != nil {
logx.Warn(ctx, "human_room_robot_candidate_rooms_failed", slog.String("country_code", countryCode), slog.String("error", err.Error()))
continue
@ -852,7 +852,11 @@ func normalizeHumanRoomRobotCountryRules(values []*roomv1.AdminHumanRoomRobotCou
return nil, xerr.New(xerr.InvalidArgument, "country max_room_count is invalid")
}
seen[countryCode] = true
rules = append(rules, HumanRoomRobotCountryRule{CountryCode: countryCode, MaxRoomCount: value.GetMaxRoomCount()})
rules = append(rules, HumanRoomRobotCountryRule{
CountryCode: countryCode,
MaxRoomCount: value.GetMaxRoomCount(),
AllowedOwnerIDs: normalizeStringSet(value.GetAllowedOwnerIds()),
})
}
sort.Slice(rules, func(i, j int) bool {
return rules[i].CountryCode < rules[j].CountryCode
@ -876,6 +880,21 @@ func humanRoomRobotCountryLimits(config HumanRoomRobotConfig) map[string]int {
return limits
}
func humanRoomRobotAllowedOwnersForCountry(config HumanRoomRobotConfig, countryCode string) []string {
countryCode = normalizeRoomCountryCode(countryCode)
for _, rule := range config.CountryRules {
if normalizeRoomCountryCode(rule.CountryCode) != countryCode {
continue
}
// 国家规则里填写房主 ID 时,它是当前国家的精确白名单;为空时允许继续使用历史全局白名单。
if len(rule.AllowedOwnerIDs) > 0 {
return append([]string(nil), rule.AllowedOwnerIDs...)
}
return append([]string(nil), config.AllowedOwnerIDs...)
}
return append([]string(nil), config.AllowedOwnerIDs...)
}
func humanRoomRobotConfigToProto(config HumanRoomRobotConfig) *roomv1.AdminHumanRoomRobotConfig {
config = withHumanRoomRobotDefaults(config)
out := &roomv1.AdminHumanRoomRobotConfig{
@ -908,8 +927,9 @@ func humanRoomRobotConfigToProto(config HumanRoomRobotConfig) *roomv1.AdminHuman
}
for _, rule := range config.CountryRules {
out.CountryRules = append(out.CountryRules, &roomv1.AdminHumanRoomRobotCountryRule{
CountryCode: rule.CountryCode,
MaxRoomCount: rule.MaxRoomCount,
CountryCode: rule.CountryCode,
MaxRoomCount: rule.MaxRoomCount,
AllowedOwnerIds: append([]string(nil), rule.AllowedOwnerIDs...),
})
}
return out

View File

@ -82,7 +82,7 @@ func TestRandomHumanRoomTargetOnlineLegacyFixedValue(t *testing.T) {
func TestNormalizeHumanRoomRobotCountryRules(t *testing.T) {
rules, err := normalizeHumanRoomRobotCountryRules([]*roomv1.AdminHumanRoomRobotCountryRule{
{CountryCode: "sa", MaxRoomCount: 2},
{CountryCode: "sa", MaxRoomCount: 2, AllowedOwnerIds: []string{" 1001 ", "1001", "1002"}},
{CountryCode: "AE", MaxRoomCount: 1},
})
if err != nil {
@ -91,12 +91,34 @@ func TestNormalizeHumanRoomRobotCountryRules(t *testing.T) {
if len(rules) != 2 || rules[0].CountryCode != "AE" || rules[1].CountryCode != "SA" || rules[1].MaxRoomCount != 2 {
t.Fatalf("country rules mismatch: %+v", rules)
}
if len(rules[1].AllowedOwnerIDs) != 2 || rules[1].AllowedOwnerIDs[0] != "1001" || rules[1].AllowedOwnerIDs[1] != "1002" {
t.Fatalf("country rule allowed owners mismatch: %+v", rules[1].AllowedOwnerIDs)
}
limits := humanRoomRobotCountryLimits(HumanRoomRobotConfig{CountryLimitEnabled: true, CountryRules: rules})
if limits["SA"] != 2 || limits["AE"] != 1 || len(limits) != 2 {
t.Fatalf("country limits mismatch: %+v", limits)
}
}
func TestHumanRoomRobotAllowedOwnersForCountryPrefersCountryRule(t *testing.T) {
config := HumanRoomRobotConfig{
AllowedOwnerIDs: []string{"global-owner"},
CountryRules: []HumanRoomRobotCountryRule{
{CountryCode: "SA", MaxRoomCount: 2, AllowedOwnerIDs: []string{"sa-owner"}},
{CountryCode: "AE", MaxRoomCount: 1},
},
}
if got := humanRoomRobotAllowedOwnersForCountry(config, "sa"); len(got) != 1 || got[0] != "sa-owner" {
t.Fatalf("country rule allowed owners should win, got %+v", got)
}
if got := humanRoomRobotAllowedOwnersForCountry(config, "AE"); len(got) != 1 || got[0] != "global-owner" {
t.Fatalf("empty country rule should fall back to global owners, got %+v", got)
}
if got := humanRoomRobotAllowedOwnersForCountry(config, "KW"); len(got) != 1 || got[0] != "global-owner" {
t.Fatalf("missing country rule should fall back to global owners, got %+v", got)
}
}
func TestNormalizeHumanRoomRobotCountryRulesRejectsDuplicate(t *testing.T) {
if _, err := normalizeHumanRoomRobotCountryRules([]*roomv1.AdminHumanRoomRobotCountryRule{
{CountryCode: "SA", MaxRoomCount: 2},

View File

@ -266,8 +266,9 @@ type HumanRoomRobotCountryPool struct {
}
type HumanRoomRobotCountryRule struct {
CountryCode string
MaxRoomCount int32
CountryCode string
MaxRoomCount int32
AllowedOwnerIDs []string
}
type HumanRoomRobotConfig struct {