Restructure app

This commit is contained in:
Eden Kirin
2023-10-23 23:05:18 +02:00
parent f0e323f2ce
commit 002f6a3d06
11 changed files with 250 additions and 10 deletions

88
app/cfg/cfg.go Normal file
View File

@ -0,0 +1,88 @@
package cfg
import (
"fmt"
"os"
"github.com/kelseyhightower/envconfig"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
)
type configStruct struct {
Database struct {
Host string `yaml:"host"`
Port string `yaml:"port"`
Name string `yaml:"name"`
Username string `yaml:"username"`
Password string `yaml:"password" json:"-"`
} `yaml:"database"`
Application struct {
LogLevel string `yaml:"logLevel"`
LogFile string `yaml:"logFile"`
Debug bool `yaml:"debug"`
DebugSQL bool `yaml:"debugSQL"`
DisableSendMail bool `yaml:"disableSendMail"`
IsProduction bool `yaml:"isProduction"`
LoopDelay uint32 `yaml:"loopDelay"`
} `yaml:"application"`
SMTP struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password" json:"-"`
StartTLS bool `yaml:"startTLS"`
UseTLS bool `yaml:"useTLS"`
FromEmail string `yaml:"fromEmail"`
} `yaml:"smtp"`
}
const DEFAULT_CONFIG_FILE = "config.yaml"
const ENV_PREFIX = "MAILSENDER"
var Config configStruct
var log = logrus.New()
func processError(err error) {
log.Error("Config file error: " + err.Error())
os.Exit(2)
}
func readFile(cfgFile string, cfg *configStruct) {
f, err := os.Open(cfgFile)
if err != nil {
processError(err)
} else {
decoder := yaml.NewDecoder(f)
err = decoder.Decode(cfg)
if err != nil {
processError(err)
}
}
defer f.Close()
}
func readEnv(cfg *configStruct) {
err := envconfig.Process(ENV_PREFIX, cfg)
if err != nil {
processError(err)
}
}
func Init() {
cfgFile := os.Getenv("MAILSENDER_CONFIG")
if cfgFile == "" {
cfgFile = DEFAULT_CONFIG_FILE
}
readFile(cfgFile, &Config)
readEnv(&Config)
maskedCfg := Config
maskedCfg.Database.Password = "**password hidden**"
maskedCfg.SMTP.Password = "**password hidden**"
fmt.Println("--- CONFIG -------------------------------")
fmt.Println(maskedCfg)
fmt.Println("------------------------------------------")
}

54
app/db/db.go Normal file
View File

@ -0,0 +1,54 @@
package db
import (
"fmt"
"iris-test/app/cfg"
"iris-test/app/logging"
"strconv"
"strings"
"time"
"gorm.io/driver/postgres"
"gorm.io/gorm"
gormLogger "gorm.io/gorm/logger"
)
const CONNECTION_MAX_IDLE_TIME = time.Minute * 1
const DB_CONNECTION_TIMEOUT = 5
var DBConn *gorm.DB
func InitDB() *gorm.DB {
var connectionString = strings.Join([]string{
"postgres://",
cfg.Config.Database.Username, ":",
cfg.Config.Database.Password, "@",
cfg.Config.Database.Host, ":",
cfg.Config.Database.Port, "/",
cfg.Config.Database.Name,
"?sslmode=disable",
"&TimeZone=UTC",
"&connect_timeout=", strconv.Itoa(DB_CONNECTION_TIMEOUT),
}, "")
var logLevel = gormLogger.Silent
if cfg.Config.Application.DebugSQL {
logLevel = gormLogger.Info
}
var err error
DBConn, err = gorm.Open(postgres.Open(connectionString), &gorm.Config{
Logger: gormLogger.Default.LogMode(logLevel),
})
if err != nil {
msg := fmt.Sprintf("Error connecting to database: %s. Terminating!", err)
logging.Error(msg)
panic(msg)
}
// set connection autodisconnect after idle time
db, _ := DBConn.DB()
db.SetConnMaxIdleTime(CONNECTION_MAX_IDLE_TIME)
return DBConn
}

65
app/logging/logging.go Normal file
View File

@ -0,0 +1,65 @@
package logging
import (
"encoding/json"
"fmt"
"io"
"iris-test/app/cfg"
"os"
"github.com/sirupsen/logrus"
)
var Log = logrus.New()
func Debug(message string) {
Log.Debug(message)
}
func Info(message string) {
Log.Info(message)
}
func Error(message string) {
Log.Error(message)
}
func Warn(message string) {
Log.Warn(message)
}
func Init() {
logLevel, err := logrus.ParseLevel(cfg.Config.Application.LogLevel)
if err != nil {
panic(fmt.Sprintf("Invalid configured logLevel: %s\n", cfg.Config.Application.LogLevel))
}
Log.SetLevel(logLevel)
Log.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
PadLevelText: true,
DisableQuote: true,
})
LogFile := cfg.Config.Application.LogFile
file, err := os.OpenFile(
LogFile,
os.O_CREATE|os.O_WRONLY|os.O_APPEND,
0655,
)
if err != nil {
msg := fmt.Sprintf("Failed to log to file %s: %s", cfg.Config.Application.LogFile, err)
Log.Warning(msg)
panic(msg)
}
mw := io.MultiWriter(os.Stdout, file)
Log.SetOutput(mw)
configJson, err := json.Marshal(cfg.Config)
if err == nil {
Info(fmt.Sprintf("Using config: %s", configJson))
}
}

