Integrate SCUM real ops workflows

This commit is contained in:
npc0-hue
2026-08-10 21:12:53 +08:00
parent 1063330710
commit a770bc6250
88 changed files with 6375 additions and 2719 deletions
+51 -1
View File
@@ -53,6 +53,16 @@ type StoreSnapshot struct {
GameGiftCatalogs []domain.GameGiftCatalog `json:"gameGiftCatalogs"`
GameGiftRevisions []domain.GameGiftRevision `json:"gameGiftRevisions"`
GameGiftGrants []domain.GameGiftGrant `json:"gameGiftGrants"`
SCUMDataObservations []domain.SCUMDataObservation `json:"scumDataObservations"`
SCUMPlayerLiveStates []domain.SCUMPlayerLiveState `json:"scumPlayerLiveStates"`
SCUMSquads []domain.SCUMSquad `json:"scumSquads"`
SCUMSquadMembers []domain.SCUMSquadMember `json:"scumSquadMembers"`
SCUMVehicles []domain.SCUMVehicle `json:"scumVehicles"`
SCUMFlags []domain.SCUMFlag `json:"scumFlags"`
SCUMCurrentPositions []domain.SCUMCurrentPosition `json:"scumCurrentPositions"`
SCUMOperationRequests []domain.SCUMOperationRequest `json:"scumOperationRequests"`
SCUMWorkflowInstances []domain.SCUMWorkflowInstance `json:"scumWorkflowInstances"`
SCUMWorkflowSteps []domain.SCUMWorkflowStep `json:"scumWorkflowSteps"`
}
type FileStore struct {
@@ -234,6 +244,36 @@ func (store *FileStore) GameGiftRevisions() GameGiftRevisionRepository {
func (store *FileStore) GameGiftGrants() GameGiftGrantRepository {
return &persistentRepository[domain.GameGiftGrant, domain.GameGiftGrantFilter]{repository: store.MemoryStore.gameGiftGrants, persist: store.persist}
}
func (store *FileStore) SCUMDataObservations() SCUMDataObservationRepository {
return &persistentRepository[domain.SCUMDataObservation, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumDataObservations, persist: store.persist}
}
func (store *FileStore) SCUMPlayerLiveStates() SCUMPlayerLiveStateRepository {
return &persistentRepository[domain.SCUMPlayerLiveState, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumPlayerLiveStates, persist: store.persist}
}
func (store *FileStore) SCUMSquads() SCUMSquadRepository {
return &persistentRepository[domain.SCUMSquad, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumSquads, persist: store.persist}
}
func (store *FileStore) SCUMSquadMembers() SCUMSquadMemberRepository {
return &persistentRepository[domain.SCUMSquadMember, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumSquadMembers, persist: store.persist}
}
func (store *FileStore) SCUMVehicles() SCUMVehicleRepository {
return &persistentRepository[domain.SCUMVehicle, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumVehicles, persist: store.persist}
}
func (store *FileStore) SCUMFlags() SCUMFlagRepository {
return &persistentRepository[domain.SCUMFlag, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumFlags, persist: store.persist}
}
func (store *FileStore) SCUMCurrentPositions() SCUMCurrentPositionRepository {
return &persistentRepository[domain.SCUMCurrentPosition, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumCurrentPositions, persist: store.persist}
}
func (store *FileStore) SCUMOperationRequests() SCUMOperationRequestRepository {
return &persistentRepository[domain.SCUMOperationRequest, domain.SCUMOperationRequestFilter]{repository: store.MemoryStore.scumOperationRequests, persist: store.persist}
}
func (store *FileStore) SCUMWorkflowInstances() SCUMWorkflowInstanceRepository {
return &persistentRepository[domain.SCUMWorkflowInstance, domain.SCUMWorkflowInstanceFilter]{repository: store.MemoryStore.scumWorkflowInstances, persist: store.persist}
}
func (store *FileStore) SCUMWorkflowSteps() SCUMWorkflowStepRepository {
return &persistentRepository[domain.SCUMWorkflowStep, domain.SCUMWorkflowStepFilter]{repository: store.MemoryStore.scumWorkflowSteps, persist: store.persist}
}
func (store *FileStore) load() error {
data, err := os.ReadFile(store.path)
@@ -307,7 +347,7 @@ func (store *FileStore) snapshot() StoreSnapshot {
GameClientBridgeCommands: snapshotRepository(store.MemoryStore.bridgeCommands.memoryRepository),
GameClientBridgeSnapshots: snapshotRepository(store.MemoryStore.bridgeSnapshots.memoryRepository),
GameClientBridgeStreams: snapshotRepository(store.MemoryStore.bridgeStreams),
GamePlayers: snapshotRepository(store.MemoryStore.gamePlayers), GamePlayerAliases: snapshotRepository(store.MemoryStore.gamePlayerAliases), GamePlayerSessions: snapshotRepository(store.MemoryStore.gamePlayerSessions), GameAccessAttempts: snapshotRepository(store.MemoryStore.gameAccessAttempts), GameSecuritySignals: snapshotRepository(store.MemoryStore.gameSecuritySignals), GamePlayerStatePatches: snapshotRepository(store.MemoryStore.gamePlayerStatePatches), GameMapTrackPoints: snapshotRepository(store.MemoryStore.gameMapTrackPoints), GamePlayerVehicleSegments: snapshotRepository(store.MemoryStore.gamePlayerVehicleSegments), GameGiftCatalogs: snapshotRepository(store.MemoryStore.gameGiftCatalogs), GameGiftRevisions: snapshotRepository(store.MemoryStore.gameGiftRevisions), GameGiftGrants: snapshotRepository(store.MemoryStore.gameGiftGrants),
GamePlayers: snapshotRepository(store.MemoryStore.gamePlayers), GamePlayerAliases: snapshotRepository(store.MemoryStore.gamePlayerAliases), GamePlayerSessions: snapshotRepository(store.MemoryStore.gamePlayerSessions), GameAccessAttempts: snapshotRepository(store.MemoryStore.gameAccessAttempts), GameSecuritySignals: snapshotRepository(store.MemoryStore.gameSecuritySignals), GamePlayerStatePatches: snapshotRepository(store.MemoryStore.gamePlayerStatePatches), GameMapTrackPoints: snapshotRepository(store.MemoryStore.gameMapTrackPoints), GamePlayerVehicleSegments: snapshotRepository(store.MemoryStore.gamePlayerVehicleSegments), GameGiftCatalogs: snapshotRepository(store.MemoryStore.gameGiftCatalogs), GameGiftRevisions: snapshotRepository(store.MemoryStore.gameGiftRevisions), GameGiftGrants: snapshotRepository(store.MemoryStore.gameGiftGrants), SCUMDataObservations: snapshotRepository(store.MemoryStore.scumDataObservations), SCUMPlayerLiveStates: snapshotRepository(store.MemoryStore.scumPlayerLiveStates), SCUMSquads: snapshotRepository(store.MemoryStore.scumSquads), SCUMSquadMembers: snapshotRepository(store.MemoryStore.scumSquadMembers), SCUMVehicles: snapshotRepository(store.MemoryStore.scumVehicles), SCUMFlags: snapshotRepository(store.MemoryStore.scumFlags), SCUMCurrentPositions: snapshotRepository(store.MemoryStore.scumCurrentPositions), SCUMOperationRequests: snapshotRepository(store.MemoryStore.scumOperationRequests), SCUMWorkflowInstances: snapshotRepository(store.MemoryStore.scumWorkflowInstances), SCUMWorkflowSteps: snapshotRepository(store.MemoryStore.scumWorkflowSteps),
}
}
@@ -352,6 +392,16 @@ func (store *FileStore) loadSnapshot(snapshot StoreSnapshot) {
loadRepository(store.MemoryStore.gameGiftCatalogs, snapshot.GameGiftCatalogs)
loadRepository(store.MemoryStore.gameGiftRevisions, snapshot.GameGiftRevisions)
loadRepository(store.MemoryStore.gameGiftGrants, snapshot.GameGiftGrants)
loadRepository(store.MemoryStore.scumDataObservations, snapshot.SCUMDataObservations)
loadRepository(store.MemoryStore.scumPlayerLiveStates, snapshot.SCUMPlayerLiveStates)
loadRepository(store.MemoryStore.scumSquads, snapshot.SCUMSquads)
loadRepository(store.MemoryStore.scumSquadMembers, snapshot.SCUMSquadMembers)
loadRepository(store.MemoryStore.scumVehicles, snapshot.SCUMVehicles)
loadRepository(store.MemoryStore.scumFlags, snapshot.SCUMFlags)
loadRepository(store.MemoryStore.scumCurrentPositions, snapshot.SCUMCurrentPositions)
loadRepository(store.MemoryStore.scumOperationRequests, snapshot.SCUMOperationRequests)
loadRepository(store.MemoryStore.scumWorkflowInstances, snapshot.SCUMWorkflowInstances)
loadRepository(store.MemoryStore.scumWorkflowSteps, snapshot.SCUMWorkflowSteps)
}
type mutableRepository[T any, F any] interface {
+41 -1
View File
@@ -204,6 +204,36 @@ func (store *MySQLStore) GameGiftRevisions() GameGiftRevisionRepository {
func (store *MySQLStore) GameGiftGrants() GameGiftGrantRepository {
return &persistentRepository[domain.GameGiftGrant, domain.GameGiftGrantFilter]{repository: store.MemoryStore.gameGiftGrants, persist: store.persist}
}
func (store *MySQLStore) SCUMDataObservations() SCUMDataObservationRepository {
return &persistentRepository[domain.SCUMDataObservation, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumDataObservations, persist: store.persist}
}
func (store *MySQLStore) SCUMPlayerLiveStates() SCUMPlayerLiveStateRepository {
return &persistentRepository[domain.SCUMPlayerLiveState, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumPlayerLiveStates, persist: store.persist}
}
func (store *MySQLStore) SCUMSquads() SCUMSquadRepository {
return &persistentRepository[domain.SCUMSquad, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumSquads, persist: store.persist}
}
func (store *MySQLStore) SCUMSquadMembers() SCUMSquadMemberRepository {
return &persistentRepository[domain.SCUMSquadMember, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumSquadMembers, persist: store.persist}
}
func (store *MySQLStore) SCUMVehicles() SCUMVehicleRepository {
return &persistentRepository[domain.SCUMVehicle, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumVehicles, persist: store.persist}
}
func (store *MySQLStore) SCUMFlags() SCUMFlagRepository {
return &persistentRepository[domain.SCUMFlag, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumFlags, persist: store.persist}
}
func (store *MySQLStore) SCUMCurrentPositions() SCUMCurrentPositionRepository {
return &persistentRepository[domain.SCUMCurrentPosition, domain.SCUMProjectionFilter]{repository: store.MemoryStore.scumCurrentPositions, persist: store.persist}
}
func (store *MySQLStore) SCUMOperationRequests() SCUMOperationRequestRepository {
return &persistentRepository[domain.SCUMOperationRequest, domain.SCUMOperationRequestFilter]{repository: store.MemoryStore.scumOperationRequests, persist: store.persist}
}
func (store *MySQLStore) SCUMWorkflowInstances() SCUMWorkflowInstanceRepository {
return &persistentRepository[domain.SCUMWorkflowInstance, domain.SCUMWorkflowInstanceFilter]{repository: store.MemoryStore.scumWorkflowInstances, persist: store.persist}
}
func (store *MySQLStore) SCUMWorkflowSteps() SCUMWorkflowStepRepository {
return &persistentRepository[domain.SCUMWorkflowStep, domain.SCUMWorkflowStepFilter]{repository: store.MemoryStore.scumWorkflowSteps, persist: store.persist}
}
func (store *MySQLStore) initialize() error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
@@ -294,7 +324,7 @@ func (store *MySQLStore) snapshot() StoreSnapshot {
GameClientBridgeCommands: snapshotRepository(store.MemoryStore.bridgeCommands.memoryRepository),
GameClientBridgeSnapshots: snapshotRepository(store.MemoryStore.bridgeSnapshots.memoryRepository),
GameClientBridgeStreams: snapshotRepository(store.MemoryStore.bridgeStreams),
GamePlayers: snapshotRepository(store.MemoryStore.gamePlayers), GamePlayerAliases: snapshotRepository(store.MemoryStore.gamePlayerAliases), GamePlayerSessions: snapshotRepository(store.MemoryStore.gamePlayerSessions), GameAccessAttempts: snapshotRepository(store.MemoryStore.gameAccessAttempts), GameSecuritySignals: snapshotRepository(store.MemoryStore.gameSecuritySignals), GamePlayerStatePatches: snapshotRepository(store.MemoryStore.gamePlayerStatePatches), GameMapTrackPoints: snapshotRepository(store.MemoryStore.gameMapTrackPoints), GamePlayerVehicleSegments: snapshotRepository(store.MemoryStore.gamePlayerVehicleSegments), GameGiftCatalogs: snapshotRepository(store.MemoryStore.gameGiftCatalogs), GameGiftRevisions: snapshotRepository(store.MemoryStore.gameGiftRevisions), GameGiftGrants: snapshotRepository(store.MemoryStore.gameGiftGrants),
GamePlayers: snapshotRepository(store.MemoryStore.gamePlayers), GamePlayerAliases: snapshotRepository(store.MemoryStore.gamePlayerAliases), GamePlayerSessions: snapshotRepository(store.MemoryStore.gamePlayerSessions), GameAccessAttempts: snapshotRepository(store.MemoryStore.gameAccessAttempts), GameSecuritySignals: snapshotRepository(store.MemoryStore.gameSecuritySignals), GamePlayerStatePatches: snapshotRepository(store.MemoryStore.gamePlayerStatePatches), GameMapTrackPoints: snapshotRepository(store.MemoryStore.gameMapTrackPoints), GamePlayerVehicleSegments: snapshotRepository(store.MemoryStore.gamePlayerVehicleSegments), GameGiftCatalogs: snapshotRepository(store.MemoryStore.gameGiftCatalogs), GameGiftRevisions: snapshotRepository(store.MemoryStore.gameGiftRevisions), GameGiftGrants: snapshotRepository(store.MemoryStore.gameGiftGrants), SCUMDataObservations: snapshotRepository(store.MemoryStore.scumDataObservations), SCUMPlayerLiveStates: snapshotRepository(store.MemoryStore.scumPlayerLiveStates), SCUMSquads: snapshotRepository(store.MemoryStore.scumSquads), SCUMSquadMembers: snapshotRepository(store.MemoryStore.scumSquadMembers), SCUMVehicles: snapshotRepository(store.MemoryStore.scumVehicles), SCUMFlags: snapshotRepository(store.MemoryStore.scumFlags), SCUMCurrentPositions: snapshotRepository(store.MemoryStore.scumCurrentPositions), SCUMOperationRequests: snapshotRepository(store.MemoryStore.scumOperationRequests), SCUMWorkflowInstances: snapshotRepository(store.MemoryStore.scumWorkflowInstances), SCUMWorkflowSteps: snapshotRepository(store.MemoryStore.scumWorkflowSteps),
}
}
@@ -339,4 +369,14 @@ func (store *MySQLStore) loadSnapshot(snapshot StoreSnapshot) {
loadRepository(store.MemoryStore.gameGiftCatalogs, snapshot.GameGiftCatalogs)
loadRepository(store.MemoryStore.gameGiftRevisions, snapshot.GameGiftRevisions)
loadRepository(store.MemoryStore.gameGiftGrants, snapshot.GameGiftGrants)
loadRepository(store.MemoryStore.scumDataObservations, snapshot.SCUMDataObservations)
loadRepository(store.MemoryStore.scumPlayerLiveStates, snapshot.SCUMPlayerLiveStates)
loadRepository(store.MemoryStore.scumSquads, snapshot.SCUMSquads)
loadRepository(store.MemoryStore.scumSquadMembers, snapshot.SCUMSquadMembers)
loadRepository(store.MemoryStore.scumVehicles, snapshot.SCUMVehicles)
loadRepository(store.MemoryStore.scumFlags, snapshot.SCUMFlags)
loadRepository(store.MemoryStore.scumCurrentPositions, snapshot.SCUMCurrentPositions)
loadRepository(store.MemoryStore.scumOperationRequests, snapshot.SCUMOperationRequests)
loadRepository(store.MemoryStore.scumWorkflowInstances, snapshot.SCUMWorkflowInstances)
loadRepository(store.MemoryStore.scumWorkflowSteps, snapshot.SCUMWorkflowSteps)
}
+211
View File
@@ -295,6 +295,66 @@ type GameGiftGrantRepository interface {
List(domain.GameGiftGrantFilter) ([]domain.GameGiftGrant, error)
Update(domain.GameGiftGrant) error
}
type SCUMDataObservationRepository interface {
Create(domain.SCUMDataObservation) error
Get(string) (domain.SCUMDataObservation, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMDataObservation, error)
Update(domain.SCUMDataObservation) error
}
type SCUMPlayerLiveStateRepository interface {
Create(domain.SCUMPlayerLiveState) error
Get(string) (domain.SCUMPlayerLiveState, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMPlayerLiveState, error)
Update(domain.SCUMPlayerLiveState) error
}
type SCUMSquadRepository interface {
Create(domain.SCUMSquad) error
Get(string) (domain.SCUMSquad, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMSquad, error)
Update(domain.SCUMSquad) error
}
type SCUMSquadMemberRepository interface {
Create(domain.SCUMSquadMember) error
Get(string) (domain.SCUMSquadMember, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMSquadMember, error)
Update(domain.SCUMSquadMember) error
}
type SCUMVehicleRepository interface {
Create(domain.SCUMVehicle) error
Get(string) (domain.SCUMVehicle, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMVehicle, error)
Update(domain.SCUMVehicle) error
}
type SCUMFlagRepository interface {
Create(domain.SCUMFlag) error
Get(string) (domain.SCUMFlag, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMFlag, error)
Update(domain.SCUMFlag) error
}
type SCUMCurrentPositionRepository interface {
Create(domain.SCUMCurrentPosition) error
Get(string) (domain.SCUMCurrentPosition, error)
List(domain.SCUMProjectionFilter) ([]domain.SCUMCurrentPosition, error)
Update(domain.SCUMCurrentPosition) error
}
type SCUMOperationRequestRepository interface {
Create(domain.SCUMOperationRequest) error
Get(string) (domain.SCUMOperationRequest, error)
List(domain.SCUMOperationRequestFilter) ([]domain.SCUMOperationRequest, error)
Update(domain.SCUMOperationRequest) error
}
type SCUMWorkflowInstanceRepository interface {
Create(domain.SCUMWorkflowInstance) error
Get(string) (domain.SCUMWorkflowInstance, error)
List(domain.SCUMWorkflowInstanceFilter) ([]domain.SCUMWorkflowInstance, error)
Update(domain.SCUMWorkflowInstance) error
}
type SCUMWorkflowStepRepository interface {
Create(domain.SCUMWorkflowStep) error
Get(string) (domain.SCUMWorkflowStep, error)
List(domain.SCUMWorkflowStepFilter) ([]domain.SCUMWorkflowStep, error)
Update(domain.SCUMWorkflowStep) error
}
type Store interface {
Users() UserRepository
@@ -337,6 +397,16 @@ type Store interface {
GameGiftCatalogs() GameGiftCatalogRepository
GameGiftRevisions() GameGiftRevisionRepository
GameGiftGrants() GameGiftGrantRepository
SCUMDataObservations() SCUMDataObservationRepository
SCUMPlayerLiveStates() SCUMPlayerLiveStateRepository
SCUMSquads() SCUMSquadRepository
SCUMSquadMembers() SCUMSquadMemberRepository
SCUMVehicles() SCUMVehicleRepository
SCUMFlags() SCUMFlagRepository
SCUMCurrentPositions() SCUMCurrentPositionRepository
SCUMOperationRequests() SCUMOperationRequestRepository
SCUMWorkflowInstances() SCUMWorkflowInstanceRepository
SCUMWorkflowSteps() SCUMWorkflowStepRepository
}
type MemoryStore struct {
@@ -380,6 +450,16 @@ type MemoryStore struct {
gameGiftCatalogs *memoryRepository[domain.GameGiftCatalog, domain.GameGiftCatalogFilter]
gameGiftRevisions *memoryRepository[domain.GameGiftRevision, domain.GameGiftRevisionFilter]
gameGiftGrants *memoryRepository[domain.GameGiftGrant, domain.GameGiftGrantFilter]
scumDataObservations *memoryRepository[domain.SCUMDataObservation, domain.SCUMProjectionFilter]
scumPlayerLiveStates *memoryRepository[domain.SCUMPlayerLiveState, domain.SCUMProjectionFilter]
scumSquads *memoryRepository[domain.SCUMSquad, domain.SCUMProjectionFilter]
scumSquadMembers *memoryRepository[domain.SCUMSquadMember, domain.SCUMProjectionFilter]
scumVehicles *memoryRepository[domain.SCUMVehicle, domain.SCUMProjectionFilter]
scumFlags *memoryRepository[domain.SCUMFlag, domain.SCUMProjectionFilter]
scumCurrentPositions *memoryRepository[domain.SCUMCurrentPosition, domain.SCUMProjectionFilter]
scumOperationRequests *memoryRepository[domain.SCUMOperationRequest, domain.SCUMOperationRequestFilter]
scumWorkflowInstances *memoryRepository[domain.SCUMWorkflowInstance, domain.SCUMWorkflowInstanceFilter]
scumWorkflowSteps *memoryRepository[domain.SCUMWorkflowStep, domain.SCUMWorkflowStepFilter]
}
func NewMemoryStore() *MemoryStore {
@@ -528,6 +608,16 @@ func NewMemoryStore() *MemoryStore {
gameGiftCatalogs: newMemoryRepository(func(v domain.GameGiftCatalog) string { return v.ID }, domain.CopyGameGiftCatalog, matchGameGiftCatalog),
gameGiftRevisions: newMemoryRepository(func(v domain.GameGiftRevision) string { return v.ID }, domain.CopyGameGiftRevision, matchGameGiftRevision),
gameGiftGrants: newMemoryRepository(func(v domain.GameGiftGrant) string { return v.ID }, domain.CopyGameGiftGrant, matchGameGiftGrant),
scumDataObservations: newMemoryRepository(func(v domain.SCUMDataObservation) string { return v.ID }, domain.CopySCUMDataObservation, matchSCUMDataObservation),
scumPlayerLiveStates: newMemoryRepository(func(v domain.SCUMPlayerLiveState) string { return v.ID }, domain.CopySCUMPlayerLiveState, matchSCUMPlayerLiveState),
scumSquads: newMemoryRepository(func(v domain.SCUMSquad) string { return v.ID }, domain.CopySCUMSquad, matchSCUMSquad),
scumSquadMembers: newMemoryRepository(func(v domain.SCUMSquadMember) string { return v.ID }, domain.CopySCUMSquadMember, matchSCUMSquadMember),
scumVehicles: newMemoryRepository(func(v domain.SCUMVehicle) string { return v.ID }, domain.CopySCUMVehicle, matchSCUMVehicle),
scumFlags: newMemoryRepository(func(v domain.SCUMFlag) string { return v.ID }, domain.CopySCUMFlag, matchSCUMFlag),
scumCurrentPositions: newMemoryRepository(func(v domain.SCUMCurrentPosition) string { return v.ID }, domain.CopySCUMCurrentPosition, matchSCUMCurrentPosition),
scumOperationRequests: newMemoryRepository(func(v domain.SCUMOperationRequest) string { return v.ID }, domain.CopySCUMOperationRequest, matchSCUMOperationRequest),
scumWorkflowInstances: newMemoryRepository(func(v domain.SCUMWorkflowInstance) string { return v.ID }, domain.CopySCUMWorkflowInstance, matchSCUMWorkflowInstance),
scumWorkflowSteps: newMemoryRepository(func(v domain.SCUMWorkflowStep) string { return v.ID }, domain.CopySCUMWorkflowStep, matchSCUMWorkflowStep),
}
}
@@ -607,6 +697,30 @@ func (store *MemoryStore) GameGiftRevisions() GameGiftRevisionRepository {
return store.gameGiftRevisions
}
func (store *MemoryStore) GameGiftGrants() GameGiftGrantRepository { return store.gameGiftGrants }
func (store *MemoryStore) SCUMDataObservations() SCUMDataObservationRepository {
return store.scumDataObservations
}
func (store *MemoryStore) SCUMPlayerLiveStates() SCUMPlayerLiveStateRepository {
return store.scumPlayerLiveStates
}
func (store *MemoryStore) SCUMSquads() SCUMSquadRepository { return store.scumSquads }
func (store *MemoryStore) SCUMSquadMembers() SCUMSquadMemberRepository {
return store.scumSquadMembers
}
func (store *MemoryStore) SCUMVehicles() SCUMVehicleRepository { return store.scumVehicles }
func (store *MemoryStore) SCUMFlags() SCUMFlagRepository { return store.scumFlags }
func (store *MemoryStore) SCUMCurrentPositions() SCUMCurrentPositionRepository {
return store.scumCurrentPositions
}
func (store *MemoryStore) SCUMOperationRequests() SCUMOperationRequestRepository {
return store.scumOperationRequests
}
func (store *MemoryStore) SCUMWorkflowInstances() SCUMWorkflowInstanceRepository {
return store.scumWorkflowInstances
}
func (store *MemoryStore) SCUMWorkflowSteps() SCUMWorkflowStepRepository {
return store.scumWorkflowSteps
}
type memoryRepository[T any, F any] struct {
mu sync.RWMutex
@@ -941,3 +1055,100 @@ func matchGameGiftRevision(v domain.GameGiftRevision, f domain.GameGiftRevisionF
func matchGameGiftGrant(v domain.GameGiftGrant, f domain.GameGiftGrantFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) && (f.GamePlayerRecordID == "" || v.GamePlayerRecordID == f.GamePlayerRecordID) && (f.IdempotencyKey == "" || v.IdempotencyKey == f.IdempotencyKey)
}
func matchSCUMDataObservation(v domain.SCUMDataObservation, f domain.SCUMProjectionFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.SubjectType == "" || v.SubjectType == string(f.SubjectType)) &&
(f.GamePlayerRecordID == "" || v.SubjectID == f.GamePlayerRecordID) &&
(f.QueryKey == "" || v.QueryKey == f.QueryKey) &&
(f.Freshness == "" || domain.SCUMProjectionFreshness(v.Status) == f.Freshness)
}
func matchSCUMPlayerLiveState(v domain.SCUMPlayerLiveState, f domain.SCUMProjectionFilter) bool {
search := strings.ToLower(strings.TrimSpace(f.Search))
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.GamePlayerID == "" || v.GamePlayerID == f.GamePlayerID) &&
(f.GamePlayerRecordID == "" || v.GamePlayerRecordID == f.GamePlayerRecordID) &&
(f.UserProfileID == "" || v.UserProfileID == f.UserProfileID) &&
(f.SteamID == "" || v.SteamID == f.SteamID) &&
(f.SquadID == "" || v.SquadID == f.SquadID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness) &&
(search == "" || strings.Contains(strings.ToLower(v.DisplayName), search) || strings.Contains(strings.ToLower(v.GamePlayerID), search) || strings.Contains(strings.ToLower(v.UserProfileID), search) || strings.Contains(strings.ToLower(v.SteamID), search))
}
func matchSCUMSquad(v domain.SCUMSquad, f domain.SCUMProjectionFilter) bool {
search := strings.ToLower(strings.TrimSpace(f.Search))
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.SquadID == "" || v.SquadID == f.SquadID) &&
(f.UserProfileID == "" || v.LeaderProfileID == f.UserProfileID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness) &&
(search == "" || strings.Contains(strings.ToLower(v.Name), search) || strings.Contains(strings.ToLower(v.SquadID), search))
}
func matchSCUMSquadMember(v domain.SCUMSquadMember, f domain.SCUMProjectionFilter) bool {
search := strings.ToLower(strings.TrimSpace(f.Search))
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.SquadID == "" || v.SquadID == f.SquadID) &&
(f.GamePlayerID == "" || v.GamePlayerID == f.GamePlayerID) &&
(f.GamePlayerRecordID == "" || v.GamePlayerRecordID == f.GamePlayerRecordID) &&
(f.UserProfileID == "" || v.UserProfileID == f.UserProfileID) &&
(f.SteamID == "" || v.SteamID == f.SteamID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness) &&
(search == "" || strings.Contains(strings.ToLower(v.DisplayName), search) || strings.Contains(strings.ToLower(v.GamePlayerID), search) || strings.Contains(strings.ToLower(v.UserProfileID), search))
}
func matchSCUMVehicle(v domain.SCUMVehicle, f domain.SCUMProjectionFilter) bool {
search := strings.ToLower(strings.TrimSpace(f.Search))
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.VehicleID == "" || v.VehicleID == f.VehicleID) &&
(f.UserProfileID == "" || v.OwnerProfileID == f.UserProfileID) &&
(f.GamePlayerID == "" || v.OwnerPlayerID == f.GamePlayerID) &&
(f.SquadID == "" || v.SquadID == f.SquadID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness) &&
(search == "" || strings.Contains(strings.ToLower(v.Label), search) || strings.Contains(strings.ToLower(v.ClassName), search) || strings.Contains(strings.ToLower(v.VehicleID), search))
}
func matchSCUMFlag(v domain.SCUMFlag, f domain.SCUMProjectionFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.FlagID == "" || v.FlagID == f.FlagID) &&
(f.UserProfileID == "" || v.OwnerProfileID == f.UserProfileID) &&
(f.GamePlayerID == "" || v.OwnerPlayerID == f.GamePlayerID) &&
(f.SquadID == "" || v.OwnerSquadID == f.SquadID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness)
}
func matchSCUMCurrentPosition(v domain.SCUMCurrentPosition, f domain.SCUMProjectionFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.SubjectType == "" || v.SubjectType == f.SubjectType) &&
(f.GamePlayerID == "" || v.GamePlayerID == f.GamePlayerID) &&
(f.GamePlayerRecordID == "" || v.GamePlayerRecordID == f.GamePlayerRecordID) &&
(f.VehicleID == "" || v.VehicleID == f.VehicleID) &&
(f.Freshness == "" || v.Freshness.Status == f.Freshness)
}
func matchSCUMOperationRequest(v domain.SCUMOperationRequest, f domain.SCUMOperationRequestFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.PluginID == "" || v.PluginID == f.PluginID) &&
(f.TemplateKey == "" || v.TemplateKey == f.TemplateKey) &&
(f.PlayerID == "" || v.PlayerID == f.PlayerID) &&
(f.RequesterID == "" || v.RequesterID == f.RequesterID) &&
(f.Status == "" || v.Status == f.Status) &&
(f.IdempotencyKey == "" || v.IdempotencyKey == f.IdempotencyKey)
}
func matchSCUMWorkflowInstance(v domain.SCUMWorkflowInstance, f domain.SCUMWorkflowInstanceFilter) bool {
return (f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.PluginID == "" || v.PluginID == f.PluginID) &&
(f.TemplateKey == "" || v.TemplateKey == f.TemplateKey) &&
(f.RequestedBy == "" || v.RequestedBy == f.RequestedBy) &&
(f.Status == "" || v.Status == f.Status) &&
(f.IdempotencyKey == "" || v.IdempotencyKey == f.IdempotencyKey)
}
func matchSCUMWorkflowStep(v domain.SCUMWorkflowStep, f domain.SCUMWorkflowStepFilter) bool {
return (f.WorkflowID == "" || v.WorkflowID == f.WorkflowID) &&
(f.ServerInstanceID == "" || v.ServerInstanceID == f.ServerInstanceID) &&
(f.StepKey == "" || v.StepKey == f.StepKey) &&
(f.Status == "" || v.Status == f.Status) &&
(f.MutatesState == nil || v.MutatesState == *f.MutatesState)
}
+67
View File
@@ -0,0 +1,67 @@
package repo
import (
"path/filepath"
"testing"
"time"
"browser.local/platform/domain"
)
func TestSCUMProjectionRepositoriesCopyFilterAndPersist(t *testing.T) {
path := filepath.Join(t.TempDir(), "metadata.json")
store, err := NewFileStore(path)
if err != nil {
t.Fatalf("create file store: %v", err)
}
stamp := time.Date(2026, 8, 10, 9, 0, 0, 0, time.UTC)
freshness := domain.SCUMProjectionFreshnessState{Status: domain.SCUMProjectionFresh, ObservationID: "obs-1", Source: "run", QueryKey: "scum.player.profile", Sequence: 7, Checksum: "sha256:projection", ObservedAt: stamp, ReceivedAt: stamp.Add(time.Second)}
state := domain.SCUMPlayerLiveState{ID: "state-1", ServerInstanceID: "server-1", GamePlayerRecordID: "game-player-1", GamePlayerID: "steam-1", UserProfileID: "profile-1", SteamID: "steam-1", DisplayName: "Moon", SquadID: "squad-1", UnknownFields: map[string]any{"schemaField": "kept"}, Freshness: freshness, CreatedAt: stamp, UpdatedAt: stamp}
if err := store.SCUMPlayerLiveStates().Create(state); err != nil {
t.Fatalf("create state: %v", err)
}
got, err := store.SCUMPlayerLiveStates().Get(state.ID)
if err != nil {
t.Fatalf("get state: %v", err)
}
got.UnknownFields["schemaField"] = "mutated"
again, err := store.SCUMPlayerLiveStates().Get(state.ID)
if err != nil {
t.Fatalf("get state again: %v", err)
}
if again.UnknownFields["schemaField"] != "kept" {
t.Fatalf("state was not copy-isolated: %+v", again.UnknownFields)
}
filtered, err := store.SCUMPlayerLiveStates().List(domain.SCUMProjectionFilter{ServerInstanceID: "server-1", UserProfileID: "profile-1", Search: "moon"})
if err != nil || len(filtered) != 1 {
t.Fatalf("filter states=%+v err=%v", filtered, err)
}
if err := store.SCUMSquads().Create(domain.SCUMSquad{ID: "squad-1", ServerInstanceID: "server-1", SquadID: "squad-1", Name: "Crystal", Freshness: freshness}); err != nil {
t.Fatalf("create squad: %v", err)
}
if err := store.SCUMVehicles().Create(domain.SCUMVehicle{ID: "vehicle-1", ServerInstanceID: "server-1", VehicleID: "veh-1", Label: "Unknown vehicle", Freshness: freshness}); err != nil {
t.Fatalf("create vehicle: %v", err)
}
if err := store.SCUMFlags().Create(domain.SCUMFlag{ID: "flag-1", ServerInstanceID: "server-1", FlagID: "flag-1", OwnerSquadID: "squad-1", Freshness: freshness}); err != nil {
t.Fatalf("create flag: %v", err)
}
if err := store.SCUMCurrentPositions().Create(domain.SCUMCurrentPosition{ID: "position-1", ServerInstanceID: "server-1", SubjectType: domain.SCUMProjectionSubjectPlayer, SubjectID: "steam-1", GamePlayerRecordID: "game-player-1", X: 1, Y: 2, HasCoordinates: true, Freshness: freshness}); err != nil {
t.Fatalf("create position: %v", err)
}
reloaded, err := NewFileStore(path)
if err != nil {
t.Fatalf("reload file store: %v", err)
}
reloadedStates, err := reloaded.SCUMPlayerLiveStates().List(domain.SCUMProjectionFilter{ServerInstanceID: "server-1", SquadID: "squad-1"})
if err != nil || len(reloadedStates) != 1 || reloadedStates[0].Freshness.QueryKey != "scum.player.profile" {
t.Fatalf("unexpected reloaded states=%+v err=%v", reloadedStates, err)
}
vehicles, err := reloaded.SCUMVehicles().List(domain.SCUMProjectionFilter{ServerInstanceID: "server-1", Search: "unknown"})
if err != nil || len(vehicles) != 1 {
t.Fatalf("unexpected reloaded vehicles=%+v err=%v", vehicles, err)
}
positions, err := reloaded.SCUMCurrentPositions().List(domain.SCUMProjectionFilter{ServerInstanceID: "server-1", SubjectType: domain.SCUMProjectionSubjectPlayer})
if err != nil || len(positions) != 1 || !positions[0].HasCoordinates {
t.Fatalf("unexpected reloaded positions=%+v err=%v", positions, err)
}
}