diff --git a/go.mod b/go.mod index b2d672f..c898a9b 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,18 @@ module github.com/ystv/computing_site go 1.21 -require github.com/gorilla/mux v1.8.1 +require github.com/labstack/echo/v4 v4.11.4 + +require ( + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect +) diff --git a/go.sum b/go.sum index 7128337..8158929 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,35 @@ -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 064cdef..74cd632 100644 --- a/main.go +++ b/main.go @@ -2,14 +2,10 @@ package main import ( "embed" - "fmt" - "github.com/gorilla/mux" + "log" + "github.com/ystv/computing_site/link" "github.com/ystv/computing_site/team" - "github.com/ystv/computing_site/templates" - "io/fs" - "log" - "net/http" ) //go:embed public/* @@ -20,68 +16,30 @@ var ( Version = "unknown" ) -type Web struct { - mux *mux.Router - t *templates.Templater - link *link.Link - team *[]team.Member -} - func main() { - var err error - - web := Web{ - mux: mux.NewRouter(), - } - web.link, err = link.New() + link1, err := link.New() if err != nil { log.Printf("failed to get link: %+v\n", err) } - web.team, err = team.New() + team1, err := team.New() if err != nil { log.Printf("failed to get team: %+v\n", err) } - assetHandler := http.FileServer(getFileSystem()) - addr := "0.0.0.0:7075" - web.mux.HandleFunc("/", web.indexPage).Methods("GET") - //web.mux.HandleFunc("/ystv.ico", web.faviconHandler) - //web.mux.HandleFunc("/stylesheet.css", web.cssHandler) - web.mux.PathPrefix("/public/").Handler(http.StripPrefix("/public/", assetHandler)) - log.Printf("YSTV Computing site: %s, commit: %s, version: %s\n", addr, Commit, Version) - log.Fatal(http.ListenAndServe(addr, web.mux)) -} - -func (web *Web) indexPage(w http.ResponseWriter, _ *http.Request) { - params := &templates.DashboardParams{ - Link: web.link, - Team: web.team, + router := NewRouter(&RouterConf{ + Address: addr, + Link: link1, + Team: team1, Commit: Commit, Version: Version, - } + }) - err := web.t.RenderTemplate(w, params, "dashboard.tmpl") - if err != nil { - err = fmt.Errorf("failed to render dashboard: %w", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} - -//func (web *Web) faviconHandler(w http.ResponseWriter, r *http.Request) { -// http.ServeFile(w, r, "public/ystv.ico") -//} -// -//func (web *Web) cssHandler(w http.ResponseWriter, r *http.Request) { -// http.ServeFile(w, r, "public/stylesheet.css") -//} + log.Printf("YSTV Computing site: %s, commit: %s, version: %s\n", addr, Commit, Version) -func getFileSystem() http.FileSystem { - fsys, err := fs.Sub(embeddedFiles, "public") + err = router.Start() if err != nil { - panic(err) + log.Fatalf("The web server couldn't be started!\n\n%s\n\nExiting!", err) } - - return http.FS(fsys) } diff --git a/router.go b/router.go new file mode 100644 index 0000000..beb6f89 --- /dev/null +++ b/router.go @@ -0,0 +1,110 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + + "github.com/ystv/computing_site/link" + "github.com/ystv/computing_site/team" + "github.com/ystv/computing_site/templates" +) + +type ( + Router struct { + address string + templater *templates.Templater + link *link.Link + team *[]team.Member + commit string + version string + router *echo.Echo + } + + RouterConf struct { + Address string + Link *link.Link + Team *[]team.Member + Commit string + Version string + } +) + +func NewRouter(conf *RouterConf) *Router { + r := &Router{ + address: conf.Address, + link: conf.Link, + team: conf.Team, + commit: conf.Commit, + version: conf.Version, + router: echo.New(), + } + r.router.HideBanner = true + + r.middleware() + + r.loadRoutes() + + return r +} + +func (r *Router) Start() error { + r.router.Logger.Error(r.router.Start(r.address)) + return fmt.Errorf("failed to start router on address %s", r.address) +} + +// middleware initialises web server middleware +func (r *Router) middleware() { + r.router.Pre(middleware.RemoveTrailingSlash()) + r.router.Use(middleware.Recover()) + r.router.Use(middleware.BodyLimit("15M")) + r.router.Use(middleware.GzipWithConfig(middleware.GzipConfig{ + Level: 5, + })) +} + +func (r *Router) loadRoutes() { + r.router.RouteNotFound("/*", func(c echo.Context) error { return c.Redirect(http.StatusFound, "/") }) + + assetHandler := http.FileServer(http.FS(echo.MustSubFS(embeddedFiles, "public"))) + + r.router.GET("/public/*", echo.WrapHandler(http.StripPrefix("/public/", assetHandler))) + + base := r.router.Group("/") + + base.GET("api/health", func(c echo.Context) error { + marshal, err := json.Marshal(struct { + Status int `json:"status"` + }{ + Status: http.StatusOK, + }) + if err != nil { + log.Println(err) + return &echo.HTTPError{ + Code: http.StatusBadRequest, + Message: err.Error(), + Internal: err, + } + } + + c.Response().Header().Set("Content-Type", "application/json") + return c.JSON(http.StatusOK, marshal) + }) + + base.GET("", r.HomeFunc) +} + +func (r *Router) HomeFunc(c echo.Context) error { + params := &templates.DashboardParams{ + Link: r.link, + Team: r.team, + Commit: r.commit, + Version: r.version, + } + + return r.templater.RenderTemplate(c.Response(), params, "dashboard.tmpl") +}