File size: 3,019 Bytes
6a7089a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package actions

import (
	"encoding/json"
	"fmt"
	"github.com/pinchtab/pinchtab/internal/cli"
	"github.com/pinchtab/pinchtab/internal/cli/apiclient"
	"log"
	"net/http"
	"os"
)

func Health(client *http.Client, base, token string) {
	apiclient.DoGet(client, base, token, "/health", nil)
}

func Instances(client *http.Client, base, token string) {
	body := apiclient.DoGetRaw(client, base, token, "/instances", nil)

	// Parse and format as JSON
	var instances []map[string]any
	if err := json.Unmarshal(body, &instances); err != nil {
		var envelope struct {
			Instances []map[string]any `json:"instances"`
		}
		if err := json.Unmarshal(body, &envelope); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parse instances: %v\n", err)
			os.Exit(1)
		}
		instances = envelope.Instances
	}

	// Transform to cleaner output format
	output := make([]map[string]any, len(instances))
	for i, inst := range instances {
		id, _ := inst["id"].(string)
		port, _ := inst["port"].(string)
		headless, _ := inst["headless"].(bool)
		status, _ := inst["status"].(string)

		mode := "headless"
		if !headless {
			mode = "headed"
		}

		output[i] = map[string]any{
			"id":     id,
			"port":   port,
			"mode":   mode,
			"status": status,
		}
	}

	// Output as JSON
	data, _ := json.MarshalIndent(output, "", "  ")
	fmt.Println(string(data))
}

// --- profiles ---

func Profiles(client *http.Client, base, token string) {
	result := apiclient.DoGet(client, base, token, "/profiles", nil)

	// Display profiles in a friendly format
	if profiles, ok := result["profiles"].([]interface{}); ok && len(profiles) > 0 {
		fmt.Println()
		for _, prof := range profiles {
			if m, ok := prof.(map[string]any); ok {
				name, _ := m["name"].(string)

				fmt.Printf("%s %s\n", cli.StyleStdout(cli.ValueStyle, "profile:"), name)
			}
		}
		fmt.Println()
	} else {
		fmt.Println("No profiles available")
	}
}

// --- internal helpers ---

// getInstances fetches the list of running instances
func getInstances(client *http.Client, base, token string) []map[string]any {
	resp, err := http.NewRequest("GET", base+"/instances", nil)
	if err != nil {
		return nil
	}
	if token != "" {
		resp.Header.Set("Authorization", "Bearer "+token)
	}

	result, err := client.Do(resp)
	if err != nil || result.StatusCode >= 400 {
		return nil
	}
	defer func() { _ = result.Body.Close() }()

	var data map[string]any
	if err := json.NewDecoder(result.Body).Decode(&data); err != nil {
		log.Printf("warning: error decoding instances response: %v", err)
	}

	if instances, ok := data["instances"].([]interface{}); ok {
		converted := make([]map[string]any, len(instances))
		for i, inst := range instances {
			if m, ok := inst.(map[string]any); ok {
				converted[i] = m
			}
		}
		return converted
	}
	return nil
}

// launchInstance launches a default instance
func launchInstance(client *http.Client, base, token string, profile string) {
	body := map[string]any{"profile": profile}
	apiclient.DoPost(client, base, token, "/instances/launch", body)
}