From 424ae360462892b765849981ab7d84d6565fd13c Mon Sep 17 00:00:00 2001 From: Cory Snider Date: Mon, 4 Dec 2023 15:35:41 -0500 Subject: [PATCH] libnetwork/diagnostic: use standard http.Handler We don't need C-style callback functions which accept a void* context parameter: Go has closures. Drop the unnecessary httpHandlerCustom type and refactor the diagnostic server handler functions into closures which capture whatever context they need implicitly. If the node leaves and rejoins a swarm, the cluster agent and its associated NetworkDB are discarded and replaced with new instances. Upon rejoin, the agent registers its NetworkDB instance with the diagnostic server. These handlers would all conflict with the handlers registered by the previous NetworkDB instance. Attempting to register a second handler on a http.ServeMux with the same pattern will panic, which the diagnostic server would historically deal with by ignoring the duplicate handler registration. Consequently, the first NetworkDB instance to be registered would "stick" to the diagnostic server for the lifetime of the process, even after it is replaced with another instance. Improve duplicate-handler registration such that the most recently-registered handler for a pattern is used for all subsequent requests. Signed-off-by: Cory Snider --- libnetwork/agent.go | 2 +- .../cmd/networkdb-test/dbserver/ndbServer.go | 12 +- .../networkdb-test/dummyclient/dummyClient.go | 42 +-- libnetwork/diagnostic/server.go | 86 +++-- libnetwork/networkdb/networkdbdiagnostic.go | 300 ++++++++---------- 5 files changed, 190 insertions(+), 252 deletions(-) diff --git a/libnetwork/agent.go b/libnetwork/agent.go index c4a200186c..3ff97c53a0 100644 --- a/libnetwork/agent.go +++ b/libnetwork/agent.go @@ -332,7 +332,7 @@ func (c *Controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr, d } // Register the diagnostic handlers - c.DiagnosticServer.RegisterHandler(nDB, networkdb.NetDbPaths2Func) + nDB.RegisterDiagnosticHandlers(c.DiagnosticServer) var cancelList []func() ch, cancel := nDB.Watch(libnetworkEPTable, "") diff --git a/libnetwork/cmd/networkdb-test/dbserver/ndbServer.go b/libnetwork/cmd/networkdb-test/dbserver/ndbServer.go index d40f000d30..83ef8931c4 100644 --- a/libnetwork/cmd/networkdb-test/dbserver/ndbServer.go +++ b/libnetwork/cmd/networkdb-test/dbserver/ndbServer.go @@ -21,11 +21,7 @@ var ( ipAddr string ) -var testerPaths2Func = map[string]diagnostic.HTTPHandlerFunc{ - "/myip": ipaddress, -} - -func ipaddress(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func ipaddress(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "%s\n", ipAddr) } @@ -63,9 +59,9 @@ func Server(args []string) { } // Register network db handlers - server.RegisterHandler(nDB, networkdb.NetDbPaths2Func) - server.RegisterHandler(nil, testerPaths2Func) - server.RegisterHandler(nDB, dummyclient.DummyClientPaths2Func) + nDB.RegisterDiagnosticHandlers(server) + server.HandleFunc("/myip", ipaddress) + dummyclient.RegisterDiagnosticHandlers(server, nDB) server.EnableDiagnostic("", port) // block here select {} diff --git a/libnetwork/cmd/networkdb-test/dummyclient/dummyClient.go b/libnetwork/cmd/networkdb-test/dummyclient/dummyClient.go index e645cb9385..ab24de8f95 100644 --- a/libnetwork/cmd/networkdb-test/dummyclient/dummyClient.go +++ b/libnetwork/cmd/networkdb-test/dummyclient/dummyClient.go @@ -11,10 +11,13 @@ import ( events "github.com/docker/go-events" ) -// DummyClientPaths2Func exported paths for the client -var DummyClientPaths2Func = map[string]diagnostic.HTTPHandlerFunc{ - "/watchtable": watchTable, - "/watchedtableentries": watchTableEntries, +type Mux interface { + HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) +} + +func RegisterDiagnosticHandlers(mux Mux, nDB *networkdb.NetworkDB) { + mux.HandleFunc("/watchtable", watchTable(nDB)) + mux.HandleFunc("/watchedtableentries", watchTableEntries) } const ( @@ -28,23 +31,22 @@ type tableHandler struct { var clientWatchTable = map[string]tableHandler{} -func watchTable(ctx interface{}, w http.ResponseWriter, r *http.Request) { - r.ParseForm() //nolint:errcheck - diagnostic.DebugHTTPForm(r) - if len(r.Form["tname"]) < 1 { - rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name", r.URL.Path)) - diagnostic.HTTPReply(w, rsp, &diagnostic.JSONOutput{}) //nolint:errcheck - return - } +func watchTable(nDB *networkdb.NetworkDB) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() //nolint:errcheck + diagnostic.DebugHTTPForm(r) + if len(r.Form["tname"]) < 1 { + rsp := diagnostic.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name", r.URL.Path)) + diagnostic.HTTPReply(w, rsp, &diagnostic.JSONOutput{}) //nolint:errcheck + return + } - tableName := r.Form["tname"][0] - if _, ok := clientWatchTable[tableName]; ok { - fmt.Fprintf(w, "OK\n") - return - } + tableName := r.Form["tname"][0] + if _, ok := clientWatchTable[tableName]; ok { + fmt.Fprintf(w, "OK\n") + return + } - nDB, ok := ctx.(*networkdb.NetworkDB) - if ok { ch, cancel := nDB.Watch(tableName, "") clientWatchTable[tableName] = tableHandler{cancelWatch: cancel, entries: make(map[string]string)} go handleTableEvents(tableName, ch) @@ -53,7 +55,7 @@ func watchTable(ctx interface{}, w http.ResponseWriter, r *http.Request) { } } -func watchTableEntries(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func watchTableEntries(w http.ResponseWriter, r *http.Request) { r.ParseForm() //nolint:errcheck diagnostic.DebugHTTPForm(r) if len(r.Form["tname"]) < 1 { diff --git a/libnetwork/diagnostic/server.go b/libnetwork/diagnostic/server.go index 1ed5657cf2..966201c448 100644 --- a/libnetwork/diagnostic/server.go +++ b/libnetwork/diagnostic/server.go @@ -16,58 +16,53 @@ import ( "github.com/docker/docker/pkg/stack" ) -// HTTPHandlerFunc TODO -type HTTPHandlerFunc func(interface{}, http.ResponseWriter, *http.Request) - -type httpHandlerCustom struct { - ctx interface{} - F func(interface{}, http.ResponseWriter, *http.Request) -} - -// ServeHTTP TODO -func (h httpHandlerCustom) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.F(h.ctx, w, r) -} - -var diagPaths2Func = map[string]HTTPHandlerFunc{ - "/": notImplemented, - "/help": help, - "/ready": ready, - "/stackdump": stackTrace, -} - // Server when the debug is enabled exposes a // This data structure is protected by the Agent mutex so does not require and additional mutex here type Server struct { - mu sync.Mutex - enable int32 - srv *http.Server - port int - mux *http.ServeMux - registeredHanders map[string]bool + mu sync.Mutex + enable int32 + srv *http.Server + port int + mux *http.ServeMux + handlers map[string]http.Handler } // New creates a new diagnostic server func New() *Server { s := &Server{ - mux: http.NewServeMux(), - registeredHanders: make(map[string]bool), + mux: http.NewServeMux(), + handlers: make(map[string]http.Handler), } - s.RegisterHandler(s, diagPaths2Func) + s.HandleFunc("/", notImplemented) + s.HandleFunc("/help", s.help) + s.HandleFunc("/ready", ready) + s.HandleFunc("/stackdump", stackTrace) return s } -// RegisterHandler allows to register new handlers to the mux and to a specific path -func (s *Server) RegisterHandler(ctx interface{}, hdlrs map[string]HTTPHandlerFunc) { +// Handle registers the handler for the given pattern, +// replacing any existing handler. +func (s *Server) Handle(pattern string, handler http.Handler) { s.mu.Lock() defer s.mu.Unlock() - for path, fun := range hdlrs { - if _, ok := s.registeredHanders[path]; ok { - continue - } - s.mux.Handle(path, httpHandlerCustom{ctx, fun}) - s.registeredHanders[path] = true + if _, ok := s.handlers[pattern]; !ok { + // Register a handler on the mux which allows the underlying handler to + // be dynamically switched out. The http.ServeMux will panic if one + // attempts to register a handler for the same pattern twice. + s.mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { + s.mu.Lock() + h := s.handlers[pattern] + s.mu.Unlock() + h.ServeHTTP(w, r) + }) } + s.handlers[pattern] = handler +} + +// Handle registers the handler function for the given pattern, +// replacing any existing handler. +func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { + s.Handle(pattern, http.HandlerFunc(handler)) } // ServeHTTP this is the method called bu the ListenAndServe, and is needed to allow us to @@ -123,7 +118,7 @@ func (s *Server) IsDiagnosticEnabled() bool { return s.enable == 1 } -func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func notImplemented(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() _, jsonOutput := ParseHTTPFormOptions(r) rsp := WrongCommand("not implemented", fmt.Sprintf("URL path: %s no method implemented check /help\n", r.URL.Path)) @@ -139,7 +134,7 @@ func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) { _, _ = HTTPReply(w, rsp, jsonOutput) } -func help(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (s *Server) help(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() _, jsonOutput := ParseHTTPFormOptions(r) @@ -151,17 +146,14 @@ func help(ctx interface{}, w http.ResponseWriter, r *http.Request) { "url": r.URL.String(), }).Info("help done") - n, ok := ctx.(*Server) var result string - if ok { - for path := range n.registeredHanders { - result += fmt.Sprintf("%s\n", path) - } - _, _ = HTTPReply(w, CommandSucceed(&StringCmd{Info: result}), jsonOutput) + for path := range s.handlers { + result += fmt.Sprintf("%s\n", path) } + _, _ = HTTPReply(w, CommandSucceed(&StringCmd{Info: result}), jsonOutput) } -func ready(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func ready(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() _, jsonOutput := ParseHTTPFormOptions(r) @@ -175,7 +167,7 @@ func ready(ctx interface{}, w http.ResponseWriter, r *http.Request) { _, _ = HTTPReply(w, CommandSucceed(&StringCmd{Info: "OK"}), jsonOutput) } -func stackTrace(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func stackTrace(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() _, jsonOutput := ParseHTTPFormOptions(r) diff --git a/libnetwork/networkdb/networkdbdiagnostic.go b/libnetwork/networkdb/networkdbdiagnostic.go index a23be599bb..9646453f3f 100644 --- a/libnetwork/networkdb/networkdbdiagnostic.go +++ b/libnetwork/networkdb/networkdbdiagnostic.go @@ -17,22 +17,25 @@ const ( dbNotAvailable = "database not available" ) -// NetDbPaths2Func TODO -var NetDbPaths2Func = map[string]diagnostic.HTTPHandlerFunc{ - "/join": dbJoin, - "/networkpeers": dbPeers, - "/clusterpeers": dbClusterPeers, - "/joinnetwork": dbJoinNetwork, - "/leavenetwork": dbLeaveNetwork, - "/createentry": dbCreateEntry, - "/updateentry": dbUpdateEntry, - "/deleteentry": dbDeleteEntry, - "/getentry": dbGetEntry, - "/gettable": dbGetTable, - "/networkstats": dbNetworkStats, +type Mux interface { + HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) } -func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) RegisterDiagnosticHandlers(m Mux) { + m.HandleFunc("/join", nDB.dbJoin) + m.HandleFunc("/networkpeers", nDB.dbPeers) + m.HandleFunc("/clusterpeers", nDB.dbClusterPeers) + m.HandleFunc("/joinnetwork", nDB.dbJoinNetwork) + m.HandleFunc("/leavenetwork", nDB.dbLeaveNetwork) + m.HandleFunc("/createentry", nDB.dbCreateEntry) + m.HandleFunc("/updateentry", nDB.dbUpdateEntry) + m.HandleFunc("/deleteentry", nDB.dbDeleteEntry) + m.HandleFunc("/getentry", nDB.dbGetEntry) + m.HandleFunc("/gettable", nDB.dbGetTable) + m.HandleFunc("/networkstats", nDB.dbNetworkStats) +} + +func (nDB *NetworkDB) dbJoin(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -53,24 +56,19 @@ func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) { return } - nDB, ok := ctx.(*NetworkDB) - if ok { - err := nDB.Join(strings.Split(r.Form["members"][0], ",")) - if err != nil { - rsp := diagnostic.FailCommand(fmt.Errorf("%s error in the DB join %s", r.URL.Path, err)) - logger.WithError(err).Error("join cluster failed") - diagnostic.HTTPReply(w, rsp, json) - return - } - - logger.Info("join cluster done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + err := nDB.Join(strings.Split(r.Form["members"][0], ",")) + if err != nil { + rsp := diagnostic.FailCommand(fmt.Errorf("%s error in the DB join %s", r.URL.Path, err)) + logger.WithError(err).Error("join cluster failed") + diagnostic.HTTPReply(w, rsp, json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + + logger.Info("join cluster done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbPeers(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -91,25 +89,20 @@ func dbPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) { return } - nDB, ok := ctx.(*NetworkDB) - if ok { - peers := nDB.Peers(r.Form["nid"][0]) - rsp := &diagnostic.TableObj{Length: len(peers)} - for i, peerInfo := range peers { - if peerInfo.IP == "unknown" { - rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: "orphan-" + peerInfo.Name, IP: peerInfo.IP}) - } else { - rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP}) - } + peers := nDB.Peers(r.Form["nid"][0]) + rsp := &diagnostic.TableObj{Length: len(peers)} + for i, peerInfo := range peers { + if peerInfo.IP == "unknown" { + rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: "orphan-" + peerInfo.Name, IP: peerInfo.IP}) + } else { + rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP}) } - logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network peers done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) - return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network peers done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) } -func dbClusterPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbClusterPeers(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -123,21 +116,16 @@ func dbClusterPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) { }) logger.Info("cluster peers") - nDB, ok := ctx.(*NetworkDB) - if ok { - peers := nDB.ClusterPeers() - rsp := &diagnostic.TableObj{Length: len(peers)} - for i, peerInfo := range peers { - rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP}) - } - logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("cluster peers done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) - return + peers := nDB.ClusterPeers() + rsp := &diagnostic.TableObj{Length: len(peers)} + for i, peerInfo := range peers { + rsp.Elements = append(rsp.Elements, &diagnostic.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP}) } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("cluster peers done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) } -func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbCreateEntry(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) unsafe, json := diagnostic.ParseHTTPFormOptions(r) @@ -176,22 +164,17 @@ func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { } } - nDB, ok := ctx.(*NetworkDB) - if ok { - if err := nDB.CreateEntry(tname, nid, key, decodedValue); err != nil { - rsp := diagnostic.FailCommand(err) - diagnostic.HTTPReply(w, rsp, json) - logger.WithError(err).Error("create entry failed") - return - } - logger.Info("create entry done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + if err := nDB.CreateEntry(tname, nid, key, decodedValue); err != nil { + rsp := diagnostic.FailCommand(err) + diagnostic.HTTPReply(w, rsp, json) + logger.WithError(err).Error("create entry failed") return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.Info("create entry done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbUpdateEntry(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) unsafe, json := diagnostic.ParseHTTPFormOptions(r) @@ -230,21 +213,16 @@ func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { } } - nDB, ok := ctx.(*NetworkDB) - if ok { - if err := nDB.UpdateEntry(tname, nid, key, decodedValue); err != nil { - logger.WithError(err).Error("update entry failed") - diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) - return - } - logger.Info("update entry done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + if err := nDB.UpdateEntry(tname, nid, key, decodedValue); err != nil { + logger.WithError(err).Error("update entry failed") + diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.Info("update entry done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbDeleteEntry(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -271,22 +249,17 @@ func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { nid := r.Form["nid"][0] key := r.Form["key"][0] - nDB, ok := ctx.(*NetworkDB) - if ok { - err := nDB.DeleteEntry(tname, nid, key) - if err != nil { - logger.WithError(err).Error("delete entry failed") - diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) - return - } - logger.Info("delete entry done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + err := nDB.DeleteEntry(tname, nid, key) + if err != nil { + logger.WithError(err).Error("delete entry failed") + diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.Info("delete entry done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbGetEntry(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) unsafe, json := diagnostic.ParseHTTPFormOptions(r) @@ -313,31 +286,26 @@ func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) { nid := r.Form["nid"][0] key := r.Form["key"][0] - nDB, ok := ctx.(*NetworkDB) - if ok { - value, err := nDB.GetEntry(tname, nid, key) - if err != nil { - logger.WithError(err).Error("get entry failed") - diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) - return - } - - var encodedValue string - if unsafe { - encodedValue = string(value) - } else { - encodedValue = base64.StdEncoding.EncodeToString(value) - } - - rsp := &diagnostic.TableEntryObj{Key: key, Value: encodedValue} - logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get entry done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) + value, err := nDB.GetEntry(tname, nid, key) + if err != nil { + logger.WithError(err).Error("get entry failed") + diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + + var encodedValue string + if unsafe { + encodedValue = string(value) + } else { + encodedValue = base64.StdEncoding.EncodeToString(value) + } + + rsp := &diagnostic.TableEntryObj{Key: key, Value: encodedValue} + logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get entry done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) } -func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbJoinNetwork(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -360,21 +328,16 @@ func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) { nid := r.Form["nid"][0] - nDB, ok := ctx.(*NetworkDB) - if ok { - if err := nDB.JoinNetwork(nid); err != nil { - logger.WithError(err).Error("join network failed") - diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) - return - } - logger.Info("join network done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + if err := nDB.JoinNetwork(nid); err != nil { + logger.WithError(err).Error("join network failed") + diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.Info("join network done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbLeaveNetwork(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -397,21 +360,16 @@ func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) { nid := r.Form["nid"][0] - nDB, ok := ctx.(*NetworkDB) - if ok { - if err := nDB.LeaveNetwork(nid); err != nil { - logger.WithError(err).Error("leave network failed") - diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) - return - } - logger.Info("leave network done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) + if err := nDB.LeaveNetwork(nid); err != nil { + logger.WithError(err).Error("leave network failed") + diagnostic.HTTPReply(w, diagnostic.FailCommand(err), json) return } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.Info("leave network done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(nil), json) } -func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbGetTable(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) unsafe, json := diagnostic.ParseHTTPFormOptions(r) @@ -436,35 +394,30 @@ func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) { tname := r.Form["tname"][0] nid := r.Form["nid"][0] - nDB, ok := ctx.(*NetworkDB) - if ok { - table := nDB.GetTableByNetwork(tname, nid) - rsp := &diagnostic.TableObj{Length: len(table)} - i := 0 - for k, v := range table { - var encodedValue string - if unsafe { - encodedValue = string(v.Value) - } else { - encodedValue = base64.StdEncoding.EncodeToString(v.Value) - } - rsp.Elements = append(rsp.Elements, - &diagnostic.TableEntryObj{ - Index: i, - Key: k, - Value: encodedValue, - Owner: v.owner, - }) - i++ + table := nDB.GetTableByNetwork(tname, nid) + rsp := &diagnostic.TableObj{Length: len(table)} + i := 0 + for k, v := range table { + var encodedValue string + if unsafe { + encodedValue = string(v.Value) + } else { + encodedValue = base64.StdEncoding.EncodeToString(v.Value) } - logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get table done") - diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) - return + rsp.Elements = append(rsp.Elements, + &diagnostic.TableEntryObj{ + Index: i, + Key: k, + Value: encodedValue, + Owner: v.owner, + }) + i++ } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get table done") + diagnostic.HTTPReply(w, diagnostic.CommandSucceed(rsp), json) } -func dbNetworkStats(ctx interface{}, w http.ResponseWriter, r *http.Request) { +func (nDB *NetworkDB) dbNetworkStats(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() diagnostic.DebugHTTPForm(r) _, json := diagnostic.ParseHTTPFormOptions(r) @@ -485,24 +438,19 @@ func dbNetworkStats(ctx interface{}, w http.ResponseWriter, r *http.Request) { return } - nDB, ok := ctx.(*NetworkDB) + nDB.RLock() + networks := nDB.networks[nDB.config.NodeID] + network, ok := networks[r.Form["nid"][0]] + + entries := -1 + qLen := -1 if ok { - nDB.RLock() - networks := nDB.networks[nDB.config.NodeID] - network, ok := networks[r.Form["nid"][0]] - - entries := -1 - qLen := -1 - if ok { - entries = int(network.entriesNumber.Load()) - qLen = network.tableBroadcasts.NumQueued() - } - nDB.RUnlock() - - rsp := diagnostic.CommandSucceed(&diagnostic.NetworkStatsResult{Entries: entries, QueueLen: qLen}) - logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network stats done") - diagnostic.HTTPReply(w, rsp, json) - return + entries = int(network.entriesNumber.Load()) + qLen = network.tableBroadcasts.NumQueued() } - diagnostic.HTTPReply(w, diagnostic.FailCommand(fmt.Errorf(dbNotAvailable)), json) + nDB.RUnlock() + + rsp := diagnostic.CommandSucceed(&diagnostic.NetworkStatsResult{Entries: entries, QueueLen: qLen}) + logger.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network stats done") + diagnostic.HTTPReply(w, rsp, json) }