~xenrox/syncthing-status

278df0b1ad94f9824069731bcfae461e23989014 — Thorben Günther 2 years ago
Initial commit
4 files changed, 146 insertions(+), 0 deletions(-)

A client.go
A go.mod
A main.go
A status.go
A  => client.go +98 -0
@@ 1,98 @@
package main

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

type Client struct {
	baseURL    string
	httpClient *http.Client
	apiKey     string
}

func readAPIKey() string {
	configDir, err := os.UserConfigDir()
	if err != nil {
		log.Fatal(err)
	}

	configFile := filepath.Join(configDir, "syncthing", "config.xml")
	file, err := os.Open(configFile)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	b, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}

	type stConfig struct {
		XMLName xml.Name `xml:"configuration"`
		GUI     struct {
			APIKey string `xml:"apikey"`
		} `xml:"gui"`
	}
	var config stConfig

	err = xml.Unmarshal(b, &config)
	if err != nil {
		log.Fatal(err)
	}

	return config.GUI.APIKey
}

func NewClient() *Client {
	httpClient := &http.Client{
		Timeout: time.Second * 3,
	}

	return &Client{httpClient: httpClient, apiKey: readAPIKey(), baseURL: "http://127.0.0.1:8384"}
}

func (client *Client) sendRequest(req *http.Request) ([]byte, error) {
	req.Header.Set("X-API-Key", client.apiKey)

	resp, err := client.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("api error")
	}

	return b, nil
}

func (client *Client) get(path string, resource interface{}) error {
	url := client.baseURL + path

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return err
	}

	b, err := client.sendRequest(req)
	if err != nil {
		return err
	}

	return json.Unmarshal(b, &resource)
}

A  => go.mod +3 -0
@@ 1,3 @@
module git.xenrox.net/~xenrox/syncthing-status

go 1.17

A  => main.go +27 -0
@@ 1,27 @@
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type Status struct {
	Local  int `json:"local"`
	Remote int `json:"remote"`
}

func main() {
	client := NewClient()
	var status Status

	localStatus := client.localStatus()
	status.Local = localStatus.Completion

	data, err := json.MarshalIndent(status, "", "  ")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", data)
}

A  => status.go +18 -0
@@ 1,18 @@
package main

import "log"

type LocalStatus struct {
	Completion int `json:"completion"`
}

func (client *Client) localStatus() *LocalStatus {
	var status *LocalStatus

	err := client.get("/rest/db/completion", &status)
	if err != nil {
		log.Fatal(err)
	}

	return status
}