A couple of updates
Some checks failed
ci/woodpecker/push/build Pipeline failed

Signed-off-by: Nikolai Rodionov <iam@allanger.xyz>
This commit is contained in:
2026-04-28 10:33:20 +02:00
parent f82778cbd1
commit 874d762efa
6 changed files with 117 additions and 117 deletions

2
.env.dev Normal file
View File

@@ -0,0 +1,2 @@
export SOFTPLAYER_DB_CONNECTION_STRING=postgres://softplayer:qwertyu9@localhost:30432/softplayer?sslmode=disable
export SOFYTPLAYER_REDIS_HOST=localhost:30379

40
Taskfile.yml Normal file
View File

@@ -0,0 +1,40 @@
# yaml-language-server: $schema=https://taskfile.dev/schema.json
version: "3"
tasks:
build:
desc: Build go code
cmd: go build
silent: true
run-migrations-dev:
desc: Execute database migrations
env:
SOFTPLAYER_DB_CONNECTION_STRING: postgres://softplayer:qwertyu9@localhost:30432/softplayer?sslmode=disable
cmd: go run main.go migrate --migrations-path=file://migrations
run-server-dev:
desc: Run the local dev server
env:
SOFTPLAYER_DB_CONNECTION_STRING: postgres://softplayer:qwertyu9@localhost:30432/softplayer?sslmode=disable
SOFTPLAYER_REDIS_HOST: localhost:30379
cmd: go run main.go serve --dev-mode --reflection
deploy-local-env:
desc: Run a kind cluster and deploy deps
deps:
- kind-cluster
- helmfile-deploy
kind-cluster:
desc: Run a kind cluster
cmd: kind create cluster --config ./kind-config.yaml
kind-cluster-remove:
desc: Remove the kind cluster
cmd: kind delete cluster
helmfile-deploy:
desc: Deploy the helmfile for the local dev
cmd: helmfile apply

View File

