From 25039a8f5412d0e8c4ae357a0a1ea5e320697844 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Mon, 3 Nov 2025 12:38:47 +0000 Subject: [PATCH] Add basic web serving and html templating --- endpoint.go | 17 ++++++++ go.mod | 5 +++ go.sum | 4 ++ html.go | 103 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 48 ++++++++++++++++++++- static/favicon.ico | Bin 0 -> 15406 bytes templates/base.html | 10 +++++ templates/root.html | 5 +++ 8 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 endpoint.go create mode 100644 go.sum create mode 100644 html.go create mode 100644 static/favicon.ico create mode 100644 templates/base.html create mode 100644 templates/root.html diff --git a/endpoint.go b/endpoint.go new file mode 100644 index 00000000..bef3d035 --- /dev/null +++ b/endpoint.go @@ -0,0 +1,17 @@ +package main + +import ( + "net/http" +) +func getFavicon(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-type", "image/x-icon") + + http.ServeFile(w, r, "static/favicon.ico") +} + +func getRoot(w http.ResponseWriter, r *http.Request) { + err := htmlRoot(w, r.URL.Path) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} diff --git a/go.mod b/go.mod index bfd0d64e..77f59ad7 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,8 @@ module github.com/Gleipnir-Technology/nidus-sync go 1.24.9 + +require ( + github.com/alexedwards/scs/v2 v2.9.0 + github.com/go-chi/chi/v5 v5.2.3 +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..428aef0e --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/alexedwards/scs/v2 v2.9.0 h1:xa05mVpwTBm1iLeTMNFfAWpKUm4fXAW7CeAViqBVS90= +github.com/alexedwards/scs/v2 v2.9.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= +github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= diff --git a/html.go b/html.go new file mode 100644 index 00000000..8474f286 --- /dev/null +++ b/html.go @@ -0,0 +1,103 @@ +package main + +import ( + "errors" + "html/template" + "io" + "log" + "os" +) + +var ( + root = newBuiltTemplate("root", "base") + dashboard = newBuiltTemplate("dashboard", "base") +) + +type BuiltTemplate struct { + files []string + template *template.Template +} + +type Link struct { + Href string + Title string +} +type ContentDashboard struct { + BabbleLinks []Link + Username string +} +type ContentRoot struct { + BabbleLinks []Link +} + +func (bt *BuiltTemplate) ExecuteTemplate(w io.Writer, data any) error { + name := bt.files[0] + ".html" + if bt.template == nil { + templ := parseFromDisk(bt.files) + if templ == nil { + w.Write([]byte("Failed to read from disk")) + return errors.New("Template parsing failed") + } + return templ.ExecuteTemplate(w, name, data) + } else { + return bt.template.ExecuteTemplate(w, name, data) + } +} + +func htmlDashboard(w io.Writer, path string, username string) error { + data := ContentDashboard{ + Username: username, + } + return dashboard.ExecuteTemplate(w, data) +} + +func htmlRoot(w io.Writer, path string) error { + data := ContentRoot{ + } + return root.ExecuteTemplate(w, data) +} + +func makeFuncMap() template.FuncMap { + funcMap := template.FuncMap{} + return funcMap +} +func newBuiltTemplate(files ...string) BuiltTemplate { + files_on_disk := true + for _, f := range files { + full_path := "templates/" + f + ".html" + _, err := os.Stat(full_path) + if err != nil { + files_on_disk = false + break + } + } + if files_on_disk { + return BuiltTemplate{ + files: files, + template: nil, + } + } + return BuiltTemplate{ + files: files, + template: parseEmbedded(files), + } +} + +func parseEmbedded(files []string) *template.Template { + return nil +} + +func parseFromDisk(files []string) *template.Template { + funcMap := makeFuncMap() + paths := make([]string, 0) + for _, f := range files { + paths = append(paths, "templates/"+f+".html") + } + name := files[0] + ".html" + templ, err := template.New(name).Funcs(funcMap).ParseFiles(paths...) + if err != nil { + log.Println("TEMPLATE FAILED", err) + return nil + } + return templ +} diff --git a/main.go b/main.go index 04621e58..a34fc64d 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,51 @@ package main + import ( - "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/alexedwards/scs/v2" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" ) + +var sessionManager *scs.SessionManager + +var BaseURL, ClientID, ClientSecret string + func main() { - fmt.Println("Hello World!") + ClientID = os.Getenv("ARCGIS_CLIENT_ID") + if ClientID == "" { + log.Println("You must specify a non-empty CLIENT_ID") + os.Exit(1) + } + ClientSecret = os.Getenv("ARCGIS_CLIENT_SECRET") + if ClientSecret == "" { + log.Println("You must specify a non-empty CLIENT_SECRET") + os.Exit(1) + } + BaseURL = os.Getenv("BASE_URL") + if BaseURL == "" { + log.Println("You must specify a non-empty BASE_URL") + os.Exit(1) + } + bind := os.Getenv("BIND") + if bind == "" { + bind = ":9001" + } + + log.Println("Starting...") + sessionManager = scs.New() + sessionManager.Lifetime = 24 * time.Hour + + r := chi.NewRouter() + r.Use(middleware.Logger) + r.Use(sessionManager.LoadAndSave) + + r.Get("/", getRoot) + r.Get("/favicon.ico", getFavicon) + log.Printf("Serving on %s", bind) + log.Fatal(http.ListenAndServe(bind, r)) } diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2f7e078a965f5cbd86f97927ee1e0101ab5bcea8 GIT binary patch literal 15406 zcmZQzU}Rus5D);-3Je)63=C!r3=9ei5Wa>W1H(KP1_lEI2tPxOf#H}a1A_(w1A_oa z9Roz1VXy+Z4}uKJ?~TCDQ~xT(p!!CdLFR)HgZzIE2E})J42mDs7?eJ$GN^u)W>9@^ zz`*dI1*}%(ojn7?e^vW4@MWOlS&^w8I<1Xf+f{H)H0~N4`E>V&&;6m(Skwg ztu@;?_?7^Fu1!zu>l_l^u|A1WBs--j@$y^CQ`f4>qOwjf3FUnCe5zR81_ zU<`@_l{YdB3Ln)O6ke+{sC-OfP<=n0LG42~gW8932DSG~8C2hSgXKVKR6c>i8I-)h z+OZOhJm))ZSI#3~yZeLFoqMA5b_deimm?`JfE; z8!q+8;vhYs@CKzBwfBmUxY*AEPD836lo%L5X#-gU5*rl1YM(?PY3D;ITt@jr7?`d4 z&W=I(qa~P)jlh+zU}`~WRPKu;j5`=;P&uQ(z`)=z*vpy05LhGK4GQn%8I(V`gUfd0 zuu%I1N=6I}pfUp_4$8Zt|9L=62IbG%U_GjDy}*3Qr(6uGAH5k=-e`gOpt4Bqg9n4m zBTg_MMu75($_G~lhAW8jTkW+5gZhVP2Bmj$FlAs`?Y%RYR{h`trq$l*F@VekaX{_` z(Q5AlKoo=OM{{uf0ydk0fdN$Jt9=N=@RREMKn9g}z6_wU6|50P{AXkUsaJd<4ijNe zc@x3_@&l-h2ML1eCn;!|sr=r7LFI!RgW88|kQ9UZ2NSSgLE<0*)pz;~YVT}7OgIMB zjUaKj02T(wKj`5ASN5L~&V(`4-aEmVcxmOg?hK%C#;XV_srJ^BLGhIul!u^T^*2I< z0W%ztC82EPkA4j5??J^8RDcLd{k zOGsYDkS9Sv zwqs|3{0J(Gz;1aT0FF52DSGs;PAq&i^?*qm>JYR>;Z>2$PH>AGO26< ze&Zlvu!KS5{ZcSidtZQG1C?dfUi*Xlrs^LKGN`?8WdPT0?-i+R3#xITb_}fTp!`7v zEUEfF2;MdVwN+F;`Y>QCtHFvXAwX@Dcd;00S>=5axZQzlG^kt#)mzA7l(Io(9;n}i zYz`=of%=c2_KxZcC1fdZy9YErfFejH2h_d+jU6Cs2Zb@H{D+Bw;sG>{0ONybP#Fd) zlfi8kkN~Op3L7|2gW7e-T0!M3sK1CT1{#x4d!GU>7h&Qc_kjAy>K}a>KxHaSoLCwZ zhbnI@P}{`+Ss2vcuYix2Ae#jW1J(B>a3Q6)It(gr+`#28hz*w@mH|q0&&khITK{<% zls?%ofZ`81u86gMRNZI@&>;js9b5wj28M*uaS}R&_NW!3Aut*O6omk2{2esz1nLul z+8x*ogSEZn9twi{i7+*wxf&7CU$@2h`30jrV}Z$Uzbe3=Fcbr5M!ST7&!2 zP$BSq2WT7~)HXpLzk|zz82_0VKz&Jh(AeRBW{?O9R(qe!Ap1cXJa&e4Tpgqz+MiMX ztjhrEufhxf_a(nW+TI{B&={cFYiIEM6R7P28Y=;bgWBq#_NnR@&=_1cgVKL~kTAIY z3~H;Yy)Q!b7ep3Jg2oV(LH*wkVcLOm0BehD-N37T61#T85*JVxebwhvQJhz8F&yboefe-}+iDM5MV zZ?X)a@jKXD2SE+U3h=}WvNB{gsO$sv*_4PJzem=Kiw!O}-ls6Y=gV;^L>B+g%%JvR zA~>BR3*%*j%D9h(kU4ZR{Ep9TP`_FIeF+0-yb<4=F3b$jSf={>!wjk)YG6WmY0wy? z>W5s2+wrO-UlLSafXY_zyb+c<5N>ik6NCEO36;v0heJW=Ve=Y{8uW9XmP`G}~ zhs=NdXN8P=zxBYV7eVEp+WYB{abWOV4CY)QXsr!sE(laMgVGOZZU)pogM|UDXwY1P z`uigcYHvZ|#?7Gi*_lD*18O-9T1%w%VFJYcAI^f?o5=0~mBlLWYQb}8pthgd`&|sG z@28-&X_3_v&Hm5G0E&BD?PriVp!qA+_YLs832OVOy$xpojk&_sD1q9~YVW$h?pJ$v zhC%H$bgmG(rby*&83SnS4Kzmq&f}nUH?KiM4j>z_V^G_bP(2K4--E~Y-sxjE1S$${ zTfCnFcAxqO&|KXl2Gut~;CXJLH+8c+S7*yX?GJwX| zL30f1@AiV{*g^8Ru*z2%@K`*k%?=7bT0PhU{L?44xax}|Cq?24jLPOe*vsd{lj65adH&<_Omd6 z#&p#_%mVidls`M-ZI6M*l|kl%+LPdZ(}zq3Q2ztejs%H;)&n88&q3`PwRg)HKyy^; zAFePczfECKd}GF-@+OG^4C?P{AY$*2F{r*x1Fwfudp92(?rIf5OdYVWeZ<%`;f8w{%N7lGHOfzl>uU5NVoQU=ia4NzQy!k?j@wD2X> z4>;AIVP#PH0BSRwU{HOZz@YYF6F96v|+RmW%ej!?)2&ZWSA^|EJRNlBUsJ@G5 zQ2%fp>i$~{YVVhU+Z^EhGaxP_!P5I2462}V1+)eMhCf_oP@zXe?71 zv^EyY_yedtr~07^zLpm57Vw&fEO0)Diy<*Uc>>gb1hvV*{-E;M56CLe*fBUQysHHF zPe5YG7&M2W`Y|59?gm*7%wEOJpz^K)+}1?N=OD@dj0~VO2I`Z7_HU?svS$zm?Ii)p zQ2~ScZlHCNs_$|bKyw!uM*e4GPHP<{gS ztw4D}{k0=_4uzUyLF)f`!E0WW--a`&ebxh6iHbpMLOzs(*FoYd4?$x+>hGIS*291d z0>y{Y2NMRBcbVY6CTMPh*fq%@{ls9 + + + + Nidus Sync + + +{{template "content" .}} + + diff --git a/templates/root.html b/templates/root.html new file mode 100644 index 00000000..66ca8799 --- /dev/null +++ b/templates/root.html @@ -0,0 +1,5 @@ +{{template "base.html" .}} + +{{define "content"}} +

Imagine there's cool stuff here.

+{{end}}