feat: it works
This commit is contained in:
parent
6302dd62d6
commit
778d5ef146
25 changed files with 638 additions and 106 deletions
|
|
@ -225,10 +225,9 @@ components:
|
|||
Error:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
message:
|
||||
type: string
|
||||
details:
|
||||
type: string
|
||||
|
|
|
|||
|
|
@ -1,7 +1,48 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/repository"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/service"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/transport/rest"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/transport/rest/handler"
|
||||
)
|
||||
|
||||
const (
|
||||
servicePrefix = "GSN"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("gsn")
|
||||
repoConfig, err := repository.NewConfig(servicePrefix)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
repo, err := repository.New(repoConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
svc := service.New(repo)
|
||||
|
||||
handler := handler.New(svc)
|
||||
|
||||
restConfig, err := rest.NewConfig(servicePrefix)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
transport, err := rest.New(handler, restConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for {
|
||||
transport.Run()
|
||||
|
||||
if r := recover(); r != nil {
|
||||
log.Println("panic occured: ", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -5,11 +5,14 @@ go 1.23.0
|
|||
toolchain go1.23.7
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
github.com/go-faster/errors v0.7.1
|
||||
github.com/go-faster/jx v1.1.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgx/v5 v5.7.4
|
||||
github.com/ogen-go/ogen v1.10.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/otel/metric v1.35.0
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
|
|
@ -17,6 +20,7 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
|
|
@ -27,6 +31,7 @@ require (
|
|||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
|
|
@ -37,4 +42,5 @@ require (
|
|||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
27
go.sum
27
go.sum
|
|
@ -1,3 +1,5 @@
|
|||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
@ -18,6 +20,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
|||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
|
@ -52,6 +56,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
|
|
@ -66,20 +71,42 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
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.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package ds
|
||||
|
||||
import "github.com/google/uuid"
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Status string
|
||||
|
||||
|
|
@ -15,3 +17,9 @@ type Station struct {
|
|||
Slug string
|
||||
Status Status
|
||||
}
|
||||
|
||||
type Satellite struct {
|
||||
ID uuid.UUID
|
||||
DisplayName string
|
||||
Status Status
|
||||
}
|
||||
25
internal/pkg/errcodes/errcodes.go
Normal file
25
internal/pkg/errcodes/errcodes.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package errcodes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ErrorCode struct {
|
||||
StatusCode int
|
||||
Message string
|
||||
Details string
|
||||
}
|
||||
|
||||
var errorCodeCounter int32
|
||||
|
||||
func New(statusCode int, message string, details ...string) *ErrorCode {
|
||||
return &ErrorCode{
|
||||
StatusCode: statusCode,
|
||||
Message: message,
|
||||
Details: strings.Join(details, " "),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ErrorCode) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
23
internal/repository/config.go
Normal file
23
internal/repository/config.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
env "github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ConnStr string `env:"CONNSTR" envDefault:"postgres://gsn:gsn@localhost:5432/gsn?sslmode=disable"`
|
||||
}
|
||||
|
||||
func NewConfig(servicePrefix string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
|
||||
if err := env.ParseWithOptions(cfg, env.Options{
|
||||
PrefixTagName: fmt.Sprintf("%s_REPOSITORY_", servicePrefix),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
-- name: GetStationByID :one
|
||||
-- name: GetSatellites :many
|
||||
select *
|
||||
from stations
|
||||
where id = @id;
|
||||
from satellites;
|
||||
|
|
@ -3,24 +3,23 @@ package repository
|
|||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/ds"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/repository/sqlc"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
queries *sqlc.Queries
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
func (r *Repository) GetStationByID(ctx context.Context, ID uuid.UUID) (ds.Station, error) {
|
||||
ret, err := r.queries.GetStationByID(ctx, UUIDToPg(ID))
|
||||
func New(cfg *Config) (*Repository, error) {
|
||||
conn, err := pgx.Connect(context.Background(), cfg.ConnStr)
|
||||
if err != nil {
|
||||
return ds.Station{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds.Station{
|
||||
ID: PGToUUID(ret.ID),
|
||||
Slug: ret.Slug,
|
||||
Status: ds.Status(ret.Status),
|
||||
return &Repository{
|
||||
queries: sqlc.New(conn),
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
27
internal/repository/satellites.go
Normal file
27
internal/repository/satellites.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/errcodes"
|
||||
)
|
||||
|
||||
func (r *Repository) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
satellites, err := r.queries.GetSatellites(ctx)
|
||||
if err != nil {
|
||||
return nil, errcodes.New(http.StatusInternalServerError, "failed to get satellites", err.Error())
|
||||
}
|
||||
|
||||
ret := make([]ds.Satellite, 0, len(satellites))
|
||||
for _, val := range satellites {
|
||||
ret = append(ret, ds.Satellite{
|
||||
ID: PGToUUID(val.ID),
|
||||
DisplayName: val.DisplayName,
|
||||
Status: ds.Status(val.Status),
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
@ -7,19 +7,29 @@ package sqlc
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const getStationByID = `-- name: GetStationByID :one
|
||||
select id, slug, status
|
||||
from stations
|
||||
where id = $1
|
||||
const getSatellites = `-- name: GetSatellites :many
|
||||
select id, display_name, status
|
||||
from satellites
|
||||
`
|
||||
|
||||
func (q *Queries) GetStationByID(ctx context.Context, id pgtype.UUID) (Station, error) {
|
||||
row := q.db.QueryRow(ctx, getStationByID, id)
|
||||
var i Station
|
||||
err := row.Scan(&i.ID, &i.Slug, &i.Status)
|
||||
return i, err
|
||||
func (q *Queries) GetSatellites(ctx context.Context) ([]Satellite, error) {
|
||||
rows, err := q.db.Query(ctx, getSatellites)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Satellite
|
||||
for rows.Next() {
|
||||
var i Satellite
|
||||
if err := rows.Scan(&i.ID, &i.DisplayName, &i.Status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
|
|||
12
internal/service/deps.go
Normal file
12
internal/service/deps.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
//go:generate mockgen -source=deps.go -destination=deps_mock.go -package=service
|
||||
type Repository interface {
|
||||
GetSatellites(ctx context.Context) ([]ds.Satellite, error)
|
||||
}
|
||||
51
internal/service/deps_mock.go
Normal file
51
internal/service/deps_mock.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: deps.go
|
||||
|
||||
// Package service is a generated GoMock package.
|
||||
package service
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
ds "git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockRepository is a mock of Repository interface.
|
||||
type MockRepository struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRepositoryMockRecorder
|
||||
}
|
||||
|
||||
// MockRepositoryMockRecorder is the mock recorder for MockRepository.
|
||||
type MockRepositoryMockRecorder struct {
|
||||
mock *MockRepository
|
||||
}
|
||||
|
||||
// NewMockRepository creates a new mock instance.
|
||||
func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
|
||||
mock := &MockRepository{ctrl: ctrl}
|
||||
mock.recorder = &MockRepositoryMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetSatellites mocks base method.
|
||||
func (m *MockRepository) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSatellites", ctx)
|
||||
ret0, _ := ret[0].([]ds.Satellite)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetSatellites indicates an expected call of GetSatellites.
|
||||
func (mr *MockRepositoryMockRecorder) GetSatellites(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSatellites", reflect.TypeOf((*MockRepository)(nil).GetSatellites), ctx)
|
||||
}
|
||||
11
internal/service/satellites.go
Normal file
11
internal/service/satellites.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
func (s *Service) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
return s.repo.GetSatellites(ctx)
|
||||
}
|
||||
66
internal/service/satellites_test.go
Normal file
66
internal/service/satellites_test.go
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_GetSatellites(t *testing.T) {
|
||||
suite := NewSuite(t)
|
||||
|
||||
var (
|
||||
commonSatelliteID = uuid.New()
|
||||
commonDisplayName = "test"
|
||||
commonStatus = ds.StatusActive
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
mock func()
|
||||
expected []ds.Satellite
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
mock: func() {
|
||||
suite.mockRepo.EXPECT().GetSatellites(gomock.Any()).Return([]ds.Satellite{
|
||||
{
|
||||
ID: commonSatelliteID,
|
||||
DisplayName: commonDisplayName,
|
||||
Status: commonStatus,
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
expected: []ds.Satellite{
|
||||
{
|
||||
ID: commonSatelliteID,
|
||||
DisplayName: commonDisplayName,
|
||||
Status: commonStatus,
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.mock != nil {
|
||||
tt.mock()
|
||||
}
|
||||
|
||||
result, err := suite.svc.GetSatellites(context.Background())
|
||||
if tt.wantErr != nil {
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.True(t, reflect.DeepEqual(tt.expected, result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
11
internal/service/service.go
Normal file
11
internal/service/service.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package service
|
||||
|
||||
type Service struct {
|
||||
repo Repository
|
||||
}
|
||||
|
||||
func New(repo Repository) *Service {
|
||||
return &Service{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
27
internal/service/service_test.go
Normal file
27
internal/service/service_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
type TestSuite struct {
|
||||
svc *Service
|
||||
mockRepo *MockRepository
|
||||
}
|
||||
|
||||
func NewSuite(t *testing.T) *TestSuite {
|
||||
t.Helper()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
mockRepo := NewMockRepository(ctrl)
|
||||
|
||||
svc := New(mockRepo)
|
||||
|
||||
return &TestSuite{
|
||||
svc: svc,
|
||||
mockRepo: mockRepo,
|
||||
}
|
||||
}
|
||||
23
internal/transport/rest/config.go
Normal file
23
internal/transport/rest/config.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
env "github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port int `env:"PORT" envDefault:"8080"`
|
||||
}
|
||||
|
||||
func NewConfig(servicePrefix string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
|
||||
if err := env.ParseWithOptions(cfg, env.Options{
|
||||
PrefixTagName: fmt.Sprintf("%s_REST_", servicePrefix),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package rest
|
||||
|
||||
type Service interface {
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
_ api.Handler = (*Handler)(nil)
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc Service
|
||||
}
|
||||
|
||||
func (h *Handler) GetSatellites(ctx context.Context) (*api.GetSatellitesOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetStations(ctx context.Context) (*api.GetStationsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetSubscriptions(ctx context.Context) (*api.GetSubscriptionsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeSatellite(ctx context.Context, req *api.SubscribeSatelliteReq) (*api.SubscribeSatelliteOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeStation(ctx context.Context, req *api.SubscribeStationReq) (*api.SubscribeStationOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) Unsubscribe(ctx context.Context, params api.UnsubscribeParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
|
||||
return nil
|
||||
}
|
||||
11
internal/transport/rest/handler/deps.go
Normal file
11
internal/transport/rest/handler/deps.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
GetSatellites(ctx context.Context) ([]ds.Satellite, error)
|
||||
}
|
||||
89
internal/transport/rest/handler/handler.go
Normal file
89
internal/transport/rest/handler/handler.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/errcodes"
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
_ api.Handler = (*Handler)(nil)
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc Service
|
||||
}
|
||||
|
||||
func New(svc Service) *Handler {
|
||||
return &Handler{
|
||||
svc: svc,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) GetSatellites(ctx context.Context) (*api.GetSatellitesOK, error) {
|
||||
satellites, err := h.svc.GetSatellites(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]api.GetSatellitesOKSatellitesItem, 0, len(satellites))
|
||||
for _, val := range satellites {
|
||||
ret = append(ret, api.GetSatellitesOKSatellitesItem{
|
||||
ID: val.ID,
|
||||
DisplayName: val.DisplayName,
|
||||
Status: api.GetSatellitesOKSatellitesItemStatus(val.Status),
|
||||
})
|
||||
}
|
||||
|
||||
return &api.GetSatellitesOK{
|
||||
Satellites: ret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetStations(ctx context.Context) (*api.GetStationsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetSubscriptions(ctx context.Context) (*api.GetSubscriptionsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeSatellite(ctx context.Context, req *api.SubscribeSatelliteReq) (*api.SubscribeSatelliteOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeStation(ctx context.Context, req *api.SubscribeStationReq) (*api.SubscribeStationOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) Unsubscribe(ctx context.Context, params api.UnsubscribeParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
|
||||
if errcode, ok := err.(*errcodes.ErrorCode); ok {
|
||||
resp := api.Error{
|
||||
Message: errcode.Message,
|
||||
}
|
||||
|
||||
if errcode.Details != "" {
|
||||
resp.Details = api.NewOptString(errcode.Details)
|
||||
}
|
||||
|
||||
return &api.ErrorStatusCode{
|
||||
StatusCode: errcode.StatusCode,
|
||||
Response: resp,
|
||||
}
|
||||
}
|
||||
|
||||
return &api.ErrorStatusCode{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Response: api.Error{
|
||||
Message: fmt.Sprintf("undefined internal error"),
|
||||
Details: api.NewOptString(err.Error()),
|
||||
},
|
||||
}
|
||||
}
|
||||
33
internal/transport/rest/transport.go
Normal file
33
internal/transport/rest/transport.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
handler "git.intra.yksa.space/gsn/gsn-proxy/internal/transport/rest/handler"
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
type Transport struct {
|
||||
cfg *Config
|
||||
srv *api.Server
|
||||
}
|
||||
|
||||
func New(handler *handler.Handler, cfg *Config) (*Transport, error) {
|
||||
srv, err := api.NewServer(handler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Transport{
|
||||
srv: srv,
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Run() {
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", t.cfg.Port), t.srv); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,19 +22,21 @@ func (s *Error) Encode(e *jx.Encoder) {
|
|||
|
||||
// encodeFields encodes fields.
|
||||
func (s *Error) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("code")
|
||||
e.Int(s.Code)
|
||||
}
|
||||
{
|
||||
e.FieldStart("message")
|
||||
e.Str(s.Message)
|
||||
}
|
||||
{
|
||||
if s.Details.Set {
|
||||
e.FieldStart("details")
|
||||
s.Details.Encode(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfError = [2]string{
|
||||
0: "code",
|
||||
1: "message",
|
||||
0: "message",
|
||||
1: "details",
|
||||
}
|
||||
|
||||
// Decode decodes Error from json.
|
||||
|
|
@ -46,20 +48,8 @@ func (s *Error) Decode(d *jx.Decoder) error {
|
|||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "code":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int()
|
||||
s.Code = int(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"code\"")
|
||||
}
|
||||
case "message":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Message = string(v)
|
||||
|
|
@ -70,6 +60,16 @@ func (s *Error) Decode(d *jx.Decoder) error {
|
|||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"message\"")
|
||||
}
|
||||
case "details":
|
||||
if err := func() error {
|
||||
s.Details.Reset()
|
||||
if err := s.Details.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"details\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ func (s *Error) Decode(d *jx.Decoder) error {
|
|||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b00000011,
|
||||
0b00000001,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
|
|
@ -977,6 +977,41 @@ func (s *GetSubscriptionsOKSubscriptionsItemType) UnmarshalJSON(data []byte) err
|
|||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode encodes string as json.
|
||||
func (o OptString) Encode(e *jx.Encoder) {
|
||||
if !o.Set {
|
||||
return
|
||||
}
|
||||
e.Str(string(o.Value))
|
||||
}
|
||||
|
||||
// Decode decodes string from json.
|
||||
func (o *OptString) Decode(d *jx.Decoder) error {
|
||||
if o == nil {
|
||||
return errors.New("invalid: unable to decode OptString to nil")
|
||||
}
|
||||
o.Set = true
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Value = string(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s OptString) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *OptString) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *SubscribeSatelliteOK) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
|
|
|
|||
|
|
@ -16,13 +16,8 @@ func (s *ErrorStatusCode) Error() string {
|
|||
|
||||
// Ref: #/components/schemas/Error
|
||||
type Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// GetCode returns the value of Code.
|
||||
func (s *Error) GetCode() int {
|
||||
return s.Code
|
||||
Message string `json:"message"`
|
||||
Details OptString `json:"details"`
|
||||
}
|
||||
|
||||
// GetMessage returns the value of Message.
|
||||
|
|
@ -30,9 +25,9 @@ func (s *Error) GetMessage() string {
|
|||
return s.Message
|
||||
}
|
||||
|
||||
// SetCode sets the value of Code.
|
||||
func (s *Error) SetCode(val int) {
|
||||
s.Code = val
|
||||
// GetDetails returns the value of Details.
|
||||
func (s *Error) GetDetails() OptString {
|
||||
return s.Details
|
||||
}
|
||||
|
||||
// SetMessage sets the value of Message.
|
||||
|
|
@ -40,6 +35,11 @@ func (s *Error) SetMessage(val string) {
|
|||
s.Message = val
|
||||
}
|
||||
|
||||
// SetDetails sets the value of Details.
|
||||
func (s *Error) SetDetails(val OptString) {
|
||||
s.Details = val
|
||||
}
|
||||
|
||||
// ErrorStatusCode wraps Error with StatusCode.
|
||||
type ErrorStatusCode struct {
|
||||
StatusCode int
|
||||
|
|
@ -412,6 +412,52 @@ func (s *GetSubscriptionsOKSubscriptionsItemType) UnmarshalText(data []byte) err
|
|||
}
|
||||
}
|
||||
|
||||
// NewOptString returns new OptString with value set to v.
|
||||
func NewOptString(v string) OptString {
|
||||
return OptString{
|
||||
Value: v,
|
||||
Set: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OptString is optional string.
|
||||
type OptString struct {
|
||||
Value string
|
||||
Set bool
|
||||
}
|
||||
|
||||
// IsSet returns true if OptString was set.
|
||||
func (o OptString) IsSet() bool { return o.Set }
|
||||
|
||||
// Reset unsets value.
|
||||
func (o *OptString) Reset() {
|
||||
var v string
|
||||
o.Value = v
|
||||
o.Set = false
|
||||
}
|
||||
|
||||
// SetTo sets value to v.
|
||||
func (o *OptString) SetTo(v string) {
|
||||
o.Set = true
|
||||
o.Value = v
|
||||
}
|
||||
|
||||
// Get returns value and boolean that denotes whether value was set.
|
||||
func (o OptString) Get() (v string, ok bool) {
|
||||
if !o.Set {
|
||||
return v, false
|
||||
}
|
||||
return o.Value, true
|
||||
}
|
||||
|
||||
// Or returns value if set, or given parameter if does not.
|
||||
func (o OptString) Or(d string) string {
|
||||
if v, ok := o.Get(); ok {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NewOptUUID returns new OptUUID with value set to v.
|
||||
func NewOptUUID(v uuid.UUID) OptUUID {
|
||||
return OptUUID{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue