[WIP] Add web client

Ignore .swp files

Rename serverCmd to apiCmd (the web client is technically a server too)

Add webCmd for html routes hosting

Add embedding and templating for web client

Add webhandlers

Fix some variables not being filled automatically by viper

Change flags and reorganize config structure
This commit is contained in:
Victor Lacasse-Beaudoin 2023-05-25 19:22:46 -04:00
parent 3e37e8ffef
commit 3aa7faa2f6
7 changed files with 201 additions and 32 deletions

View file

@ -18,11 +18,22 @@ var (
apiKey string
)
// serverCmd represents the server command
var serverCmd = &cobra.Command{
Use: "server",
// apiCmd represents the api command
var apiCmd = &cobra.Command{
Use: "api",
Short: "Démarrer le serveur API",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
apiKey = viper.GetString("api.key")
apiPort = viper.GetInt("api.port")
connection := data.PostgresConnection{
User: viper.GetString("db.user"),
Password: viper.GetString("db.password"),
Host: viper.GetString("db.host"),
Database: viper.GetString("db.database"),
Port: viper.GetInt("db.port"),
}
e := echo.New()
@ -52,14 +63,6 @@ var serverCmd = &cobra.Command{
// Execution
connection := data.PostgresConnection{
User: viper.GetString("db.user"),
Password: viper.GetString("db.password"),
Host: viper.GetString("db.host"),
Database: viper.GetString("db.database"),
Port: viper.GetInt("db.port"),
}
client, err := data.NewDataClient(connection)
if err != nil {
log.Fatalf("Could not establish database connection.\n Error: %s\n", err)
@ -72,40 +75,45 @@ var serverCmd = &cobra.Command{
client.DB.Close()
log.Println("apiPort: ", apiPort)
log.Println("apiKey: ", apiKey)
e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", apiPort)))
},
}
func init() {
rootCmd.AddCommand(serverCmd)
rootCmd.AddCommand(apiCmd)
// api.key
serverCmd.Flags().StringVar(
&apiKey, "api-key", "bottin",
apiCmd.Flags().String(
"api-key", "bottin",
"API server key. Leave empty for no key auth. (config: 'api.key')")
viper.BindPFlag("api.key", apiCmd.Flags().Lookup("api-key"))
// api.port
serverCmd.Flags().IntVar(
&apiPort, "api-port", 1312,
apiCmd.Flags().Int(
"api-port", 1312,
"API server port (config:'api.port')")
viper.BindPFlag("api.port", apiCmd.Flags().Lookup("api-port"))
// db.database
serverCmd.Flags().String("db-database", "bottin", "Postgres database (config:'db.database')")
viper.BindPFlag("db.database", serverCmd.Flags().Lookup("db-database"))
apiCmd.Flags().String("db-database", "bottin", "Postgres database (config:'db.database')")
viper.BindPFlag("db.database", apiCmd.Flags().Lookup("db-database"))
// db.host
serverCmd.Flags().String("db-host", "postgres", "Postgres host (config:'db.host')")
viper.BindPFlag("db.host", serverCmd.Flags().Lookup("db-host"))
apiCmd.Flags().String("db-host", "db", "Postgres host (config:'db.host')")
viper.BindPFlag("db.host", apiCmd.Flags().Lookup("db-host"))
// db.password
serverCmd.Flags().String("db-password", "bottin", "Postgres password (config:'db.password')")
viper.BindPFlag("db.password", serverCmd.Flags().Lookup("db-password"))
apiCmd.Flags().String("db-password", "bottin", "Postgres password (config:'db.password')")
viper.BindPFlag("db.password", apiCmd.Flags().Lookup("db-password"))
// db.port
serverCmd.Flags().Int("db-port", 5432, "Postgres port (config:'db.port')")
viper.BindPFlag("db.port", serverCmd.Flags().Lookup("db-port"))
apiCmd.Flags().Int("db-port", 5432, "Postgres port (config:'db.port')")
viper.BindPFlag("db.port", apiCmd.Flags().Lookup("db-port"))
// db.user
serverCmd.Flags().String("db-user", "bottin", "Postgres user (config:'db.user')")
viper.BindPFlag("db.user", serverCmd.Flags().Lookup("db-user"))
apiCmd.Flags().String("db-user", "bottin", "Postgres user (config:'db.user')")
viper.BindPFlag("db.user", apiCmd.Flags().Lookup("db-user"))
}

View file

@ -1,20 +1,129 @@
package cmd
import (
"crypto/subtle"
"embed"
"fmt"
"html/template"
"io"
"log"
"git.agecem.com/agecem/bottin/v4/web"
"git.agecem.com/agecem/bottin/v4/web/webhandlers"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
webUser string
webPassword string
webPort int
webApiHost string
webApiKey string
webApiPort int
)
var templatesFS embed.FS
type Template struct {
templates *template.Template
}
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return t.templates.ExecuteTemplate(w, name, data)
}
// webCmd represents the web command
var webCmd = &cobra.Command{
Use: "web",
Short: "Démarrer le client web",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("web called")
webApiHost = viper.GetString("web.api.host")
webApiKey = viper.GetString("web.api.key")
webApiPort = viper.GetInt("web.api.port")
webPassword = viper.GetString("web.password")
webPort = viper.GetInt("web.port")
webUser = viper.GetString("web.user")
e := echo.New()
// Middlewares
e.Pre(middleware.AddTrailingSlash())
e.Use(middleware.BasicAuth(func(user, password string, c echo.Context) (bool, error) {
usersMatch := subtle.ConstantTimeCompare([]byte(user), []byte(webUser)) == 1
passwordsMatch := subtle.ConstantTimeCompare([]byte(password), []byte(webPassword)) == 1
return usersMatch && passwordsMatch, nil
}))
// Template
t := &Template{
templates: template.Must(template.ParseFS(templatesFS, "templates/*.html")),
}
e.Renderer = t
// Routes
e.GET("/", webhandlers.GetIndex)
// Execution
fmt.Println("webPort: ", webPort)
fmt.Println("web.port: ", viper.GetInt("web.port"))
webPortFlag, err := cmd.Flags().GetInt("web-port")
if err != nil {
log.Fatal(err)
}
fmt.Println("web-port: ", webPortFlag)
e.Logger.Fatal(e.Start(
fmt.Sprintf(":%d", webPort)))
},
}
func init() {
rootCmd.AddCommand(webCmd)
templatesFS = web.GetTemplates()
// web.api.host
webCmd.Flags().String(
"web-api-host", "api",
"Remote API server host (config:'web.api.host')")
viper.BindPFlag("web.api.host", webCmd.Flags().Lookup("web-api-host"))
// web.api.key
webCmd.Flags().String(
"web-api-key", "bottin",
"Remote API server key (config:'web.api.key')")
viper.BindPFlag("web.api.key", webCmd.Flags().Lookup("web-api-key"))
// web.api.port
webCmd.Flags().Int(
"web-api-port", 1312,
"Remote API server port (config:'web.api.port')")
viper.BindPFlag("web.api.port", webCmd.Flags().Lookup("web-api-port"))
// web.password
webCmd.Flags().String(
"web-password", "bottin",
"Web client password (config:'web.password')")
viper.BindPFlag("web.password", webCmd.Flags().Lookup("web-password"))
// web.port
webCmd.Flags().Int(
"web-port", 2312,
"Web client port (config:'web.port')")
viper.BindPFlag("web.port", webCmd.Flags().Lookup("web-port"))
// web.user
webCmd.Flags().String(
"web-user", "bottin",
"Web client user (config:'web.user')")
viper.BindPFlag("web.user", webCmd.Flags().Lookup("web-user"))
}