internal/app/state: include et header
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m17s
Test / Hakurei (push) Successful in 3m5s
Test / Hpkg (push) Successful in 3m55s
Test / Sandbox (race detector) (push) Successful in 4m2s
Test / Hakurei (race detector) (push) Successful in 4m49s
Test / Flake checks (push) Successful in 1m22s
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m17s
Test / Hakurei (push) Successful in 3m5s
Test / Hpkg (push) Successful in 3m55s
Test / Sandbox (race detector) (push) Successful in 4m2s
Test / Hakurei (race detector) (push) Successful in 4m49s
Test / Flake checks (push) Successful in 1m22s
This is the initial step of implementing #19. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -117,7 +117,7 @@ type multiBackend struct {
|
|||||||
|
|
||||||
func (b *multiBackend) filename(id *hst.ID) string { return path.Join(b.path, id.String()) }
|
func (b *multiBackend) filename(id *hst.ID) string { return path.Join(b.path, id.String()) }
|
||||||
|
|
||||||
// reads all launchers in simpleBackend
|
// reads all launchers in multiBackend
|
||||||
// file contents are ignored if decode is false
|
// file contents are ignored if decode is false
|
||||||
func (b *multiBackend) load(decode bool) (map[hst.ID]*hst.State, error) {
|
func (b *multiBackend) load(decode bool) (map[hst.ID]*hst.State, error) {
|
||||||
b.mu.RLock()
|
b.mu.RLock()
|
||||||
@@ -161,18 +161,22 @@ func (b *multiBackend) load(decode bool) (map[hst.ID]*hst.State, error) {
|
|||||||
|
|
||||||
// append regardless, but only parse if required, implements Len
|
// append regardless, but only parse if required, implements Len
|
||||||
if decode {
|
if decode {
|
||||||
if err = gob.NewDecoder(f).Decode(&s); err != nil {
|
var et hst.Enablement
|
||||||
|
if et, err = entryReadHeader(f); err != nil {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return &hst.AppError{Step: "decode state data", Err: err}
|
return &hst.AppError{Step: "decode state header", Err: err}
|
||||||
|
} else if err = gob.NewDecoder(f).Decode(&s); err != nil {
|
||||||
|
_ = f.Close()
|
||||||
|
return &hst.AppError{Step: "decode state body", Err: err}
|
||||||
} else if s.ID != id {
|
} else if s.ID != id {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return fmt.Errorf("state entry %s has unexpected id %s", id, &s.ID)
|
return fmt.Errorf("state entry %s has unexpected id %s", id, &s.ID)
|
||||||
} else if err = f.Close(); err != nil {
|
} else if err = f.Close(); err != nil {
|
||||||
return &hst.AppError{Step: "close state file", Err: err}
|
return &hst.AppError{Step: "close state file", Err: err}
|
||||||
}
|
} else if err = s.Config.Validate(); err != nil {
|
||||||
|
return err
|
||||||
if s.Config == nil {
|
} else if s.Enablements.Unwrap() != et {
|
||||||
return ErrNoConfig
|
return fmt.Errorf("state entry %s has unexpected enablement byte %x, %x", id, s.Enablements, et)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,22 +190,24 @@ func (b *multiBackend) load(decode bool) (map[hst.ID]*hst.State, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save writes process state to filesystem
|
// Save writes process state to filesystem.
|
||||||
func (b *multiBackend) Save(state *hst.State) error {
|
func (b *multiBackend) Save(state *hst.State) error {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
if state.Config == nil {
|
if err := state.Config.Validate(); err != nil {
|
||||||
return ErrNoConfig
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
statePath := b.filename(&state.ID)
|
statePath := b.filename(&state.ID)
|
||||||
|
|
||||||
if f, err := os.OpenFile(statePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600); err != nil {
|
if f, err := os.OpenFile(statePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600); err != nil {
|
||||||
return &hst.AppError{Step: "create state file", Err: err}
|
return &hst.AppError{Step: "create state file", Err: err}
|
||||||
|
} else if err = entryWriteHeader(f, state.Enablements.Unwrap()); err != nil {
|
||||||
|
_ = f.Close()
|
||||||
|
return &hst.AppError{Step: "encode state header", Err: err}
|
||||||
} else if err = gob.NewEncoder(f).Encode(state); err != nil {
|
} else if err = gob.NewEncoder(f).Encode(state); err != nil {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return &hst.AppError{Step: "encode state data", Err: err}
|
return &hst.AppError{Step: "encode state body", Err: err}
|
||||||
} else if err = f.Close(); err != nil {
|
} else if err = f.Close(); err != nil {
|
||||||
return &hst.AppError{Step: "close state file", Err: err}
|
return &hst.AppError{Step: "close state file", Err: err}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,9 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoConfig is returned by [Cursor] when used with a nil [hst.Config].
|
|
||||||
var ErrNoConfig = errors.New("state does not contain config")
|
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Do calls f exactly once and ensures store exclusivity until f returns.
|
// Do calls f exactly once and ensures store exclusivity until f returns.
|
||||||
// Returns whether f is called and any errors during the locking process.
|
// Returns whether f is called and any errors during the locking process.
|
||||||
|
|||||||
Reference in New Issue
Block a user