This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,10 +2,8 @@ deploy/.env
|
||||
!deploy/.env.dist
|
||||
deploy/.env.*
|
||||
|
||||
deploy/app.run
|
||||
|
||||
deploy/server
|
||||
deploy/chronos
|
||||
deploy/scheduler
|
||||
|
||||
!deploy/certs/.gitkeep
|
||||
deploy/certs/*
|
||||
|
||||
@@ -3,14 +3,13 @@ FROM golang:alpine
|
||||
|
||||
ARG BIN_OUTPUT=/go/bin
|
||||
ARG GO_SERVER=cmd/server/main.go
|
||||
ARG GO_CHRONOS=cmd/scheduler/main.go
|
||||
ARG GO_MIGRATE=cmd/migrate/main.go
|
||||
ARG GO_CHRONOS=cmd/chronos/main.go
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY src/ ./
|
||||
|
||||
RUN export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/chronos" $GO_CHRONOS
|
||||
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/scheduler" $GO_CHRONOS && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE
|
||||
|
||||
@@ -17,9 +17,11 @@ LABEL dev.egommerce.image.version=${SVC_VER}
|
||||
LABEL dev.egommerce.image.build_time=${BUILD_TIME}
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=builder /go/bin/server /usr/local/bin/server
|
||||
COPY --from=builder /go/bin/migrate /usr/local/bin/migrate
|
||||
COPY --from=builder /go/bin/chronos /usr/local/bin/chronos
|
||||
COPY --from=builder /go/bin/scheduler /usr/local/bin/scheduler
|
||||
|
||||
COPY deploy/.env.docker /.env
|
||||
COPY ./bin/* /usr/local/bin/
|
||||
|
||||
|
||||
8
Makefile
8
Makefile
@@ -19,8 +19,8 @@ build-local-server:
|
||||
run-local-server:
|
||||
- cd deploy/ && ./server
|
||||
|
||||
build-local-chronos:
|
||||
- go build -C ${SRC_DIR} -o ../deploy/chronos cmd/chronos/main.go
|
||||
build-local-scheduler:
|
||||
- go build -C ${SRC_DIR} -o ../deploy/scheduler cmd/scheduler/main.go
|
||||
|
||||
run-local-chronos:
|
||||
- cd deploy/ && ./chronos
|
||||
run-local-scheduler:
|
||||
- cd deploy/ && ./scheduler
|
||||
|
||||
@@ -2,9 +2,7 @@ SERVER_ADDR=:443
|
||||
|
||||
APP_NAME=identity-svc
|
||||
APP_DOMAIN=identity.service.ego.io
|
||||
APP_PATH_PREFIX=/identity
|
||||
|
||||
API_LOGGER_ADDR=api-logger:24224
|
||||
API_DATABASE_URL=postgres://postgres:12345678@db-postgres:5432/egommerce
|
||||
API_CACHE_ADDR=api-cache:6379
|
||||
API_CACHE_USERNAME=default
|
||||
|
||||
@@ -10,7 +10,7 @@ TARGET=${1:-latest}
|
||||
|
||||
[ ! -d "src/vendor" ] && sh -c "cd src; go mod vendor"
|
||||
|
||||
echo "Building tmp $IMAGE_PREFIX image..."
|
||||
echo "Building target $IMAGE_PREFIX images..."
|
||||
docker build --rm -t $BUILDER_IMAGE -f Dockerfile.builder .
|
||||
|
||||
if [ $TARGET = "latest" ]
|
||||
@@ -23,7 +23,7 @@ then
|
||||
--build-arg BUILD_TIME \
|
||||
--rm --cache-from $SERVER_IMAGE:$TARGET \
|
||||
-t $SERVER_IMAGE:$TARGET \
|
||||
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
-f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
else
|
||||
# DEV
|
||||
docker build \
|
||||
@@ -32,7 +32,7 @@ else
|
||||
--build-arg BUILDER_IMAGE=$BUILDER_IMAGE \
|
||||
--build-arg BUILD_TIME \
|
||||
--rm --no-cache -t $SERVER_IMAGE:$TARGET \
|
||||
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
-f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
fi
|
||||
|
||||
echo "Done."
|
||||
|
||||
@@ -11,4 +11,4 @@ echo $DOCKER_PASSWORD | docker login git.ego.freeddns.org -u $DOCKER_USERNAME --
|
||||
docker push "$SERVER_IMAGE:$TARGET"
|
||||
|
||||
# Restart container
|
||||
curl -X POST http://127.0.0.1:9001/api/webhooks/64ea5d78-ae21-474c-ad4d-1d98f6b83acb
|
||||
# TODO
|
||||
40
src/app/app.go
Normal file
40
src/app/app.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
worker Worker
|
||||
}
|
||||
|
||||
func NewApp(worker Worker) *App {
|
||||
return &App{
|
||||
worker: worker,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) Start(while chan struct{}) error {
|
||||
go func(while chan struct{}) {
|
||||
sigint := make(chan os.Signal, 1)
|
||||
signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigint
|
||||
|
||||
log.Println("Received signal:", sigint)
|
||||
app.Shutdown()
|
||||
close(while)
|
||||
}(while)
|
||||
|
||||
return app.worker.Start()
|
||||
}
|
||||
|
||||
func (app *App) Shutdown() {
|
||||
app.worker.OnShutdown()
|
||||
}
|
||||
|
||||
func (app *App) RegisterPlugin(plugin Plugin) {
|
||||
app.worker.addPlugin(plugin.name, plugin.fn)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -53,21 +53,21 @@ func NewConfig(name string) *Config {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Config) GetAppFullName() string {
|
||||
// func (c *Config) GetArray() map[string]string { // FIXME fix types etc
|
||||
// arr := make(map[string]string)
|
||||
// arr["id"] = c.ID
|
||||
// arr["name"] = c.Name
|
||||
// arr["appFullname"] = c.getAppFullName()
|
||||
// arr["domain"] = c.Domain
|
||||
// arr["netAddr"] = c.NetAddr
|
||||
// arr["cacheAddr"] = c.CacheAddr
|
||||
// arr["cacheUsername"] = c.CacheUsername
|
||||
// arr["cachePassword"] = c.CachePassword
|
||||
// arr["dbURL"] = c.DbURL
|
||||
|
||||
// return arr
|
||||
// }
|
||||
|
||||
func (c *Config) getAppFullName() string {
|
||||
return fmt.Sprintf("%s_%s", c.Name, c.ID)
|
||||
}
|
||||
|
||||
func (c *Config) GetArray() map[string]string { // FIXME fix types etc
|
||||
arr := make(map[string]string)
|
||||
arr["id"] = c.ID
|
||||
arr["name"] = c.Name
|
||||
arr["appFullname"] = c.GetAppFullName()
|
||||
arr["domain"] = c.Domain
|
||||
arr["netAddr"] = c.NetAddr
|
||||
arr["cacheAddr"] = c.CacheAddr
|
||||
arr["cacheUsername"] = c.CacheUsername
|
||||
arr["cachePassword"] = c.CachePassword
|
||||
arr["dbURL"] = c.DbURL
|
||||
|
||||
return arr
|
||||
}
|
||||
19
src/app/dependencies.go
Normal file
19
src/app/dependencies.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type Dependencies struct {
|
||||
cache *redis.Client
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
func (d *Dependencies) GetCache() *redis.Client {
|
||||
return d.cache
|
||||
}
|
||||
|
||||
func (d *Dependencies) GetDatabase() *pgxpool.Pool {
|
||||
return d.db
|
||||
}
|
||||
23
src/app/interface.go
Normal file
23
src/app/interface.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package app
|
||||
|
||||
type (
|
||||
Application interface {
|
||||
Start()
|
||||
RegisterPlugin(Plugin)
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
Worker interface {
|
||||
Start() error
|
||||
OnShutdown()
|
||||
|
||||
addPlugin(name string, fn PluginFn)
|
||||
}
|
||||
|
||||
Plugin struct {
|
||||
name string
|
||||
fn PluginFn
|
||||
}
|
||||
|
||||
PluginFn func() any
|
||||
)
|
||||
41
src/app/plugins.go
Normal file
41
src/app/plugins.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
redis "github.com/go-redis/redis/v8"
|
||||
db "github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func CachePlugin(cnf *Config) Plugin {
|
||||
return Plugin{
|
||||
name: "cache",
|
||||
fn: func() any {
|
||||
return redis.NewClient(&redis.Options{
|
||||
Addr: cnf.CacheAddr,
|
||||
Username: cnf.CacheUsername,
|
||||
Password: cnf.CachePassword,
|
||||
DB: 0, // TODO
|
||||
DialTimeout: 100 * time.Millisecond, // TODO
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DatabasePlugin(cnf *Config) Plugin {
|
||||
return Plugin{
|
||||
name: "database",
|
||||
fn: func() any {
|
||||
dbConn, err := db.New(context.Background(), cnf.DbURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cnf.DbURL, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return dbConn
|
||||
},
|
||||
}
|
||||
}
|
||||
1
src/app/scheduler.go
Normal file
1
src/app/scheduler.go
Normal file
@@ -0,0 +1 @@
|
||||
package app
|
||||
165
src/app/server.go
Normal file
165
src/app/server.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
jwt "github.com/gofiber/contrib/jwt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/http"
|
||||
)
|
||||
|
||||
var defaultCORS = cors.New(
|
||||
cors.Config{
|
||||
// DEV CONFIG
|
||||
AllowOrigins: "*",
|
||||
AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS",
|
||||
AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id",
|
||||
// PROD CONFIG
|
||||
// AllowOrigins: "http://egommerce.io:3001", // client(reactjs) app url
|
||||
// AllowCredentials: true,
|
||||
// AllowMethods: "GET, POST, PATCH, PUT, DELETE",
|
||||
},
|
||||
)
|
||||
|
||||
type (
|
||||
Server struct {
|
||||
*fiber.App
|
||||
|
||||
ID string
|
||||
addr string // e.g. "127.0.0.1:443"
|
||||
plugins map[string]any
|
||||
}
|
||||
|
||||
// HeaderRequestID struct {
|
||||
// RequestID string `reqHeader:"x-request-id"`
|
||||
// }
|
||||
)
|
||||
|
||||
func NewServer(c *Config) *Server {
|
||||
srv := &Server{
|
||||
ID: c.ID,
|
||||
App: fiber.New(fiber.Config{
|
||||
AppName: c.ID,
|
||||
ServerHeader: c.Name + ":" + c.ID,
|
||||
ReadTimeout: c.ReadTimeout * time.Millisecond,
|
||||
WriteTimeout: c.WriteTimeout * time.Millisecond,
|
||||
IdleTimeout: c.IdleTimeout * time.Millisecond,
|
||||
}),
|
||||
addr: c.NetAddr,
|
||||
plugins: make(map[string]any),
|
||||
}
|
||||
|
||||
return srv
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
s.setupMiddleware()
|
||||
s.setupRouter()
|
||||
|
||||
crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}
|
||||
ln, _ := net.Listen("tcp", s.addr)
|
||||
ln = tls.NewListener(ln, tlsCnf)
|
||||
|
||||
return s.Listener(ln)
|
||||
}
|
||||
|
||||
func (s *Server) OnShutdown() {
|
||||
log.Printf("Server %s is going down...", s.ID)
|
||||
|
||||
s.getDatabase().Close()
|
||||
s.getCache().Close()
|
||||
|
||||
s.Shutdown()
|
||||
}
|
||||
|
||||
func (s *Server) addPlugin(name string, fn PluginFn) {
|
||||
s.plugins[name] = fn()
|
||||
}
|
||||
|
||||
// Plugin helper functions - using hardcoded keys because we rely on a specific implementation here...
|
||||
func (s *Server) getCache() *redis.Client {
|
||||
return (s.plugins["cache"]).(*redis.Client)
|
||||
}
|
||||
|
||||
func (s *Server) getDatabase() *pgxpool.Pool {
|
||||
return (s.plugins["database"]).(*pgxpool.Pool)
|
||||
}
|
||||
|
||||
// func GetRequestID(c *fiber.Ctx) (string, error) {
|
||||
// var hdr = new(HeaderRequestID)
|
||||
// if err := c.ReqHeaderParser(hdr); err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return hdr.RequestID, nil
|
||||
// }
|
||||
|
||||
func (s *Server) setupRouter() {
|
||||
s.Options("*", defaultCORS)
|
||||
s.Use(defaultCORS)
|
||||
|
||||
s.Get("/health", http.HealthHandlerFn(s.getDatabase(), s.getCache()))
|
||||
|
||||
s.Group("/v1").
|
||||
Post("/login", http.LoginHandlerFn(s.getDatabase(), s.getCache())).
|
||||
Post("/refresh", http.RefreshHandlerFn(s.getDatabase(), s.getCache())). // add JWTProtected() and get token from Auth Bearer header not from the body?
|
||||
Post("/register", http.RegisterHandlerFn(s.getDatabase(), s.getCache())).
|
||||
Get("/access", JWTProtected(), http.AccessHandlerFn(s.getDatabase(), s.getCache()))
|
||||
}
|
||||
|
||||
func (s *Server) setupMiddleware() {
|
||||
s.Use(LoggingMiddleware())
|
||||
s.Use(XRequestIDMiddleware())
|
||||
}
|
||||
|
||||
func LoggingMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
log.Printf("Request: %s, remote: %s, via: %s",
|
||||
c.Request().URI().String(),
|
||||
c.Context().RemoteIP().String(),
|
||||
string(c.Context().UserAgent()),
|
||||
)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func XRequestIDMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
c.Set("X-Request-ID", uuid.New().String())
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func JWTProtected() func(c *fiber.Ctx) error {
|
||||
secret := []byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret"))
|
||||
|
||||
return jwt.New(jwt.Config{
|
||||
SigningKey: jwt.SigningKey{Key: secret},
|
||||
ContextKey: "jwt",
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(commonDTO.ErrorResponseDTO{Error: "unauthorized"})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// func (s *Server) Error(c *fiber.Ctx, code int, msg string) error {
|
||||
// return c.Status(code).JSON(dto.ErrorResponseDTO{Error: msg})
|
||||
// }
|
||||
@@ -1,36 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/common"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/chronos"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs)
|
||||
}
|
||||
|
||||
c := common.NewConfig("identity-cronjob")
|
||||
cArr := c.GetArray()
|
||||
|
||||
doer := chronos.New(c)
|
||||
a := common.NewApp(doer)
|
||||
a.RegisterPlugin(common.CachePlugin(cArr))
|
||||
a.RegisterPlugin(common.DatabasePlugin(cArr))
|
||||
|
||||
while := make(chan struct{})
|
||||
err := a.Start(while)
|
||||
<-while
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to chronos. Reason: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
36
src/cmd/scheduler/main.go
Normal file
36
src/cmd/scheduler/main.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/app"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/cli/scheduler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs)
|
||||
}
|
||||
|
||||
c := app.NewConfig("identity-cronjob")
|
||||
cArr := c.GetArray()
|
||||
|
||||
doer := scheduler.New(c)
|
||||
a := app.NewApp(doer)
|
||||
a.RegisterPlugin(app.CachePlugin(cArr))
|
||||
a.RegisterPlugin(app.DatabasePlugin(cArr))
|
||||
|
||||
while := make(chan struct{})
|
||||
err := a.Start(while)
|
||||
<-while
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to scheduler. Reason: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
@@ -6,25 +6,23 @@ import (
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/common"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/server"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs)
|
||||
log.Panicln(cnf.ErrLoadingEnvs.Error())
|
||||
}
|
||||
|
||||
c := common.NewConfig("identity-svc")
|
||||
cArr := c.GetArray()
|
||||
cnf := app.NewConfig("identity-svc")
|
||||
worker := app.NewServer(cnf)
|
||||
|
||||
doer := server.New(c)
|
||||
a := common.NewApp(doer)
|
||||
a.RegisterPlugin(common.CachePlugin(cArr))
|
||||
a.RegisterPlugin(common.DatabasePlugin(cArr))
|
||||
srv := app.NewApp(worker)
|
||||
srv.RegisterPlugin(app.CachePlugin(cnf))
|
||||
srv.RegisterPlugin(app.DatabasePlugin(cnf))
|
||||
|
||||
while := make(chan struct{})
|
||||
err := a.Start(while)
|
||||
err := srv.Start(while)
|
||||
<-while
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type (
|
||||
App struct {
|
||||
doer Doer
|
||||
}
|
||||
)
|
||||
|
||||
func NewApp(d Doer) *App {
|
||||
return &App{
|
||||
doer: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Start(while chan struct{}) error {
|
||||
go func() {
|
||||
sigint := make(chan os.Signal, 1)
|
||||
signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigint
|
||||
fmt.Println("Received signal:", sigint)
|
||||
|
||||
a.Shutdown()
|
||||
|
||||
close(while)
|
||||
}()
|
||||
|
||||
err := a.doer.Start()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start app. Reason: %v\n", err)
|
||||
close(while)
|
||||
}
|
||||
<-while
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *App) RegisterPlugin(p Plugin) error {
|
||||
a.doer.RegisterHandler(p.name, p.fn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) Shutdown() {
|
||||
a.doer.OnShutdown()
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package common
|
||||
|
||||
type (
|
||||
Doer interface {
|
||||
Start() error
|
||||
RegisterHandler(string, func() any)
|
||||
OnShutdown()
|
||||
}
|
||||
Application interface {
|
||||
Start(while chan struct{})
|
||||
RegisterPlugin(PluginFn) error
|
||||
Shutdown()
|
||||
}
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
db "git.ego.freeddns.org/egommerce/go-api-pkg/database"
|
||||
|
||||
redis "github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type (
|
||||
Plugin struct {
|
||||
name string
|
||||
fn PluginFn
|
||||
}
|
||||
PluginFn func() any
|
||||
)
|
||||
|
||||
func CachePlugin(cArr map[string]string) Plugin {
|
||||
return Plugin{
|
||||
name: "cache",
|
||||
fn: func() any {
|
||||
return redis.NewClient(&redis.Options{
|
||||
Addr: cArr["cacheAddr"],
|
||||
Username: cArr["cacheUsername"],
|
||||
Password: cArr["cachePassword"],
|
||||
DB: 0,
|
||||
DialTimeout: 100 * time.Millisecond,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DatabasePlugin(cArr map[string]string) Plugin {
|
||||
return Plugin{
|
||||
name: "database",
|
||||
fn: func() any {
|
||||
dbConn, err := db.Connect(cArr["dbURL"])
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cArr["dbURL"], err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return dbConn
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ toolchain go1.24.1
|
||||
|
||||
require (
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2
|
||||
github.com/georgysavva/scany/v2 v2.1.4
|
||||
github.com/go-pg/migrations/v8 v8.1.0
|
||||
github.com/go-pg/pg/v10 v10.15.0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34 h1:WftM9cvV3JmbS1DlHCIiV3tsYIpALj9IXo90mkgZNWQ=
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9 h1:Y9MisGDhl/ti4gsegl9MC7KoY2aHuyA0LvIESPoiPkE=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9/go.mod h1:Q4onxocNdFhzD9QnQK3ubd68chbJPexjDraEHoIEN3Y=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2 h1:szfCwZ8S1Yf3b6LwpBs0DZYQZMsVl4Fe6VU1ou4LTOE=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2/go.mod h1:T3ia8iprzlTRznPVXYCgEzQb/1UvIcdn9FHabE58vy0=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
|
||||
|
||||
@@ -6,7 +6,7 @@ type UserRepositoryInterface interface {
|
||||
FindAll() ([]entity.User, error)
|
||||
FindByID(id string) (*entity.User, error)
|
||||
FindByUsername(login string) (*entity.User, error)
|
||||
Create(user *entity.User) (string, error)
|
||||
Update(user *entity.User) (*entity.User, error)
|
||||
Create(user *entity.User) (string, error) // FIXME types
|
||||
Update(user *entity.User) (*entity.User, error) // FIXME types
|
||||
Delete(id int64) (bool, error)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/go-api-pkg/database"
|
||||
database "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
@@ -87,7 +87,6 @@ func (r *URLAccessRepository) FindByURLAndServiceForRole(url, service, role stri
|
||||
err := r.db.QueryRow(context.Background(), sql, url, service).
|
||||
Scan(&entity.ID, &entity.Roles, &entity.URL, &entity.Service)
|
||||
if err != nil {
|
||||
fmt.Println(sql, url, service, role)
|
||||
if err = database.NoRowsInQuerySet(err); err != nil {
|
||||
return nil, errors.New("no url found for: " + url + " and role: " + role)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
db "git.ego.freeddns.org/egommerce/go-api-pkg/database"
|
||||
db "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql"
|
||||
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package chronos
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/common"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/onatm/clockwerk"
|
||||
)
|
||||
|
||||
type Chronos struct {
|
||||
handlers map[string]any
|
||||
}
|
||||
|
||||
func New(c *common.Config) *Chronos {
|
||||
return &Chronos{
|
||||
handlers: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chronos) Start() error {
|
||||
job := NewCachePermissionsJob(c)
|
||||
sch := clockwerk.New()
|
||||
sch.Every(30 * time.Minute).Do(job)
|
||||
sch.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Chronos) RegisterHandler(name string, fn func() any) {
|
||||
c.handlers[name] = fn()
|
||||
}
|
||||
|
||||
func (c *Chronos) OnShutdown() {
|
||||
log.Println("Chronos is going down...")
|
||||
|
||||
c.GetDatabase().Close()
|
||||
c.GetCache().Close()
|
||||
}
|
||||
|
||||
// Plugin helper funcitons - refactor needed cause funcs are duplcated in server.go
|
||||
// TODO: move functions below to some common place
|
||||
func (c *Chronos) GetCache() *redis.Client {
|
||||
return (c.handlers["cache"]).(*redis.Client)
|
||||
}
|
||||
|
||||
func (c *Chronos) GetDatabase() *pgxpool.Pool {
|
||||
return (c.handlers["database"]).(*pgxpool.Pool)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package chronos
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type CachePermissionsJob struct {
|
||||
sch *Chronos
|
||||
sch *Scheduler
|
||||
}
|
||||
|
||||
func NewCachePermissionsJob(sch *Chronos) CachePermissionsJob {
|
||||
func NewCachePermissionsJob(sch *Scheduler) CachePermissionsJob {
|
||||
return CachePermissionsJob{sch: sch}
|
||||
}
|
||||
|
||||
52
src/internal/cli/scheduler/scheduler.go
Normal file
52
src/internal/cli/scheduler/scheduler.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package scheduler
|
||||
|
||||
import ( // REFACTOR IT LIKE A SERVER WAS
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/app"
|
||||
|
||||
// "github.com/go-redis/redis/v8"
|
||||
// "github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/onatm/clockwerk"
|
||||
)
|
||||
|
||||
type Scheduler struct {
|
||||
handlers map[string]any
|
||||
}
|
||||
|
||||
func New(c *app.Config) *Scheduler {
|
||||
return &Scheduler{
|
||||
handlers: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Scheduler) Start() error {
|
||||
job := NewCachePermissionsJob(c)
|
||||
sch := clockwerk.New()
|
||||
sch.Every(30 * time.Minute).Do(job)
|
||||
sch.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (c *Scheduler) RegisterHandler(name string, fn func() any) {
|
||||
// c.handlers[name] = fn()
|
||||
// }
|
||||
|
||||
func (c *Scheduler) OnShutdown() {
|
||||
log.Println("Chronos is going down...")
|
||||
|
||||
// c.GetDatabase().Close()
|
||||
// c.GetCache().Close()
|
||||
}
|
||||
|
||||
// Plugin helper funcitons - refactor needed cause funcs are duplcated in server.go
|
||||
// TODO: move functions below to some common place
|
||||
// func (c *Scheduler) GetCache() *redis.Client {
|
||||
// return (c.handlers["cache"]).(*redis.Client)
|
||||
// }
|
||||
|
||||
// func (c *Scheduler) GetDatabase() *pgxpool.Pool {
|
||||
// return (c.handlers["database"]).(*pgxpool.Pool)
|
||||
// }
|
||||
34
src/internal/http/access_handler.go
Normal file
34
src/internal/http/access_handler.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func AccessHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
roleRepo := repository.NewRoleRepository(db)
|
||||
urlRepo := repository.NewURLAccessRepository(db)
|
||||
authSrv := service.NewAuthService(userRepo, cache)
|
||||
guardSrv := service.NewGuardService(authSrv, cache, userRepo, roleRepo, urlRepo)
|
||||
|
||||
url, srvName := c.Query("q"), c.Query("srv")
|
||||
header := new(identityDTO.AuthorizationHeaderDTO)
|
||||
c.ReqHeaderParser(header)
|
||||
|
||||
if err := ui.NewAccessActionUI(guardSrv).Execute(header, url, srvName); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
}
|
||||
33
src/internal/http/health_handler.go
Normal file
33
src/internal/http/health_handler.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func HealthHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Only 404 indicate service as not-healthy
|
||||
err := db.Ping(context.Background())
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
err = cache.Ping(context.Background()).Err()
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.JSON(&HealthResponse{
|
||||
Status: "OK",
|
||||
})
|
||||
}
|
||||
}
|
||||
35
src/internal/http/login_handler.go
Normal file
35
src/internal/http/login_handler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
)
|
||||
|
||||
func LoginHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
req := new(identityDTO.AuthLoginRequestDTO)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: "error parsing input"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "error parsing input")
|
||||
}
|
||||
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
authSrv := service.NewAuthService(userRepo, cache)
|
||||
|
||||
token, err := ui.NewLoginActionUI(authSrv).Execute(req)
|
||||
if err != nil { // TODO: handle other response status codes -- add struct to decorate error with code and message
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthLoginResponseDTO{Token: token})
|
||||
}
|
||||
}
|
||||
35
src/internal/http/refresh_handler.go
Normal file
35
src/internal/http/refresh_handler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func RefreshHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
header := new(identityDTO.AuthorizationHeaderDTO)
|
||||
if err := c.ReqHeaderParser(header); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing headers"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "Error parsing headers")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(db)
|
||||
authSrv := service.NewAuthService(repo, cache)
|
||||
|
||||
token, err := ui.NewRefreshTokenActionUI(authSrv).Execute(header)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthRefreshTokenResponseDTO{Token: token})
|
||||
}
|
||||
}
|
||||
33
src/internal/http/register_handler.go
Normal file
33
src/internal/http/register_handler.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func RegisterHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
data := new(identityDTO.AuthRegisterRequestDTO)
|
||||
if err := c.BodyParser(data); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing input"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "Error parsing input")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(db)
|
||||
|
||||
id, err := ui.NewRegisterActionUI(repo, cache).Execute(data)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthRegisterResponseDTO{ID: id})
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AccessHandlerFn(c *fiber.Ctx) error {
|
||||
userRepo := repository.NewUserRepository(s.GetDatabase())
|
||||
roleRepo := repository.NewRoleRepository(s.GetDatabase())
|
||||
urlRepo := repository.NewURLAccessRepository(s.GetDatabase())
|
||||
authSrv := service.NewAuthService(userRepo, s.GetCache())
|
||||
guardSrv := service.NewGuardService(authSrv, s.GetCache(), userRepo, roleRepo, urlRepo)
|
||||
|
||||
url, srvName := c.Query("q"), c.Query("srv")
|
||||
header := new(dto.AuthorizationHeaderDTO)
|
||||
c.ReqHeaderParser(header)
|
||||
|
||||
if err := ui.NewAccessActionUI(guardSrv).Execute(header, url, srvName); err != nil {
|
||||
return s.Error(c, fiber.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Server) HealthHandler(c *fiber.Ctx) error {
|
||||
// Only 404 indicate service as not-healthy
|
||||
err := s.GetDatabase().Ping(context.Background())
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
err = s.GetCache().Ping(context.Background()).Err()
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.JSON(&HealthResponse{
|
||||
Status: "OK",
|
||||
})
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) LoginHandlerFn(c *fiber.Ctx) error {
|
||||
req := new(dto.AuthLoginRequestDTO)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return s.Error(c, fiber.StatusBadRequest, "error parsing input")
|
||||
}
|
||||
|
||||
userRepo := repository.NewUserRepository(s.GetDatabase())
|
||||
authSrv := service.NewAuthService(userRepo, s.GetCache())
|
||||
|
||||
token, err := ui.NewLoginActionUI(authSrv).Execute(req)
|
||||
if err != nil { // TODO: handle other response status codes -- add struct to decorate error with code and message
|
||||
return s.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&dto.AuthLoginResponseDTO{Token: token})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
jwt "github.com/gofiber/contrib/jwt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// "github.com/gofiber/fiber/v2"
|
||||
// "github.com/gofiber/fiber/v2/middleware/cors"
|
||||
|
||||
func SetupMiddleware(s *Server) {
|
||||
s.Use(LoggingMiddleware())
|
||||
s.Use(XRequestIDMiddleware())
|
||||
}
|
||||
|
||||
func LoggingMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
log.Printf("Request: %s, remote: %s, via: %s",
|
||||
c.Request().URI().String(),
|
||||
c.Context().RemoteIP().String(),
|
||||
string(c.Context().UserAgent()),
|
||||
)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func XRequestIDMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
c.Set("X-Request-ID", uuid.New().String())
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func JWTProtected(s *Server) func(c *fiber.Ctx) error {
|
||||
secret := []byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret"))
|
||||
|
||||
return func(c *fiber.Ctx) error {
|
||||
return jwt.New(jwt.Config{
|
||||
SigningKey: jwt.SigningKey{Key: secret},
|
||||
ContextKey: "jwt",
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
return s.Error(c, fiber.StatusUnauthorized, "unauthorized")
|
||||
},
|
||||
})(c)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) RefreshHandlerFn(c *fiber.Ctx) error {
|
||||
header := new(dto.AuthorizationHeaderDTO)
|
||||
if err := c.ReqHeaderParser(header); err != nil {
|
||||
return s.Error(c, fiber.StatusBadRequest, "Error parsing headers")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(s.GetDatabase())
|
||||
authSrv := service.NewAuthService(repo, s.GetCache())
|
||||
|
||||
token, err := ui.NewRefreshTokenActionUI(authSrv).Execute(header)
|
||||
if err != nil {
|
||||
return s.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&dto.AuthRefreshTokenResponseDTO{Token: token})
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterHandlerFn(c *fiber.Ctx) error {
|
||||
data := new(dto.AuthRegisterRequestDTO)
|
||||
if err := c.BodyParser(data); err != nil {
|
||||
return s.Error(c, fiber.StatusBadRequest, "Error parsing input")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(s.GetDatabase())
|
||||
|
||||
id, err := ui.NewRegisterActionUI(repo, s.GetCache()).Execute(data)
|
||||
if err != nil {
|
||||
return s.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&dto.AuthRegisterResponseDTO{ID: id})
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultCORS = cors.New(cors.Config{
|
||||
AllowOrigins: "*",
|
||||
// AllowCredentials: true,
|
||||
AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS",
|
||||
AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id",
|
||||
})
|
||||
)
|
||||
|
||||
func SetupRouter(s *Server) {
|
||||
s.Options("*", defaultCORS)
|
||||
s.Use(defaultCORS)
|
||||
|
||||
s.Get("/health", s.HealthHandler)
|
||||
|
||||
s.Group("/v1").
|
||||
Post("/login", s.LoginHandlerFn).
|
||||
Post("/refresh", s.RefreshHandlerFn). // TODO: add JWTProtected() and get token from Auth Bearer Header not from the Body
|
||||
Post("/register", s.RegisterHandlerFn).
|
||||
Get("/access", JWTProtected(s), s.AccessHandlerFn)
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/common"
|
||||
)
|
||||
|
||||
type (
|
||||
Server struct {
|
||||
*fiber.App
|
||||
|
||||
ID string
|
||||
addr string // e.g. "127.0.0.1:443"
|
||||
handlers map[string]any
|
||||
}
|
||||
HeaderRequestID struct {
|
||||
RequestID string `reqHeader:"x-request-id"`
|
||||
}
|
||||
)
|
||||
|
||||
func New(c *common.Config) *Server {
|
||||
return &Server{
|
||||
ID: c.ID,
|
||||
App: fiber.New(fiber.Config{
|
||||
AppName: c.ID,
|
||||
ServerHeader: c.Name + ":" + c.ID,
|
||||
ReadTimeout: c.ReadTimeout * time.Millisecond,
|
||||
WriteTimeout: c.WriteTimeout * time.Millisecond,
|
||||
IdleTimeout: c.IdleTimeout * time.Millisecond,
|
||||
}),
|
||||
addr: c.NetAddr,
|
||||
handlers: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
SetupMiddleware(s)
|
||||
SetupRouter(s)
|
||||
|
||||
crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}
|
||||
ln, _ := net.Listen("tcp", s.addr)
|
||||
ln = tls.NewListener(ln, tlsCnf)
|
||||
|
||||
return s.Listener(ln)
|
||||
}
|
||||
|
||||
func (s *Server) RegisterHandler(name string, fn func() any) {
|
||||
s.handlers[name] = fn()
|
||||
}
|
||||
|
||||
func (s *Server) OnShutdown() {
|
||||
log.Printf("Server %s is going down...", s.ID)
|
||||
|
||||
s.GetDatabase().Close()
|
||||
s.GetCache().Close()
|
||||
|
||||
s.Shutdown()
|
||||
}
|
||||
|
||||
func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) {
|
||||
var hdr = new(HeaderRequestID)
|
||||
if err := c.ReqHeaderParser(hdr); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hdr.RequestID, nil
|
||||
}
|
||||
|
||||
func (s *Server) Error(c *fiber.Ctx, code int, msg string) error {
|
||||
return c.Status(code).JSON(dto.ErrorResponseDTO{Error: msg})
|
||||
}
|
||||
|
||||
// Plugin helper funcitons - refactor needed cause funcs are duplcated in chronos.go
|
||||
func (s *Server) GetCache() *redis.Client {
|
||||
return (s.handlers["cache"]).(*redis.Client)
|
||||
}
|
||||
|
||||
func (s *Server) GetDatabase() *pgxpool.Pool {
|
||||
return (s.handlers["database"]).(*pgxpool.Pool)
|
||||
}
|
||||
@@ -6,15 +6,15 @@ import (
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type AccessActionUI struct {
|
||||
type CheckUserPermissionsUI struct {
|
||||
guard *service.GuardService
|
||||
}
|
||||
|
||||
func NewAccessActionUI(guard *service.GuardService) *AccessActionUI {
|
||||
return &AccessActionUI{guard: guard}
|
||||
func NewAccessActionUI(guard *service.GuardService) *CheckUserPermissionsUI {
|
||||
return &CheckUserPermissionsUI{guard: guard}
|
||||
}
|
||||
|
||||
func (ui *AccessActionUI) Execute(data *dto.AuthorizationHeaderDTO, url, srvName string) error { // TODO: rename to CheckAccess
|
||||
func (ui *CheckUserPermissionsUI) Execute(data *dto.AuthorizationHeaderDTO, url, srvName string) error { // TODO: rename to CheckAccess
|
||||
err := ui.guard.CheckUserPermissions(data, url, srvName)
|
||||
if err != nil {
|
||||
return err
|
||||
Reference in New Issue
Block a user