go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

persist.go (2404B)


      1 package engine
      2 
      3 import (
      4 	"context"
      5 	"io"
      6 
      7 	"git.defalsify.org/vise.git/persist"
      8 	"git.defalsify.org/vise.git/resource"
      9 )
     10 
     11 // PersistedEngine adds persisted state to the Engine object. It provides a persisted state option for synchronous/interactive clients.
     12 type PersistedEngine struct {
     13 	*Engine
     14 	pr persist.Persister
     15 }
     16 
     17 
     18 // NewPersistedEngine creates a new PersistedEngine
     19 func NewPersistedEngine(ctx context.Context, cfg Config, pr persist.Persister, rs resource.Resource) (PersistedEngine, error) {
     20 	err := pr.Load(cfg.SessionId)
     21 	if err != nil {
     22 		return PersistedEngine{}, err
     23 	}
     24 	st := pr.GetState()
     25 	ca := pr.GetMemory()
     26 	
     27 	enb := NewEngine(ctx, cfg, st, rs, ca)
     28 	en := PersistedEngine{
     29 		&enb,
     30 		pr,
     31 	}
     32 	return en, err
     33 }
     34 
     35 // Exec executes the parent method Engine.Exec, and afterwards persists the new state.
     36 func(pe PersistedEngine) Exec(ctx context.Context, input []byte) (bool, error) {
     37 	v, err := pe.Engine.Exec(ctx, input)
     38 	if err != nil {
     39 		return v, err
     40 	}
     41 	err = pe.pr.Save(pe.Engine.session)
     42 	return v, err
     43 }
     44 
     45 // Finish implements EngineIsh interface
     46 func(pe PersistedEngine) Finish() error {
     47 	Logg.Tracef("that's a wrap", "engine", pe)
     48 	return pe.pr.Save(pe.Engine.session)
     49 }
     50 
     51 // RunPersisted performs a single vm execution from client input using a persisted state.
     52 //
     53 // State is first loaded from storage. The vm is initialized with the state and executed. The new state is then saved to storage.
     54 //
     55 // The resulting output of the execution will be written to the provided writer.
     56 //
     57 // The state is identified by the SessionId member of the Config. Before first execution, the caller must ensure that an
     58 // initialized state actually is available for the identifier, otherwise the method will fail.
     59 //
     60 // It will also fail if execution by the underlying Engine fails.
     61 func RunPersisted(cfg Config, rs resource.Resource, pr persist.Persister, input []byte, w io.Writer, ctx context.Context) error {
     62 	err := pr.Load(cfg.SessionId)
     63 	if err != nil {
     64 		return err
     65 	}
     66 
     67 	st := pr.GetState()
     68 	ca := pr.GetMemory()
     69 	en := NewEngine(ctx, cfg, st, rs, ca)
     70 
     71 	c, err := en.WriteResult(ctx, w)
     72 	if err != nil {
     73 		return err
     74 	}
     75 	err = pr.Save(cfg.SessionId)
     76 	if err != nil {
     77 		return err
     78 	}
     79 	if c > 0 {
     80 		return err
     81 	}
     82 
     83 	_, err = en.Exec(ctx, input)
     84 	if err != nil {
     85 		return err
     86 	}
     87 	_, err = en.WriteResult(ctx, w)
     88 	if err != nil {
     89 		return err
     90 	}
     91 	en.Finish()
     92 	return pr.Save(cfg.SessionId)
     93 }