refactor(ax): make public docs example-driven
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
41dd111072
commit
16d968b551
11 changed files with 93 additions and 88 deletions
|
|
@ -36,7 +36,10 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// Medium is an in-memory storage backend backed by a Borg DataNode.
|
||||
// Example: medium := datanode.New()
|
||||
// _ = medium.Write("jobs/run.log", "started")
|
||||
// snapshot, _ := medium.Snapshot()
|
||||
//
|
||||
// All paths are relative (no leading slash). Thread-safe via RWMutex.
|
||||
type Medium struct {
|
||||
dataNode *borgdatanode.DataNode
|
||||
|
|
@ -44,10 +47,8 @@ type Medium struct {
|
|||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// New creates an in-memory Medium that snapshots to tar.
|
||||
//
|
||||
// medium := datanode.New()
|
||||
// _ = medium.Write("jobs/run.log", "started")
|
||||
// Example: medium := datanode.New()
|
||||
// _ = medium.Write("jobs/run.log", "started")
|
||||
func New() *Medium {
|
||||
return &Medium{
|
||||
dataNode: borgdatanode.New(),
|
||||
|
|
|
|||
33
io.go
33
io.go
|
|
@ -10,16 +10,18 @@ import (
|
|||
"dappco.re/go/core/io/local"
|
||||
)
|
||||
|
||||
// Medium defines the standard interface for a storage backend.
|
||||
// This allows for different implementations (e.g., local disk, S3, SFTP)
|
||||
// to be used interchangeably.
|
||||
// Medium is the storage boundary used across CoreGO.
|
||||
//
|
||||
// medium, _ := io.NewSandboxed("/srv/app")
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
// backup, _ := io.NewSandboxed("/srv/backup")
|
||||
// _ = io.Copy(medium, "data/report.json", backup, "daily/report.json")
|
||||
type Medium interface {
|
||||
Read(path string) (string, error)
|
||||
|
||||
Write(path, content string) error
|
||||
|
||||
// WriteMode saves content with explicit file permissions.
|
||||
// Use 0600 for sensitive files (keys, secrets, encrypted output).
|
||||
// Example: _ = medium.WriteMode("keys/private.key", key, 0600)
|
||||
WriteMode(path, content string, mode fs.FileMode) error
|
||||
|
||||
EnsureDir(path string) error
|
||||
|
|
@ -46,18 +48,16 @@ type Medium interface {
|
|||
|
||||
Append(path string) (goio.WriteCloser, error)
|
||||
|
||||
// ReadStream returns a reader for the file content.
|
||||
// Use this for large files to avoid loading the entire content into memory.
|
||||
// Example: reader, _ := medium.ReadStream("logs/app.log")
|
||||
ReadStream(path string) (goio.ReadCloser, error)
|
||||
|
||||
// WriteStream returns a writer for the file content.
|
||||
// Use this for large files to avoid loading the entire content into memory.
|
||||
// Example: writer, _ := medium.WriteStream("logs/app.log")
|
||||
WriteStream(path string) (goio.WriteCloser, error)
|
||||
|
||||
// Exists checks if a path exists (file or directory).
|
||||
// Example: ok := medium.Exists("config/app.yaml")
|
||||
Exists(path string) bool
|
||||
|
||||
// IsDir checks if a path exists and is a directory.
|
||||
// Example: ok := medium.IsDir("config")
|
||||
IsDir(path string) bool
|
||||
}
|
||||
|
||||
|
|
@ -98,9 +98,9 @@ func (de DirEntry) Type() fs.FileMode { return de.mode.Type() }
|
|||
|
||||
func (de DirEntry) Info() (fs.FileInfo, error) { return de.info, nil }
|
||||
|
||||
// Local is a pre-initialised medium for the local filesystem.
|
||||
// It uses "/" as root, providing unsandboxed access to the filesystem.
|
||||
// For sandboxed access, use NewSandboxed with a specific root path.
|
||||
// Local is the unsandboxed filesystem medium rooted at "/".
|
||||
//
|
||||
// io.Local.Read("/etc/hostname")
|
||||
var Local Medium
|
||||
|
||||
var _ Medium = (*local.Medium)(nil)
|
||||
|
|
@ -171,7 +171,10 @@ func Copy(source Medium, sourcePath string, destination Medium, destinationPath
|
|||
|
||||
// --- MockMedium ---
|
||||
|
||||
// MockMedium is an in-memory implementation of Medium for testing.
|
||||
// MockMedium is an in-memory Medium for tests.
|
||||
//
|
||||
// medium := io.NewMockMedium()
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
type MockMedium struct {
|
||||
Files map[string]string
|
||||
Dirs map[string]bool
|
||||
|
|
|
|||
|
|
@ -13,16 +13,15 @@ import (
|
|||
core "dappco.re/go/core"
|
||||
)
|
||||
|
||||
// Medium is a local filesystem storage backend.
|
||||
// Medium is the local filesystem backend returned by New.
|
||||
type Medium struct {
|
||||
filesystemRoot string
|
||||
}
|
||||
|
||||
var unrestrictedFileSystem = (&core.Fs{}).NewUnrestricted()
|
||||
|
||||
// New creates a filesystem rooted at root.
|
||||
//
|
||||
// Pass "/" for full filesystem access, or a project path to sandbox.
|
||||
// local.New("/") exposes the full filesystem.
|
||||
// local.New("/srv/app") confines access to a project root.
|
||||
//
|
||||
// medium, _ := local.New("/srv/app")
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
|
|
|
|||
16
node/node.go
16
node/node.go
|
|
@ -23,7 +23,11 @@ import (
|
|||
coreio "dappco.re/go/core/io"
|
||||
)
|
||||
|
||||
// Node is an in-memory filesystem that satisfies coreio.Medium and fs.FS.
|
||||
// Example: nodeTree := node.New()
|
||||
// nodeTree.AddData("config/app.yaml", []byte("port: 8080"))
|
||||
// snapshot, _ := nodeTree.ToTar()
|
||||
// restored, _ := node.FromTar(snapshot)
|
||||
//
|
||||
// Directories are implicit: they exist whenever a file path contains a "/".
|
||||
type Node struct {
|
||||
files map[string]*dataFile
|
||||
|
|
@ -33,10 +37,8 @@ type Node struct {
|
|||
var _ coreio.Medium = (*Node)(nil)
|
||||
var _ fs.ReadFileFS = (*Node)(nil)
|
||||
|
||||
// Use New when you need an in-memory filesystem that can be snapshotted.
|
||||
//
|
||||
// nodeTree := New()
|
||||
// nodeTree.AddData("config/app.yaml", []byte("port: 8080"))
|
||||
// Example: nodeTree := node.New()
|
||||
// nodeTree.AddData("config/app.yaml", []byte("port: 8080"))
|
||||
func New() *Node {
|
||||
return &Node{files: make(map[string]*dataFile)}
|
||||
}
|
||||
|
|
@ -135,7 +137,7 @@ func (n *Node) WalkNode(root string, fn fs.WalkDirFunc) error {
|
|||
return fs.WalkDir(n, root, fn)
|
||||
}
|
||||
|
||||
// WalkOptions configures WalkWithOptions.
|
||||
// Example: options := node.WalkOptions{MaxDepth: 1, SkipErrors: true}
|
||||
type WalkOptions struct {
|
||||
// MaxDepth limits how many directory levels to descend. 0 means unlimited.
|
||||
MaxDepth int
|
||||
|
|
@ -380,7 +382,7 @@ func (n *Node) FileSet(filePath, content string) error {
|
|||
return n.Write(filePath, content)
|
||||
}
|
||||
|
||||
// EnsureDir is a no-op because directories are implicit in Node.
|
||||
// Example: _ = nodeTree.EnsureDir("config")
|
||||
func (n *Node) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
37
s3/s3.go
37
s3/s3.go
|
|
@ -33,7 +33,10 @@ type Client interface {
|
|||
CopyObject(ctx context.Context, params *awss3.CopyObjectInput, optFns ...func(*awss3.Options)) (*awss3.CopyObjectOutput, error)
|
||||
}
|
||||
|
||||
// Medium is the concrete io.Medium returned by New.
|
||||
// Medium is the S3-backed io.Medium returned by New.
|
||||
//
|
||||
// medium, _ := s3.New(s3.Options{Bucket: "backups", Client: client, Prefix: "daily/"})
|
||||
// _ = medium.Write("reports/daily.txt", "done")
|
||||
type Medium struct {
|
||||
client Client
|
||||
bucket string
|
||||
|
|
@ -42,7 +45,7 @@ type Medium struct {
|
|||
|
||||
var _ coreio.Medium = (*Medium)(nil)
|
||||
|
||||
// Options configures New.
|
||||
// Example: medium, _ := s3.New(s3.Options{Bucket: "backups", Client: client, Prefix: "daily/"})
|
||||
type Options struct {
|
||||
// Bucket is the target S3 bucket name.
|
||||
Bucket string
|
||||
|
|
@ -90,10 +93,8 @@ func normalisePrefix(prefix string) string {
|
|||
return clean
|
||||
}
|
||||
|
||||
// New opens an S3-backed medium for one bucket and optional prefix.
|
||||
//
|
||||
// medium, _ := s3.New(s3.Options{Bucket: "backups", Client: client, Prefix: "daily/"})
|
||||
// _ = medium.Write("reports/daily.txt", "done")
|
||||
// Example: medium, _ := s3.New(s3.Options{Bucket: "backups", Client: client, Prefix: "daily/"})
|
||||
// _ = medium.Write("reports/daily.txt", "done")
|
||||
func New(options Options) (*Medium, error) {
|
||||
if options.Bucket == "" {
|
||||
return nil, core.E("s3.New", "bucket name is required", nil)
|
||||
|
|
@ -167,17 +168,17 @@ func (m *Medium) Write(filePath, content string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteMode ignores the requested mode because S3 objects do not store POSIX permissions.
|
||||
// Example: _ = medium.WriteMode("keys/private.key", key, 0600)
|
||||
func (m *Medium) WriteMode(filePath, content string, _ fs.FileMode) error {
|
||||
return m.Write(filePath, content)
|
||||
}
|
||||
|
||||
// EnsureDir is a no-op for S3 (S3 has no real directories).
|
||||
// Example: _ = medium.EnsureDir("reports/2026")
|
||||
func (m *Medium) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsFile checks if a path exists and is a regular file (not a "directory" prefix).
|
||||
// Example: ok := medium.IsFile("reports/daily.txt")
|
||||
func (m *Medium) IsFile(filePath string) bool {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -218,7 +219,7 @@ func (m *Medium) Delete(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DeleteAll removes all objects under the given prefix.
|
||||
// Example: _ = medium.DeleteAll("reports/2026")
|
||||
func (m *Medium) DeleteAll(filePath string) error {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -283,7 +284,7 @@ func (m *Medium) DeleteAll(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Rename moves an object by copying then deleting the original.
|
||||
// Example: _ = medium.Rename("drafts/todo.txt", "archive/todo.txt")
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldKey := m.objectKey(oldPath)
|
||||
newKey := m.objectKey(newPath)
|
||||
|
|
@ -313,7 +314,7 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// List returns directory entries for the given path using ListObjectsV2 with delimiter.
|
||||
// Example: entries, _ := medium.List("reports")
|
||||
func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
||||
prefix := m.objectKey(filePath)
|
||||
if prefix != "" && !core.HasSuffix(prefix, "/") {
|
||||
|
|
@ -386,7 +387,7 @@ func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// Stat returns file information for the given path using HeadObject.
|
||||
// Example: info, _ := medium.Stat("reports/daily.txt")
|
||||
func (m *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -456,8 +457,7 @@ func (m *Medium) Open(filePath string) (fs.File, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Create creates or truncates the named file. Returns a writer that
|
||||
// uploads the content on Close.
|
||||
// Example: writer, _ := medium.Create("reports/daily.txt")
|
||||
func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -469,8 +469,7 @@ func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Append opens the named file for appending. It downloads the existing
|
||||
// content (if any) and re-uploads the combined content on Close.
|
||||
// Example: writer, _ := medium.Append("reports/daily.txt")
|
||||
func (m *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -514,7 +513,7 @@ func (m *Medium) WriteStream(filePath string) (goio.WriteCloser, error) {
|
|||
return m.Create(filePath)
|
||||
}
|
||||
|
||||
// Exists checks if a path exists (file or directory prefix).
|
||||
// Example: ok := medium.Exists("reports/daily.txt")
|
||||
func (m *Medium) Exists(filePath string) bool {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -546,7 +545,7 @@ func (m *Medium) Exists(filePath string) bool {
|
|||
return len(listOut.Contents) > 0 || len(listOut.CommonPrefixes) > 0
|
||||
}
|
||||
|
||||
// IsDir checks if a path exists and is a directory (has objects under it as a prefix).
|
||||
// Example: ok := medium.IsDir("reports")
|
||||
func (m *Medium) IsDir(filePath string) bool {
|
||||
key := m.objectKey(filePath)
|
||||
if key == "" {
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ func TestS3_ReadWrite_Prefix_Good(t *testing.T) {
|
|||
|
||||
func TestS3_EnsureDir_Good(t *testing.T) {
|
||||
m, _ := newTestMedium(t)
|
||||
// EnsureDir is a no-op for S3
|
||||
// Example: err := m.EnsureDir("any/path")
|
||||
err := m.EnsureDir("any/path")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,8 +207,8 @@ func (s *ShuffleMaskObfuscator) deriveMask(entropy []byte, length int) []byte {
|
|||
return mask
|
||||
}
|
||||
|
||||
// ChaChaPolySigil is returned by NewChaChaPolySigil and
|
||||
// NewChaChaPolySigilWithObfuscator.
|
||||
// Example: cipherSigil, _ := sigil.NewChaChaPolySigil(key)
|
||||
// Example: cipherSigil, _ := sigil.NewChaChaPolySigilWithObfuscator(key, &sigil.ShuffleMaskObfuscator{})
|
||||
type ChaChaPolySigil struct {
|
||||
Key []byte
|
||||
Obfuscator PreObfuscator
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ import (
|
|||
_ "modernc.org/sqlite" // Pure Go SQLite driver
|
||||
)
|
||||
|
||||
// Medium is a SQLite-backed storage backend implementing the io.Medium interface.
|
||||
// Medium stores filesystem-shaped content in SQLite.
|
||||
//
|
||||
// medium, _ := sqlite.New(sqlite.Options{Path: ":memory:"})
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
type Medium struct {
|
||||
database *sql.DB
|
||||
table string
|
||||
|
|
@ -26,7 +29,7 @@ type Medium struct {
|
|||
|
||||
var _ coreio.Medium = (*Medium)(nil)
|
||||
|
||||
// Options configures a SQLite-backed Medium.
|
||||
// Example: medium, _ := sqlite.New(sqlite.Options{Path: ":memory:", Table: "files"})
|
||||
type Options struct {
|
||||
// Path is the SQLite database path. Use ":memory:" for tests.
|
||||
Path string
|
||||
|
|
@ -41,10 +44,8 @@ func normaliseTableName(table string) string {
|
|||
return table
|
||||
}
|
||||
|
||||
// New opens a SQLite-backed Medium at the provided database path.
|
||||
//
|
||||
// medium, _ := sqlite.New(sqlite.Options{Path: ":memory:", Table: "files"})
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
// Example: medium, _ := sqlite.New(sqlite.Options{Path: ":memory:", Table: "files"})
|
||||
// _ = medium.Write("config/app.yaml", "port: 8080")
|
||||
func New(options Options) (*Medium, error) {
|
||||
if options.Path == "" {
|
||||
return nil, core.E("sqlite.New", "database path is required", nil)
|
||||
|
|
@ -125,7 +126,7 @@ func (m *Medium) Write(filePath, content string) error {
|
|||
return m.WriteMode(filePath, content, 0644)
|
||||
}
|
||||
|
||||
// WriteMode saves the given content with explicit permissions.
|
||||
// Example: _ = medium.WriteMode("keys/private.key", key, 0600)
|
||||
func (m *Medium) WriteMode(filePath, content string, mode fs.FileMode) error {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -143,7 +144,7 @@ func (m *Medium) WriteMode(filePath, content string, mode fs.FileMode) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// EnsureDir makes sure a directory exists, creating it if necessary.
|
||||
// Example: _ = medium.EnsureDir("config")
|
||||
func (m *Medium) EnsureDir(filePath string) error {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -186,7 +187,7 @@ func (m *Medium) FileSet(filePath, content string) error {
|
|||
return m.Write(filePath, content)
|
||||
}
|
||||
|
||||
// Delete removes a file or empty directory.
|
||||
// Example: _ = medium.Delete("config/app.yaml")
|
||||
func (m *Medium) Delete(filePath string) error {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -231,7 +232,7 @@ func (m *Medium) Delete(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DeleteAll removes a file or directory and all its contents recursively.
|
||||
// Example: _ = medium.DeleteAll("config")
|
||||
func (m *Medium) DeleteAll(filePath string) error {
|
||||
key := normaliseEntryPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -255,7 +256,7 @@ func (m *Medium) DeleteAll(filePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Rename moves a file or directory from oldPath to newPath.
|
||||
// Example: _ = medium.Rename("drafts/todo.txt", "archive/todo.txt")
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldKey := normaliseEntryPath(oldPath)
|
||||
newKey := normaliseEntryPath(newPath)
|
||||
|
|
@ -353,7 +354,7 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
return tx.Commit()
|
||||
}
|
||||
|
||||
// List returns the directory entries for the given path.
|
||||
// Example: entries, _ := medium.List("config")
|
||||
func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
||||
prefix := normaliseEntryPath(filePath)
|
||||
if prefix != "" {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ import (
|
|||
coreio "dappco.re/go/core/io"
|
||||
)
|
||||
|
||||
// Medium wraps a Store to satisfy the io.Medium interface.
|
||||
// Example: medium, _ := store.NewMedium(store.Options{Path: "config.db"})
|
||||
// _ = medium.Write("app/theme", "midnight")
|
||||
// entries, _ := medium.List("app")
|
||||
//
|
||||
// Paths are mapped as group/key - the first segment is the group,
|
||||
// the rest is the key. List("") returns groups as directories,
|
||||
// List("group") returns keys as files.
|
||||
|
|
@ -20,10 +23,8 @@ type Medium struct {
|
|||
|
||||
var _ coreio.Medium = (*Medium)(nil)
|
||||
|
||||
// NewMedium exposes a Store as an io.Medium.
|
||||
//
|
||||
// medium, _ := store.NewMedium(store.Options{Path: "config.db"})
|
||||
// _ = medium.Write("app/theme", "midnight")
|
||||
// Example: medium, _ := store.NewMedium(store.Options{Path: "config.db"})
|
||||
// _ = medium.Write("app/theme", "midnight")
|
||||
func NewMedium(options Options) (*Medium, error) {
|
||||
store, err := New(options)
|
||||
if err != nil {
|
||||
|
|
@ -77,12 +78,12 @@ func (m *Medium) Write(entryPath, content string) error {
|
|||
return m.store.Set(group, key, content)
|
||||
}
|
||||
|
||||
// WriteMode ignores the requested mode because key-value entries do not store POSIX permissions.
|
||||
// Example: _ = medium.WriteMode("app/theme", "midnight", 0600)
|
||||
func (m *Medium) WriteMode(entryPath, content string, _ fs.FileMode) error {
|
||||
return m.Write(entryPath, content)
|
||||
}
|
||||
|
||||
// EnsureDir is a no-op — groups are created implicitly on Set.
|
||||
// Example: _ = medium.EnsureDir("app")
|
||||
func (m *Medium) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -149,8 +150,7 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
return m.store.Delete(oldGroup, oldKey)
|
||||
}
|
||||
|
||||
// List returns directory entries. Empty path returns groups.
|
||||
// A group path returns keys in that group.
|
||||
// Example: entries, _ := medium.List("app")
|
||||
func (m *Medium) List(entryPath string) ([]fs.DirEntry, error) {
|
||||
group, key := splitGroupKeyPath(entryPath)
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ func (m *Medium) List(entryPath string) ([]fs.DirEntry, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// Stat returns file info for a group (dir) or key (file).
|
||||
// Example: info, _ := medium.Stat("app/theme")
|
||||
func (m *Medium) Stat(entryPath string) (fs.FileInfo, error) {
|
||||
group, key := splitGroupKeyPath(entryPath)
|
||||
if group == "" {
|
||||
|
|
|
|||
|
|
@ -13,21 +13,21 @@ import (
|
|||
// NotFoundError is returned when a key does not exist in the store.
|
||||
var NotFoundError = errors.New("key not found")
|
||||
|
||||
// Store is returned by New for grouped key/value access.
|
||||
// Store is the grouped key/value database returned by New.
|
||||
//
|
||||
// keyValueStore, _ := store.New(store.Options{Path: ":memory:"})
|
||||
type Store struct {
|
||||
database *sql.DB
|
||||
}
|
||||
|
||||
// Options configures New.
|
||||
// Example: keyValueStore, _ := store.New(store.Options{Path: ":memory:"})
|
||||
type Options struct {
|
||||
// Path is the SQLite database path. Use ":memory:" for tests.
|
||||
Path string
|
||||
}
|
||||
|
||||
// New opens a SQLite-backed key/value store.
|
||||
//
|
||||
// keyValueStore, _ := store.New(store.Options{Path: ":memory:"})
|
||||
// _ = keyValueStore.Set("app", "theme", "midnight")
|
||||
// Example: keyValueStore, _ := store.New(store.Options{Path: ":memory:"})
|
||||
// _ = keyValueStore.Set("app", "theme", "midnight")
|
||||
func New(options Options) (*Store, error) {
|
||||
if options.Path == "" {
|
||||
return nil, core.E("store.New", "database path is required", fs.ErrInvalid)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import (
|
|||
"dappco.re/go/core/io"
|
||||
)
|
||||
|
||||
// Workspace is the interface returned by New.
|
||||
// Workspace is the workspace service interface returned by New.
|
||||
//
|
||||
// service, _ := workspace.New(workspace.Options{Core: core.New(), Crypt: cryptProvider})
|
||||
type Workspace interface {
|
||||
CreateWorkspace(identifier, password string) (string, error)
|
||||
SwitchWorkspace(workspaceID string) error
|
||||
|
|
@ -24,7 +26,7 @@ type CryptProvider interface {
|
|||
CreateKeyPair(name, passphrase string) (string, error)
|
||||
}
|
||||
|
||||
// Options configures New.
|
||||
// Example: service, _ := workspace.New(workspace.Options{Core: core.New(), Crypt: cryptProvider})
|
||||
type Options struct {
|
||||
// Core is the Core runtime used by the service.
|
||||
Core *core.Core
|
||||
|
|
@ -32,7 +34,7 @@ type Options struct {
|
|||
Crypt CryptProvider
|
||||
}
|
||||
|
||||
// Service is the concrete Workspace implementation.
|
||||
// Service is the Workspace implementation returned by New.
|
||||
type Service struct {
|
||||
core *core.Core
|
||||
crypt CryptProvider
|
||||
|
|
@ -44,10 +46,8 @@ type Service struct {
|
|||
|
||||
var _ Workspace = (*Service)(nil)
|
||||
|
||||
// New creates an encrypted workspace service.
|
||||
//
|
||||
// service, _ := workspace.New(workspace.Options{Core: core.New(), Crypt: cryptProvider})
|
||||
// workspaceID, _ := service.CreateWorkspace("alice", "pass123")
|
||||
// Example: service, _ := workspace.New(workspace.Options{Core: core.New(), Crypt: cryptProvider})
|
||||
// workspaceID, _ := service.CreateWorkspace("alice", "pass123")
|
||||
func New(options Options) (*Service, error) {
|
||||
home := resolveWorkspaceHomeDirectory()
|
||||
if home == "" {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue