embed.go

 1package plugins
 2
 3import (
 4	"encoding/json"
 5	"fmt"
 6	"io"
 7	"net/http"
 8	"time"
 9)
10
11const RegistryURL = "https://raw.githubusercontent.com/floatpane/matcha/master/plugins/registry.json"
12const RawPluginBaseURL = "https://raw.githubusercontent.com/floatpane/matcha/master/plugins/"
13
14// PluginEntry represents a single plugin in the registry.
15type PluginEntry struct {
16	Name        string `json:"name"`
17	Title       string `json:"title"`
18	Description string `json:"description"`
19	File        string `json:"file"`
20	URL         string `json:"url,omitempty"`
21}
22
23// FetchRegistry fetches the plugin registry from GitHub.
24func FetchRegistry() ([]PluginEntry, error) {
25	client := &http.Client{Timeout: 10 * time.Second}
26	resp, err := client.Get(RegistryURL)
27	if err != nil {
28		return nil, fmt.Errorf("failed to fetch registry: %w", err)
29	}
30	defer resp.Body.Close()
31
32	if resp.StatusCode != http.StatusOK {
33		return nil, fmt.Errorf("registry returned status %d", resp.StatusCode)
34	}
35
36	body, err := io.ReadAll(resp.Body)
37	if err != nil {
38		return nil, fmt.Errorf("failed to read registry: %w", err)
39	}
40
41	var entries []PluginEntry
42	if err := json.Unmarshal(body, &entries); err != nil {
43		return nil, fmt.Errorf("failed to parse registry: %w", err)
44	}
45	return entries, nil
46}
47
48// FetchPlugin downloads a plugin file. If the entry has a URL, it downloads
49// from there; otherwise it falls back to the default repo location.
50func FetchPlugin(entry PluginEntry) ([]byte, error) {
51	url := entry.URL
52	if url == "" {
53		url = RawPluginBaseURL + entry.File
54	}
55
56	client := &http.Client{Timeout: 10 * time.Second}
57	resp, err := client.Get(url)
58	if err != nil {
59		return nil, fmt.Errorf("failed to fetch plugin: %w", err)
60	}
61	defer resp.Body.Close()
62
63	if resp.StatusCode != http.StatusOK {
64		return nil, fmt.Errorf("plugin download returned status %d", resp.StatusCode)
65	}
66
67	return io.ReadAll(resp.Body)
68}