@@ -46,7 +46,7 @@ func (a *AccountsNoAuthServer) SignUp(ctx context.Context, in *accounts.SignUpRe
return nil, status.Error(codes.Aborted, "Couldn't generate Access Token")
}
refreshToken, err := a.ctrl.GenerateRefreshToken(uuid)
refreshToken, err := a.ctrl.GenerateRefreshToken(ctx, uuid)
if err != nil {
log.Error(err, "Couldn't generate a refresh token")
return nil, status.Error(codes.Aborted, "Couldn't generate Access Token")

View File

@@ -1,5 +1,6 @@
environments:
default:
kubeContext: kind-kind
values:
- databases:
postgres:

View File

@@ -3,6 +3,7 @@ package controllers
import (
"context"
"database/sql"
"fmt"
"time"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/hash"
@@ -17,7 +18,7 @@ type AccountController struct {
DevMode bool
HashCost int16
AccessTokenTTL time.Duration
RefrestTokenTTL time.Duration
RefreshTokenTTL time.Duration
JWTSecret []byte
}
@@ -62,15 +63,19 @@ func (c *AccountController) GenerateAccessToken(userID string) (string, error) {
return token.SignedString(c.JWTSecret)
}
func (c *AccountController) GenerateRefreshToken(userID string) (string, error) {
func (c *AccountController) GenerateRefreshToken(ctx context.Context, userID string) (string, error) {
tokenID := uuid.New().String()
claims := jwt.MapClaims{
"user_id": userID,
"token_id": tokenID,
"type": "refresh",
"exp": time.Now().Add(c.RefrestTokenTTL).Unix(),
"exp": time.Now().Add(c.RefreshTokenTTL).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
redisKey := fmt.Sprintf("refresh_token:%s", tokenID)
if err := c.Redis.Set(ctx, redisKey, userID, c.RefreshTokenTTL).Err(); err != nil {
return "", err
}
return token.SignedString(c.JWTSecret)
}

178
main.go
View File

@@ -6,52 +6,54 @@ import (
"errors"
"fmt"
"net"
"os"
"strings"
"time"
v1 "gitea.badhouseplants.net/softplayer/softplayer-backend/api/v1"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/controllers"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/tools/logger"
accounts "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
applications_proto "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/applications/v1"
email_proto "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/email/v1"
"gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/environments/v1"
"github.com/alecthomas/kong"
"github.com/golang-jwt/jwt/v5"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
_ "github.com/lib/pq"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/reflection"
ctrl "sigs.k8s.io/controller-runtime"
"github.com/redis/go-redis/v9"
)
type Serve struct {
Port int64 `short:"p" env:"SOFTPLAYER_PORT" default:"4020"`
Host string `env:"SOFTPLAYER_HOST" default:"0.0.0.0"`
HashCost int16 `env:"SOFTPLAYER_HASH_COST" default:"1"`
Reflection bool `env:"SOFTPLAYER_REFLECTION" default:"false"`
DevMode bool `env:"SOFTPLAYER_DEV_MODE" default:"false"`
SmtpHost string `env:"SOFTPLAYER_SMTP_HOST"`
SmtpPort string `env:"SOFTPLAYER_SMTP_PORT" default:"587"`
SmtpFrom string `env:"SOFTPLAYER_SMTP_FROM" default:"overlord@badhouseplants.net"`
SmtpPassword string `env:"SOFTPLAYER_SMTP_PASSWORD"`
DownloadDir string `env:"SOFTPLAYER_DOWNLOAD_DIR" default:"/tmp/softplayer"`
DBConnectionString string `env:"SOFTPLAYER_DB_CONNECTION_STRING"`
RedisHost string `env:"SOFTPLAYER_REDIS_HOST"`
RefrestTokenTTL time.Duration `default:"8h"`
AccessTokenTTL time.Duration `default:"15m"`
JWTSecret string `default:"qwertyu9"`
var CLI struct {
Serve Serve `cmd:"" help:"Start the grpc server"`
Migrate Migrate `cmd:"" help:"Run the database migrations"`
}
var CLI struct {
Serve Serve `cmd:"" help:"Start the grpc server"`
type Serve struct {
// Service related
Port int64 `short:"p" env:"SOFTPLAYER_PORT" default:"4020"`
Host string `env:"SOFTPLAYER_HOST" default:"0.0.0.0"`
HashCost int16 `env:"SOFTPLAYER_HASH_COST" default:"1"`
// SMTP Config
SMTPHost string `env:"SOFTPLAYER_SMTP_HOST"`
SMTPPort string `env:"SOFTPLAYER_SMTP_PORT" default:"587"`
SMTPFrom string `env:"SOFTPLAYER_SMTP_FROM" default:"overlord@badhouseplants.net"`
SMTPPassword string `env:"SOFTPLAYER_SMTP_PASSWORD"`
// Database and redis
DBConnectionString string `env:"SOFTPLAYER_DB_CONNECTION_STRING"`
RedisHost string `env:"SOFTPLAYER_REDIS_HOST"`
// JWT parameters
RefrestTokenTTL time.Duration `default:"8h"`
AccessTokenTTL time.Duration `default:"15m"`
JWTSecret string `default:"qwertyu9"`
// Dev and logging
Reflection bool `env:"SOFTPLAYER_REFLECTION" default:"false"`
DevMode bool `env:"SOFTPLAYER_DEV_MODE" default:"false"`
}
type Migrate struct {
DBConnectionString string `env:"SOFTPLAYER_DB_CONNECTION_STRING"`
MigrationsPath string `env:"SOFTPLAYER_DB_MIGRATIOON_PATH" default:"file://migrations"`
}
func main() {
@@ -62,15 +64,25 @@ func main() {
if err := server(ctx, CLI.Serve); err != nil {
panic(err)
}
case "migrate":
if err := migrateDB(ctx, CLI.Migrate); err != nil {
panic(err)
}
default:
panic(kongCtx.Command())
}
}
func migrateDB(ctx context.Context, db *sql.DB) error {
// Migrate the database to the latest version
func migrateDB(ctx context.Context, params Migrate) error {
log := logger.FromContext(ctx)
log.Info("Starting a database migration driver")
db, err := sql.Open("postgres", params.DBConnectionString)
if err != nil {
log.Error(err, "Couldn't start a database driver")
return err
}
driver, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
log.Error(err, "Couldn't start a database migration driver")
@@ -79,7 +91,7 @@ func migrateDB(ctx context.Context, db *sql.DB) error {
log.Info("Preparing database migrations")
m, err := migrate.NewWithDatabaseInstance(
"file://migrations",
params.MigrationsPath,
"postgres", driver)
if err != nil {
log.Error(err, "Couldn't perform database migrations")
@@ -87,7 +99,7 @@ func migrateDB(ctx context.Context, db *sql.DB) error {
}
log.Info("Starting database migrations")
err = m.Up() // or m.Steps(2) if you want to explicitly set the number of migrations to r
err = m.Up()
if err != nil {
if errors.Is(err, migrate.ErrNoChange) {
log.Info("Database is already up-to-date")
@@ -100,93 +112,40 @@ func migrateDB(ctx context.Context, db *sql.DB) error {
return nil
}
func extractToken(ctx context.Context) (string, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return "", fmt.Errorf("missing metadata")
}
auth := md.Get("authorization")
if len(auth) == 0 {
return "", fmt.Errorf("missing auth token")
}
token := strings.TrimPrefix(auth[0], "Bearer ")
return token, nil
}
func AuthInterceptor(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
if !strings.Contains(info.FullMethod, "NoAuth") {
tokenString, err := extractToken(ctx)
if err != nil {
return nil, err
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte("qwertyu9"), nil
}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
fmt.Println(claims["foo"], claims["nbf"])
} else {
fmt.Println(err)
}
return handler(ctx, req)
}
return nil, nil
}
// Run the grpc backend server
func server(ctx context.Context, params Serve) error {
// Make sure the download dir exists
log := logger.FromContext(ctx)
if err := os.MkdirAll(params.DownloadDir, 0o777); err != nil {
log.Error(err, "Coulnd't create a download dir")
return err
}
// Init a logger
log.Info("Starting a kubernetes manager")
controller, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
if err != nil {
log.Error(err, "Coulnd't start a kube manager")
return err
}
//log.Info("Starting a kubernetes manager")
//controller, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
//if err != nil {
// log.Error(err, "Coulnd't start a kube manager")
// return err
//}
// TODO: Handle the error
go func() {
if err := controller.Start(ctx); err != nil {
panic(err)
}
}()
//go func() {
// if err := controller.Start(ctx); err != nil {
// panic(err)
// }
//}()
log.Info("Opening a database connection")
db, err := sql.Open("postgres", params.DBConnectionString)
if err != nil {
log.Error(err, "Couldn't start a database driver")
return err
}
if err := migrateDB(ctx, db); err != nil {
log.Error(err, "Error occured while executing migrations")
return err
}
emailConfig := email.EmailConf{
From: params.SmtpFrom,
Password: params.SmtpPassword,
SmtpHost: params.SmtpHost,
SmtpPort: params.SmtpPort,
}
//emailConfig := email.EmailConf{
// From: params.SmtpFrom,
// Password: params.SmtpPassword,
// SmtpHost: params.SmtpHost,
// SmtpPort: params.SmtpPort,
//}
address := fmt.Sprintf("%s:%d", params.Host, params.Port)
lis, err := net.Listen("tcp", address)
@@ -197,17 +156,12 @@ func server(ctx context.Context, params Serve) error {
grpc.UnaryInterceptor(
grpc_zap.UnaryServerInterceptor(logger.SetupLogger("info")),
),
grpc.UnaryInterceptor(AuthInterceptor),
grpc.StreamInterceptor(grpc_zap.StreamServerInterceptor(logger.SetupLogger("info"))),
)
rdb := redis.NewClient(&redis.Options{
Addr: params.RedisHost,
})
err = rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
if params.Reflection {
reflection.Register(grpcServer)
}
@@ -216,14 +170,12 @@ func server(ctx context.Context, params Serve) error {
HashCost: params.HashCost,
DB: db,
DevMode: params.DevMode,
RefrestTokenTTL: params.RefrestTokenTTL,
RefreshTokenTTL: params.RefrestTokenTTL,
AccessTokenTTL: params.AccessTokenTTL,
JWTSecret: []byte(params.JWTSecret),
Redis: rdb,
}
environments.RegisterEnvironmentsServer(grpcServer, v1.NewapiGrpcImpl(controller, log))
accounts.RegisterAccountsNoAuthServiceServer(grpcServer, v1.NewAccountRPCImpl(accountCtrl))
email_proto.RegisterEmailValidationServer(grpcServer, v1.InitEmailServer(controller, &emailConfig, params.DevMode))
applications_proto.RegisterApplicationsServer(grpcServer, v1.NewApplicationsGrpcImpl(controller, log))
if err := grpcServer.Serve(lis); err != nil {
return err