first commit

This commit is contained in:
npc0-hue
2026-07-11 14:56:10 +08:00
commit 7e05d0a4e7
660 changed files with 78119 additions and 0 deletions
+315
View File
@@ -0,0 +1,315 @@
package repo
import (
"errors"
"sort"
"sync"
"browser.local/platform/domain"
)
var (
ErrDuplicate = errors.New("resource already exists")
ErrNotFound = errors.New("resource not found")
)
type UserRepository interface {
Create(domain.User) error
Get(id string) (domain.User, error)
List(domain.UserFilter) ([]domain.User, error)
Update(domain.User) error
}
type AIProviderRepository interface {
Create(domain.AIProvider) error
Get(id string) (domain.AIProvider, error)
List(domain.AIProviderFilter) ([]domain.AIProvider, error)
Update(domain.AIProvider) error
}
type GamePluginRepository interface {
Create(domain.GamePlugin) error
Get(id string) (domain.GamePlugin, error)
List(domain.GamePluginFilter) ([]domain.GamePlugin, error)
Update(domain.GamePlugin) error
}
type ServerInstanceRepository interface {
Create(domain.ServerInstance) error
Get(id string) (domain.ServerInstance, error)
List(domain.ServerInstanceFilter) ([]domain.ServerInstance, error)
Update(domain.ServerInstance) error
}
type RunEndpointRepository interface {
Create(domain.RunEndpoint) error
Get(id string) (domain.RunEndpoint, error)
List(domain.RunEndpointFilter) ([]domain.RunEndpoint, error)
Update(domain.RunEndpoint) error
}
type JobRepository interface {
Create(domain.Job) error
Get(id string) (domain.Job, error)
GetByIdempotency(runEndpointID string, idempotencyKey string) (domain.Job, error)
List(domain.JobFilter) ([]domain.Job, error)
Update(domain.Job) error
}
type ArtifactRepository interface {
Create(domain.Artifact) error
Get(id string) (domain.Artifact, error)
List(domain.ArtifactFilter) ([]domain.Artifact, error)
Update(domain.Artifact) error
}
type LogStreamRepository interface {
Create(domain.LogStream) error
Get(id string) (domain.LogStream, error)
List(domain.LogStreamFilter) ([]domain.LogStream, error)
Update(domain.LogStream) error
}
type AuditEventRepository interface {
Create(domain.AuditEvent) error
Get(id string) (domain.AuditEvent, error)
List(domain.AuditEventFilter) ([]domain.AuditEvent, error)
Update(domain.AuditEvent) error
}
type Store interface {
Users() UserRepository
AIProviders() AIProviderRepository
GamePlugins() GamePluginRepository
ServerInstances() ServerInstanceRepository
RunEndpoints() RunEndpointRepository
Jobs() JobRepository
Artifacts() ArtifactRepository
LogStreams() LogStreamRepository
AuditEvents() AuditEventRepository
}
type MemoryStore struct {
users *memoryRepository[domain.User, domain.UserFilter]
aiProviders *memoryRepository[domain.AIProvider, domain.AIProviderFilter]
gamePlugins *memoryRepository[domain.GamePlugin, domain.GamePluginFilter]
serverInstances *memoryRepository[domain.ServerInstance, domain.ServerInstanceFilter]
runEndpoints *memoryRepository[domain.RunEndpoint, domain.RunEndpointFilter]
jobs *memoryJobRepository
artifacts *memoryRepository[domain.Artifact, domain.ArtifactFilter]
logStreams *memoryRepository[domain.LogStream, domain.LogStreamFilter]
auditEvents *memoryRepository[domain.AuditEvent, domain.AuditEventFilter]
}
func NewMemoryStore() *MemoryStore {
return &MemoryStore{
users: newMemoryRepository(
func(user domain.User) string { return user.ID },
domain.CopyUser,
matchUser,
),
aiProviders: newMemoryRepository(
func(provider domain.AIProvider) string { return provider.ID },
domain.CopyAIProvider,
matchAIProvider,
),
gamePlugins: newMemoryRepository(
func(plugin domain.GamePlugin) string { return plugin.ID },
domain.CopyGamePlugin,
matchGamePlugin,
),
serverInstances: newMemoryRepository(
func(instance domain.ServerInstance) string { return instance.ID },
domain.CopyServerInstance,
matchServerInstance,
),
runEndpoints: newMemoryRepository(
func(endpoint domain.RunEndpoint) string { return endpoint.ID },
domain.CopyRunEndpoint,
matchRunEndpoint,
),
jobs: newMemoryJobRepository(),
artifacts: newMemoryRepository(
func(artifact domain.Artifact) string { return artifact.ID },
domain.CopyArtifact,
matchArtifact,
),
logStreams: newMemoryRepository(
func(stream domain.LogStream) string { return stream.ID },
domain.CopyLogStream,
matchLogStream,
),
auditEvents: newMemoryRepository(
func(event domain.AuditEvent) string { return event.ID },
domain.CopyAuditEvent,
matchAuditEvent,
),
}
}
func (store *MemoryStore) Users() UserRepository { return store.users }
func (store *MemoryStore) AIProviders() AIProviderRepository { return store.aiProviders }
func (store *MemoryStore) GamePlugins() GamePluginRepository { return store.gamePlugins }
func (store *MemoryStore) ServerInstances() ServerInstanceRepository { return store.serverInstances }
func (store *MemoryStore) RunEndpoints() RunEndpointRepository { return store.runEndpoints }
func (store *MemoryStore) Jobs() JobRepository { return store.jobs }
func (store *MemoryStore) Artifacts() ArtifactRepository { return store.artifacts }
func (store *MemoryStore) LogStreams() LogStreamRepository { return store.logStreams }
func (store *MemoryStore) AuditEvents() AuditEventRepository { return store.auditEvents }
type memoryRepository[T any, F any] struct {
mu sync.RWMutex
byID map[string]T
idOf func(T) string
copyOf func(T) T
match func(T, F) bool
}
func newMemoryRepository[T any, F any](idOf func(T) string, copyOf func(T) T, match func(T, F) bool) *memoryRepository[T, F] {
return &memoryRepository[T, F]{
byID: map[string]T{},
idOf: idOf,
copyOf: copyOf,
match: match,
}
}
func (repository *memoryRepository[T, F]) Create(value T) error {
repository.mu.Lock()
defer repository.mu.Unlock()
id := repository.idOf(value)
if _, exists := repository.byID[id]; exists {
return ErrDuplicate
}
repository.byID[id] = repository.copyOf(value)
return nil
}
func (repository *memoryRepository[T, F]) Get(id string) (T, error) {
repository.mu.RLock()
defer repository.mu.RUnlock()
value, exists := repository.byID[id]
if !exists {
var zero T
return zero, ErrNotFound
}
return repository.copyOf(value), nil
}
func (repository *memoryRepository[T, F]) List(filter F) ([]T, error) {
repository.mu.RLock()
defer repository.mu.RUnlock()
ids := make([]string, 0, len(repository.byID))
for id := range repository.byID {
ids = append(ids, id)
}
sort.Strings(ids)
values := make([]T, 0, len(ids))
for _, id := range ids {
value := repository.byID[id]
if repository.match(value, filter) {
values = append(values, repository.copyOf(value))
}
}
return values, nil
}
func (repository *memoryRepository[T, F]) Update(value T) error {
repository.mu.Lock()
defer repository.mu.Unlock()
id := repository.idOf(value)
if _, exists := repository.byID[id]; !exists {
return ErrNotFound
}
repository.byID[id] = repository.copyOf(value)
return nil
}
type memoryJobRepository struct {
*memoryRepository[domain.Job, domain.JobFilter]
}
func newMemoryJobRepository() *memoryJobRepository {
return &memoryJobRepository{
memoryRepository: newMemoryRepository(
func(job domain.Job) string { return job.ID },
domain.CopyJob,
matchJob,
),
}
}
func (repository *memoryJobRepository) GetByIdempotency(runEndpointID string, idempotencyKey string) (domain.Job, error) {
repository.mu.RLock()
defer repository.mu.RUnlock()
for _, job := range repository.byID {
if job.RunEndpointID == runEndpointID && job.IdempotencyKey == idempotencyKey {
return domain.CopyJob(job), nil
}
}
return domain.Job{}, ErrNotFound
}
func matchUser(user domain.User, filter domain.UserFilter) bool {
return filter.Status == "" || user.Status == filter.Status
}
func matchAIProvider(provider domain.AIProvider, filter domain.AIProviderFilter) bool {
return (filter.Kind == "" || provider.Kind == filter.Kind) &&
(filter.Status == "" || provider.Status == filter.Status)
}
func matchGamePlugin(plugin domain.GamePlugin, filter domain.GamePluginFilter) bool {
return (filter.ServerType == "" || plugin.ServerType == filter.ServerType) &&
(filter.Status == "" || plugin.Status == filter.Status)
}
func matchServerInstance(instance domain.ServerInstance, filter domain.ServerInstanceFilter) bool {
return (filter.PluginID == "" || instance.PluginID == filter.PluginID) &&
(filter.RunEndpointID == "" || instance.RunEndpointID == filter.RunEndpointID) &&
(filter.State == "" || instance.State == filter.State) &&
(filter.VisibleToUserID == "" || instance.OwnerUserID == filter.VisibleToUserID || containsString(instance.AdminUserIDs, filter.VisibleToUserID))
}
func containsString(values []string, target string) bool {
for _, value := range values {
if value == target {
return true
}
}
return false
}
func matchRunEndpoint(endpoint domain.RunEndpoint, filter domain.RunEndpointFilter) bool {
return filter.Status == "" || endpoint.Status == filter.Status
}
func matchJob(job domain.Job, filter domain.JobFilter) bool {
return (filter.ServerInstanceID == "" || job.ServerInstanceID == filter.ServerInstanceID) &&
(filter.RunEndpointID == "" || job.RunEndpointID == filter.RunEndpointID) &&
(filter.State == "" || job.State == filter.State)
}
func matchArtifact(artifact domain.Artifact, filter domain.ArtifactFilter) bool {
return (filter.OwnerKind == "" || artifact.OwnerKind == filter.OwnerKind) &&
(filter.OwnerID == "" || artifact.OwnerID == filter.OwnerID) &&
(filter.State == "" || artifact.State == filter.State)
}
func matchLogStream(stream domain.LogStream, filter domain.LogStreamFilter) bool {
return (filter.ServerInstanceID == "" || stream.ServerInstanceID == filter.ServerInstanceID) &&
(filter.StreamKey == "" || stream.StreamKey == filter.StreamKey)
}
func matchAuditEvent(event domain.AuditEvent, filter domain.AuditEventFilter) bool {
return (filter.ActorID == "" || event.ActorID == filter.ActorID) &&
(filter.ResourceKind == "" || event.ResourceKind == filter.ResourceKind) &&
(filter.ResourceID == "" || event.ResourceID == filter.ResourceID) &&
(filter.Result == "" || event.Result == filter.Result)
}