pprofweb/pkg/profileinstance/instancestore.go

82 lines
1.5 KiB
Go

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
}