182 lines
4.1 KiB
Go
182 lines
4.1 KiB
Go
//go:generate go run git.brut.systems/judah/rivit2html@latest docs/index.riv
|
|
//go:generate go run git.brut.systems/judah/rivit2html@latest docs/main.riv docs/main.go
|
|
package main
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
API_URL string
|
|
API_TOKEN string
|
|
REDIRECT_URL string
|
|
PORT string
|
|
)
|
|
|
|
func main() {
|
|
var err error
|
|
if API_URL, err = GetEnvironmentVariable("API_URL"); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
if _, err := url.Parse(API_URL); err != nil {
|
|
log.Fatalf("invalid API_URL %q", err)
|
|
}
|
|
|
|
if !strings.HasPrefix(API_URL, "http") {
|
|
log.Fatalf("invalid API_URL %q - must being with http(s)://", API_URL)
|
|
}
|
|
}
|
|
|
|
if REDIRECT_URL, err = GetEnvironmentVariable("REDIRECT_URL"); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
if _, err := url.Parse(REDIRECT_URL); err != nil {
|
|
log.Fatalf("invalid REDIRECT_URL %q", err)
|
|
}
|
|
|
|
if !strings.HasPrefix(REDIRECT_URL, "http") {
|
|
log.Fatalf("invalid REDIRECT_URL %q - must begin with \"http(s)://\"", REDIRECT_URL)
|
|
}
|
|
}
|
|
|
|
if token, err := GetEnvironmentVariable("API_TOKEN"); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
API_TOKEN = "token " + token
|
|
}
|
|
|
|
if PORT, err = GetEnvironmentVariable("PORT"); err != nil {
|
|
log.Fatal(err)
|
|
} else {
|
|
if _, err = strconv.ParseInt(PORT, 10, 64); err != nil {
|
|
log.Fatalf("invalid port number %q", PORT)
|
|
}
|
|
}
|
|
|
|
redirect := func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, REDIRECT_URL, http.StatusTemporaryRedirect)
|
|
}
|
|
|
|
sv := new(http.ServeMux)
|
|
sv.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
redirect(w, r)
|
|
})
|
|
sv.HandleFunc("/{user}/{repo}/", func(w http.ResponseWriter, r *http.Request) {
|
|
user := strings.TrimSpace(r.PathValue("user"))
|
|
repo := strings.TrimSpace(r.PathValue("repo"))
|
|
|
|
if len(user) == 0 || len(repo) == 0 {
|
|
redirect(w, r)
|
|
return
|
|
}
|
|
|
|
path := r.URL.Path
|
|
path = strings.TrimSpace(path[strings.Index(path, repo)+len(repo):])
|
|
path = strings.TrimPrefix(path, "/")
|
|
|
|
if len(path) == 0 {
|
|
path = "docs/index.html"
|
|
}
|
|
|
|
log.Printf("fetching file content %s:%s - %q", user, repo, path)
|
|
|
|
content, err := FetchFile(user, repo, path)
|
|
if err != nil {
|
|
log.Println(err)
|
|
redirect(w, r)
|
|
return
|
|
}
|
|
|
|
if _, err := w.Write(content); err != nil {
|
|
log.Println(err)
|
|
redirect(w, r)
|
|
return
|
|
}
|
|
})
|
|
|
|
addr := fmt.Sprintf(":%s", PORT)
|
|
log.Printf("Listening at %s", addr)
|
|
|
|
if err := http.ListenAndServe(addr, sv); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func FetchFile(user, repo, path string) ([]byte, error) {
|
|
api_endpoint := FormatEndpoint("/repos/%s/%s/contents/%s", user, repo, url.PathEscape(path))
|
|
body, status, err := ApiGet(api_endpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if status != http.StatusOK {
|
|
return nil, fmt.Errorf("response had unexpected status %d - %s", status, string(body))
|
|
}
|
|
|
|
var response struct {
|
|
Encoding string `json:"encoding"`
|
|
Content string `json:"content"`
|
|
}
|
|
|
|
err = json.Unmarshal(body, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if response.Encoding != "base64" {
|
|
return nil, fmt.Errorf("expected base64 encoding, found %q", response.Encoding)
|
|
}
|
|
|
|
file, err := base64.StdEncoding.DecodeString(response.Content)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return file, nil
|
|
}
|
|
|
|
func ApiGet(endpoint string) ([]byte, int, error) {
|
|
req, err := http.NewRequest("GET", endpoint, nil)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
|
|
req.Header.Add("accept", "application/json")
|
|
req.Header.Add("Authorization", API_TOKEN)
|
|
|
|
var client http.Client
|
|
log.Printf("GET %q", endpoint)
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
|
|
body, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
|
|
return body, res.StatusCode, nil
|
|
}
|
|
|
|
func GetEnvironmentVariable(name string) (string, error) {
|
|
envvar := strings.TrimSpace(os.Getenv(name))
|
|
if len(envvar) == 0 {
|
|
return "", fmt.Errorf("required environment variable %q was not set", name)
|
|
}
|
|
return envvar, nil
|
|
}
|
|
|
|
func FormatEndpoint(endpoint string, args ...any) string {
|
|
url, _ := url.JoinPath(API_URL, "api/v1", fmt.Sprintf(endpoint, args...))
|
|
return url
|
|
}
|