diff --git a/engine/persist.go b/engine/persist.go index f815093..5170568 100644 --- a/engine/persist.go +++ b/engine/persist.go @@ -9,6 +9,16 @@ import ( "git.defalsify.org/festive/resource" ) +// RunPersisted performs a single vm execution from client input using a persisted state. +// +// State is first loaded from storage. The vm is initialized with the state and executed. The new state is then saved to storage. +// +// The resulting output of the execution will be written to the provided writer. +// +// The state is identified by the SessionId member of the Config. Before first execution, the caller must ensure that an +// initialized state actually is available for the identifier, otherwise the method will fail. +// +// It will also fail if execution by the underlying Engine fails. func RunPersisted(cfg Config, rs resource.Resource, pr persist.Persister, input []byte, w io.Writer, ctx context.Context) error { err := pr.Load(cfg.SessionId) if err != nil { @@ -24,5 +34,5 @@ func RunPersisted(cfg Config, rs resource.Resource, pr persist.Persister, input return err } } - return nil + return en.WriteResult(w, ctx) } diff --git a/persist/fs.go b/persist/fs.go index 57dbbec..85a6796 100644 --- a/persist/fs.go +++ b/persist/fs.go @@ -11,12 +11,16 @@ import ( "git.defalsify.org/festive/state" ) +// FsPersister is an implementation of Persister that saves state to the file system. type FsPersister struct { State *state.State Memory *cache.Cache dir string } +// NewFsPersister creates a new FsPersister. +// +// The filesystem store will be at the given directory. The directory must exist. func NewFsPersister(dir string) *FsPersister { fp, err := filepath.Abs(dir) if err != nil { @@ -27,29 +31,37 @@ func NewFsPersister(dir string) *FsPersister { } } +// WithContent sets a current State and Cache object. +// +// This method is normally called before Serialize / Save. func(p *FsPersister) WithContent(st *state.State, ca *cache.Cache) *FsPersister { p.State = st p.Memory = ca return p } +// GetState implements the Persister interface. func(p *FsPersister) GetState() *state.State { return p.State } +// GetState implements the Persister interface. func(p *FsPersister) GetMemory() cache.Memory { return p.Memory } +// GetState implements the Persister interface. func(p *FsPersister) Serialize() ([]byte, error) { return cbor.Marshal(p) } +// GetState implements the Persister interface. func(p *FsPersister) Deserialize(b []byte) error { err := cbor.Unmarshal(b, p) return err } +// GetState implements the Persister interface. func(p *FsPersister) Save(key string) error { b, err := p.Serialize() if err != nil { @@ -60,6 +72,7 @@ func(p *FsPersister) Save(key string) error { return ioutil.WriteFile(fp, b, 0600) } +// GetState implements the Persister interface. func(p *FsPersister) Load(key string) error { fp := path.Join(p.dir, key) b, err := ioutil.ReadFile(fp) diff --git a/persist/persist.go b/persist/persist.go index 9eb64d3..2087c43 100644 --- a/persist/persist.go +++ b/persist/persist.go @@ -5,12 +5,13 @@ import ( "git.defalsify.org/festive/state" ) +// Persister interface defines the methods needed for a component that can store the execution state to a storage location. type Persister interface { - Serialize() ([]byte, error) - Deserialize(b []byte) error - Save(key string) error - Load(key string) error - GetState() *state.State - GetMemory() cache.Memory + Serialize() ([]byte, error) // Output serializes representation of the state. + Deserialize(b []byte) error // Restore state from a serialized state. + Save(key string) error // Serialize and commit the state representation to persisted storage. + Load(key string) error // Load the state representation from persisted storage and Deserialize. + GetState() *state.State // Get the currently loaded State object. + GetMemory() cache.Memory // Get the currently loaded Cache object. } diff --git a/resource/resource.go b/resource/resource.go index ee1bfed..106dd46 100644 --- a/resource/resource.go +++ b/resource/resource.go @@ -4,10 +4,11 @@ import ( "context" ) +// Result contains the results of an external code operation. type Result struct { - Content string - FlagSet []uint32 - FlagReset []uint32 + Content string // content value for symbol after execution. + FlagSet []uint32 // request caller to set error flags at given indices. + FlagReset []uint32 // request caller to reset error flags at given indices. } // EntryFunc is a function signature for retrieving value for a key @@ -23,6 +24,9 @@ type Resource interface { FuncFor(sym string) (EntryFunc, error) // Resolve symbol content point for. } +// MenuResource contains the base definition for building Resource implementations. +// +// TODO: Rename to BaseResource type MenuResource struct { sinkValues []string codeFunc CodeFunc @@ -53,14 +57,17 @@ func(m *MenuResource) WithTemplateGetter(templateGetter TemplateFunc) *MenuResou return m } +// FuncFor implements Resource interface func(m *MenuResource) FuncFor(sym string) (EntryFunc, error) { return m.funcFunc(sym) } +// GetCode implements Resource interface func(m *MenuResource) GetCode(sym string) ([]byte, error) { return m.codeFunc(sym) } +// GetTemplate implements Resource interface func(m *MenuResource) GetTemplate(sym string) (string, error) { return m.templateFunc(sym) }