diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c5510a9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "debug", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceRoot}/backend/cmd/main.go", + "args": [ + "-log-level=debug", + "-log-local=true", + "-log-add-source=true", + + "-rest-address=localhost:8080", + "-db-host=localhost:8432", + "-db-database=blockd", + "-db-user=blockd", + "-db-secret=blockd", + "-db-enable-tls=false" + ] + } + ] +} \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..e08d30f --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1 @@ +build/blockd \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..1f1e408 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,19 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV CGO_ENABLED 0 + +RUN apk update --no-cache && apk add --no-cache tzdata + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . +RUN go build -ldflags="-s -w" -o /app/blockd cmd/main.go + +EXPOSE 8080 + +CMD ["/app/blockd", "-log-level=info", "-address=0.0.0.0:8080", "-db-host=blockd-db:8432", "-db-user=blockd", "-db-password=blockd"] diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 0000000..ee2bba6 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,33 @@ +bin.build: + mkdir -p build + rm -f build/blockd + go build -ldflags="-s -w" -o build/blockd cmd/main.go + +d.build: + sudo docker buildx build . -t blockd:latest + +.PHONY: run.local +run.local: bin.build + ./build/blockd \ + -log-level=debug \ + -log-local=true \ + -log-add-source=true \ + -rest-address=localhost:8080 \ + -db-host=localhost:8432 \ + -db-database=blockd \ + -db-user=blockd \ + -db-secret=blockd \ + -db-enable-tls=false + +.PHONY: run.debug +run.debug: bin.build + ./build/blockd \ + -log-level=debug \ + -log-local=false \ + -log-add-source=true \ + -rest-address=localhost:8080 \ + -db-host=localhost:8432 \ + -db-database=blockd \ + -db-user=blockd \ + -db-secret=blockd \ + -db-enable-tls=false \ No newline at end of file diff --git a/backend/cmd/main.go b/backend/cmd/main.go index 6b3285e..846cd97 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -7,6 +7,8 @@ import ( "syscall" "github.com/emochka2007/block-accounting/cmd/commands" + "github.com/emochka2007/block-accounting/internal/config" + "github.com/emochka2007/block-accounting/internal/factory" cli "github.com/urfave/cli/v2" ) @@ -17,33 +19,91 @@ func main() { Version: "0.0.1a", Commands: commands.Commands(), Flags: []cli.Flag{ + // common &cli.StringFlag{ Name: "log-level", Value: "debug", }, - &cli.StringFlag{ - Name: "address", - Value: "localhost:8080", + &cli.BoolFlag{ + Name: "log-local", }, + &cli.StringFlag{ + Name: "log-file", + }, + &cli.BoolFlag{ + Name: "log-add-source", + Value: true, + }, + + // rest + &cli.StringFlag{ + Name: "rest-address", + Value: "localhost:8080", + }, + &cli.BoolFlag{ + Name: "rest-enable-tls", + }, + &cli.StringFlag{ + Name: "rest-cert-path", + }, + &cli.StringFlag{ + Name: "rest-key-path", + }, + + // database &cli.StringFlag{ Name: "db-host", }, + &cli.StringFlag{ + Name: "db-database", + }, &cli.StringFlag{ Name: "db-user", }, &cli.StringFlag{ - Name: "db-password", + Name: "db-secret", + }, + &cli.BoolFlag{ + Name: "db-enable-tls", }, }, Action: func(c *cli.Context) error { ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() - // todo build config + config := config.Config{ + Common: config.CommonConfig{ + LogLevel: c.String("log-level"), + LogLocal: c.Bool("log-local"), + LogFile: c.String("log-file"), + LogAddSource: c.Bool("log-add-source"), + }, + Rest: config.RestConfig{ + Address: c.String("rest-address"), + TLS: c.Bool("rest-enable-tls"), + }, + DB: config.DBConfig{ + Host: c.String("db-host"), + EnableSSL: c.Bool("db-enable-ssl"), + Database: c.String("db-database"), + User: c.String("db-user"), + Secret: c.String("db-secret"), + }, + } - // todo build service + service, cleanup, err := factory.ProvideService(config) + if err != nil { + panic(err) + } - // todo run service + defer func() { + cleanup() + service.Stop() + }() + + if err = service.Run(ctx); err != nil { + return err + } return nil }, diff --git a/backend/docker-compose.yaml b/backend/docker-compose.yaml new file mode 100644 index 0000000..655a4fe --- /dev/null +++ b/backend/docker-compose.yaml @@ -0,0 +1,45 @@ +version: '3' +networks: + blockd-net: + external: true + name: blockd-net + driver: bridge + +volumes: + blockd-data: {} + +services: + blockd: + container_name: blockd + image: blockd:latest + ports: + - 8071:8071 + expose: + - 8080 + networks: + - blockd-net + depends_on: + blockd-db: + condition: service_started + + blockd-db: + container_name: blockd-db + image: postgres:16 + restart: always + environment: + - POSTGRES_USER=blockd + - POSTGRES_PASSWORD=blockd + - POSTGRES_DB=blockd + volumes: + - blockd-data:/var/lib/postgresql/data + - ./migrations/blockd.sql:/docker-entrypoint-initdb.d/init.sql + ports: + - 8432:5432 + networks: + - blockd-net + healthcheck: + test: [ "CMD", "-U", "blockd", "pg_isready" ] + interval: 5s + timeout: 5s + retries: 10 + start_period: 10s \ No newline at end of file diff --git a/backend/go.mod b/backend/go.mod index 536df6d..aaf8a15 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,6 +5,7 @@ go 1.22.2 require ( github.com/fatih/color v1.16.0 github.com/go-chi/chi/v5 v5.0.12 + github.com/google/wire v0.6.0 github.com/urfave/cli/v2 v2.27.2 golang.org/x/sync v0.7.0 ) @@ -15,5 +16,5 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.16.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 9da23ad..8ed4195 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -4,20 +4,74 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= 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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go new file mode 100644 index 0000000..a05b2bc --- /dev/null +++ b/backend/internal/config/config.go @@ -0,0 +1,32 @@ +package config + +type Config struct { + Common CommonConfig + Rest RestConfig + DB DBConfig + Eth EthConfig +} + +type CommonConfig struct { + LogLevel string + LogLocal bool + LogFile string + LogAddSource bool +} + +type RestConfig struct { + Address string + TLS bool +} + +type DBConfig struct { + Host string + EnableSSL bool + Database string + User string + Secret string +} + +type EthConfig struct { + // todo +} diff --git a/backend/internal/factory/service.go b/backend/internal/factory/service.go index 7312cd2..c73a6c8 100644 --- a/backend/internal/factory/service.go +++ b/backend/internal/factory/service.go @@ -1 +1,70 @@ +//go:build wireinject +// +build wireinject + package factory + +import ( + "log/slog" + "os" + + "github.com/emochka2007/block-accounting/internal/config" + "github.com/emochka2007/block-accounting/internal/interface/controllers" + "github.com/emochka2007/block-accounting/internal/interface/rest" + "github.com/emochka2007/block-accounting/internal/logger" + "github.com/emochka2007/block-accounting/internal/service" + "github.com/google/wire" +) + +func ProvideService(c config.Config) (service.Service, func(), error) { + wire.Build( + provideLogger, + provideControllers, + provideRestServer, + service.NewService, + ) + + return &service.ServiceImpl{}, func() {}, nil +} + +func provideLogger(c config.Config) *slog.Logger { + lb := new(logger.LoggerBuilder).WithLevel(logger.MapLevel(c.Common.LogLevel)).WithWriter(os.Stdout) + + if c.Common.LogLocal { + lb.Local() + } + + if c.Common.LogFile != "" { + logFile, err := os.Open(c.Common.LogFile) + if err != nil { + panic(err) + } + + lb.WithWriter(logFile) + } + + if c.Common.LogAddSource { + lb.WithSource() + } + + return lb.Build() +} + +func provideControllers( + log *slog.Logger, +) *controllers.RootController { + return &controllers.RootController{ + Ping: controllers.NewPingController(log.WithGroup("ping-controller")), + } +} + +func provideRestServer( + log *slog.Logger, + controllers *controllers.RootController, + c config.Config, +) *rest.Server { + return rest.NewServer( + log.WithGroup("rest"), + c.Rest, + controllers, + ) +} diff --git a/backend/internal/factory/wire_gen.go b/backend/internal/factory/wire_gen.go new file mode 100644 index 0000000..ecd20f9 --- /dev/null +++ b/backend/internal/factory/wire_gen.go @@ -0,0 +1,71 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject + +package factory + +import ( + "github.com/emochka2007/block-accounting/internal/config" + "github.com/emochka2007/block-accounting/internal/interface/controllers" + "github.com/emochka2007/block-accounting/internal/interface/rest" + "github.com/emochka2007/block-accounting/internal/logger" + "github.com/emochka2007/block-accounting/internal/service" + "log/slog" + "os" +) + +// Injectors from service.go: + +func ProvideService(c config.Config) (service.Service, func(), error) { + logger := provideLogger(c) + rootController := provideControllers(logger) + server := provideRestServer(logger, rootController, c) + serviceService := service.NewService(logger, server) + return serviceService, func() { + }, nil +} + +// service.go: + +func provideLogger(c config.Config) *slog.Logger { + lb := new(logger.LoggerBuilder).WithLevel(logger.MapLevel(c.Common.LogLevel)).WithWriter(os.Stdout) + + if c.Common.LogLocal { + lb.Local() + } + + if c.Common.LogFile != "" { + logFile, err := os.Open(c.Common.LogFile) + if err != nil { + panic(err) + } + + lb.WithWriter(logFile) + } + + if c.Common.LogAddSource { + lb.WithSource() + } + + return lb.Build() +} + +func provideControllers( + log *slog.Logger, +) *controllers.RootController { + return &controllers.RootController{ + Ping: controllers.NewPingController(log.WithGroup("ping-controller")), + } +} + +func provideRestServer( + log *slog.Logger, controllers2 *controllers.RootController, + c config.Config, +) *rest.Server { + return rest.NewServer( + log.WithGroup("rest"), + c.Rest, controllers2, + ) +} diff --git a/backend/internal/interface/rest/server.go b/backend/internal/interface/rest/server.go index 1f3ed8f..6235480 100644 --- a/backend/internal/interface/rest/server.go +++ b/backend/internal/interface/rest/server.go @@ -7,6 +7,7 @@ import ( "net/http" "sync" + "github.com/emochka2007/block-accounting/internal/config" "github.com/emochka2007/block-accounting/internal/interface/controllers" "github.com/emochka2007/block-accounting/internal/logger" "github.com/go-chi/chi/v5" @@ -29,12 +30,13 @@ type Server struct { func NewServer( log *slog.Logger, - addr string, + conf config.RestConfig, controllers *controllers.RootController, ) *Server { s := &Server{ log: log, - addr: addr, + addr: conf.Address, + tls: conf.TLS, controllers: controllers, } @@ -46,6 +48,12 @@ func NewServer( func (s *Server) Serve(ctx context.Context) error { s.ctx = ctx + s.log.Info( + "starting rest interface", + slog.String("addr", s.addr), + slog.Bool("tls", s.tls), + ) + if s.tls { return http.ListenAndServeTLS(s.addr, "/todo", "/todo", s) } @@ -67,9 +75,30 @@ func (s *Server) buildRouter() { s.With(mw.RequestID) s.With(s.handleMw) - s.Get("/ping", s.handlePing) + s.Get("/ping", s.handlePing) // debug + + // auth + s.Post("/join", nil) // new user + s.Post("/login", nil) // login + + s.Route("/organization/{organization_id}", func(r chi.Router) { + s.Route("/transactions", func(r chi.Router) { + r.Get("/", nil) // list + r.Post("/", nil) // add + r.Put("/{tx_id}", nil) // update / approve (or maybe body?) + r.Delete("/{tx_id}", nil) // remove + }) + + s.Post("/invite", nil) // create a new invite link + + s.Route("/employees", func(r chi.Router) { + r.Get("/", nil) // list + r.Post("/", nil) // add + r.Put("/{employee_id}", nil) // update (or maybe body?) + r.Delete("/{employee_id}", nil) // remove + }) + }) - // todo build rest api router } func (s *Server) responseError(w http.ResponseWriter, e error) { @@ -102,6 +131,8 @@ func (s *Server) handleMw(next http.Handler) http.Handler { } func (s *Server) handlePing(w http.ResponseWriter, req *http.Request) { + s.log.Debug("ping request") + if err := s.controllers.Ping.HandlePing(s.ctx, req, w); err != nil { s.responseError(w, err) } diff --git a/backend/internal/logger/slogpretty.go b/backend/internal/logger/slogpretty.go index d6d56b9..6e95568 100644 --- a/backend/internal/logger/slogpretty.go +++ b/backend/internal/logger/slogpretty.go @@ -89,7 +89,7 @@ func (h *PrettyHandler) WithAttrs(attrs []slog.Attr) slog.Handler { } } -func (h *PrettyHandler) WithGroup(name string) slog.Handler { +func (h *PrettyHandler) WithGroup(name string) slog.Handler { return &PrettyHandler{ Handler: h.Handler.WithGroup(name), l: h.l, diff --git a/backend/internal/service/service.go b/backend/internal/service/service.go index c0dbbb1..648295a 100644 --- a/backend/internal/service/service.go +++ b/backend/internal/service/service.go @@ -2,10 +2,10 @@ package service import ( "context" + "fmt" "log/slog" "github.com/emochka2007/block-accounting/internal/interface/rest" - "golang.org/x/sync/errgroup" ) type Service interface { @@ -13,7 +13,7 @@ type Service interface { Stop() } -type service struct { +type ServiceImpl struct { log *slog.Logger rest *rest.Server } @@ -22,20 +22,33 @@ func NewService( log *slog.Logger, rest *rest.Server, ) Service { - return &service{ - log: log, + return &ServiceImpl{ + log: log, + rest: rest, } } -func (s *service) Run(ctx context.Context) error { - g, ctx := errgroup.WithContext(ctx) +func (s *ServiceImpl) Run(ctx context.Context) error { + errch := make(chan error) - g.Go(func() error { - return s.rest.Serve(ctx) - }) + defer s.rest.Close() - return g.Wait() + go func() { + defer func() { + close(errch) + }() + + errch <- s.rest.Serve(ctx) + }() + + select { + case <-ctx.Done(): + return nil + case err := <-errch: + return fmt.Errorf("error at service runtime. %w", err) + } } -func (s *service) Stop() { +func (s *ServiceImpl) Stop() { + }