diff --git a/.air.toml b/.air.toml index d35912f..dc36096 100644 --- a/.air.toml +++ b/.air.toml @@ -4,7 +4,7 @@ tmp_dir = "tmp" [build] args_bin = [] - bin = "fibertest.exe" + bin = "webapp" cmd = "make build" delay = 1000 exclude_dir = ["assets", "tmp", "vendor", "testdata"] diff --git a/Makefile b/Makefile index c976969..6e27444 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ build: go build . +html: + go tool qtc -dir templates + docs: go tool godoc -http=localhost:6060 -index -index_files godoc.idx build_docs: - go tool godoc -v -http=localhost:6060 -index -index_files godoc.idx -write_index + go tool godoc -v -http=localhost:6060 -index -index_files godoc.idx -write_index dev: go tool air diff --git a/README.md b/README.md index 3b311a5..0276114 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,43 @@ go tool godoc -http=localhost:6060 -index > ___NOTE:___ Google doesn't know how the internet works so you have to use `localhost:PORT` and not `127.0.0.1:PORT` when you run this. After that it'll take some time to index everything but you can already start browsing the APIs you need, and your project's stuff is in the _Third Party_ section. + +## Dealing With Module Bullshit + +The way to think about Go's modules is that they don't have modules, they have "projects." Every +directory's .go files export all of their functions without any namespacing based on the file's +name. So if you put `FooBar` into `tools.go` and `Dipshit` in `fuckyou.go` then your namespace for +_all_ files has raw dogged `FooBar` and `Dipshit` without any reference to `tools` or `fuckyou`. + +That's because your root directory is a whole __project__, not a module. To then create a namespace +you have to make a directory, place the files in that directory, and add `package mymod` at the top +of those files. You then have to import this as if it's an __entire fucking project__ everywhere +you want to use it: + +```go +import 'mywholewebsite.com/rootproject/subproject' +``` + +In this case you have a directory `subproject` and in there are a bunch of .go files with `package subproject` at the top to indicate they are in that subproject. Thinking about Go's modules as separate projects helps to sort out this `import` statement. + +1. mkdir tools +2. Create files in tools/ with `package tools` +3. `import "zedshaw.games/webapp/tools"` to get the subdirectory + +## Why Did Go Do This? + +That's because it comes from Google, and Google is famous for two things: + +1. Using a monorepo. +2. Assuming everyone else uses a monorepo. + +Don't believe me? Go look at the official first document [covering modules](https://go.dev/doc/tutorial/create-module) and you'll see they create two _totally separate projects at the root which then link to each other_. That's not how anyone else thinks when they make a single project to work on, but if you're suffering in monorepo hell you'll do it this way. + +I'll also posit that Google has some weird incentive that measures numbers of projects in the +monorepo as some kind of metric for employee productivity, so everyone working there is motivated +to get as many little projects into the monorepo as possible, thus a great way to get them to adopt +Go is to make Go support pulling tons of random projects from the root of a monorepo. + +So that's why you have to put your whole entire domain name into the import, and why you have all +the functions just raw dogged into your face when you make multiple files, and why subdirectories +are treated like whole little projects. diff --git a/go.mod b/go.mod index 3c55ad6..3bd634e 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,15 @@ -module zedshaw-games/fibertest +module zedshaw.games/webapp go 1.24.2 require ( github.com/Masterminds/squirrel v1.5.4 + github.com/go-playground/validator/v10 v10.26.0 github.com/gofiber/fiber/v2 v2.52.8 + github.com/gofiber/template/html/v2 v2.1.3 github.com/jmoiron/sqlx v1.4.0 github.com/mattn/go-sqlite3 v1.14.28 + github.com/valyala/quicktemplate v1.8.0 ) require ( @@ -35,9 +38,10 @@ require ( github.com/go-faster/errors v0.7.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/utils v1.1.0 // indirect github.com/gohugoio/hugo v0.147.6 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect @@ -78,7 +82,6 @@ require ( github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.58.0 // indirect - github.com/valyala/quicktemplate v1.8.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/vertica/vertica-sql-go v1.3.3 // indirect github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 // indirect diff --git a/go.sum b/go.sum index ac3aa54..8d67c56 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1 github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -150,6 +152,12 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4= github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= +github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= +github.com/gofiber/template/html/v2 v2.1.3 h1:n1LYBtmr9C0V/k/3qBblXyMxV5B0o/gpb6dFLp8ea+o= +github.com/gofiber/template/html/v2 v2.1.3/go.mod h1:U5Fxgc5KpyujU9OqKzy6Kn6Qup6Tm7zdsISR+VpnHRE= +github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= +github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e h1:QArsSubW7eDh8APMXkByjQWvuljwPGAGQpJEFn0F0wY= github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e/go.mod h1:3Ltoo9Banwq0gOtcOwxuHG6omk+AwsQPADyw2vQYOJQ= diff --git a/main.go b/main.go index 2d62584..a50d8fb 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,15 @@ -package main +package webapp import ( "log" + "zedshaw.games/webapp/tools" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/logger" + "github.com/gofiber/template/html/v2" _ "github.com/mattn/go-sqlite3" "github.com/jmoiron/sqlx" sq "github.com/Masterminds/squirrel" - - "github.com/go-playground/validator/v10" ) type Link struct { @@ -26,34 +26,6 @@ type Stream struct { } -func SelectJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error { - if(err != nil) { - log.Fatalln(err) - } - var result []T - - err = db.Select(&result, sql, args...) - if(err != nil) { - log.Fatalln(err); - } - - return c.JSON(&result); -} - -func GetJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error { - if(err != nil) { - log.Fatalln(err) - } - var result T - - err = db.Get(&result, sql, args...) - if(err != nil) { - log.Fatalln(err); - } - - return c.JSON(&result); -} - func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) @@ -62,41 +34,35 @@ func main() { log.Fatalln(err) } - app := fiber.New() + engine := html.New("./views", ".html") + app := fiber.New(fiber.Config{ + Views: engine, + }) app.Use(logger.New()) // handler that returns one json from a sql database app.Get("/api/stream/", func (c *fiber.Ctx) error { sql, args, err := sq.Select("*").From("stream").ToSql() - return SelectJson[Stream](db, c, err, sql, args...) + return tools.SelectJson[Stream](db, c, err, sql, args...) }) app.Get("/api/stream/:id", func (c *fiber.Ctx) error { sql, args, err := sq.Select("*").From("stream").Where("id", c.Params("id")).ToSql() - return GetJson[Stream](db, c, err, sql, args...) + return tools.GetJson[Stream](db, c, err, sql, args...) }) app.Get("/api/stream/:id/links", func (c *fiber.Ctx) error { sql, args, err := sq.Select("*").From("stream_link").Where("stream_id", c.Params("id")).ToSql() - return SelectJson[Link](db, c, err, sql, args...) + return tools.SelectJson[Link](db, c, err, sql, args...) }) app.Post("/api/link", func (c *fiber.Ctx) error { - link := new(Link) - - if err := c.BodyParser(link); err != nil { - log.Println(err); - return c.Redirect("/live/") - } + link, err := tools.GetThing[Link](c) - var validate *validator.Validate - validate = validator.New(validator.WithRequiredStructEnabled()) - - if err := validate.Struct(link); err != nil { - validationErrors := err.(validator.ValidationErrors) - log.Println(validationErrors) - return c.Redirect("/live/") + if(err != nil) { + log.Println(err) + c.Redirect("/live/") } sql, args, err := sq.Insert("stream_link").Columns("stream_id", "url", "description").Values(link.StreamId, link.Url, link.Description).ToSql() @@ -113,5 +79,11 @@ func main() { app.Static("/", "./public") + app.Get("/test/", func (c *fiber.Ctx) error { + return c.Render("index", fiber.Map{ + "Title": "Hello, World!", + }) + }) + log.Fatal(app.Listen(":5001")) } diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..7a82e05 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,59 @@ +package tools + +import ( + "log" + "github.com/gofiber/fiber/v2" + + _ "github.com/mattn/go-sqlite3" + "github.com/jmoiron/sqlx" + "github.com/go-playground/validator/v10" + ) + +func SelectJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error { + if(err != nil) { + log.Fatalln(err) + } + var result []T + + err = db.Select(&result, sql, args...) + if(err != nil) { + log.Fatalln(err); + } + + return c.JSON(&result); +} + +func GetJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error { + if(err != nil) { + log.Fatalln(err) + } + var result T + + err = db.Get(&result, sql, args...) + if(err != nil) { + log.Fatalln(err); + } + + return c.JSON(&result); +} + +func GetThing[T any](c *fiber.Ctx) (*T, error) { + var result *T + result = new(T) + + if err := c.BodyParser(result); err != nil { + log.Println(err); + return result, err + } + + var validate *validator.Validate + validate = validator.New(validator.WithRequiredStructEnabled()) + + if err := validate.Struct(result); err != nil { + validationErrors := err.(validator.ValidationErrors) + log.Println(validationErrors) + return result, err + } + + return result, nil +} diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..6c8f1e5 --- /dev/null +++ b/views/index.html @@ -0,0 +1,5 @@ +{{template "partials/header" .}} + +