github.com/yggdrasil-network/yggdrasil-go@v0.5.6/src/admin/admin.go (about) 1 package admin 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net" 8 "net/url" 9 "os" 10 "sort" 11 12 "strings" 13 "time" 14 15 "github.com/yggdrasil-network/yggdrasil-go/src/core" 16 ) 17 18 // TODO: Add authentication 19 20 type AdminSocket struct { 21 core *core.Core 22 log core.Logger 23 listener net.Listener 24 handlers map[string]handler 25 done chan struct{} 26 config struct { 27 listenaddr ListenAddress 28 } 29 } 30 31 type AdminSocketRequest struct { 32 Name string `json:"request"` 33 Arguments json.RawMessage `json:"arguments,omitempty"` 34 KeepAlive bool `json:"keepalive,omitempty"` 35 } 36 37 type AdminSocketResponse struct { 38 Status string `json:"status"` 39 Error string `json:"error,omitempty"` 40 Request AdminSocketRequest `json:"request"` 41 Response json.RawMessage `json:"response"` 42 } 43 44 type handler struct { 45 desc string // What does the endpoint do? 46 args []string // List of human-readable argument names 47 handler core.AddHandlerFunc // First is input map, second is output 48 } 49 50 type ListResponse struct { 51 List []ListEntry `json:"list"` 52 } 53 54 type ListEntry struct { 55 Command string `json:"command"` 56 Description string `json:"description"` 57 Fields []string `json:"fields,omitempty"` 58 } 59 60 // AddHandler is called for each admin function to add the handler and help documentation to the API. 61 func (a *AdminSocket) AddHandler(name, desc string, args []string, handlerfunc core.AddHandlerFunc) error { 62 if _, ok := a.handlers[strings.ToLower(name)]; ok { 63 return errors.New("handler already exists") 64 } 65 a.handlers[strings.ToLower(name)] = handler{ 66 desc: desc, 67 args: args, 68 handler: handlerfunc, 69 } 70 return nil 71 } 72 73 // Init runs the initial admin setup. 74 func New(c *core.Core, log core.Logger, opts ...SetupOption) (*AdminSocket, error) { 75 a := &AdminSocket{ 76 core: c, 77 log: log, 78 handlers: make(map[string]handler), 79 } 80 for _, opt := range opts { 81 a._applyOption(opt) 82 } 83 if a.config.listenaddr == "none" || a.config.listenaddr == "" { 84 return nil, nil 85 } 86 _ = a.AddHandler("list", "List available commands", []string{}, func(_ json.RawMessage) (interface{}, error) { 87 res := &ListResponse{} 88 for name, handler := range a.handlers { 89 res.List = append(res.List, ListEntry{ 90 Command: name, 91 Description: handler.desc, 92 Fields: handler.args, 93 }) 94 } 95 sort.SliceStable(res.List, func(i, j int) bool { 96 return strings.Compare(res.List[i].Command, res.List[j].Command) < 0 97 }) 98 return res, nil 99 }) 100 a.done = make(chan struct{}) 101 go a.listen() 102 return a, a.core.SetAdmin(a) 103 } 104 105 func (a *AdminSocket) SetupAdminHandlers() { 106 _ = a.AddHandler( 107 "getSelf", "Show details about this node", []string{}, 108 func(in json.RawMessage) (interface{}, error) { 109 req := &GetSelfRequest{} 110 res := &GetSelfResponse{} 111 if err := json.Unmarshal(in, &req); err != nil { 112 return nil, err 113 } 114 if err := a.getSelfHandler(req, res); err != nil { 115 return nil, err 116 } 117 return res, nil 118 }, 119 ) 120 _ = a.AddHandler( 121 "getPeers", "Show directly connected peers", []string{}, 122 func(in json.RawMessage) (interface{}, error) { 123 req := &GetPeersRequest{} 124 res := &GetPeersResponse{} 125 if err := json.Unmarshal(in, &req); err != nil { 126 return nil, err 127 } 128 if err := a.getPeersHandler(req, res); err != nil { 129 return nil, err 130 } 131 return res, nil 132 }, 133 ) 134 _ = a.AddHandler( 135 "getTree", "Show known Tree entries", []string{}, 136 func(in json.RawMessage) (interface{}, error) { 137 req := &GetTreeRequest{} 138 res := &GetTreeResponse{} 139 if err := json.Unmarshal(in, &req); err != nil { 140 return nil, err 141 } 142 if err := a.getTreeHandler(req, res); err != nil { 143 return nil, err 144 } 145 return res, nil 146 }, 147 ) 148 _ = a.AddHandler( 149 "getPaths", "Show established paths through this node", []string{}, 150 func(in json.RawMessage) (interface{}, error) { 151 req := &GetPathsRequest{} 152 res := &GetPathsResponse{} 153 if err := json.Unmarshal(in, &req); err != nil { 154 return nil, err 155 } 156 if err := a.getPathsHandler(req, res); err != nil { 157 return nil, err 158 } 159 return res, nil 160 }, 161 ) 162 _ = a.AddHandler( 163 "getSessions", "Show established traffic sessions with remote nodes", []string{}, 164 func(in json.RawMessage) (interface{}, error) { 165 req := &GetSessionsRequest{} 166 res := &GetSessionsResponse{} 167 if err := json.Unmarshal(in, &req); err != nil { 168 return nil, err 169 } 170 if err := a.getSessionsHandler(req, res); err != nil { 171 return nil, err 172 } 173 return res, nil 174 }, 175 ) 176 _ = a.AddHandler( 177 "addPeer", "Add a peer to the peer list", []string{"uri", "interface"}, 178 func(in json.RawMessage) (interface{}, error) { 179 req := &AddPeerRequest{} 180 res := &AddPeerResponse{} 181 if err := json.Unmarshal(in, &req); err != nil { 182 return nil, err 183 } 184 if err := a.addPeerHandler(req, res); err != nil { 185 return nil, err 186 } 187 return res, nil 188 }, 189 ) 190 _ = a.AddHandler( 191 "removePeer", "Remove a peer from the peer list", []string{"uri", "interface"}, 192 func(in json.RawMessage) (interface{}, error) { 193 req := &RemovePeerRequest{} 194 res := &RemovePeerResponse{} 195 if err := json.Unmarshal(in, &req); err != nil { 196 return nil, err 197 } 198 if err := a.removePeerHandler(req, res); err != nil { 199 return nil, err 200 } 201 return res, nil 202 }, 203 ) 204 //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) 205 //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) 206 //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) 207 //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) 208 } 209 210 // IsStarted returns true if the module has been started. 211 func (a *AdminSocket) IsStarted() bool { 212 select { 213 case <-a.done: 214 // Not blocking, so we're not currently running 215 return false 216 default: 217 // Blocked, so we must have started 218 return true 219 } 220 } 221 222 // Stop will stop the admin API and close the socket. 223 func (a *AdminSocket) Stop() error { 224 if a == nil { 225 return nil 226 } 227 if a.listener != nil { 228 select { 229 case <-a.done: 230 default: 231 close(a.done) 232 } 233 return a.listener.Close() 234 } 235 return nil 236 } 237 238 // listen is run by start and manages API connections. 239 func (a *AdminSocket) listen() { 240 listenaddr := string(a.config.listenaddr) 241 u, err := url.Parse(listenaddr) 242 if err == nil { 243 switch strings.ToLower(u.Scheme) { 244 case "unix": 245 if _, err := os.Stat(listenaddr[7:]); err == nil { 246 a.log.Debugln("Admin socket", listenaddr[7:], "already exists, trying to clean up") 247 if _, err := net.DialTimeout("unix", listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() { 248 a.log.Errorln("Admin socket", listenaddr[7:], "already exists and is in use by another process") 249 os.Exit(1) 250 } else { 251 if err := os.Remove(listenaddr[7:]); err == nil { 252 a.log.Debugln(listenaddr[7:], "was cleaned up") 253 } else { 254 a.log.Errorln(listenaddr[7:], "already exists and was not cleaned up:", err) 255 os.Exit(1) 256 } 257 } 258 } 259 a.listener, err = net.Listen("unix", listenaddr[7:]) 260 if err == nil { 261 switch listenaddr[7:8] { 262 case "@": // maybe abstract namespace 263 default: 264 if err := os.Chmod(listenaddr[7:], 0660); err != nil { 265 a.log.Warnln("WARNING:", listenaddr[:7], "may have unsafe permissions!") 266 } 267 } 268 } 269 case "tcp": 270 a.listener, err = net.Listen("tcp", u.Host) 271 default: 272 // err = errors.New(fmt.Sprint("protocol not supported: ", u.Scheme)) 273 a.listener, err = net.Listen("tcp", listenaddr) 274 } 275 } else { 276 a.listener, err = net.Listen("tcp", listenaddr) 277 } 278 if err != nil { 279 a.log.Errorf("Admin socket failed to listen: %v", err) 280 os.Exit(1) 281 } 282 a.log.Infof("%s admin socket listening on %s", 283 strings.ToUpper(a.listener.Addr().Network()), 284 a.listener.Addr().String()) 285 defer a.listener.Close() 286 for { 287 conn, err := a.listener.Accept() 288 if err == nil { 289 go a.handleRequest(conn) 290 } else { 291 select { 292 case <-a.done: 293 // Not blocked, so we havent started or already stopped 294 return 295 default: 296 // Blocked, so we're supposed to keep running 297 } 298 } 299 } 300 } 301 302 // handleRequest calls the request handler for each request sent to the admin API. 303 func (a *AdminSocket) handleRequest(conn net.Conn) { 304 decoder := json.NewDecoder(conn) 305 decoder.DisallowUnknownFields() 306 307 encoder := json.NewEncoder(conn) 308 encoder.SetIndent("", " ") 309 310 defer conn.Close() 311 312 /* 313 defer func() { 314 r := recover() 315 if r != nil { 316 fmt.Println("ERROR:", r) 317 a.log.Debugln("Admin socket error:", r) 318 if err := encoder.Encode(&ErrorResponse{ 319 Error: "Check your syntax and input types", 320 }); err != nil { 321 fmt.Println("ERROR 2:", err) 322 a.log.Debugln("Admin socket JSON encode error:", err) 323 } 324 conn.Close() 325 } 326 }() 327 */ 328 329 for { 330 var err error 331 var buf json.RawMessage 332 var req AdminSocketRequest 333 var resp AdminSocketResponse 334 req.Arguments = []byte("{}") 335 if err := func() error { 336 if err = decoder.Decode(&buf); err != nil { 337 return fmt.Errorf("Failed to find request") 338 } 339 if err = json.Unmarshal(buf, &req); err != nil { 340 return fmt.Errorf("Failed to unmarshal request") 341 } 342 resp.Request = req 343 if req.Name == "" { 344 return fmt.Errorf("No request specified") 345 } 346 reqname := strings.ToLower(req.Name) 347 handler, ok := a.handlers[reqname] 348 if !ok { 349 return fmt.Errorf("Unknown action '%s', try 'list' for help", reqname) 350 } 351 res, err := handler.handler(req.Arguments) 352 if err != nil { 353 return err 354 } 355 if resp.Response, err = json.Marshal(res); err != nil { 356 return fmt.Errorf("Failed to marshal response: %w", err) 357 } 358 resp.Status = "success" 359 return nil 360 }(); err != nil { 361 resp.Status = "error" 362 resp.Error = err.Error() 363 } 364 if err = encoder.Encode(resp); err != nil { 365 a.log.Debugln("Encode error:", err) 366 } 367 if !req.KeepAlive { 368 break 369 } else { 370 continue 371 } 372 } 373 } 374 375 type DataUnit uint64 376 377 func (d DataUnit) String() string { 378 switch { 379 case d > 1024*1024*1024*1024: 380 return fmt.Sprintf("%2.ftb", float64(d)/1024/1024/1024/1024) 381 case d > 1024*1024*1024: 382 return fmt.Sprintf("%2.fgb", float64(d)/1024/1024/1024) 383 case d > 1024*1024: 384 return fmt.Sprintf("%2.fmb", float64(d)/1024/1024) 385 default: 386 return fmt.Sprintf("%2.fkb", float64(d)/1024) 387 } 388 }