Rebuild SCUM plugin-owned data flow

This commit is contained in:
npc0-hue
2026-08-18 07:01:17 +08:00
parent 302f1f64b7
commit 98bf944f4c
39 changed files with 1832 additions and 223 deletions
+84 -12
View File
@@ -61,24 +61,68 @@ type GameClientBridgeSnapshotDeclaration struct {
}
type GameClientBridgeQueryTemplateDeclaration struct {
Key string
Title string
Permission string
Engine string
TransportKey string
TargetKey string
ParameterSchemaRef string
ResultSchemaRef string
SQLRef string
MaxRows int
TimeoutSeconds int
RowTarget *PluginDataRowTargetDeclaration
Key string
Title string
Permission string
Engine string
TransportKey string
TargetKey string
ParameterSchemaRef string
ResultSchemaRef string
SQLRef string
MaxRows int
TimeoutSeconds int
PollIntervalSeconds int
RowTarget *PluginDataRowTargetDeclaration
}
const (
PluginDataRowWriteModeMerge = "merge"
PluginDataRowWriteModeReplace = "replace"
)
type PluginDataRowTargetDeclaration struct {
Collection string
UpsertKeys []string
ColumnMappings map[string]string
WriteMode string
}
type GameClientBridgeLogProjectionStepDeclaration struct {
Pattern string
}
type GameClientBridgeLogProjectionTargetDeclaration struct {
Collection string
UpsertKeys []string
CaptureMappings map[string]string
FixedValues map[string]string
ObservedAtField string
}
type GameClientBridgeLogProjectionAnnouncementDeclaration struct {
ProfileKey string
CommandType string
TextField string
NewTextTemplate string
ReturningTextTemplate string
}
type GameClientBridgeLogProjectionPresenceDeclaration struct {
TimestampField string
ActiveWindowSeconds int
ActivityTarget *GameClientBridgeLogProjectionTargetDeclaration
Announcement GameClientBridgeLogProjectionAnnouncementDeclaration
}
type GameClientBridgeLogProjectionDeclaration struct {
Key string
StreamKeys []string
Steps []GameClientBridgeLogProjectionStepDeclaration
CorrelationFields []string
MaxInterveningLines int
Target GameClientBridgeLogProjectionTargetDeclaration
Presence *GameClientBridgeLogProjectionPresenceDeclaration
}
type GameClientBridgeDataPackDeclaration struct {
@@ -170,6 +214,7 @@ type GameClientBridgeManifest struct {
Commands []GameClientBridgeCommandDeclaration
Snapshots []GameClientBridgeSnapshotDeclaration
QueryTemplates []GameClientBridgeQueryTemplateDeclaration
LogProjections []GameClientBridgeLogProjectionDeclaration
DataPacks []GameClientBridgeDataPackDeclaration
OperationTemplates []GameClientBridgeOperationTemplateDeclaration
Retention GameClientBridgeRetention
@@ -475,6 +520,10 @@ func CopyGameClientBridgeManifest(value GameClientBridgeManifest) GameClientBrid
value.QueryTemplates[index].RowTarget = &copy
}
}
value.LogProjections = append([]GameClientBridgeLogProjectionDeclaration(nil), value.LogProjections...)
for index := range value.LogProjections {
value.LogProjections[index] = CopyGameClientBridgeLogProjectionDeclaration(value.LogProjections[index])
}
value.DataPacks = append([]GameClientBridgeDataPackDeclaration(nil), value.DataPacks...)
for index := range value.DataPacks {
value.DataPacks[index].LogParserRefs = CopyStringSlice(value.DataPacks[index].LogParserRefs)
@@ -503,6 +552,29 @@ func CopyPluginDataRowTargetDeclaration(value PluginDataRowTargetDeclaration) Pl
return value
}
func CopyGameClientBridgeLogProjectionDeclaration(value GameClientBridgeLogProjectionDeclaration) GameClientBridgeLogProjectionDeclaration {
value.StreamKeys = CopyStringSlice(value.StreamKeys)
value.Steps = append([]GameClientBridgeLogProjectionStepDeclaration(nil), value.Steps...)
value.CorrelationFields = CopyStringSlice(value.CorrelationFields)
value.Target = CopyGameClientBridgeLogProjectionTargetDeclaration(value.Target)
if value.Presence != nil {
presence := *value.Presence
if presence.ActivityTarget != nil {
activityTarget := CopyGameClientBridgeLogProjectionTargetDeclaration(*presence.ActivityTarget)
presence.ActivityTarget = &activityTarget
}
value.Presence = &presence
}
return value
}
func CopyGameClientBridgeLogProjectionTargetDeclaration(value GameClientBridgeLogProjectionTargetDeclaration) GameClientBridgeLogProjectionTargetDeclaration {
value.UpsertKeys = CopyStringSlice(value.UpsertKeys)
value.CaptureMappings = CopyStringMap(value.CaptureMappings)
value.FixedValues = CopyStringMap(value.FixedValues)
return value
}
func copyGameClientBridgePayloadValue(value any) any {
switch typed := value.(type) {
case map[string]any:
+10 -2
View File
@@ -4,7 +4,12 @@ import "testing"
func TestCopyGameClientBridgeDeclarationsCopiesQueryTemplateSlices(t *testing.T) {
manifest := GameClientBridgeManifest{
QueryTemplates: []GameClientBridgeQueryTemplateDeclaration{{Key: "player.lookup", RowTarget: &PluginDataRowTargetDeclaration{Collection: "users", UpsertKeys: []string{"userId"}, ColumnMappings: map[string]string{"userId": "user_id"}}}},
QueryTemplates: []GameClientBridgeQueryTemplateDeclaration{{Key: "player.lookup", PollIntervalSeconds: 3, RowTarget: &PluginDataRowTargetDeclaration{Collection: "users", UpsertKeys: []string{"userId"}, ColumnMappings: map[string]string{"userId": "user_id"}, WriteMode: PluginDataRowWriteModeMerge}}},
LogProjections: []GameClientBridgeLogProjectionDeclaration{{
Key: "player.login", StreamKeys: []string{"process.stdout"}, Steps: []GameClientBridgeLogProjectionStepDeclaration{{Pattern: `Player (?<slot>\d+)`}}, CorrelationFields: []string{"slot"}, MaxInterveningLines: 8,
Target: GameClientBridgeLogProjectionTargetDeclaration{Collection: "users", UpsertKeys: []string{"steamId"}, CaptureMappings: map[string]string{"steamId": "steamId"}, FixedValues: map[string]string{"source": "stdout"}, ObservedAtField: "lastLoginAt"},
Presence: &GameClientBridgeLogProjectionPresenceDeclaration{TimestampField: "lastLoginAt", ActiveWindowSeconds: 600, ActivityTarget: &GameClientBridgeLogProjectionTargetDeclaration{Collection: "activity", UpsertKeys: []string{"steamId"}, CaptureMappings: map[string]string{"steamId": "steamId"}}},
}},
DataPacks: []GameClientBridgeDataPackDeclaration{{Key: "db-v1", LogParserRefs: []string{"logs.json"}, ConfigMapRefs: []string{"config.json"}}},
OperationTemplates: []GameClientBridgeOperationTemplateDeclaration{{Key: "player.fame.set"}},
Pages: []GameClientBridgePageContract{{PageKey: "players", QueryTemplateKeys: []string{"player.lookup"}, OperationKeys: []string{"player.fame.set"}}},
@@ -12,11 +17,14 @@ func TestCopyGameClientBridgeDeclarationsCopiesQueryTemplateSlices(t *testing.T)
manifestCopy := CopyGameClientBridgeManifest(manifest)
manifestCopy.QueryTemplates[0].Key = "mutated"
manifestCopy.QueryTemplates[0].RowTarget.ColumnMappings["userId"] = "mutated"
manifestCopy.LogProjections[0].StreamKeys[0] = "mutated"
manifestCopy.LogProjections[0].Target.CaptureMappings["steamId"] = "mutated"
manifestCopy.LogProjections[0].Presence.ActivityTarget.CaptureMappings["steamId"] = "mutated"
manifestCopy.DataPacks[0].LogParserRefs[0] = "mutated"
manifestCopy.OperationTemplates[0].Key = "mutated"
manifestCopy.Pages[0].QueryTemplateKeys[0] = "mutated"
manifestCopy.Pages[0].OperationKeys[0] = "mutated"
if manifest.QueryTemplates[0].Key != "player.lookup" || manifest.QueryTemplates[0].RowTarget.ColumnMappings["userId"] != "user_id" || manifest.DataPacks[0].LogParserRefs[0] != "logs.json" || manifest.OperationTemplates[0].Key != "player.fame.set" || manifest.Pages[0].QueryTemplateKeys[0] != "player.lookup" || manifest.Pages[0].OperationKeys[0] != "player.fame.set" {
if manifest.QueryTemplates[0].Key != "player.lookup" || manifest.QueryTemplates[0].RowTarget.ColumnMappings["userId"] != "user_id" || manifest.LogProjections[0].StreamKeys[0] != "process.stdout" || manifest.LogProjections[0].Target.CaptureMappings["steamId"] != "steamId" || manifest.LogProjections[0].Presence.ActivityTarget.CaptureMappings["steamId"] != "steamId" || manifest.DataPacks[0].LogParserRefs[0] != "logs.json" || manifest.OperationTemplates[0].Key != "player.fame.set" || manifest.Pages[0].QueryTemplateKeys[0] != "player.lookup" || manifest.Pages[0].OperationKeys[0] != "player.fame.set" {
t.Fatalf("manifest copy aliases query template declarations: source=%#v copy=%#v", manifest, manifestCopy)
}