ironlicensing-go/transport.go

194 lines
4.9 KiB
Go

package ironlicensing
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"runtime"
"time"
"github.com/google/uuid"
)
type Transport struct {
baseURL string
publicKey string
productSlug string
debug bool
httpClient *http.Client
machineID string
}
func NewTransport(baseURL, publicKey, productSlug string, timeout time.Duration, debug bool) *Transport {
t := &Transport{
baseURL: baseURL,
publicKey: publicKey,
productSlug: productSlug,
debug: debug,
httpClient: &http.Client{Timeout: timeout},
}
t.machineID = t.getMachineID()
return t
}
func (t *Transport) log(msg string) {
if t.debug {
fmt.Printf("[IronLicensing] %s\n", msg)
}
}
func (t *Transport) getMachineID() string {
homeDir, _ := os.UserHomeDir()
idPath := filepath.Join(homeDir, ".ironlicensing", "machine_id")
if data, err := os.ReadFile(idPath); err == nil {
return string(data)
}
id := uuid.New().String()
os.MkdirAll(filepath.Dir(idPath), 0755)
os.WriteFile(idPath, []byte(id), 0644)
return id
}
func (t *Transport) request(ctx context.Context, method, path string, body any) (*http.Response, error) {
var reqBody io.Reader
if body != nil {
data, _ := json.Marshal(body)
reqBody = bytes.NewReader(data)
}
req, err := http.NewRequestWithContext(ctx, method, t.baseURL+path, reqBody)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Public-Key", t.publicKey)
req.Header.Set("X-Product-Slug", t.productSlug)
return t.httpClient.Do(req)
}
func (t *Transport) Validate(ctx context.Context, licenseKey string) LicenseResult {
t.log(fmt.Sprintf("Validating: %s...", licenseKey[:min(10, len(licenseKey))]))
resp, err := t.request(ctx, "POST", "/api/v1/validate", map[string]string{
"licenseKey": licenseKey,
"machineId": t.machineID,
})
if err != nil {
return LicenseResult{Valid: false, Error: err.Error()}
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var result LicenseResult
json.Unmarshal(body, &result)
return result
}
var errResp struct{ Error string }
json.Unmarshal(body, &errResp)
return LicenseResult{Valid: false, Error: errResp.Error}
}
func (t *Transport) Activate(ctx context.Context, licenseKey, machineName string) LicenseResult {
t.log(fmt.Sprintf("Activating: %s...", licenseKey[:min(10, len(licenseKey))]))
if machineName == "" {
machineName, _ = os.Hostname()
}
resp, err := t.request(ctx, "POST", "/api/v1/activate", map[string]string{
"licenseKey": licenseKey,
"machineId": t.machineID,
"machineName": machineName,
"platform": runtime.GOOS,
})
if err != nil {
return LicenseResult{Valid: false, Error: err.Error()}
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var result LicenseResult
json.Unmarshal(body, &result)
return result
}
var errResp struct{ Error string }
json.Unmarshal(body, &errResp)
return LicenseResult{Valid: false, Error: errResp.Error}
}
func (t *Transport) Deactivate(ctx context.Context, licenseKey string) bool {
resp, err := t.request(ctx, "POST", "/api/v1/deactivate", map[string]string{
"licenseKey": licenseKey,
"machineId": t.machineID,
})
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == 200
}
func (t *Transport) StartTrial(ctx context.Context, email string) LicenseResult {
t.log(fmt.Sprintf("Starting trial for: %s", email))
resp, err := t.request(ctx, "POST", "/api/v1/trial", map[string]string{
"email": email,
"machineId": t.machineID,
})
if err != nil {
return LicenseResult{Valid: false, Error: err.Error()}
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var result LicenseResult
json.Unmarshal(body, &result)
return result
}
var errResp struct{ Error string }
json.Unmarshal(body, &errResp)
return LicenseResult{Valid: false, Error: errResp.Error}
}
func (t *Transport) GetTiers(ctx context.Context) []ProductTier {
resp, err := t.request(ctx, "GET", "/api/v1/tiers", nil)
if err != nil {
return nil
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var result struct{ Tiers []ProductTier }
json.NewDecoder(resp.Body).Decode(&result)
return result.Tiers
}
return nil
}
func (t *Transport) StartCheckout(ctx context.Context, tierID, email string) CheckoutResult {
resp, err := t.request(ctx, "POST", "/api/v1/checkout", map[string]string{
"tierId": tierID,
"email": email,
})
if err != nil {
return CheckoutResult{Success: false, Error: err.Error()}
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var result CheckoutResult
json.Unmarshal(body, &result)
result.Success = true
return result
}
var errResp struct{ Error string }
json.Unmarshal(body, &errResp)
return CheckoutResult{Success: false, Error: errResp.Error}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}