-
Notifications
You must be signed in to change notification settings - Fork 219
/
file.go
162 lines (134 loc) · 3.37 KB
/
file.go
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package config
import (
"bytes"
"context"
"io"
"os"
"path/filepath"
"github.com/superfly/flyctl/wg"
"gopkg.in/yaml.v3"
"github.com/superfly/flyctl/flyctl"
"github.com/superfly/flyctl/internal/filemu"
)
func ReadAccessToken(path string) (string, error) {
s := struct {
AccessToken string `yaml:"access_token"`
}{}
if err := unmarshal(path, &s); err != nil {
return "", err
}
return s.AccessToken, nil
}
// SetAccessToken sets the value of the access token at the configuration file
// found at path.
func SetAccessToken(path, token string) error {
return set(path, map[string]interface{}{
AccessTokenFileKey: token,
})
}
// SetMetricsToken sets the value of the metrics token at the configuration file
// found at path.
func SetMetricsToken(path, token string) error {
return set(path, map[string]interface{}{
MetricsTokenFileKey: token,
})
}
// SetSendMetrics sets the value of the send metrics flag at the configuration file
// found at path.
func SetSendMetrics(path string, sendMetrics bool) error {
return set(path, map[string]interface{}{
SendMetricsFileKey: sendMetrics,
})
}
// SetAutoUpdate sets the value of the autoupdate flag at the configuration file
// found at path.
func SetAutoUpdate(path string, autoUpdate bool) error {
return set(path, map[string]interface{}{
AutoUpdateFileKey: autoUpdate,
})
}
func SetWireGuardState(path string, state wg.States) error {
return set(path, map[string]interface{}{
WireGuardStateFileKey: state,
})
}
func SetWireGuardWebsocketsEnabled(path string, enabled bool) error {
return set(path, map[string]interface{}{
WireGuardWebsocketsFileKey: enabled,
})
}
// Clear clears the access token, metrics token, and wireguard-related keys of the configuration
// file found at path.
func Clear(path string) (err error) {
return set(path, map[string]interface{}{
AccessTokenFileKey: "",
MetricsTokenFileKey: "",
WireGuardStateFileKey: map[string]interface{}{},
})
}
func set(path string, vals map[string]interface{}) error {
m := make(map[string]interface{})
switch err := unmarshal(path, &m); {
case err == nil, os.IsNotExist(err):
break
default:
return err
}
for k, v := range vals {
m[k] = v
}
return marshal(path, m)
}
func lockPath() string {
return filepath.Join(flyctl.ConfigDir(), "flyctl.config.lock")
}
func unmarshal(path string, v interface{}) (err error) {
var unlock filemu.UnlockFunc
if unlock, err = filemu.RLock(context.Background(), lockPath()); err != nil {
return
}
defer func() {
if e := unlock(); err == nil {
err = e
}
}()
err = unmarshalUnlocked(path, v)
return
}
func unmarshalUnlocked(path string, v interface{}) (err error) {
var f *os.File
if f, err = os.Open(path); err != nil {
return
}
defer func() {
if e := f.Close(); err == nil {
err = e
}
}()
err = yaml.NewDecoder(f).Decode(v)
if err == io.EOF {
err = nil
}
return
}
func marshal(path string, v interface{}) (err error) {
var unlock filemu.UnlockFunc
if unlock, err = filemu.Lock(context.Background(), lockPath()); err != nil {
return
}
defer func() {
if e := unlock(); err == nil {
err = e
}
}()
err = marshalUnlocked(path, v)
return
}
func marshalUnlocked(path string, v interface{}) (err error) {
var b bytes.Buffer
if err = yaml.NewEncoder(&b).Encode(v); err == nil {
// TODO: os.WriteFile does not flush
err = os.WriteFile(path, b.Bytes(), 0o600)
}
return
}