Skip to content

Commit 5a62246

Browse files
authored
📦 new: use configbuilder to parse config files into Config struct (#25)
* new: configbuilder.ConfigJSON * fix: unused wasmClone * new: configbuilder.ConfigProtoBuf Plus, make configbuilder no longer an internal package. * feat: UnmarshalJSON and UnmarshalProto for Config * deprecated: use of Argv and Env inside WATM Deprecate the use of `argv` and `env` inside a WATM. A WATM is encouraged to be configured with `Config.TransportModuleConfig`. To prevent the unnecessary warning this may introduce to some undocumented legitimate use, we will not add `Deprecated` flag on the related fields and functions. Signed-off-by: Gaukas Wang <[email protected]> --------- Signed-off-by: Gaukas Wang <[email protected]>
1 parent a667ea2 commit 5a62246

9 files changed

Lines changed: 743 additions & 1 deletion

File tree

‎config.go‎

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package water
22

33
import (
4+
"encoding/json"
5+
"errors"
46
"net"
7+
"os"
58

9+
"github.com/gaukas/water/configbuilder"
610
"github.com/gaukas/water/internal/log"
711
"github.com/gaukas/water/internal/wasm"
12+
"google.golang.org/protobuf/proto"
813
)
914

1015
// Config defines the configuration for the WATER Dialer/Config interface.
@@ -56,7 +61,7 @@ func (c *Config) Clone() *Config {
5661
copy(wasmClone, c.TransportModuleBin)
5762

5863
return &Config{
59-
TransportModuleBin: c.TransportModuleBin,
64+
TransportModuleBin: wasmClone,
6065
NetworkDialerFunc: c.NetworkDialerFunc,
6166
NetworkListener: c.NetworkListener,
6267
TransportModuleConfig: c.TransportModuleConfig,
@@ -126,3 +131,133 @@ func (c *Config) Logger() *log.Logger {
126131

127132
return log.GetDefaultLogger()
128133
}
134+
135+
// UnmarshalJSON implements the json.Unmarshaler interface.
136+
func (c *Config) UnmarshalJSON(data []byte) error {
137+
var confJson configbuilder.ConfigJSON
138+
139+
err := json.Unmarshal(data, &confJson)
140+
if err != nil {
141+
return err
142+
}
143+
144+
tmBin, err := os.ReadFile(confJson.TransportModule.BinPath)
145+
if err != nil {
146+
return err
147+
}
148+
c.TransportModuleBin = tmBin
149+
150+
if len(confJson.TransportModule.ConfigPath) > 0 {
151+
c.TransportModuleConfig, err = TransportModuleConfigFromFile(confJson.TransportModule.ConfigPath)
152+
if err != nil {
153+
return err
154+
}
155+
}
156+
157+
if len(confJson.Network.Listener.Network) > 0 && len(confJson.Network.Listener.Address) > 0 {
158+
c.NetworkListener, err = net.Listen(confJson.Network.Listener.Network, confJson.Network.Listener.Address)
159+
if err != nil {
160+
return err
161+
}
162+
}
163+
164+
c.ModuleConfigFactory = wasm.NewModuleConfigFactory()
165+
if len(confJson.Module.Argv) > 0 {
166+
c.ModuleConfigFactory.SetArgv(confJson.Module.Argv)
167+
}
168+
169+
var envKeys []string
170+
var envValues []string
171+
for k, v := range confJson.Module.Env {
172+
envKeys = append(envKeys, k)
173+
envValues = append(envValues, v)
174+
}
175+
if len(envKeys) > 0 {
176+
c.ModuleConfigFactory.SetEnv(envKeys, envValues)
177+
}
178+
179+
if confJson.Module.InheritStdin {
180+
c.ModuleConfigFactory.InheritStdin()
181+
}
182+
183+
if confJson.Module.InheritStdout {
184+
c.ModuleConfigFactory.InheritStdout()
185+
}
186+
187+
if confJson.Module.InheritStderr {
188+
c.ModuleConfigFactory.InheritStderr()
189+
}
190+
191+
for k, v := range confJson.Module.PreopenedDirs {
192+
c.ModuleConfigFactory.SetPreopenDir(k, v)
193+
}
194+
195+
return nil
196+
}
197+
198+
// UnmarshalProto provides a way to unmarshal a protobuf message into a Config.
199+
//
200+
// The message definition is defined in configbuilder/pb/config.proto.
201+
func (c *Config) UnmarshalProto(b []byte) error {
202+
var confProto configbuilder.ConfigProtoBuf
203+
204+
unmarshalOptions := proto.UnmarshalOptions{
205+
AllowPartial: true,
206+
}
207+
err := unmarshalOptions.Unmarshal(b, &confProto)
208+
if err != nil {
209+
return err
210+
}
211+
212+
// Parse TransportModuleBin
213+
c.TransportModuleBin = confProto.GetTransportModule().GetBin()
214+
if len(c.TransportModuleBin) == 0 {
215+
return errors.New("water: transport module binary is not provided in config")
216+
}
217+
218+
// Parse TransportModuleConfig
219+
c.TransportModuleConfig = TransportModuleConfigFromBytes(confProto.GetTransportModule().GetConfig())
220+
221+
// Parse NetworkListener
222+
listenerNetwork, listenerAddress := confProto.GetNetwork().GetListener().GetNetwork(), confProto.GetNetwork().GetListener().GetAddress()
223+
if len(listenerNetwork) > 0 && len(listenerAddress) > 0 {
224+
c.NetworkListener, err = net.Listen(listenerNetwork, listenerAddress)
225+
if err != nil {
226+
return err
227+
}
228+
}
229+
230+
// Parse ModuleConfigFactory
231+
c.ModuleConfigFactory = wasm.NewModuleConfigFactory()
232+
if len(confProto.GetModule().GetArgv()) > 0 {
233+
c.ModuleConfigFactory.SetArgv(confProto.Module.Argv)
234+
}
235+
236+
var envKeys []string
237+
var envValues []string
238+
for k, v := range confProto.GetModule().GetEnv() {
239+
envKeys = append(envKeys, k)
240+
envValues = append(envValues, v)
241+
}
242+
if len(envKeys) > 0 {
243+
c.ModuleConfigFactory.SetEnv(envKeys, envValues)
244+
}
245+
246+
if confProto.GetModule().GetInheritStdin() {
247+
c.ModuleConfigFactory.InheritStdin()
248+
}
249+
250+
if confProto.GetModule().GetInheritStdout() {
251+
c.ModuleConfigFactory.InheritStdout()
252+
}
253+
254+
if confProto.GetModule().GetInheritStderr() {
255+
c.ModuleConfigFactory.InheritStderr()
256+
}
257+
258+
for k, v := range confProto.GetModule().GetPreopenedDirs() {
259+
c.ModuleConfigFactory.SetPreopenDir(k, v)
260+
}
261+
262+
return nil
263+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package configbuilder
2+
3+
// ConfigJSON defines the JSON format of the Config.
4+
//
5+
// This struct may fail to fully represent the Config struct, as it is
6+
// non-trivial to represent a func or other non-serialized structures.
7+
type ConfigJSON struct {
8+
TransportModule struct {
9+
BinPath string `json:"bin"` // Path to the transport module binary
10+
ConfigPath string `json:"config,omitempty"` // Path to the transport module config file
11+
} `json:"transport_module"`
12+
13+
Network struct {
14+
// DialerFunc string `json:"dialer_func,omitempty"` // we have no good way to represent a func in JSON format yet
15+
Listener struct {
16+
Network string `json:"network"` // e.g. "tcp"
17+
Address string `json:"address"` // e.g. "0.0.0.0:0"
18+
} `json:"listener,omitempty"`
19+
} `json:"network,omitempty"`
20+
21+
Module struct {
22+
Argv []string `json:"argv,omitempty"` // Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file.
23+
Env map[string]string `json:"env,omitempty"` // Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file.
24+
InheritStdin bool `json:"inherit_stdin,omitempty"`
25+
InheritStdout bool `json:"inherit_stdout,omitempty"`
26+
InheritStderr bool `json:"inherit_stderr,omitempty"`
27+
PreopenedDirs map[string]string `json:"preopened_dirs,omitempty"` // hostPath: guestPath
28+
} `json:"module,omitempty"`
29+
}

‎configbuilder/config.pb.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package configbuilder
2+
3+
import "github.com/gaukas/water/configbuilder/pb"
4+
5+
// ConfigProtoBuf defines the Protobuf format of the Config.
6+
//
7+
// This struct may fail to fully represent the Config struct, as it is
8+
// non-trivial to represent a func or other non-serialized structures.
9+
type ConfigProtoBuf = pb.Config

‎configbuilder/pb/Makefile‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
protobuf: config.proto
2+
protoc --go_out=. --go_opt=paths=source_relative $<
3+
4+
.PHONY: protobuf

0 commit comments

Comments
 (0)