From 8ce5189b628536184e7f086d6023411db26f3808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie=20Delhaie?= Date: Fri, 1 Nov 2024 22:41:06 +0100 Subject: [PATCH] First commit --- api/api.go | 73 ++++++++++++++++++++++++++++++++++ api/templates/description.html | 41 +++++++++++++++++++ api/templates/index.html | 34 ++++++++++++++++ data/data.go | 61 ++++++++++++++++++++++++++++ go.mod | 8 ++++ go.sum | 4 ++ main.go | 18 +++++++++ 7 files changed, 239 insertions(+) create mode 100644 api/api.go create mode 100644 api/templates/description.html create mode 100644 api/templates/index.html create mode 100644 data/data.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..0030d71 --- /dev/null +++ b/api/api.go @@ -0,0 +1,73 @@ +package api + +import ( + "downloadhub/data" + _ "embed" + "fmt" + "html/template" + "log/slog" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +type ( + Server struct { + r chi.Router + d data.Service + port uint16 + } +) + +//go:embed templates/index.html +var index string + +//go:embed templates/description.html +var description string + +func New(port uint16, d data.Service) *Server { + indexTemplate := template.New("index") + indexTemplate.Parse(index) + + descTemplate := template.New("description") + descTemplate.Parse(description) + + r := chi.NewRouter() + r.Use(middleware.Logger) + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + err := indexTemplate.Execute(w, d.Softwares) + if err != nil { + slog.Error(fmt.Sprintf("failed to execute template index: %s", err)) + } + }) + r.Get("/d/{softID}", func(w http.ResponseWriter, r *http.Request) { + softID := chi.URLParam(r, "softID") + var soft data.Software + var found bool + for _, s := range d.Softwares { + if s.UUID == softID { + soft = s + found = true + } + } + if !found { + w.Header().Add("Location", "/") + w.WriteHeader(http.StatusTemporaryRedirect) + return + } + err := descTemplate.Execute(w, soft) + if err != nil { + slog.Error(fmt.Sprintf("failed to execute template index: %s", err)) + } + }) + return &Server{ + r: r, + d: d, + port: port, + } +} + +func (s *Server) Serve() error { + return http.ListenAndServe(fmt.Sprintf(":%d", s.port), s.r) +} diff --git a/api/templates/description.html b/api/templates/description.html new file mode 100644 index 0000000..43a4c1c --- /dev/null +++ b/api/templates/description.html @@ -0,0 +1,41 @@ + + + + + + DownloadHub - {{.Name}} + + + + + +
+

{{.Name}} ({{.Version}})

+ +

{{.Description}}

+
+
+
+ Download +
+ +
+
+ + + + + \ No newline at end of file diff --git a/api/templates/index.html b/api/templates/index.html new file mode 100644 index 0000000..eeae2b7 --- /dev/null +++ b/api/templates/index.html @@ -0,0 +1,34 @@ + + + + + + DownloadHub + + + + + +
+ {{range .}} +
+
+ +
+
+

{{.Name}}

+

{{.Description}}

+
+
+
+ {{end}} +
+ + + + \ No newline at end of file diff --git a/data/data.go b/data/data.go new file mode 100644 index 0000000..9d82eab --- /dev/null +++ b/data/data.go @@ -0,0 +1,61 @@ +package data + +import ( + "encoding/json" + "os" + + "github.com/google/uuid" +) + +type ( + Service struct { + Softwares []Software + } + + Software struct { + UUID string + Name string `json:"name"` + Description string `json:"description"` + Version string `json:"version"` + IconURL string `json:"icon_url"` + ScreenshotURLs []string `json:"screenshot_urls"` + DownloadLinks []DownloadLink `json:"download_links"` + } + + DownloadLink struct { + OS string `json:"os"` + Arch string `json:"arch"` + URL string `json:"url"` + } + + document struct { + Softwares []Software `json:"softwares"` + } +) + +func Load(path string) Service { + f, err := os.OpenFile(path, os.O_RDONLY, 0744) + if err != nil { + panic("failed to open data file: " + err.Error()) + } + defer f.Close() + + var s document + d := json.NewDecoder(f) + err = d.Decode(&s) + if err != nil { + panic("failed to parse data file: " + err.Error()) + } + s = generateUUID(s) + return Service{ + Softwares: s.Softwares, + } +} + +func generateUUID(d document) document { + for i, s := range d.Softwares { + s.UUID = uuid.New().String() + d.Softwares[i] = s + } + return d +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ef4213f --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module downloadhub + +go 1.22 + +require ( + github.com/go-chi/chi/v5 v5.1.0 + github.com/google/uuid v1.6.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..67edbd5 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/main.go b/main.go new file mode 100644 index 0000000..1b0b425 --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "downloadhub/api" + "downloadhub/data" + "flag" +) + +func main() { + var configFile string + flag.StringVar(&configFile, "c", "config.json", "Configuration file path") + flag.Parse() + + d := data.Load(configFile) + + s := api.New(3000, d) + s.Serve() +}