farside/services/services.go
Ben Busby b5bad4defc
Rewrite project, add daily update of services list
The project was rewritten from Elixir to Go, primarily because:

- I don't write Elixir anymore and don't want to maintain a project in a
  language I no longer write
- I already write Go for other projects, including my day job, so it's
  a safer bet for a project that I want to maintain long term
- Go allows me to build portable executables that will make it easier
  for others to run farside on their own machines

The Go version of Farsside also has a built in task to fetch the latest
services{-full}.json file from the repo and ingest it, which makes
running a farside server a lot simpler.

It also automatically fetches the latest instance state from
https://farside.link unless configured as a primary farside node, which
will allow others to use farside without increasing traffic to all
instances that are queried by farside (just to the farside node itself).
2025-01-21 13:46:29 -07:00

94 lines
1.7 KiB
Go

package services
import (
"encoding/json"
"io"
"net/http"
"os"
)
var (
ServiceList []Service
FallbackMap map[string]string
)
const (
baseRepoLink = "https://git.sr.ht/~benbusby/farside/blob/main/"
noCFServicesJSON = "services.json"
fullServicesJSON = "services-full.json"
)
type Service struct {
Type string `json:"type"`
TestURL string `json:"test_url,omitempty"`
Fallback string `json:"fallback,omimtempty"`
Instances []string `json:"instances"`
}
func ingestServicesList(servicesBytes []byte) error {
err := json.Unmarshal(servicesBytes, &ServiceList)
return err
}
func GetServicesFileName() string {
cloudflareEnabled := false
cfEnabledVar := os.Getenv("FARSIDE_CF_ENABLED")
if len(cfEnabledVar) > 0 && cfEnabledVar == "1" {
cloudflareEnabled = true
}
serviceJSON := noCFServicesJSON
if cloudflareEnabled {
serviceJSON = fullServicesJSON
}
return serviceJSON
}
func FetchServicesFile(serviceJSON string) ([]byte, error) {
resp, err := http.Get(baseRepoLink + serviceJSON)
if err != nil {
return nil, err
}
defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = os.WriteFile(serviceJSON, bodyBytes, 0666)
if err != nil {
return nil, err
}
return bodyBytes, nil
}
func InitializeServices() error {
serviceJSON := GetServicesFileName()
fileBytes, err := os.ReadFile(serviceJSON)
if err != nil {
fileBytes, err = FetchServicesFile(serviceJSON)
if err != nil {
return err
}
}
err = ingestServicesList(fileBytes)
if err != nil {
return err
}
FallbackMap = make(map[string]string)
for _, serviceElement := range ServiceList {
FallbackMap[serviceElement.Type] = serviceElement.Fallback
}
return nil
}