package sdk import ( "bytes" "encoding/json" "fmt" "io" "net/http" "strings" ) func (c *Client) doReq(method, path string, body, out interface{}) error { url := strings.TrimRight(c.cfg.ControllerURL, "/") + path var r io.Reader if body != nil { data, err := json.Marshal(body) if err != nil { return fmt.Errorf("marshal body: %w", err) } r = bytes.NewReader(data) } req, err := http.NewRequest(method, url, r) if err != nil { return fmt.Errorf("create request: %w", err) } if c.cfg.Token != "" { req.Header.Set("Authorization", "Bearer "+c.cfg.Token) } if r != nil { req.Header.Set("Content-Type", "application/json") } resp, err := c.httpc.Do(req) if err != nil { return fmt.Errorf("do request: %w", err) } defer resp.Body.Close() respData, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("read response: %w", err) } if resp.StatusCode >= 400 { var errResp struct{ Error string `json:"error"` } if json.Unmarshal(respData, &errResp) == nil && errResp.Error != "" { return fmt.Errorf("%s", errResp.Error) } return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(respData)) } if out != nil { if err := json.Unmarshal(respData, out); err != nil { return fmt.Errorf("unmarshal response: %w", err) } } return nil } func (c *Client) Login(username, password string) error { var resp AuthResponse if err := c.doReq("POST", "/api/v1/auth/login", map[string]string{ "username": username, "password": password, }, &resp); err != nil { return err } c.cfg.Token = resp.Token return nil } func (c *Client) Register(username, password string) (*User, error) { var resp AuthResponse if err := c.doReq("POST", "/api/v1/auth/register", map[string]string{ "username": username, "password": password, }, &resp); err != nil { return nil, err } c.cfg.Token = resp.Token return resp.User, nil } func (c *Client) InitAdmin(username, password string) (*User, error) { var resp AuthResponse if err := c.doReq("POST", "/api/v1/auth/init", map[string]string{ "username": username, "password": password, }, &resp); err != nil { return nil, err } c.cfg.Token = resp.Token return resp.User, nil } func (c *Client) CheckAdmin() (bool, error) { var resp struct{ AdminExists bool `json:"admin_exists"` } if err := c.doReq("GET", "/api/v1/admin/check", nil, &resp); err != nil { return false, err } return resp.AdminExists, nil } func (c *Client) Dashboard() (*DashboardStats, error) { var stats DashboardStats if err := c.doReq("GET", "/api/v1/dashboard", nil, &stats); err != nil { return nil, err } return &stats, nil } func (c *Client) AdminDashboard() (*DashboardStats, error) { var stats DashboardStats if err := c.doReq("GET", "/api/v1/admin/dashboard", nil, &stats); err != nil { return nil, err } return &stats, nil } func (c *Client) Profile() (*ProfileResponse, error) { var resp ProfileResponse if err := c.doReq("GET", "/api/v1/user/profile", nil, &resp); err != nil { return nil, err } return &resp, nil } func (c *Client) CreateNetwork(name, ipRange string) (*Network, error) { body := map[string]string{"name": name} if ipRange != "" { body["ip_range"] = ipRange } var resp struct{ Network *Network `json:"network"` } if err := c.doReq("POST", "/api/v1/network/create", body, &resp); err != nil { return nil, err } return resp.Network, nil } func (c *Client) ListNetworks() ([]Network, error) { var resp NetworkListResponse if err := c.doReq("GET", "/api/v1/network/list", nil, &resp); err != nil { return nil, err } return resp.Networks, nil } func (c *Client) GetNetwork(id uint32) (*Network, error) { var resp struct{ Network *Network `json:"network"` } if err := c.doReq("GET", fmt.Sprintf("/api/v1/network/%d", id), nil, &resp); err != nil { return nil, err } return resp.Network, nil } func (c *Client) DeleteNetwork(id uint32) error { return c.doReq("DELETE", fmt.Sprintf("/api/v1/network/%d", id), nil, nil) } func (c *Client) NetworkMembers(id uint32) ([]NetworkMember, error) { var resp MembersResponse if err := c.doReq("GET", fmt.Sprintf("/api/v1/network/%d/members", id), nil, &resp); err != nil { return nil, err } return resp.Members, nil } func (c *Client) AuthorizeMember(networkID uint32, nodeID string) error { return c.doReq("POST", fmt.Sprintf("/api/v1/network/%d/authorize", networkID), map[string]string{"node_id": nodeID}, nil) } func (c *Client) DeauthorizeMember(networkID uint32, nodeID string) error { return c.doReq("POST", fmt.Sprintf("/api/v1/network/%d/deauthorize", networkID), map[string]string{"node_id": nodeID}, nil) } func (c *Client) RegisterNode(nodeID, publicKey, name, ipAddr string, port int, version string) (*Node, error) { body := map[string]interface{}{ "node_id": nodeID, "public_key": publicKey, "name": name, } if ipAddr != "" { body["ip_address"] = ipAddr } if port > 0 { body["port"] = port } if version != "" { body["version"] = version } var resp struct{ Node *Node `json:"node"` } if err := c.doReq("POST", "/api/v1/node/register", body, &resp); err != nil { return nil, err } return resp.Node, nil } func (c *Client) ListNodes() ([]Node, error) { var resp NodeListResponse if err := c.doReq("GET", "/api/v1/node/list", nil, &resp); err != nil { return nil, err } return resp.Nodes, nil } func (c *Client) ListOnlineNodes() ([]Node, error) { var resp NodeListResponse if err := c.doReq("GET", "/api/v1/node/online", nil, &resp); err != nil { return nil, err } return resp.Nodes, nil }