package profileinstance import ( "fmt" "time" "gfx.cafe/util/go/generic" "github.com/rs/xid" "github.com/spf13/afero" ) type InstanceStore interface { NewInstance(xs []byte) (*Instance, error) GetInstance(id xid.ID) (*Instance, error) } type fileBasedInstanceStore struct { expiry time.Duration fs afero.Fs cache generic.Map[xid.ID, *Instance] } func NewFileBasedInstanceStore(fs afero.Fs, expiry time.Duration) *fileBasedInstanceStore { return &fileBasedInstanceStore{ fs: fs, expiry: expiry, } } func (o *fileBasedInstanceStore) NewInstance(xs []byte) (*Instance, error) { // save instance id := xid.New() i := &Instance{ id: id, dat: xs, } file, err := o.fs.Create(id.String()) if err != nil { return nil, err } _, err = file.Write(xs) if err != nil { file.Close() return nil, err } err = file.Close() if err != nil { return nil, err } err = i.startServer() if err != nil { return nil, err } o.cache.Store(id, i) return i, nil } func (o *fileBasedInstanceStore) GetInstance(id xid.ID) (*Instance, error) { if i, ok := o.cache.Load(id); ok { return i, nil } if o.expiry > 0 { if id.Time().After(time.Now().Add(o.expiry)) { o.fs.Remove(id.String()) return nil, fmt.Errorf("profile expired") } } bts, err := afero.ReadFile(o.fs, id.String()) if err != nil { return nil, err } i := &Instance{id: id, dat: bts} err = i.startServer() if err != nil { return nil, err } o.cache.Store(id, i) return i, nil }