From 0e18e4202be7538a3985f758fc0e064176065be6 Mon Sep 17 00:00:00 2001 From: Judah Caruso Date: Wed, 28 Jan 2026 20:12:42 -0700 Subject: [PATCH] minor changes --- docs/index.html | 2 +- docs/index.riv | 2 +- main.go | 218 ++++++++++++++++++++++++------------------------ 3 files changed, 111 insertions(+), 111 deletions(-) diff --git a/docs/index.html b/docs/index.html index 09d7417..7253f1e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -68,6 +68,6 @@ Environment="PORT=<port>" WantedBy=multi-user.target

Then start the service:

sudo systemctl enable docs.brut
 sudo systemctl start docs.brut
-

Usage Within Git.Brut.Systems

Those with repositories on git.brut.systems can serve websites by creating a docs/ folder (on the default branch). While any file from the repository can be accessed, files within docs/ are accessible from /. If a file within docs/ conflicts with another file in the repository, the file in docs/ take precedence.

+

Usage Within Git.Brut.Systems

Those with repositories on git.brut.systems can serve websites by creating a docs/ folder (on the default branch). While any file from the repository can be accessed, files within docs/ are accessible from /. If a file within docs/ conflicts with another file in the repository, the file in docs/ take precedence.

\ No newline at end of file diff --git a/docs/index.riv b/docs/index.riv index 34f8ae2..0612503 100644 --- a/docs/index.riv +++ b/docs/index.riv @@ -46,4 +46,4 @@ Then start the service: USAGE WITHIN GIT.BRUT.SYSTEMS -Those with repositories on [https://git.brut.systems git.brut.systems] can serve websites by creating a `docs/` folder (on the default branch). While any file from the repository can be accessed, files within `docs/` are accessible from `/`. If a file within `docs/` conflicts with another file in the repository, the file in `docs/` take precedence. +Those with repositories on [https://git.brut.systems git.brut.systems] can serve websites by creating a `docs/` folder (on the default branch). While any file from the repository can be accessed, files within `docs/` are accessible from `/`. If a [/main.go file] within `docs/` conflicts with another file in the repository, the file in `docs/` take precedence. diff --git a/main.go b/main.go index e16dc93..e3439f8 100644 --- a/main.go +++ b/main.go @@ -21,38 +21,104 @@ var ( PORT string ) -type Server struct { - http.ServeMux +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 (sv *Server) getfile(user, repo, path string) ([]byte, error) { - var ( - endpoint = endpoint("/repos/%s/%s/contents/%s", user, repo, url.PathEscape(path)) - ) - - req, err := http.NewRequest("GET", endpoint, nil) +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 } - req.Header.Add("accept", "application/json") - req.Header.Add("Authorization", API_TOKEN) - - log.Printf("GET %q", endpoint) - - var client http.Client - res, err := client.Do(req) - if err != nil { - return nil, err - } - - body, err := io.ReadAll(res.Body) - if err != nil { - return nil, err - } - - if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("response had unexpected status %d - %s", res.StatusCode, string(body)) + if status != http.StatusOK { + return nil, fmt.Errorf("response had unexpected status %d - %s", status, string(body)) } var response struct { @@ -77,97 +143,31 @@ func (sv *Server) getfile(user, repo, path string) ([]byte, error) { return file, nil } -func main() { - var err error - if API_URL, err = getvar("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) - } +func ApiGet(endpoint string) ([]byte, int, error) { + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return nil, -1, err } - if REDIRECT_URL, err = getvar("REDIRECT_URL"); err != nil { - log.Fatal(err) - } else { - if _, err := url.Parse(REDIRECT_URL); err != nil { - log.Fatalf("invalid REDIRECT_URL %q", err) - } + req.Header.Add("accept", "application/json") + req.Header.Add("Authorization", API_TOKEN) - if !strings.HasPrefix(REDIRECT_URL, "http") { - log.Fatalf("invalid REDIRECT_URL %q - must begin with \"http(s)://\"", REDIRECT_URL) - } + var client http.Client + log.Printf("GET %q", endpoint) + res, err := client.Do(req) + if err != nil { + return nil, -1, err } - if token, err := getvar("API_TOKEN"); err != nil { - log.Fatal(err) - } else { - API_TOKEN = "token " + token + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, -1, err } - if PORT, err = getvar("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(Server) - 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 := sv.getfile(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) - } + return body, res.StatusCode, nil } -func getvar(name string) (string, error) { +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) @@ -175,7 +175,7 @@ func getvar(name string) (string, error) { return envvar, nil } -func endpoint(endpoint string, args ...any) string { +func FormatEndpoint(endpoint string, args ...any) string { url, _ := url.JoinPath(API_URL, "api/v1", fmt.Sprintf(endpoint, args...)) return url }