mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Admin socket and yggdrasilctl refactoring (#939)
				
					
				
			This commit is contained in:
		
							parent
							
								
									4f2abece81
								
							
						
					
					
						commit
						c6fe81b5d2
					
				
					 11 changed files with 401 additions and 470 deletions
				
			
		| 
						 | 
				
			
			@ -7,6 +7,7 @@ import (
 | 
			
		|||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,13 +29,17 @@ type AdminSocket struct {
 | 
			
		|||
	done       chan struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AdminSocketRequest struct {
 | 
			
		||||
	Name      string            `json:"request"`
 | 
			
		||||
	Arguments map[string]string `json:"arguments,omitempty"`
 | 
			
		||||
	KeepAlive bool              `json:"keepalive,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AdminSocketResponse struct {
 | 
			
		||||
	Status  string `json:"status"`
 | 
			
		||||
	Request struct {
 | 
			
		||||
		Name      string `json:"request"`
 | 
			
		||||
		KeepAlive bool   `json:"keepalive"`
 | 
			
		||||
	} `json:"request"`
 | 
			
		||||
	Response interface{} `json:"response"`
 | 
			
		||||
	Status   string             `json:"status"`
 | 
			
		||||
	Error    string             `json:"error,omitempty"`
 | 
			
		||||
	Request  AdminSocketRequest `json:"request"`
 | 
			
		||||
	Response json.RawMessage    `json:"response"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type handler struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +48,12 @@ type handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type ListResponse struct {
 | 
			
		||||
	List map[string]ListEntry `json:"list"`
 | 
			
		||||
	List []ListEntry `json:"list"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListEntry struct {
 | 
			
		||||
	Fields []string `json:"fields"`
 | 
			
		||||
	Command string   `json:"command"`
 | 
			
		||||
	Fields  []string `json:"fields,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddHandler is called for each admin function to add the handler and help documentation to the API.
 | 
			
		||||
| 
						 | 
				
			
			@ -73,14 +79,16 @@ func (a *AdminSocket) Init(c *core.Core, nc *config.NodeConfig, log *log.Logger,
 | 
			
		|||
	a.done = make(chan struct{})
 | 
			
		||||
	close(a.done) // Start in a done / not-started state
 | 
			
		||||
	_ = a.AddHandler("list", []string{}, func(_ json.RawMessage) (interface{}, error) {
 | 
			
		||||
		res := &ListResponse{
 | 
			
		||||
			List: map[string]ListEntry{},
 | 
			
		||||
		}
 | 
			
		||||
		res := &ListResponse{}
 | 
			
		||||
		for name, handler := range a.handlers {
 | 
			
		||||
			res.List[name] = ListEntry{
 | 
			
		||||
				Fields: handler.args,
 | 
			
		||||
			}
 | 
			
		||||
			res.List = append(res.List, ListEntry{
 | 
			
		||||
				Command: name,
 | 
			
		||||
				Fields:  handler.args,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		sort.SliceStable(res.List, func(i, j int) bool {
 | 
			
		||||
			return strings.Compare(res.List[i].Command, res.List[j].Command) < 0
 | 
			
		||||
		})
 | 
			
		||||
		return res, nil
 | 
			
		||||
	})
 | 
			
		||||
	return a.core.SetAdmin(a)
 | 
			
		||||
| 
						 | 
				
			
			@ -277,22 +285,28 @@ func (a *AdminSocket) handleRequest(conn net.Conn) {
 | 
			
		|||
		if err = json.Unmarshal(buf, &resp.Request); err == nil {
 | 
			
		||||
			if resp.Request.Name == "" {
 | 
			
		||||
				resp.Status = "error"
 | 
			
		||||
				resp.Response = &ErrorResponse{
 | 
			
		||||
				resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
					Error: "No request specified",
 | 
			
		||||
				}
 | 
			
		||||
				})
 | 
			
		||||
			} else if h, ok := a.handlers[strings.ToLower(resp.Request.Name)]; ok {
 | 
			
		||||
				resp.Response, err = h.handler(buf)
 | 
			
		||||
				res, err := h.handler(buf)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					resp.Status = "error"
 | 
			
		||||
					resp.Response = &ErrorResponse{
 | 
			
		||||
					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 = &ErrorResponse{
 | 
			
		||||
				resp.Response, _ = json.Marshal(ErrorResponse{
 | 
			
		||||
					Error: fmt.Sprintf("Unknown action '%s', try 'list' for help", resp.Request.Name),
 | 
			
		||||
				}
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err = encoder.Encode(resp); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -305,3 +319,16 @@ func (a *AdminSocket) handleRequest(conn net.Conn) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DataUnit uint64
 | 
			
		||||
 | 
			
		||||
func (d DataUnit) String() string {
 | 
			
		||||
	switch {
 | 
			
		||||
	case d > 1024*1024*1024:
 | 
			
		||||
		return fmt.Sprintf("%2.fgb", float64(d)/1024/1024/1024)
 | 
			
		||||
	case d > 1024*1024:
 | 
			
		||||
		return fmt.Sprintf("%2.fmb", float64(d)/1024/1024)
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Sprintf("%2.fkb", float64(d)/1024)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ package admin
 | 
			
		|||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -10,25 +12,30 @@ import (
 | 
			
		|||
type GetDHTRequest struct{}
 | 
			
		||||
 | 
			
		||||
type GetDHTResponse struct {
 | 
			
		||||
	DHT map[string]DHTEntry `json:"dht"`
 | 
			
		||||
	DHT []DHTEntry `json:"dht"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DHTEntry struct {
 | 
			
		||||
	IPAddress string `json:"address"`
 | 
			
		||||
	PublicKey string `json:"key"`
 | 
			
		||||
	Port      uint64 `json:"port"`
 | 
			
		||||
	Rest      uint64 `json:"rest"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) getDHTHandler(req *GetDHTRequest, res *GetDHTResponse) error {
 | 
			
		||||
	res.DHT = map[string]DHTEntry{}
 | 
			
		||||
	for _, d := range a.core.GetDHT() {
 | 
			
		||||
	dht := a.core.GetDHT()
 | 
			
		||||
	res.DHT = make([]DHTEntry, 0, len(dht))
 | 
			
		||||
	for _, d := range dht {
 | 
			
		||||
		addr := address.AddrForKey(d.Key)
 | 
			
		||||
		so := net.IP(addr[:]).String()
 | 
			
		||||
		res.DHT[so] = DHTEntry{
 | 
			
		||||
		res.DHT = append(res.DHT, DHTEntry{
 | 
			
		||||
			IPAddress: net.IP(addr[:]).String(),
 | 
			
		||||
			PublicKey: hex.EncodeToString(d.Key[:]),
 | 
			
		||||
			Port:      d.Port,
 | 
			
		||||
			Rest:      d.Rest,
 | 
			
		||||
		}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	sort.SliceStable(res.DHT, func(i, j int) bool {
 | 
			
		||||
		return strings.Compare(res.DHT[i].PublicKey, res.DHT[j].PublicKey) < 0
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ package admin
 | 
			
		|||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -11,23 +13,28 @@ type GetPathsRequest struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type GetPathsResponse struct {
 | 
			
		||||
	Paths map[string]PathEntry `json:"paths"`
 | 
			
		||||
	Paths []PathEntry `json:"paths"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PathEntry struct {
 | 
			
		||||
	IPAddress string   `json:"address"`
 | 
			
		||||
	PublicKey string   `json:"key"`
 | 
			
		||||
	Path      []uint64 `json:"path"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) getPathsHandler(req *GetPathsRequest, res *GetPathsResponse) error {
 | 
			
		||||
	res.Paths = map[string]PathEntry{}
 | 
			
		||||
	for _, p := range a.core.GetPaths() {
 | 
			
		||||
	paths := a.core.GetPaths()
 | 
			
		||||
	res.Paths = make([]PathEntry, 0, len(paths))
 | 
			
		||||
	for _, p := range paths {
 | 
			
		||||
		addr := address.AddrForKey(p.Key)
 | 
			
		||||
		so := net.IP(addr[:]).String()
 | 
			
		||||
		res.Paths[so] = PathEntry{
 | 
			
		||||
		res.Paths = append(res.Paths, PathEntry{
 | 
			
		||||
			IPAddress: net.IP(addr[:]).String(),
 | 
			
		||||
			PublicKey: hex.EncodeToString(p.Key),
 | 
			
		||||
			Path:      p.Path,
 | 
			
		||||
		}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	sort.SliceStable(res.Paths, func(i, j int) bool {
 | 
			
		||||
		return strings.Compare(res.Paths[i].PublicKey, res.Paths[j].PublicKey) < 0
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package admin
 | 
			
		|||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -11,33 +12,38 @@ type GetPeersRequest struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type GetPeersResponse struct {
 | 
			
		||||
	Peers map[string]PeerEntry `json:"peers"`
 | 
			
		||||
	Peers []PeerEntry `json:"peers"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PeerEntry struct {
 | 
			
		||||
	IPAddress string   `json:"address"`
 | 
			
		||||
	PublicKey string   `json:"key"`
 | 
			
		||||
	Port      uint64   `json:"port"`
 | 
			
		||||
	Coords    []uint64 `json:"coords"`
 | 
			
		||||
	Remote    string   `json:"remote"`
 | 
			
		||||
	RXBytes   uint64   `json:"bytes_recvd"`
 | 
			
		||||
	TXBytes   uint64   `json:"bytes_sent"`
 | 
			
		||||
	RXBytes   DataUnit `json:"bytes_recvd"`
 | 
			
		||||
	TXBytes   DataUnit `json:"bytes_sent"`
 | 
			
		||||
	Uptime    float64  `json:"uptime"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersResponse) error {
 | 
			
		||||
	res.Peers = map[string]PeerEntry{}
 | 
			
		||||
	for _, p := range a.core.GetPeers() {
 | 
			
		||||
	peers := a.core.GetPeers()
 | 
			
		||||
	res.Peers = make([]PeerEntry, 0, len(peers))
 | 
			
		||||
	for _, p := range peers {
 | 
			
		||||
		addr := address.AddrForKey(p.Key)
 | 
			
		||||
		so := net.IP(addr[:]).String()
 | 
			
		||||
		res.Peers[so] = PeerEntry{
 | 
			
		||||
		res.Peers = append(res.Peers, PeerEntry{
 | 
			
		||||
			IPAddress: net.IP(addr[:]).String(),
 | 
			
		||||
			PublicKey: hex.EncodeToString(p.Key),
 | 
			
		||||
			Port:      p.Port,
 | 
			
		||||
			Coords:    p.Coords,
 | 
			
		||||
			Remote:    p.Remote,
 | 
			
		||||
			RXBytes:   p.RXBytes,
 | 
			
		||||
			TXBytes:   p.TXBytes,
 | 
			
		||||
			RXBytes:   DataUnit(p.RXBytes),
 | 
			
		||||
			TXBytes:   DataUnit(p.TXBytes),
 | 
			
		||||
			Uptime:    p.Uptime.Seconds(),
 | 
			
		||||
		}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	sort.Slice(res.Peers, func(i, j int) bool {
 | 
			
		||||
		return res.Peers[i].Port < res.Peers[j].Port
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,28 +9,22 @@ import (
 | 
			
		|||
type GetSelfRequest struct{}
 | 
			
		||||
 | 
			
		||||
type GetSelfResponse struct {
 | 
			
		||||
	Self map[string]SelfEntry `json:"self"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SelfEntry struct {
 | 
			
		||||
	BuildName    string   `json:"build_name"`
 | 
			
		||||
	BuildVersion string   `json:"build_version"`
 | 
			
		||||
	PublicKey    string   `json:"key"`
 | 
			
		||||
	IPAddress    string   `json:"address"`
 | 
			
		||||
	Coords       []uint64 `json:"coords"`
 | 
			
		||||
	Subnet       string   `json:"subnet"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) getSelfHandler(req *GetSelfRequest, res *GetSelfResponse) error {
 | 
			
		||||
	res.Self = make(map[string]SelfEntry)
 | 
			
		||||
	self := a.core.GetSelf()
 | 
			
		||||
	addr := a.core.Address().String()
 | 
			
		||||
	snet := a.core.Subnet()
 | 
			
		||||
	res.Self[addr] = SelfEntry{
 | 
			
		||||
		BuildName:    version.BuildName(),
 | 
			
		||||
		BuildVersion: version.BuildVersion(),
 | 
			
		||||
		PublicKey:    hex.EncodeToString(self.Key[:]),
 | 
			
		||||
		Subnet:       snet.String(),
 | 
			
		||||
		Coords:       self.Coords,
 | 
			
		||||
	}
 | 
			
		||||
	res.BuildName = version.BuildName()
 | 
			
		||||
	res.BuildVersion = version.BuildVersion()
 | 
			
		||||
	res.PublicKey = hex.EncodeToString(self.Key[:])
 | 
			
		||||
	res.IPAddress = a.core.Address().String()
 | 
			
		||||
	res.Subnet = snet.String()
 | 
			
		||||
	res.Coords = self.Coords
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ package admin
 | 
			
		|||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -10,21 +12,26 @@ import (
 | 
			
		|||
type GetSessionsRequest struct{}
 | 
			
		||||
 | 
			
		||||
type GetSessionsResponse struct {
 | 
			
		||||
	Sessions map[string]SessionEntry `json:"sessions"`
 | 
			
		||||
	Sessions []SessionEntry `json:"sessions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SessionEntry struct {
 | 
			
		||||
	IPAddress string `json:"address"`
 | 
			
		||||
	PublicKey string `json:"key"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AdminSocket) getSessionsHandler(req *GetSessionsRequest, res *GetSessionsResponse) error {
 | 
			
		||||
	res.Sessions = map[string]SessionEntry{}
 | 
			
		||||
	for _, s := range a.core.GetSessions() {
 | 
			
		||||
	sessions := a.core.GetSessions()
 | 
			
		||||
	res.Sessions = make([]SessionEntry, 0, len(sessions))
 | 
			
		||||
	for _, s := range sessions {
 | 
			
		||||
		addr := address.AddrForKey(s.Key)
 | 
			
		||||
		so := net.IP(addr[:]).String()
 | 
			
		||||
		res.Sessions[so] = SessionEntry{
 | 
			
		||||
		res.Sessions = append(res.Sessions, SessionEntry{
 | 
			
		||||
			IPAddress: net.IP(addr[:]).String(),
 | 
			
		||||
			PublicKey: hex.EncodeToString(s.Key[:]),
 | 
			
		||||
		}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	sort.SliceStable(res.Sessions, func(i, j int) bool {
 | 
			
		||||
		return strings.Compare(res.Sessions[i].PublicKey, res.Sessions[j].PublicKey) < 0
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue