From 049ecf2c931b7e088e2c5031e5cd3731b1069f61 Mon Sep 17 00:00:00 2001 From: Xinyu Ma Date: Mon, 6 Dec 2021 14:37:34 -0800 Subject: [PATCH] webui: Finish config page --- cmd/yanfdui/main.go | 2 +- cmd/yanfdui/server/server.go | 95 ++++++++++++++++++++++- cmd/yanfdui/templates/config.go.tmpl | 111 +++++++++++++++------------ 3 files changed, 156 insertions(+), 52 deletions(-) diff --git a/cmd/yanfdui/main.go b/cmd/yanfdui/main.go index 66b0d2ca..cedd715a 100644 --- a/cmd/yanfdui/main.go +++ b/cmd/yanfdui/main.go @@ -50,7 +50,7 @@ func main() { } if runtime.GOOS == "windows" && configFileName[0] == '/' { - configFileName = "yanfd.toml" // On Windows, read the file in the same folder by default + configFileName = os.ExpandEnv("${APPDATA}\\ndn\\yanfd.toml") } config := executor.YaNFDConfig{ diff --git a/cmd/yanfdui/server/server.go b/cmd/yanfdui/server/server.go index bb155b3e..b9e16980 100644 --- a/cmd/yanfdui/server/server.go +++ b/cmd/yanfdui/server/server.go @@ -4,10 +4,13 @@ import ( "fmt" "html/template" "net/http" + "os" "os/exec" + "reflect" "runtime" "sort" "strconv" + "strings" "sync" "time" @@ -16,6 +19,7 @@ import ( "github.com/named-data/YaNFD/face" "github.com/named-data/YaNFD/fw" "github.com/named-data/YaNFD/table" + "github.com/pelletier/go-toml" ) type menuList struct { @@ -81,6 +85,7 @@ type renderInput struct { Setting setting } +// TODO: setting is a temporary solution; should change to toml.Marshal type setting struct { LogLevel string `toml:"core.log_level"` FacesQueueSize int `toml:"faces.queue_size"` @@ -132,6 +137,68 @@ var menus = []menuList{ {LinkName: "/config", PageName: "Configuration"}, } +func tomlTreeToSetting(tree *toml.Tree) *setting { + var s setting + sType := reflect.TypeOf(s) + for i := 0; i < sType.NumField(); i++ { + f := sType.Field(i) + if fName := f.Tag.Get("toml"); fName != "" { + switch f.Type.Kind() { + case reflect.String: + if v, ok := tree.Get(fName).(string); ok { + reflect.ValueOf(&s).Elem().Field(i).SetString(v) + } + case reflect.Uint16: + if v, ok := tree.Get(fName).(int64); ok { + reflect.ValueOf(&s).Elem().Field(i).SetUint(uint64(v)) + } + case reflect.Int: + if v, ok := tree.Get(fName).(int64); ok { + reflect.ValueOf(&s).Elem().Field(i).SetInt(v) + } + case reflect.Bool: + if v, ok := tree.Get(fName).(bool); ok { + reflect.ValueOf(&s).Elem().Field(i).SetBool(v) + } + } + } + } + return &s +} + +func tomlFormToTree(tree *toml.Tree, r *http.Request) { + sType := reflect.TypeOf(setting{}) + for i := 0; i < sType.NumField(); i++ { + f := sType.Field(i) + val := r.Form.Get(f.Name) + if val == "" { + continue + } + if fName := f.Tag.Get("toml"); fName != "" { + switch f.Type.Kind() { + case reflect.String: + tree.Set(fName, val) + case reflect.Uint16: + v, err := strconv.ParseUint(val, 10, 16) + if err != nil { + tree.Set(fName, v) + } + case reflect.Int: + v, err := strconv.Atoi(val) + if err != nil { + tree.Set(fName, v) + } + case reflect.Bool: + if strings.ToUpper(val) == "TRUE" { + tree.Set(fName, true) + } else { + tree.Set(fName, false) + } + } + } + } +} + func forwarderStatus(w http.ResponseWriter, req *http.Request) { var nPitEntries, nCsEntries, nInInterests, nInData, nOutInterests, nFibEntries uint64 var nOutData, nSatisfiedInterests, nUnsatisfiedInterests uint64 @@ -437,15 +504,39 @@ func autoconf(w http.ResponseWriter, req *http.Request) { func config(w http.ResponseWriter, req *http.Request) { action := req.URL.Path[len("/config/"):] req.ParseForm() + + tree, err := toml.LoadFile(configFile) + if err != nil { + core.LogError("HttpServer", "toml.LoadFile failed with: ", err) + // TODO: handle error + http.Redirect(w, req, "/", http.StatusFound) + return + } + switch action { case "save": - // TODO: save configuration - notImplemented(w, req, "/config/") + tomlFormToTree(tree, req) + s, err := tree.ToTomlString() + if err == nil { + file, err := os.Create(configFile) + if err == nil { + file.WriteString(s) + } else { + core.LogError("HttpServer", "os.Create failed with: ", err) + } + } else { + core.LogError("HttpServer", "toml.ToTomlString failed with: ", err) + } + http.Redirect(w, req, "/config/", http.StatusFound) + return } + set := tomlTreeToSetting(tree) + input := renderInput{ ReferName: "/", MenuList: menus, + Setting: *set, } // Render diff --git a/cmd/yanfdui/templates/config.go.tmpl b/cmd/yanfdui/templates/config.go.tmpl index 2fd0785f..d941b464 100644 --- a/cmd/yanfdui/templates/config.go.tmpl +++ b/cmd/yanfdui/templates/config.go.tmpl @@ -19,10 +19,10 @@
@@ -30,173 +30,185 @@ Face System
- +
- +
- +
Ethernet Face
- +
- +
+ placeholder="01:00:5e:00:17:aa" value="{{.Setting.EtherAddr}}"/>
UDP Face
- +
- +
+ placeholder="224.0.23.170" value="{{.Setting.UdpMulticastIpv4}}"/>
+ placeholder="ff02::114" value="{{.Setting.UdpMulticastIpv6}}"/>
+ placeholder="600" value="{{.Setting.UdpLifetime}}" min="1" max="316224000"/>
TCP Face
- +
- +
+ placeholder="600" value="{{.Setting.TcpLifetime}}" min="1" max="316224000"/>
Unix Socket Face
- +
+ placeholder="${TEMP}\\nfd.sock" value="{{.Setting.UnixSocketPath}}"/>
WebSocket Face
- +
+ placeholder="" value="{{.Setting.WsBind}}"/>
- +
- +
+ placeholder="" value="{{.Setting.WsTlsCert}}"/>
+ placeholder="" value="{{.Setting.WsTlsKey}}"/>
Forwarding Threads
- +
- +
- +
Management
- +
Tables General
- +
Content Store
- +
- +
- +
@@ -204,21 +216,22 @@ Dead Nonce List
- +
RIB
- +
- +
-{{end}} \ No newline at end of file +{{end}}