// SPDX-License-Identifier: EUPL-1.2 // Package pairing handles the handshake between LetheanGateway and lthn.io. // // client := pairing.NewClient("https://lthn.io", "api-key", "charon", "eu-west", "10.69.69.165:51820") // client.Pair() // client.Heartbeat(stats) package pairing import ( "encoding/json" "net/http" core "dappco.re/go/core" ) // Client manages the pairing lifecycle with lthn.io. type Client struct { apiURL string apiKey string name string region string wireguardEndpoint string } // NewClient creates a pairing client for the given gateway. // // client := pairing.NewClient("https://lthn.io", "key", "charon", "eu-west", "10.0.0.1:51820") func NewClient(apiURL, apiKey, name, region, wireguardEndpoint string) *Client { return &Client{ apiURL: apiURL, apiKey: apiKey, name: name, region: region, wireguardEndpoint: wireguardEndpoint, } } // Pair registers this gateway with lthn.io. // // err := client.Pair() func (c *Client) Pair() error { body := map[string]interface{}{ "name": c.name, "capabilities": []string{"vpn", "dns", "proxy"}, "region": c.region, "bandwidth_mbps": 100, "max_connections": 50, "wireguard_endpoint": c.wireguardEndpoint, } data, _ := json.Marshal(body) request, err := http.NewRequest("POST", c.apiURL+"/v1/gateway/pair", core.NewReader(string(data))) if err != nil { return core.E("pairing.Pair", "failed to create request", err) } request.Header.Set("Content-Type", "application/json") if c.apiKey != "" { request.Header.Set("Authorization", "Bearer "+c.apiKey) } response, err := http.DefaultClient.Do(request) if err != nil { return core.E("pairing.Pair", "request failed", err) } defer response.Body.Close() if response.StatusCode != 200 { return core.E("pairing.Pair", core.Sprintf("status %d", response.StatusCode), nil) } return nil } // Heartbeat sends alive status + stats to lthn.io. // // err := client.Heartbeat(map[string]interface{}{"connections": 5, "load": 23}) func (c *Client) Heartbeat(stats map[string]interface{}) error { stats["name"] = c.name data, _ := json.Marshal(stats) request, err := http.NewRequest("POST", c.apiURL+"/v1/gateway/heartbeat", core.NewReader(string(data))) if err != nil { return core.E("pairing.Heartbeat", "failed to create request", err) } request.Header.Set("Content-Type", "application/json") if c.apiKey != "" { request.Header.Set("Authorization", "Bearer "+c.apiKey) } response, err := http.DefaultClient.Do(request) if err != nil { return core.E("pairing.Heartbeat", "request failed", err) } defer response.Body.Close() return nil }