103
app/main.go Normal file
View File

@ -0,0 +1,103 @@
// Package main an example on how to naming your routes & use the custom 'url path' Jet Template Engine.
package main
import (
"github.com/kataras/iris/v12"
)
type User struct {
firstName string
lastName string
email string
}
var users = []User{
{
firstName: "Pero",
lastName: "Perić",
email: "pero@gmail.com",
},
{
firstName: "Mirko",
lastName: "Mirković",
email: "mirko@gmail.com",
},
{
firstName: "Ivo",
lastName: "Ivić",
email: "ivo@gmail.com",
},
{
firstName: "Slavko",
lastName: "Slavković",
email: "slavko@gmail.com",
},
}
func main() {
app := iris.New()
app.RegisterView(iris.Jet("./app/templates", ".jet").Reload(true))
// mypathRoute := app.Get("/mypath", writePathHandler)
// mypathRoute.Name = "my-page1"
// mypath2Route := app.Get("/mypath2/{paramfirst}/{paramsecond}", writePathHandler)
// mypath2Route.Name = "my-page2"
// mypath3Route := app.Get("/mypath3/{paramfirst}/statichere/{paramsecond}", writePathHandler)
// mypath3Route.Name = "my-page3"
// mypath4Route := app.Get("/mypath4/{paramfirst}/statichere/{paramsecond}/{otherparam}/{something:path}", writePathHandler)
// // same as: app.Get("/mypath4/:paramfirst/statichere/:paramsecond/:otherparam/*something", writePathHandler)
// mypath4Route.Name = "my-page4"
// // same with Handle/Func
// mypath5Route := app.Handle("GET", "/mypath5/{paramfirst:int}/statichere/{paramsecond}/{otherparam}/anything/{something:path}", writePathHandlerPage5)
// mypath5Route.Name = "my-page5"
// mypath6Route := app.Get("/mypath6/{paramfirst}/{paramsecond}/statichere/{paramThirdAfterStatic}", writePathHandler)
// mypath6Route.Name = "my-page6"
app.Get("/", func(ctx iris.Context) {
// templateContext := map[string]string{}
params1 := []string{"param 1", "param 2", "param 3"}
ctx.ViewData("params1", params1)
ctx.ViewData("users", users)
if err := ctx.View("pages/index.jet"); err != nil {
ctx.HTML("<h3>%s</h3>", err.Error())
return
}
})
app.Get("/redirect/{namedRoute}", func(ctx iris.Context) {
routeName := ctx.Params().Get("namedRoute")
r := app.GetRoute(routeName)
if r == nil {
ctx.StatusCode(iris.StatusNotFound)
ctx.Writef("Route with name %s not found", routeName)
return
}
println("The path of " + routeName + "is: " + r.Path)
// if routeName == "my-page1"
// prints: The path of of my-page1 is: /mypath
// if it's a path which takes named parameters
// then use "r.ResolvePath(paramValuesHere)"
ctx.Redirect(r.Path)
// http://localhost:8080/redirect/my-page1 will redirect to -> http://localhost:8080/mypath
})
// http://localhost:8080
// http://localhost:8080/redirect/my-page1
app.Listen(":8000")
}
func writePathHandler(ctx iris.Context) {
ctx.Writef("Hello from %s.", ctx.Path())
}
func writePathHandlerPage5(ctx iris.Context) {
ctx.Writef("Hello from %s.\nparamfirst(int)=%d", ctx.Path(), ctx.Params().GetIntDefault("paramfirst", 0))
}

View File

@ -0,0 +1,21 @@
{{ title := "Hello world" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid">
<h1>{{ title }}</h1>
<main>
{{ yield mainContent() }}
</main>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
{{ block usersTable(users) }}
<p>blablabla</p>
<table class="table">
<tbody>
{{ range users }}
<tr>
<td>{{ .firstName }}</td>
<td>{{ .lastName }}</td>
<td>{{ .email }}</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}

View File

@ -0,0 +1,18 @@
{{ extends "/base/base.jet" }}
{{ import "/components/table_component.jet" }}
{{ block mainContent() }}
{{ title = "Hello world from index" }}
<ul>
{{ range params1 }}
<li>{{ . }}</li>
{{ end }}
</ul>
<h3>{{ title }}</h3>
{{ yield usersTable(users=users) }}
{{ end }}