diff --git a/go.mod b/go.mod index b0ec7af..2628fad 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,18 @@ go 1.24.1 require ( github.com/google/uuid v1.6.0 // indirect + github.com/labstack/echo/v4 v4.13.3 // 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.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/rs/zerolog v1.33.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/ziflex/lecho/v3 v3.7.0 // indirect golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + golang.org/x/time v0.8.0 // indirect ) diff --git a/go.sum b/go.sum index f6a0b8d..c5ad46c 100644 --- a/go.sum +++ b/go.sum @@ -2,21 +2,39 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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= +github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= +github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= +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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +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= +github.com/ziflex/lecho/v3 v3.7.0 h1:MSzYINEHtAaCx2XpbdF1A85aSyXitNJxF4T9dG6jzRQ= +github.com/ziflex/lecho/v3 v3.7.0/go.mod h1:LBlLsyIwa0MFxtJ2WU5WzHfuMR/jnq26TXddWfJ+s/0= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= diff --git a/main/main.go b/main/main.go index 263ced6..215f617 100644 --- a/main/main.go +++ b/main/main.go @@ -2,13 +2,16 @@ package main import ( "os" + "playback-device-server/server" "playback-device-server/users" + "sync" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) const USER_DATABASE_DIR = "." +const WEB_SERVER_PORT = "8080" func main() { initializeLogger() @@ -28,6 +31,24 @@ func main() { if err != nil { log.Error().Err(err).Msg("failed to initialize user manager") } + + webServer := server.WebServer{} + webServer.SetWebAppDirectoryPath("www") + webServer.SetPort(WEB_SERVER_PORT) + webServer.Initialize() + defer webServer.Close() + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + log.Info().Msg("starting web server") + err := webServer.Start() + if err != nil { + log.Error().Err(err).Msg("failed to start web server") + } + }() + wg.Wait() } func initializeLogger() { diff --git a/server/web_server.go b/server/web_server.go new file mode 100644 index 0000000..c3c7bde --- /dev/null +++ b/server/web_server.go @@ -0,0 +1,80 @@ +package server + +import ( + "fmt" + "path/filepath" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/rs/zerolog/log" + "github.com/ziflex/lecho/v3" +) + +type WebServer struct { + router *echo.Echo + webAppDirectoryPath string + port string +} + +func (r *WebServer) Initialize() { + r.router = echo.New() + r.router.HideBanner = true + //r.router.HidePort = true + r.router.Logger = lecho.From(log.Logger) + r.router.Static("/", "www/dist") + r.router.Use(SetContentType) + r.router.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ + Format: "${time_rfc3339} ${method} ${uri} status ${status}\n", + })) + r.router.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"http://localhost:*", "https://localhost:*"}, + AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE}, + })) +} + +func SetContentType(next echo.HandlerFunc) echo.HandlerFunc { + return func(context echo.Context) error { + request := context.Request() + path := request.URL.Path + extension := filepath.Ext(path) + if extension == ".jsx" { + context.Response().Header().Set("Content-Type", "text/javascript") + } + return next(context) + } +} + +func (r *WebServer) Start() error { + err := r.router.Start(fmt.Sprintf(":%s", r.port)) + if err != nil { + return err + } + log.Info().Msgf("web server started on port %s", r.port) + return nil +} + +func (r *WebServer) Close() { + r.router.Close() +} + +func (r *WebServer) SetWebAppDirectoryPath(DirectoryPath string) { + r.webAppDirectoryPath = DirectoryPath +} + +func (r *WebServer) SetPort(Port string) { + r.port = Port +} + +func (r WebServer) Router() *echo.Echo { + return r.router +} + +func sendError(statusCode int, context echo.Context, message string) { + log.Info().Msg(message) + responseData := struct { + Error string `json:"error"` + }{ + Error: message, + } + context.JSON(statusCode, responseData) +}