2024-09-11 00:52:18 +00:00
|
|
|
package h
|
|
|
|
|
|
|
|
|
|
import (
|
2024-09-26 16:40:31 +00:00
|
|
|
"fmt"
|
2024-09-26 19:40:09 +00:00
|
|
|
"github.com/labstack/echo/v4"
|
2024-09-21 16:52:56 +00:00
|
|
|
"github.com/maddalax/htmgo/framework/hx"
|
2024-09-23 01:59:44 +00:00
|
|
|
"github.com/maddalax/htmgo/framework/service"
|
2024-09-26 16:40:31 +00:00
|
|
|
"log/slog"
|
|
|
|
|
"os/exec"
|
|
|
|
|
"runtime"
|
|
|
|
|
"time"
|
2024-09-11 00:52:18 +00:00
|
|
|
)
|
|
|
|
|
|
2024-09-18 19:52:57 +00:00
|
|
|
type RequestContext struct {
|
2024-09-26 19:40:09 +00:00
|
|
|
echo.Context
|
2024-09-21 16:52:56 +00:00
|
|
|
locator *service.Locator
|
|
|
|
|
isBoosted bool
|
|
|
|
|
currentBrowserUrl string
|
|
|
|
|
hxPromptResponse string
|
|
|
|
|
isHxRequest bool
|
|
|
|
|
hxTargetId string
|
|
|
|
|
hxTriggerName string
|
|
|
|
|
hxTriggerId string
|
2024-09-18 19:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *RequestContext) ServiceLocator() *service.Locator {
|
|
|
|
|
return c.locator
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AppOpts struct {
|
|
|
|
|
LiveReload bool
|
|
|
|
|
ServiceLocator *service.Locator
|
2024-09-26 19:40:09 +00:00
|
|
|
Register func(echo *echo.Echo)
|
2024-09-18 19:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-11 00:52:18 +00:00
|
|
|
type App struct {
|
2024-09-26 19:40:09 +00:00
|
|
|
Opts AppOpts
|
|
|
|
|
Echo *echo.Echo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var instance *App
|
|
|
|
|
|
|
|
|
|
func GetApp() *App {
|
|
|
|
|
if instance == nil {
|
|
|
|
|
panic("App instance not initialized")
|
|
|
|
|
}
|
|
|
|
|
return instance
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-18 19:52:57 +00:00
|
|
|
func Start(opts AppOpts) {
|
2024-09-26 19:40:09 +00:00
|
|
|
e := echo.New()
|
2024-09-18 19:52:57 +00:00
|
|
|
instance := App{
|
2024-09-26 19:40:09 +00:00
|
|
|
Opts: opts,
|
|
|
|
|
Echo: e,
|
2024-09-18 19:52:57 +00:00
|
|
|
}
|
|
|
|
|
instance.start()
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-21 16:52:56 +00:00
|
|
|
func populateHxFields(cc *RequestContext) {
|
2024-09-26 19:40:09 +00:00
|
|
|
cc.isBoosted = cc.Request().Header.Get(hx.BoostedHeader) == "true"
|
|
|
|
|
cc.currentBrowserUrl = cc.Request().Header.Get(hx.CurrentUrlHeader)
|
|
|
|
|
cc.hxPromptResponse = cc.Request().Header.Get(hx.PromptResponseHeader)
|
|
|
|
|
cc.isHxRequest = cc.Request().Header.Get(hx.RequestHeader) == "true"
|
|
|
|
|
cc.hxTargetId = cc.Request().Header.Get(hx.TargetIdHeader)
|
|
|
|
|
cc.hxTriggerName = cc.Request().Header.Get(hx.TriggerNameHeader)
|
|
|
|
|
cc.hxTriggerId = cc.Request().Header.Get(hx.TriggerIdHeader)
|
2024-09-21 16:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
func (a App) start() {
|
2024-09-11 00:52:18 +00:00
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
if a.Opts.Register != nil {
|
|
|
|
|
a.Opts.Register(a.Echo)
|
|
|
|
|
}
|
2024-09-20 18:25:14 +00:00
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
a.Echo.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
|
|
|
return func(c echo.Context) error {
|
2024-09-18 19:52:57 +00:00
|
|
|
cc := &RequestContext{
|
2024-09-26 19:40:09 +00:00
|
|
|
Context: c,
|
|
|
|
|
locator: a.Opts.ServiceLocator,
|
2024-09-18 19:52:57 +00:00
|
|
|
}
|
2024-09-21 16:52:56 +00:00
|
|
|
populateHxFields(cc)
|
2024-09-26 19:40:09 +00:00
|
|
|
return next(cc)
|
|
|
|
|
}
|
2024-09-18 19:52:57 +00:00
|
|
|
})
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
if a.Opts.LiveReload && IsDevelopment() {
|
|
|
|
|
AddLiveReloadHandler("/dev/livereload", a.Echo)
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-17 15:41:29 +00:00
|
|
|
port := ":3000"
|
2024-09-26 19:40:09 +00:00
|
|
|
err := a.Echo.Start(port)
|
2024-09-11 00:52:18 +00:00
|
|
|
|
|
|
|
|
if err != nil {
|
2024-09-26 16:40:31 +00:00
|
|
|
// If we are in watch mode, just try to kill any processes holding that port
|
|
|
|
|
// and try again
|
|
|
|
|
if IsDevelopment() && IsWatchMode() {
|
|
|
|
|
slog.Info("Port already in use, trying to kill the process and start again")
|
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
|
cmd := exec.Command("cmd", "/C", fmt.Sprintf(`for /F "tokens=5" %%i in ('netstat -aon ^| findstr :%s') do taskkill /F /PID %%i`, port))
|
|
|
|
|
cmd.Run()
|
|
|
|
|
} else {
|
|
|
|
|
cmd := exec.Command("bash", "-c", fmt.Sprintf("kill -9 $(lsof -ti%s)", port))
|
|
|
|
|
cmd.Run()
|
|
|
|
|
}
|
|
|
|
|
time.Sleep(time.Millisecond * 50)
|
2024-09-26 19:40:09 +00:00
|
|
|
err = a.Echo.Start(port)
|
2024-09-26 16:40:31 +00:00
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2024-09-24 16:08:35 +00:00
|
|
|
panic(err)
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
func HtmlView(c echo.Context, page *Page) error {
|
|
|
|
|
root := page.Root
|
|
|
|
|
return c.HTML(200,
|
|
|
|
|
Render(
|
|
|
|
|
root,
|
|
|
|
|
),
|
|
|
|
|
)
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
func PartialViewWithHeaders(c echo.Context, headers *Headers, partial *Partial) error {
|
2024-09-11 18:09:55 +00:00
|
|
|
if partial.Headers != nil {
|
|
|
|
|
for s, a := range *partial.Headers {
|
2024-09-26 19:40:09 +00:00
|
|
|
c.Set(s, a)
|
2024-09-11 18:09:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if headers != nil {
|
|
|
|
|
for s, a := range *headers {
|
2024-09-26 19:40:09 +00:00
|
|
|
c.Response().Header().Set(s, a)
|
2024-09-11 18:09:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
return c.HTML(200,
|
|
|
|
|
Render(
|
|
|
|
|
partial,
|
|
|
|
|
),
|
|
|
|
|
)
|
2024-09-11 18:09:55 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
func PartialView(c echo.Context, partial *Partial) error {
|
|
|
|
|
c.Set(echo.HeaderContentType, echo.MIMETextHTML)
|
2024-09-11 00:52:18 +00:00
|
|
|
if partial.Headers != nil {
|
|
|
|
|
for s, a := range *partial.Headers {
|
2024-09-26 19:40:09 +00:00
|
|
|
c.Response().Header().Set(s, a)
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 19:40:09 +00:00
|
|
|
return c.HTML(200,
|
|
|
|
|
Render(
|
|
|
|
|
partial,
|
|
|
|
|
),
|
|
|
|
|
)
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|