From 8347d0353fef9843364a5018de44639ef283aab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Sat, 18 May 2024 12:10:09 -0300 Subject: [PATCH 01/16] temp: run lua inside go --- go.mod | 1 + go.sum | 2 ++ lua.go | 26 ++++++++++++++++++++++++++ main.lua | 11 +++++++++++ 4 files changed, 40 insertions(+) create mode 100644 lua.go create mode 100644 main.lua diff --git a/go.mod b/go.mod index 0267644..3893733 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/marco-souza/marco.fly.dev go 1.22 require ( + github.com/Shopify/go-lua v0.0.0-20240312125312-5d657e363856 github.com/go-playground/validator/v10 v10.16.0 github.com/gofiber/fiber/v2 v2.52.1 github.com/gofiber/storage/sqlite3/v2 v2.1.0 diff --git a/go.sum b/go.sum index 80ac990..7dbd8cd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Shopify/go-lua v0.0.0-20240312125312-5d657e363856 h1:N32EXb3LZ0FJwbdoMokLXysTHgWHccuYUPxmVqPowkw= +github.com/Shopify/go-lua v0.0.0-20240312125312-5d657e363856/go.mod h1:M4CxjVc/1Nwka5atBv7G/sb7Ac2BDe3+FxbiT9iVNIQ= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/lua.go b/lua.go new file mode 100644 index 0000000..7267ed4 --- /dev/null +++ b/lua.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + "os" + + "github.com/Shopify/go-lua" +) + +func main() { + l := lua.NewState() + lua.OpenLibraries(l) + + // run snippet + lua.DoString(l, "print('Hello from Lua!')") + + if len(os.Args) == 1 { + log.Println("No file to run") + return + } + + filename := os.Args[1] + if err := lua.DoFile(l, filename); err != nil { + panic(err) + } +} diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..160b9da --- /dev/null +++ b/main.lua @@ -0,0 +1,11 @@ +--@param count number of times to run the function +function times(count, func) + for i = 1, count do + print("running function: " .. i) + func() + end +end + +times(5, function() + print "Hello, World!" +end) From a967c9f16f3fe0a6c120dc1e00280944fcae3b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 11:47:24 -0300 Subject: [PATCH 02/16] fea: add lua runtime service --- go.mod | 4 ++++ go.sum | 5 +++-- internal/lua/lua.go | 25 +++++++++++++++++++++++++ internal/lua/lua_test.go | 27 +++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 internal/lua/lua.go create mode 100644 internal/lua/lua_test.go diff --git a/go.mod b/go.mod index 3893733..e7bf9c2 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/gofiber/template/html/v2 v2.0.5 github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 github.com/joho/godotenv v1.5.1 + github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.51.0 gorm.io/driver/sqlite v1.5.4 gorm.io/gorm v1.25.5 @@ -17,6 +18,7 @@ require ( require ( github.com/andybalholm/brotli v1.0.6 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -32,6 +34,7 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-sqlite3 v1.14.18 // indirect github.com/philhofer/fwd v1.1.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -40,4 +43,5 @@ require ( golang.org/x/net v0.19.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7dbd8cd..622fff5 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -111,6 +111,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/lua/lua.go b/internal/lua/lua.go new file mode 100644 index 0000000..d6b74fd --- /dev/null +++ b/internal/lua/lua.go @@ -0,0 +1,25 @@ +package lua + +import ( + "log" + + "github.com/Shopify/go-lua" +) + +type luaRuntime struct { + l *lua.State +} + +func new() *luaRuntime { + l := lua.NewState() + lua.OpenLibraries(l) + return &luaRuntime{l} +} + +func (r *luaRuntime) Run(snippet string) (string, error) { + log.Println("Running Lua snippet", snippet) + // TODO: get lua execution output: https://github.com/Shopify/go-lua/pull/43 + return "", lua.DoString(r.l, snippet) +} + +var Runtime = new() diff --git a/internal/lua/lua_test.go b/internal/lua/lua_test.go new file mode 100644 index 0000000..27f79e8 --- /dev/null +++ b/internal/lua/lua_test.go @@ -0,0 +1,27 @@ +package lua + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLua(t *testing.T) { + t.Run("should run code if valid", func(t *testing.T) { + snippet := "return 1+1" + output, err := Runtime.Run(snippet) + assert.Nil(t, err) + assert.Equal(t, output, "") // TODO: fix it later + }) + + t.Run("should error with invalid code", func(t *testing.T) { + _, err := Runtime.Run("(- (+ 1 1) 2)") + assert.Error(t, err, "syntax error") + + _, err = Runtime.Run("function js() { return 1+1 } js()") + assert.Error(t, err, "syntax error") + + _, err = Runtime.Run("invalid code") + assert.Error(t, err, "syntax error") + }) +} From 0b00daaf5a8447b9530fa65cdec45d37d999ea65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 11:47:48 -0300 Subject: [PATCH 03/16] fea: add endpoint to run lua - add code template - also improve routes.go security with authMiddleware --- internal/server/routes/api/lua.go | 26 ++++++++++++++ internal/server/routes/api/routes.go | 54 +++++++++++++++++++--------- views/partials/code.html | 1 + 3 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 internal/server/routes/api/lua.go create mode 100644 views/partials/code.html diff --git a/internal/server/routes/api/lua.go b/internal/server/routes/api/lua.go new file mode 100644 index 0000000..b051051 --- /dev/null +++ b/internal/server/routes/api/lua.go @@ -0,0 +1,26 @@ +package api + +import ( + "log" + + "github.com/gofiber/fiber/v2" + "github.com/marco-souza/marco.fly.dev/internal/lua" +) + +func luaHandler(c *fiber.Ctx) error { + snippet := c.FormValue("snippet") + if snippet == "" { + log.Println("No snippet provided.") + return c.Render("partials/code", fiber.Map{"Code": "No output yet."}, "layouts/empty") + } + + log.Println("Lua code:", snippet) + code, err := lua.Runtime.Run(snippet) + if err != nil { + log.Println("Lua error:", err) + return c.Render("partials/code", fiber.Map{"Code": err.Error()}, "layouts/empty") + } + + log.Println("Lua output:", code) + return c.Render("partials/code", fiber.Map{"Code": code}, "layouts/empty") +} diff --git a/internal/server/routes/api/routes.go b/internal/server/routes/api/routes.go index f1445e2..f9d2bce 100644 --- a/internal/server/routes/api/routes.go +++ b/internal/server/routes/api/routes.go @@ -1,41 +1,61 @@ package api import ( + "log" + "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/limiter" "github.com/gofiber/storage/sqlite3/v2" "github.com/marco-souza/marco.fly.dev/internal/config" + "github.com/marco-souza/marco.fly.dev/internal/github" ) var conf = config.Load() +// create auth check middleware +func authMiddleware(c *fiber.Ctx) error { + token := github.AccessToken(c) + if token == "" { + log.Println("Unauthorized access, redirecting to login page.") + return c.Redirect(conf.Github.LoginPage) + } + return c.Next() +} + func Apply(router fiber.Router) { // https://docs.gofiber.io/api/middleware/limiter - router.Use(limiter.New(limiter.Config{ - Max: conf.RateLimit, - Storage: sqlite3.New(), - })) - - router.Group("/orders"). - Get("/", ordersHandler). - Post("/", createOrderHandler). - Delete("/:id", deleteOrderHandler) + if conf.Env == "production" { + router.Use(limiter.New(limiter.Config{ + Max: conf.RateLimit, + Storage: sqlite3.New(), + })) + } - router.Group("/auth/github"). + // public routes + router.Group("/"). + Get("/resume", resumeHandler). + Get("/menu", menuHandler). + // auth + Group("/auth/github"). Get("/", redirectGithubAuth). Get("/callback", callbackGithubAuth). Get("/refresh", logoutGithubAuth). Get("/logout", logoutGithubAuth) - // ref into one Group - router.Group("/"). - Get("/now", nowHandler). - Get("/sse", sseHandler). - Get("/resume", resumeHandler). - Get("/menu", menuHandler) - if conf.Env == "development" { router.Get("/reload", sseReloadHandler) } + + // private routes + router.Group("/"). + Use(authMiddleware). + Post("/lua", luaHandler). + Get("/now", nowHandler). + Get("/sse", sseHandler) + + router.Group("/orders"). + Get("/", ordersHandler). + Post("/", createOrderHandler). + Delete("/:id", deleteOrderHandler) } diff --git a/views/partials/code.html b/views/partials/code.html new file mode 100644 index 0000000..a932734 --- /dev/null +++ b/views/partials/code.html @@ -0,0 +1 @@ +{{.Code}} From ed69767847080123f715b91236ce974c273f6e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 11:49:42 -0300 Subject: [PATCH 04/16] fea: add lua editor to playground --- views/partials/editor.html | 19 +++++++++++++++++++ views/playground.html | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 views/partials/editor.html diff --git a/views/partials/editor.html b/views/partials/editor.html new file mode 100644 index 0000000..4e930b9 --- /dev/null +++ b/views/partials/editor.html @@ -0,0 +1,19 @@ +
+
+ + + + + +
+ + No output yet. +
diff --git a/views/playground.html b/views/playground.html index 622708e..e56ca44 100644 --- a/views/playground.html +++ b/views/playground.html @@ -20,3 +20,5 @@

{{.Title}}

Contents of this box will be updated in real time with every SSE message received from the chatroom. + +{{ template "partials/editor" . }} From 17ff73e0c50fd18561d6d9a175114c4e4fe1f49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 11:53:54 -0300 Subject: [PATCH 05/16] ref: clean-up temp files --- lua.go | 26 -------------------------- main.lua | 11 ----------- 2 files changed, 37 deletions(-) delete mode 100644 lua.go delete mode 100644 main.lua diff --git a/lua.go b/lua.go deleted file mode 100644 index 7267ed4..0000000 --- a/lua.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "log" - "os" - - "github.com/Shopify/go-lua" -) - -func main() { - l := lua.NewState() - lua.OpenLibraries(l) - - // run snippet - lua.DoString(l, "print('Hello from Lua!')") - - if len(os.Args) == 1 { - log.Println("No file to run") - return - } - - filename := os.Args[1] - if err := lua.DoFile(l, filename); err != nil { - panic(err) - } -} diff --git a/main.lua b/main.lua deleted file mode 100644 index 160b9da..0000000 --- a/main.lua +++ /dev/null @@ -1,11 +0,0 @@ ---@param count number of times to run the function -function times(count, func) - for i = 1, count do - print("running function: " .. i) - func() - end -end - -times(5, function() - print "Hello, World!" -end) From 95507e1da57e542f7f7683e1b6199376226a7d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 13:27:37 -0300 Subject: [PATCH 06/16] fea: pipe stdout to an output variable --- internal/lua/lua.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/internal/lua/lua.go b/internal/lua/lua.go index d6b74fd..d54017a 100644 --- a/internal/lua/lua.go +++ b/internal/lua/lua.go @@ -1,7 +1,9 @@ package lua import ( + "io" "log" + "os" "github.com/Shopify/go-lua" ) @@ -18,8 +20,28 @@ func new() *luaRuntime { func (r *luaRuntime) Run(snippet string) (string, error) { log.Println("Running Lua snippet", snippet) - // TODO: get lua execution output: https://github.com/Shopify/go-lua/pull/43 - return "", lua.DoString(r.l, snippet) + + outputReader, outputWriter, _ := os.Pipe() + rescueStdout := os.Stdout // save the actual stdout + os.Stdout = outputWriter // redirect stdout to pipe + + err := lua.DoString(r.l, snippet) + if err != nil { + log.Println("Error running Lua snippet", err) + return "", err + } + + outputWriter.Close() // close pipe writer + os.Stdout = rescueStdout // restore stdout + + output, err := io.ReadAll(outputReader) + if err != nil { + log.Println("Error reading Lua output", err) + return "", err + } + + log.Println("Lua output", string(output)) + return string(output), nil } var Runtime = new() From 7f89dcf076050c1367eb07243850cc3765c197cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 13:44:17 -0300 Subject: [PATCH 07/16] fea: implement server graceful shutdown --- internal/server/server.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/server/server.go b/internal/server/server.go index 15a9faf..f2b3ffc 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -3,6 +3,8 @@ package server import ( "fmt" "log" + "os" + "os/signal" "time" "github.com/gofiber/fiber/v2" @@ -53,7 +55,20 @@ func (s *server) Start() { models.Seed() } - log.Fatal(s.app.Listen(s.addr)) + shutdown := make(chan os.Signal, 1) + signal.Notify(shutdown, os.Interrupt) // register channel to interrupt signals + teardown := func() { + <-shutdown + fmt.Println("shutting down server...") + s.app.Shutdown() + } + + go teardown() // start listening for interrupt signals + + // await for server to shutdown + if err := s.app.Listen(s.addr); err != nil { + log.Fatal(err) + } } func (s *server) setupRoutes() { From 85105a4b2aabab4a897547692ce01bc99ebc2aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 13:44:38 -0300 Subject: [PATCH 08/16] fix: kill previous server on air reload --- .air.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.air.toml b/.air.toml index 53197bd..a3dd87b 100644 --- a/.air.toml +++ b/.air.toml @@ -6,7 +6,7 @@ testdata_dir = "testdata" [build] args_bin = [] bin = "./tmp/server" - cmd = "CGO_ENABLED=1 go build -o ./tmp/server ./cmd/api/main.go" + cmd = "pkill server; CGO_ENABLED=1 go build -o ./tmp/server ./cmd/main.go" include_ext = ["go", "tpl", "tmpl", "html"] exclude_dir = ["assets", "tmp", "vendor", "testdata"] exclude_regex = ["(\\.null-ls.*|_test)\\.go"] From 4cfd34083893f7893d26bf0986f8289448c1ef44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 13:51:42 -0300 Subject: [PATCH 09/16] fix: lua tests --- Makefile | 2 +- internal/lua/lua_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7859db3..bd75c46 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ fmt: t: test test: ./tests/ - go test -v ./tests/ + go test -v ./... encrypt: .env gpg -c .env diff --git a/internal/lua/lua_test.go b/internal/lua/lua_test.go index 27f79e8..3833905 100644 --- a/internal/lua/lua_test.go +++ b/internal/lua/lua_test.go @@ -8,10 +8,10 @@ import ( func TestLua(t *testing.T) { t.Run("should run code if valid", func(t *testing.T) { - snippet := "return 1+1" + snippet := "print(10^3)" output, err := Runtime.Run(snippet) assert.Nil(t, err) - assert.Equal(t, output, "") // TODO: fix it later + assert.Contains(t, output, "1000") }) t.Run("should error with invalid code", func(t *testing.T) { From 593eb8227a1931de474740c40a905ba2c0c3d87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ant=C3=B4nio?= Date: Mon, 20 May 2024 13:53:08 -0300 Subject: [PATCH 10/16] fix: time pooling frequency --- views/playground.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/playground.html b/views/playground.html index e56ca44..5a578c8 100644 --- a/views/playground.html +++ b/views/playground.html @@ -2,7 +2,7 @@

{{.Title}}