-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcontroller.go
More file actions
144 lines (119 loc) · 3.62 KB
/
Copy pathcontroller.go
File metadata and controls
144 lines (119 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package data
import (
"context"
"encoding/json"
"errors"
"os"
"strings"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/omniviewdev/omniview/internal/appstate"
logging "github.com/omniviewdev/plugin-sdk/log"
)
// Controller provides a JSON key-value store for plugins to persist arbitrary data.
// Each key is stored as a separate JSON file under <stateRoot>/plugins/{pluginID}/data/.
type Controller interface {
ServiceStartup(ctx context.Context, options application.ServiceOptions) error
ServiceShutdown() error
Get(pluginID, key string) (any, error)
Set(pluginID, key string, value any) error
Delete(pluginID, key string) error
Keys(pluginID string) ([]string, error)
}
var _ Controller = (*controller)(nil)
type controller struct {
logger logging.Logger
pluginDataFn func(pluginID string) (*appstate.ScopedRoot, error)
}
// NewController creates a new data store controller.
// pluginDataFn returns a ScopedRoot for the given plugin's data directory.
func NewController(logger logging.Logger, pluginDataFn func(string) (*appstate.ScopedRoot, error)) Controller {
return &controller{
logger: logger.Named("DataController"),
pluginDataFn: pluginDataFn,
}
}
func (c *controller) ServiceStartup(_ context.Context, _ application.ServiceOptions) error {
return nil
}
func (c *controller) ServiceShutdown() error {
return nil
}
func (c *controller) Get(pluginID, key string) (any, error) {
logger := c.logger.With(logging.Any("pluginID", pluginID), logging.Any("key", key))
root, err := c.pluginDataFn(pluginID)
if err != nil {
return nil, err
}
data, err := root.ReadFile(key + ".json")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
logger.Errorw(context.Background(), "failed to read data file", "error", err)
return nil, err
}
var value any
if err := json.Unmarshal(data, &value); err != nil {
logger.Errorw(context.Background(), "failed to unmarshal data", "error", err)
return nil, err
}
return value, nil
}
func (c *controller) Set(pluginID, key string, value any) error {
logger := c.logger.With(logging.Any("pluginID", pluginID), logging.Any("key", key))
root, err := c.pluginDataFn(pluginID)
if err != nil {
return err
}
data, err := json.MarshalIndent(value, "", " ")
if err != nil {
logger.Errorw(context.Background(), "failed to marshal data", "error", err)
return err
}
if err := root.WriteFile(key+".json", data, 0600); err != nil {
logger.Errorw(context.Background(), "failed to write data file", "error", err)
return err
}
return nil
}
func (c *controller) Delete(pluginID, key string) error {
logger := c.logger.With(logging.Any("pluginID", pluginID), logging.Any("key", key))
root, err := c.pluginDataFn(pluginID)
if err != nil {
return err
}
if err := root.Remove(key + ".json"); err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
logger.Errorw(context.Background(), "failed to delete data file", "error", err)
return err
}
return nil
}
func (c *controller) Keys(pluginID string) ([]string, error) {
logger := c.logger.With(logging.Any("pluginID", pluginID))
root, err := c.pluginDataFn(pluginID)
if err != nil {
return nil, err
}
entries, err := root.ReadDir(".")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return []string{}, nil
}
logger.Errorw(context.Background(), "failed to read data dir", "error", err)
return nil, err
}
keys := make([]string, 0, len(entries))
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if strings.HasSuffix(name, ".json") {
keys = append(keys, strings.TrimSuffix(name, ".json"))
}
}
return keys, nil
}