mirror of
https://github.com/benbusby/farside.git
synced 2025-03-15 11:46:32 -04:00

Some checks are pending
Tests / test (1.21.x, macos-latest) (push) Waiting to run
Tests / test (1.21.x, ubuntu-latest) (push) Waiting to run
Tests / test (1.21.x, windows-latest) (push) Waiting to run
Tests / test (1.22.x, macos-latest) (push) Waiting to run
Tests / test (1.22.x, ubuntu-latest) (push) Waiting to run
Tests / test (1.22.x, windows-latest) (push) Waiting to run
Tests / test (1.23.x, macos-latest) (push) Waiting to run
Tests / test (1.23.x, ubuntu-latest) (push) Waiting to run
Tests / test (1.23.x, windows-latest) (push) Waiting to run
Query params were previously getting ignored in farside redirects, this updates the routing to append the original url query params to the end of the redirected instance.
155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
package server
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/benbusby/farside/db"
|
|
"github.com/benbusby/farside/services"
|
|
)
|
|
|
|
//go:embed index.html
|
|
var indexHTML string
|
|
|
|
//go:embed route.html
|
|
var routeHTML string
|
|
|
|
type indexData struct {
|
|
LastUpdated time.Time
|
|
ServiceList []services.Service
|
|
}
|
|
|
|
type routeData struct {
|
|
InstanceURL string
|
|
}
|
|
|
|
func home(w http.ResponseWriter, r *http.Request) {
|
|
serviceList := db.GetServiceList()
|
|
data := indexData{
|
|
LastUpdated: db.LastUpdate,
|
|
ServiceList: serviceList,
|
|
}
|
|
|
|
tmpl, err := template.New("").Parse(indexHTML)
|
|
if err != nil {
|
|
log.Println(err)
|
|
http.Error(w, "Error parsing template", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
|
|
err = tmpl.Execute(w, data)
|
|
if err != nil {
|
|
log.Println(err)
|
|
http.Error(w, "Error executing template", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
func state(w http.ResponseWriter, r *http.Request) {
|
|
storedServices := db.GetServiceList()
|
|
jsonData, _ := json.Marshal(storedServices)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write(jsonData)
|
|
}
|
|
|
|
func baseRouting(w http.ResponseWriter, r *http.Request) {
|
|
routing(w, r, false, r.URL.RawQuery)
|
|
}
|
|
|
|
func jsRouting(w http.ResponseWriter, r *http.Request) {
|
|
r.URL.Path = strings.Replace(r.URL.Path, "/_", "", 1)
|
|
routing(w, r, true, r.URL.RawQuery)
|
|
}
|
|
|
|
func routing(w http.ResponseWriter, r *http.Request, jsEnabled bool, query string) {
|
|
value := r.PathValue("routing")
|
|
if len(value) == 0 {
|
|
value = r.URL.Path
|
|
}
|
|
|
|
parsedURL, _ := url.Parse(value)
|
|
path := strings.TrimPrefix(parsedURL.Path, "/")
|
|
segments := strings.Split(path, "/")
|
|
|
|
if len(segments[0]) == 0 {
|
|
http.Redirect(w, r, "", http.StatusTemporaryRedirect)
|
|
}
|
|
|
|
target, err := services.MatchRequest(segments[0])
|
|
if err != nil {
|
|
log.Printf("Error during match request: %v\n", err)
|
|
http.Error(w, "No routing found for "+target, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var servicePath string
|
|
if target == "breezewiki" {
|
|
// Breezewiki requires the subdomain of the instance to be
|
|
// preserved for correct routing
|
|
splitDomain := strings.Split(path, ".")
|
|
if len(splitDomain) > 2 {
|
|
servicePath = strings.Split(path, ".")[0]
|
|
}
|
|
}
|
|
|
|
instance, err := db.GetInstance(target, servicePath)
|
|
if err != nil {
|
|
log.Printf("Error fetching instance from db: %v\n", err)
|
|
http.Error(
|
|
w,
|
|
"Error fetching instance for "+target,
|
|
http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if len(segments) > 1 {
|
|
targetPath := strings.Join(segments[1:], "/")
|
|
instance = instance + "/" + targetPath
|
|
}
|
|
|
|
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
|
|
w.Header().Set("Pragma", "no-cache")
|
|
w.Header().Set("Expires", "0")
|
|
|
|
instance += fmt.Sprintf("?%s", query)
|
|
if jsEnabled {
|
|
data := routeData{
|
|
InstanceURL: instance,
|
|
}
|
|
tmpl, _ := template.New("").Parse(routeHTML)
|
|
w.Header().Set("Content-Type", "text/html")
|
|
_ = tmpl.Execute(w, data)
|
|
} else {
|
|
http.Redirect(w, r, instance, http.StatusFound)
|
|
}
|
|
}
|
|
|
|
func RunServer() {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/{$}", home)
|
|
mux.HandleFunc("/state/{$}", state)
|
|
mux.HandleFunc("/{routing...}", baseRouting)
|
|
mux.HandleFunc("/_/{routing...}", jsRouting)
|
|
|
|
port := os.Getenv("FARSIDE_PORT")
|
|
if len(port) == 0 {
|
|
port = "4001"
|
|
}
|
|
|
|
log.Println("Starting server on http://localhost:" + port)
|
|
|
|
err := http.ListenAndServe(":"+port, mux)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|