-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprovider.go
More file actions
142 lines (117 loc) · 4.88 KB
/
provider.go
File metadata and controls
142 lines (117 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package pecs
import (
"context"
"reflect"
"time"
)
// Provider is the base interface for all data providers.
// Providers bridge PECS with external data sources (gRPC services, databases, etc.).
type Provider interface {
// Name returns a unique identifier for this provider (for logging/debugging).
Name() string
}
// PeerProvider fetches and syncs per-player data for Peer[T] resolution.
// Implement this interface to enable cross-server player data access.
type PeerProvider interface {
Provider
// PlayerComponents returns the component types this provider handles.
// PECS will only call this provider for Peer[T] where T is in this list.
PlayerComponents() []reflect.Type
// FetchPlayer retrieves components for a single player.
// Returns nil (not error) if the player doesn't exist.
FetchPlayer(ctx context.Context, playerID string) ([]any, error)
// FetchPlayers batch-fetches components for multiple players.
// Returns a map of playerID -> components.
// Missing players should be omitted from the map (not nil values).
FetchPlayers(ctx context.Context, playerIDs []string) (map[string][]any, error)
// SubscribePlayer starts receiving real-time updates for a player.
// Updates should be sent to the channel until the subscription is closed.
// Return an error if the player doesn't exist or subscription fails.
SubscribePlayer(ctx context.Context, playerID string, updates chan<- PlayerUpdate) (Subscription, error)
}
// SharedProvider fetches and syncs shared entity data for Shared[T] resolution.
// Implement this interface for data shared across multiple players (parties, matches, etc.).
type SharedProvider interface {
Provider
// EntityComponents returns the component types this provider handles.
// PECS will only call this provider for Shared[T] where T is in this list.
EntityComponents() []reflect.Type
// FetchEntity retrieves a shared entity by ID.
// Returns nil (not error) if the entity doesn't exist.
FetchEntity(ctx context.Context, entityID string) (any, error)
// FetchEntities batch-fetches components for multiple entities.
// Returns a map of entityID -> component.
// Missing entities should be omitted from the map.
FetchEntities(ctx context.Context, entityIDs []string) (map[string]any, error)
// SubscribeEntity starts receiving real-time updates for an entity.
// Updates should be sent to the channel until the subscription is closed.
// Return an error if the entity doesn't exist or subscription fails.
SubscribeEntity(ctx context.Context, entityID string, updates chan<- any) (Subscription, error)
}
// PlayerUpdate represents an update to a player's component from a provider.
type PlayerUpdate struct {
// ComponentType is the type of component being updated.
ComponentType reflect.Type
// Data is a pointer to the new component data.
// If nil, the component should be removed.
Data any
}
// Subscription represents an active subscription to updates.
// Call Close() to stop receiving updates and release resources.
type Subscription interface {
Close() error
}
// ProviderOptions configures provider behavior.
type ProviderOptions struct {
// FetchTimeout is the maximum time to wait for Fetch calls.
// Default: 5 seconds.
FetchTimeout time.Duration
// GracePeriod is how long to keep cached data after the last reference is released.
// This prevents thrashing when players rapidly reference/dereference the same target.
// Default: 30 seconds.
GracePeriod time.Duration
// StaleTimeout defines when cached data is considered too old to use.
// If a subscription fails and data is older than this, resolution fails.
// Default: 5 minutes.
StaleTimeout time.Duration
// Required indicates this provider must succeed for session creation.
// If true, NewSession returns an error if this provider fails.
// If false, provider failures are logged but session creation continues.
// Default: false.
Required bool
}
// defaultProviderOptions returns sensible defaults.
func defaultProviderOptions() ProviderOptions {
return ProviderOptions{
FetchTimeout: 5 * time.Second,
GracePeriod: 30 * time.Second,
StaleTimeout: 5 * time.Minute,
}
}
// ProviderOption configures a provider.
type ProviderOption func(*ProviderOptions)
// WithFetchTimeout sets the fetch timeout.
func WithFetchTimeout(d time.Duration) ProviderOption {
return func(o *ProviderOptions) {
o.FetchTimeout = d
}
}
// WithGracePeriod sets the grace period.
func WithGracePeriod(d time.Duration) ProviderOption {
return func(o *ProviderOptions) {
o.GracePeriod = d
}
}
// WithStaleTimeout sets the stale timeout.
func WithStaleTimeout(d time.Duration) ProviderOption {
return func(o *ProviderOptions) {
o.StaleTimeout = d
}
}
// WithRequired marks the provider as required for session creation.
// If a required provider fails during NewSession, the session creation fails.
func WithRequired(required bool) ProviderOption {
return func(o *ProviderOptions) {
o.Required = required
}
}