110 lines
1.9 KiB
Go
110 lines
1.9 KiB
Go
package playback
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
)
|
|
|
|
type PlaylistController struct {
|
|
playlist Playlist
|
|
retry RetryPolicy
|
|
sessions chan<- SessionCommand
|
|
|
|
mu sync.RWMutex
|
|
snapshot PlaylistSnapshot
|
|
hasSnapshot bool
|
|
}
|
|
|
|
type PlaylistSnapshot struct {
|
|
State PlaylistState
|
|
Entry PlaylistEntry
|
|
Revision uint64
|
|
}
|
|
|
|
var (
|
|
ErrNilSessionCommandChannel = errors.New("session-command channel is nil")
|
|
)
|
|
|
|
func NewPlaylistController(
|
|
playlist Playlist,
|
|
retry RetryPolicy,
|
|
sessions chan<- SessionCommand,
|
|
) (*PlaylistController, error) {
|
|
if err := playlist.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := retry.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
if sessions == nil {
|
|
return nil, ErrNilSessionCommandChannel
|
|
}
|
|
return &PlaylistController{
|
|
playlist: playlist,
|
|
retry: retry,
|
|
sessions: sessions,
|
|
}, nil
|
|
}
|
|
|
|
func (c *PlaylistController) Run(
|
|
ctx context.Context,
|
|
commands <-chan PlaylistCommand,
|
|
) error {
|
|
state := PlaylistState{}
|
|
revision := uint64(0)
|
|
c.publish(state, revision)
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
|
|
case command, ok := <-commands:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
next, sessionCommand, apply, err := ApplyPlaylistSelection(
|
|
c.playlist,
|
|
state,
|
|
command,
|
|
c.retry,
|
|
)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if apply {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case c.sessions <- sessionCommand:
|
|
}
|
|
revision++
|
|
}
|
|
|
|
state = next
|
|
c.publish(state, revision)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *PlaylistController) Snapshot() (PlaylistSnapshot, bool) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return c.snapshot, c.hasSnapshot
|
|
}
|
|
|
|
func (c *PlaylistController) publish(state PlaylistState, revision uint64) {
|
|
entry, _ := state.Entry(c.playlist)
|
|
|
|
c.mu.Lock()
|
|
c.snapshot = PlaylistSnapshot{
|
|
State: state,
|
|
Entry: entry,
|
|
Revision: revision,
|
|
}
|
|
c.hasSnapshot = true
|
|
c.mu.Unlock()
|
|
}
|