minor changes

This commit is contained in:
Judah Caruso 2026-01-28 20:12:42 -07:00
parent d61374b9e2
commit 0e18e4202b
3 changed files with 111 additions and 111 deletions

View file

@ -68,6 +68,6 @@ Environment="PORT=<port>"
WantedBy=multi-user.target
</code></pre><p>Then start the service:</p><pre><code>sudo systemctl enable docs.brut
sudo systemctl start docs.brut
</code></pre><h2>Usage Within Git.Brut.Systems</h2><p>Those with repositories on <a href="https://git.brut.systems">git.brut.systems</a> can serve websites by creating a <code>docs/</code> folder (on the default branch). While any file from the repository can be accessed, files within <code>docs/</code> are accessible from <code>/</code>. If a file within <code>docs/</code> conflicts with another file in the repository, the file in <code>docs/</code> take precedence.</p>
</code></pre><h2>Usage Within Git.Brut.Systems</h2><p>Those with repositories on <a href="https://git.brut.systems">git.brut.systems</a> can serve websites by creating a <code>docs/</code> folder (on the default branch). While any file from the repository can be accessed, files within <code>docs/</code> are accessible from <code>/</code>. If a <a href="/main.go">file</a> within <code>docs/</code> conflicts with another file in the repository, the file in <code>docs/</code> take precedence.</p>
</body>
</html>

View file

@ -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.

222
main.go
View file

@ -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)
}
func (sv *Server) getfile(user, repo, path string) ([]byte, error) {
var (
endpoint = endpoint("/repos/%s/%s/contents/%s", user, repo, url.PathEscape(path))
)
if !strings.HasPrefix(API_URL, "http") {
log.Fatalf("invalid API_URL %q - must being with http(s)://", API_URL)
}
}
req, err := http.NewRequest("GET", endpoint, nil)
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
}
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)
}
}
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)
}
if !strings.HasPrefix(REDIRECT_URL, "http") {
log.Fatalf("invalid REDIRECT_URL %q - must begin with \"http(s)://\"", REDIRECT_URL)
}
}
if token, err := getvar("API_TOKEN"); err != nil {
log.Fatal(err)
} else {
API_TOKEN = "token " + token
}
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)
func ApiGet(endpoint string) ([]byte, int, error) {
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
log.Println(err)
redirect(w, r)
return
return nil, -1, err
}
if _, err := w.Write(content); err != nil {
log.Println(err)
redirect(w, r)
return
}
})
req.Header.Add("accept", "application/json")
req.Header.Add("Authorization", API_TOKEN)
addr := fmt.Sprintf(":%s", PORT)
log.Printf("Listening at %s", addr)
if err := http.ListenAndServe(addr, sv); err != nil {
log.Fatal(err)
}
var client http.Client
log.Printf("GET %q", endpoint)
res, err := client.Do(req)
if err != nil {
return nil, -1, err
}
func getvar(name string) (string, error) {
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)
@ -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
}