mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Admin socket and yggdrasilctl improvements
				
					
				
			This refactors the request parsing, as well as improving the output for some request types. It also tweaks `yggdrasilctl` output, which should help with #947.
This commit is contained in:
		
							parent
							
								
									5ef61faeff
								
							
						
					
					
						commit
						b67c313f44
					
				
					 5 changed files with 193 additions and 123 deletions
				
			
		| 
						 | 
				
			
			@ -43,6 +43,7 @@ type AdminSocketResponse struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type handler struct {
 | 
			
		||||
	desc    string              // What does the endpoint do?
 | 
			
		||||
	args    []string            // List of human-readable argument names
 | 
			
		||||
	handler core.AddHandlerFunc // First is input map, second is output
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -52,16 +53,18 @@ type ListResponse struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type ListEntry struct {
 | 
			
		||||
	Command string   `json:"command"`
 | 
			
		||||
	Fields  []string `json:"fields,omitempty"`
 | 
			
		||||
	Command     string   `json:"command"`
 | 
			
		||||
	Description string   `json:"description"`
 | 
			
		||||
	Fields      []string `json:"fields,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddHandler is called for each admin function to add the handler and help documentation to the API.
 | 
			
		||||
func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc core.AddHandlerFunc) error {
 | 
			
		||||
func (a *AdminSocket) AddHandler(name, desc string, args []string, handlerfunc core.AddHandlerFunc) error {
 | 
			
		||||
	if _, ok := a.handlers[strings.ToLower(name)]; ok {
 | 
			
		||||
		return errors.New("handler already exists")
 | 
			
		||||
	}
 | 
			
		||||
	a.handlers[strings.ToLower(name)] = handler{
 | 
			
		||||
		desc:    desc,
 | 
			
		||||
		args:    args,
 | 
			
		||||
		handler: handlerfunc,
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -81,12 +84,13 @@ func New(c *core.Core, log util.Logger, opts ...SetupOption) (*AdminSocket, erro
 | 
			
		|||
	if a.config.listenaddr == "none" || a.config.listenaddr == "" {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	_ = a.AddHandler("list", []string{}, func(_ json.RawMessage) (interface{}, error) {
 | 
			
		||||
	_ = a.AddHandler("list", "List available commands", []string{}, func(_ json.RawMessage) (interface{}, error) {
 | 
			
		||||
		res := &ListResponse{}
 | 
			
		||||
		for name, handler := range a.handlers {
 | 
			
		||||
			res.List = append(res.List, ListEntry{
 | 
			
		||||
				Command: name,
 | 
			
		||||
				Fields:  handler.args,
 | 
			
		||||
				Command:     name,
 | 
			
		||||
				Description: handler.desc,
 | 
			
		||||
				Fields:      handler.args,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		sort.SliceStable(res.List, func(i, j int) bool {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,61 +104,76 @@ func New(c *core.Core, log util.Logger, opts ...SetupOption) (*AdminSocket, erro
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) SetupAdminHandlers() {
 | 
			
		||||
	_ = a.AddHandler("getSelf", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetSelfRequest{}
 | 
			
		||||
		res := &GetSelfResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := a.getSelfHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler("getPeers", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetPeersRequest{}
 | 
			
		||||
		res := &GetPeersResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := a.getPeersHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler("getDHT", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetDHTRequest{}
 | 
			
		||||
		res := &GetDHTResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := a.getDHTHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler("getPaths", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetPathsRequest{}
 | 
			
		||||
		res := &GetPathsResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := a.getPathsHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler("getSessions", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetSessionsRequest{}
 | 
			
		||||
		res := &GetSessionsResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := a.getSessionsHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getSelf", "Show details about this node", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetSelfRequest{}
 | 
			
		||||
			res := &GetSelfResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := a.getSelfHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getPeers", "Show directly connected peers", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetPeersRequest{}
 | 
			
		||||
			res := &GetPeersResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := a.getPeersHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getDHT", "Show known DHT entries", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetDHTRequest{}
 | 
			
		||||
			res := &GetDHTResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := a.getDHTHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getPaths", "Show established paths through this node", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetPathsRequest{}
 | 
			
		||||
			res := &GetPathsResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := a.getPathsHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getSessions", "Show established traffic sessions with remote nodes", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetSessionsRequest{}
 | 
			
		||||
			res := &GetSessionsResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := a.getSessionsHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	//_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler)
 | 
			
		||||
	//_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler)
 | 
			
		||||
	//_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler)
 | 
			
		||||
| 
						 | 
				
			
			@ -279,35 +298,34 @@ func (a *AdminSocket) handleRequest(conn net.Conn) {
 | 
			
		|||
	for {
 | 
			
		||||
		var err error
 | 
			
		||||
		var buf json.RawMessage
 | 
			
		||||
		_ = decoder.Decode(&buf)
 | 
			
		||||
		var resp AdminSocketResponse
 | 
			
		||||
		resp.Status = "success"
 | 
			
		||||
		if err = json.Unmarshal(buf, &resp.Request); err == nil {
 | 
			
		||||
			if resp.Request.Name == "" {
 | 
			
		||||
				resp.Status = "error"
 | 
			
		||||
				resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
					Error: "No request specified",
 | 
			
		||||
				})
 | 
			
		||||
			} else if h, ok := a.handlers[strings.ToLower(resp.Request.Name)]; ok {
 | 
			
		||||
				res, err := h.handler(buf)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					resp.Status = "error"
 | 
			
		||||
					resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
						Error: err.Error(),
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Response, err = json.Marshal(res); err != nil {
 | 
			
		||||
					resp.Status = "error"
 | 
			
		||||
					resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
						Error: err.Error(),
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				resp.Status = "error"
 | 
			
		||||
				resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
					Error: fmt.Sprintf("Unknown action '%s', try 'list' for help", resp.Request.Name),
 | 
			
		||||
				})
 | 
			
		||||
		if err := func() error {
 | 
			
		||||
			if err = decoder.Decode(&buf); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to find request")
 | 
			
		||||
			}
 | 
			
		||||
			if err = json.Unmarshal(buf, &resp.Request); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to unmarshal request")
 | 
			
		||||
			}
 | 
			
		||||
			if resp.Request.Name == "" {
 | 
			
		||||
				return fmt.Errorf("No request specified")
 | 
			
		||||
			}
 | 
			
		||||
			reqname := strings.ToLower(resp.Request.Name)
 | 
			
		||||
			handler, ok := a.handlers[reqname]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("Unknown action '%s', try 'list' for help", reqname)
 | 
			
		||||
			}
 | 
			
		||||
			res, err := handler.handler(buf)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("Handler returned error: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			if resp.Response, err = json.Marshal(res); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to marshal response: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			resp.Status = "success"
 | 
			
		||||
			return nil
 | 
			
		||||
		}(); err != nil {
 | 
			
		||||
			resp.Status = "error"
 | 
			
		||||
			resp.Error = err.Error()
 | 
			
		||||
		}
 | 
			
		||||
		if err = encoder.Encode(resp); err != nil {
 | 
			
		||||
			a.log.Debugln("Encode error:", err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -273,7 +273,7 @@ func (c *Core) PublicKey() ed25519.PublicKey {
 | 
			
		|||
// Hack to get the admin stuff working, TODO something cleaner
 | 
			
		||||
 | 
			
		||||
type AddHandler interface {
 | 
			
		||||
	AddHandler(name string, args []string, handlerfunc AddHandlerFunc) error
 | 
			
		||||
	AddHandler(name, desc string, args []string, handlerfunc AddHandlerFunc) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddHandlerFunc func(json.RawMessage) (interface{}, error)
 | 
			
		||||
| 
						 | 
				
			
			@ -281,16 +281,28 @@ type AddHandlerFunc func(json.RawMessage) (interface{}, error)
 | 
			
		|||
// SetAdmin must be called after Init and before Start.
 | 
			
		||||
// It sets the admin handler for NodeInfo and the Debug admin functions.
 | 
			
		||||
func (c *Core) SetAdmin(a AddHandler) error {
 | 
			
		||||
	if err := a.AddHandler("getNodeInfo", []string{"key"}, c.proto.nodeinfo.nodeInfoAdminHandler); err != nil {
 | 
			
		||||
	if err := a.AddHandler(
 | 
			
		||||
		"getNodeInfo", "Request nodeinfo from a remote node by its public key", []string{"key"},
 | 
			
		||||
		c.proto.nodeinfo.nodeInfoAdminHandler,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := a.AddHandler("debug_remoteGetSelf", []string{"key"}, c.proto.getSelfHandler); err != nil {
 | 
			
		||||
	if err := a.AddHandler(
 | 
			
		||||
		"debug_remoteGetSelf", "Debug use only", []string{"key"},
 | 
			
		||||
		c.proto.getSelfHandler,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := a.AddHandler("debug_remoteGetPeers", []string{"key"}, c.proto.getPeersHandler); err != nil {
 | 
			
		||||
	if err := a.AddHandler(
 | 
			
		||||
		"debug_remoteGetPeers", "Debug use only", []string{"key"},
 | 
			
		||||
		c.proto.getPeersHandler,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := a.AddHandler("debug_remoteGetDHT", []string{"key"}, c.proto.getDHTHandler); err != nil {
 | 
			
		||||
	if err := a.AddHandler(
 | 
			
		||||
		"debug_remoteGetDHT", "Debug use only", []string{"key"},
 | 
			
		||||
		c.proto.getDHTHandler,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,15 +20,18 @@ func (m *Multicast) getMulticastInterfacesHandler(req *GetMulticastInterfacesReq
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (m *Multicast) SetupAdminHandlers(a *admin.AdminSocket) {
 | 
			
		||||
	_ = a.AddHandler("getMulticastInterfaces", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetMulticastInterfacesRequest{}
 | 
			
		||||
		res := &GetMulticastInterfacesResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := m.getMulticastInterfacesHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getMulticastInterfaces", "Show which interfaces multicast is enabled on", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetMulticastInterfacesRequest{}
 | 
			
		||||
			res := &GetMulticastInterfacesResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := m.getMulticastInterfacesHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,31 +7,39 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type GetTUNRequest struct{}
 | 
			
		||||
type GetTUNResponse map[string]TUNEntry
 | 
			
		||||
type GetTUNResponse struct {
 | 
			
		||||
	Enabled bool   `json:"enabled"`
 | 
			
		||||
	Name    string `json:"name,omitempty"`
 | 
			
		||||
	MTU     uint64 `json:"mtu,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TUNEntry struct {
 | 
			
		||||
	MTU uint64 `json:"mtu"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *TunAdapter) getTUNHandler(req *GetTUNRequest, res *GetTUNResponse) error {
 | 
			
		||||
	*res = GetTUNResponse{
 | 
			
		||||
		t.Name(): TUNEntry{
 | 
			
		||||
			MTU: t.MTU(),
 | 
			
		||||
		},
 | 
			
		||||
	res.Enabled = t.isEnabled
 | 
			
		||||
	if !t.isEnabled {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	res.Name = t.Name()
 | 
			
		||||
	res.MTU = t.MTU()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) {
 | 
			
		||||
	_ = a.AddHandler("getTunTap", []string{}, func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
		req := &GetTUNRequest{}
 | 
			
		||||
		res := &GetTUNResponse{}
 | 
			
		||||
		if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := t.getTUNHandler(req, res); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	_ = a.AddHandler(
 | 
			
		||||
		"getTun", "Show information about the node's TUN interface", []string{},
 | 
			
		||||
		func(in json.RawMessage) (interface{}, error) {
 | 
			
		||||
			req := &GetTUNRequest{}
 | 
			
		||||
			res := &GetTUNResponse{}
 | 
			
		||||
			if err := json.Unmarshal(in, &req); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if err := t.getTUNHandler(req, res); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return res, nil
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue