summaryrefslogtreecommitdiff
path: root/server/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/server.go')
-rw-r--r--server/server.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/server/server.go b/server/server.go
new file mode 100644
index 0000000..0a0b683
--- /dev/null
+++ b/server/server.go
@@ -0,0 +1,138 @@
+package server
+
+import (
+ _ "embed"
+ "encoding/json"
+ "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)
+}
+
+func jsRouting(w http.ResponseWriter, r *http.Request) {
+ r.URL.Path = strings.Replace(r.URL.Path, "/_", "", 1)
+ routing(w, r, true)
+}
+
+func routing(w http.ResponseWriter, r *http.Request, jsEnabled bool) {
+ value := r.PathValue("routing")
+ if len(value) == 0 {
+ value = r.URL.Path
+ }
+
+ url, _ := url.Parse(value)
+ path := strings.TrimPrefix(url.Path, "/")
+ segments := strings.Split(path, "/")
+
+ 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
+ }
+
+ instance, err := db.GetInstance(target)
+ 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")
+
+ 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)
+ }
+}