Brian Picciano
8c3e6a2845
In a world where the daemon can manage more than one network, the Daemon is really responsible only for knowing which networks are currently joined, creating/joining/leaving networks, and routing incoming RPC requests to the correct network handler as needed. The new network package, with its Network interface, inherits most of the logic that Daemon used to have, leaving Daemon only the parts needed for the functionality just described. There's a lot of cleanup done here in order to really nail down the separation of concerns between the two, especially around directory creation.
81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
package secrets
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type fsStore struct {
|
|
dirPath string
|
|
}
|
|
|
|
type fsStorePayload[Body any] struct {
|
|
Version int
|
|
Body Body
|
|
}
|
|
|
|
// NewFSStore returns a Store which will store secrets to the given directory.
|
|
// The directory must already exist.
|
|
func NewFSStore(dirPath string) Store {
|
|
return &fsStore{dirPath}
|
|
}
|
|
|
|
func (s *fsStore) path(id ID) string {
|
|
return filepath.Join(s.dirPath, string(id))
|
|
}
|
|
|
|
func (s *fsStore) Set(_ context.Context, id ID, payload any) error {
|
|
path := s.path(id)
|
|
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
return fmt.Errorf("creating file %q: %w", path, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
if err := json.NewEncoder(f).Encode(fsStorePayload[any]{
|
|
Version: 1,
|
|
Body: payload,
|
|
}); err != nil {
|
|
return fmt.Errorf("writing JSON encoded payload to %q: %w", path, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *fsStore) Get(_ context.Context, into any, id ID) error {
|
|
path := s.path(id)
|
|
|
|
f, err := os.Open(path)
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return fmt.Errorf("creating file %q: %w", path, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
var fullPayload fsStorePayload[json.RawMessage]
|
|
if err := json.NewDecoder(f).Decode(&fullPayload); err != nil {
|
|
return fmt.Errorf("decoding JSON payload from %q: %w", path, err)
|
|
}
|
|
|
|
if fullPayload.Version != 1 {
|
|
return fmt.Errorf(
|
|
"unexpected JSON payload version %d", fullPayload.Version,
|
|
)
|
|
}
|
|
|
|
if err := json.Unmarshal(fullPayload.Body, into); err != nil {
|
|
return fmt.Errorf(
|
|
"decoding JSON payload body from %q into %T: %w", path, into, err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|