feat: init

This commit is contained in:
awend0 2025-03-26 15:07:12 +03:00
parent 7688020b52
commit e8b8c10faa
33 changed files with 6027 additions and 0 deletions

5
Makefile Normal file
View file

@ -0,0 +1,5 @@
generate-ogen:
go run github.com/ogen-go/ogen/cmd/ogen@latest --target pkg/rest -package gsn --clean api/rest/gsn.swagger.yml
generate-sqlc:
go run github.com/sqlc-dev/sqlc/cmd/sqlc@latest generate -f configs/sqlc.yaml

234
api/rest/gsn.swagger.yml Normal file
View file

@ -0,0 +1,234 @@
openapi: 3.0.4
info:
title: Swagger GSN - OpenAPI 3.0
version: 0.0.1
paths:
/subscription:
get:
tags:
- Subscriptions
summary: Get current subscriptions
operationId: GetSubscriptions
responses:
200:
description: Subscriptions list
content:
application/json:
schema:
type: object
required:
- subscriptions
properties:
subscriptions:
type: array
items:
type: object
required:
- id
- type
- status
- created_at
properties:
id:
type: string
format: uuid
type:
type: string
enum: ["station", "satellite"]
status:
type: string
enum: ["active", "offline", "busy"]
created_at:
type: string
format: date-time
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
tags:
- Subscriptions
summary: Remove subscription by subscription ID
operationId: Unsubscribe
parameters:
- name: id
in: query
schema:
type: string
format: uuid
responses:
200:
description: Succesful operation
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/station:
get:
tags:
- Stations
summary: Get available stations
operationId: GetStations
responses:
200:
description: Stations list
content:
application/json:
schema:
type: object
required:
- stations
properties:
stations:
type: array
items:
type: object
required:
- id
- slug
- status
properties:
id:
type: string
format: uuid
slug:
type: string
status:
type: string
enum: ["active", "offline", "busy"]
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/station/subscribe:
post:
tags:
- Stations
summary: Subscribe to a given station
operationId: SubscribeStation
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
format: uuid
description: Subscription ID
responses:
200:
description: Successful operation
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
format: uuid
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/satellite:
get:
tags:
- Satellites
summary: Get available satellites
operationId: GetSatellites
responses:
200:
description: Satellites list
content:
application/json:
schema:
type: object
required:
- stations
properties:
satellites:
type: array
items:
type: object
required:
- id
- display_name
- status
properties:
id:
type: string
format: uuid
display_name:
type: string
status:
type: string
enum: ["active", "offline", "busy"]
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/satellite/subscribe:
post:
tags:
- Satellites
summary: Subscribe to a given station
operationId: SubscribeSatellite
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
format: uuid
responses:
200:
description: Successful operation
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
format: uuid
default:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
message:
type: string

7
cmd/api/main.go Normal file
View file

@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("gsn")
}

10
configs/sqlc.yaml Normal file
View file

@ -0,0 +1,10 @@
version: "2"
sql:
- engine: "postgresql"
queries: "../internal/repository/queries/queries.sql"
schema: "../internal/repository/migrations/"
gen:
go:
package: "sqlc"
out: "../internal/repository/sqlc"
sql_package: "pgx/v5"

40
go.mod Normal file
View file

@ -0,0 +1,40 @@
module git.intra.yksa.space/gsn/gsn-proxy
go 1.23.0
toolchain go1.23.7
require (
github.com/go-faster/errors v0.7.1
github.com/go-faster/jx v1.1.0
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.4
github.com/ogen-go/ogen v1.10.1
go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/metric v1.35.0
go.opentelemetry.io/otel/trace v1.35.0
go.uber.org/multierr v1.11.0
)
require (
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-faster/yaml v0.4.6 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
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/segmentio/asm v1.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

90
go.sum Normal file
View file

@ -0,0 +1,90 @@
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=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg=
github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg=
github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I=
github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
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/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=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/ogen-go/ogen v1.10.1 h1:oeSN8AF9mhTVfapbMuL8pQTF2ToqyW9xXaStmOhHKTA=
github.com/ogen-go/ogen v1.10.1/go.mod h1:fXCg9PsNYEzJ8ABdmZ2A7j4hMi9EDHP53jzsNtIM3d0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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=
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=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
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.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/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.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
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=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

17
internal/ds/ds.go Normal file
View file

@ -0,0 +1,17 @@
package ds
import "github.com/google/uuid"
type Status string
const (
StatusActive Status = "active"
StatusOffline Status = "offline"
StatusBusy Status = "busy"
)
type Station struct {
ID uuid.UUID
Slug string
Status Status
}

View file

@ -0,0 +1,22 @@
package repository
import (
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
)
func UUIDToPg(in uuid.UUID) pgtype.UUID {
if in == uuid.Nil {
return pgtype.UUID{}
}
return pgtype.UUID{Bytes: in, Valid: true}
}
func PGToUUID(in pgtype.UUID) uuid.UUID {
if !in.Valid {
return uuid.Nil
}
return in.Bytes
}

View file

@ -0,0 +1,29 @@
create table users (
id uuid primary key,
login text not null
);
create type status as enum ('active', 'offline', 'busy');
create table stations (
id uuid primary key,
slug text not null,
status status not null
);
create table satellites (
id uuid primary key,
display_name text not null,
status status not null
);
create table subscriptions (
id uuid primary key,
user_id uuid not null references users(id),
station_id uuid null references satellites(id),
satellite_id uuid null references stations(id),
created_at timestamp not null,
updated_at timestamp not null,
check (station_id is not null or satellite_id is not null)
);

View file

@ -0,0 +1,4 @@
-- name: GetStationByID :one
select *
from stations
where id = @id;

View file

@ -0,0 +1,26 @@
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"
)
type Repository struct {
queries *sqlc.Queries
}
func (r *Repository) GetStationByID(ctx context.Context, ID uuid.UUID) (ds.Station, error) {
ret, err := r.queries.GetStationByID(ctx, UUIDToPg(ID))
if err != nil {
return ds.Station{}, err
}
return ds.Station{
ID: PGToUUID(ret.ID),
Slug: ret.Slug,
Status: ds.Status(ret.Status),
}, nil
}

View file

@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0
package sqlc
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View file

@ -0,0 +1,81 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0
package sqlc
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype"
)
type Status string
const (
StatusActive Status = "active"
StatusOffline Status = "offline"
StatusBusy Status = "busy"
)
func (e *Status) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = Status(s)
case string:
*e = Status(s)
default:
return fmt.Errorf("unsupported scan type for Status: %T", src)
}
return nil
}
type NullStatus struct {
Status Status
Valid bool // Valid is true if Status is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullStatus) Scan(value interface{}) error {
if value == nil {
ns.Status, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.Status.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.Status), nil
}
type Satellite struct {
ID pgtype.UUID
DisplayName string
Status Status
}
type Station struct {
ID pgtype.UUID
Slug string
Status Status
}
type Subscription struct {
ID pgtype.UUID
UserID pgtype.UUID
StationID pgtype.UUID
SatelliteID pgtype.UUID
CreatedAt pgtype.Timestamp
UpdatedAt pgtype.Timestamp
}
type User struct {
ID pgtype.UUID
Login string
}

View file

@ -0,0 +1,25 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0
// source: queries.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const getStationByID = `-- name: GetStationByID :one
select id, slug, status
from stations
where id = $1
`
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
}

View file

@ -0,0 +1,4 @@
package rest
type Service interface {
}

View file

@ -0,0 +1,43 @@
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
}

283
pkg/rest/oas_cfg_gen.go Normal file
View file

@ -0,0 +1,283 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/otelogen"
)
var (
// Allocate option closure once.
clientSpanKind = trace.WithSpanKind(trace.SpanKindClient)
// Allocate option closure once.
serverSpanKind = trace.WithSpanKind(trace.SpanKindServer)
)
type (
optionFunc[C any] func(*C)
otelOptionFunc func(*otelConfig)
)
type otelConfig struct {
TracerProvider trace.TracerProvider
Tracer trace.Tracer
MeterProvider metric.MeterProvider
Meter metric.Meter
}
func (cfg *otelConfig) initOTEL() {
if cfg.TracerProvider == nil {
cfg.TracerProvider = otel.GetTracerProvider()
}
if cfg.MeterProvider == nil {
cfg.MeterProvider = otel.GetMeterProvider()
}
cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name,
trace.WithInstrumentationVersion(otelogen.SemVersion()),
)
cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name,
metric.WithInstrumentationVersion(otelogen.SemVersion()),
)
}
// ErrorHandler is error handler.
type ErrorHandler = ogenerrors.ErrorHandler
type serverConfig struct {
otelConfig
NotFound http.HandlerFunc
MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)
ErrorHandler ErrorHandler
Prefix string
Middleware Middleware
MaxMultipartMemory int64
}
// ServerOption is server config option.
type ServerOption interface {
applyServer(*serverConfig)
}
var _ ServerOption = (optionFunc[serverConfig])(nil)
func (o optionFunc[C]) applyServer(c *C) {
o(c)
}
var _ ServerOption = (otelOptionFunc)(nil)
func (o otelOptionFunc) applyServer(c *serverConfig) {
o(&c.otelConfig)
}
func newServerConfig(opts ...ServerOption) serverConfig {
cfg := serverConfig{
NotFound: http.NotFound,
MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) {
status := http.StatusMethodNotAllowed
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Methods", allowed)
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
status = http.StatusNoContent
} else {
w.Header().Set("Allow", allowed)
}
w.WriteHeader(status)
},
ErrorHandler: ogenerrors.DefaultErrorHandler,
Middleware: nil,
MaxMultipartMemory: 32 << 20, // 32 MB
}
for _, opt := range opts {
opt.applyServer(&cfg)
}
cfg.initOTEL()
return cfg
}
type baseServer struct {
cfg serverConfig
requests metric.Int64Counter
errors metric.Int64Counter
duration metric.Float64Histogram
}
func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) {
s.cfg.NotFound(w, r)
}
func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) {
s.cfg.MethodNotAllowed(w, r, allowed)
}
func (cfg serverConfig) baseServer() (s baseServer, err error) {
s = baseServer{cfg: cfg}
if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil {
return s, err
}
if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil {
return s, err
}
if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil {
return s, err
}
return s, nil
}
type clientConfig struct {
otelConfig
Client ht.Client
}
// ClientOption is client config option.
type ClientOption interface {
applyClient(*clientConfig)
}
var _ ClientOption = (optionFunc[clientConfig])(nil)
func (o optionFunc[C]) applyClient(c *C) {
o(c)
}
var _ ClientOption = (otelOptionFunc)(nil)
func (o otelOptionFunc) applyClient(c *clientConfig) {
o(&c.otelConfig)
}
func newClientConfig(opts ...ClientOption) clientConfig {
cfg := clientConfig{
Client: http.DefaultClient,
}
for _, opt := range opts {
opt.applyClient(&cfg)
}
cfg.initOTEL()
return cfg
}
type baseClient struct {
cfg clientConfig
requests metric.Int64Counter
errors metric.Int64Counter
duration metric.Float64Histogram
}
func (cfg clientConfig) baseClient() (c baseClient, err error) {
c = baseClient{cfg: cfg}
if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil {
return c, err
}
if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil {
return c, err
}
if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil {
return c, err
}
return c, nil
}
// Option is config option.
type Option interface {
ServerOption
ClientOption
}
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
//
// If none is specified, the global provider is used.
func WithTracerProvider(provider trace.TracerProvider) Option {
return otelOptionFunc(func(cfg *otelConfig) {
if provider != nil {
cfg.TracerProvider = provider
}
})
}
// WithMeterProvider specifies a meter provider to use for creating a meter.
//
// If none is specified, the otel.GetMeterProvider() is used.
func WithMeterProvider(provider metric.MeterProvider) Option {
return otelOptionFunc(func(cfg *otelConfig) {
if provider != nil {
cfg.MeterProvider = provider
}
})
}
// WithClient specifies http client to use.
func WithClient(client ht.Client) ClientOption {
return optionFunc[clientConfig](func(cfg *clientConfig) {
if client != nil {
cfg.Client = client
}
})
}
// WithNotFound specifies Not Found handler to use.
func WithNotFound(notFound http.HandlerFunc) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if notFound != nil {
cfg.NotFound = notFound
}
})
}
// WithMethodNotAllowed specifies Method Not Allowed handler to use.
func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if methodNotAllowed != nil {
cfg.MethodNotAllowed = methodNotAllowed
}
})
}
// WithErrorHandler specifies error handler to use.
func WithErrorHandler(h ErrorHandler) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if h != nil {
cfg.ErrorHandler = h
}
})
}
// WithPathPrefix specifies server path prefix.
func WithPathPrefix(prefix string) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
cfg.Prefix = prefix
})
}
// WithMiddleware specifies middlewares to use.
func WithMiddleware(m ...Middleware) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
switch len(m) {
case 0:
cfg.Middleware = nil
case 1:
cfg.Middleware = m[0]
default:
cfg.Middleware = middleware.ChainMiddlewares(m...)
}
})
}
// WithMaxMultipartMemory specifies limit of memory for storing file parts.
// File parts which can't be stored in memory will be stored on disk in temporary files.
func WithMaxMultipartMemory(max int64) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if max > 0 {
cfg.MaxMultipartMemory = max
}
})
}

573
pkg/rest/oas_client_gen.go Normal file
View file

@ -0,0 +1,573 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"context"
"net/url"
"strings"
"time"
"github.com/go-faster/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
"github.com/ogen-go/ogen/conv"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/otelogen"
"github.com/ogen-go/ogen/uri"
)
func trimTrailingSlashes(u *url.URL) {
u.Path = strings.TrimRight(u.Path, "/")
u.RawPath = strings.TrimRight(u.RawPath, "/")
}
// Invoker invokes operations described by OpenAPI v3 specification.
type Invoker interface {
// GetSatellites invokes GetSatellites operation.
//
// Get available satellites.
//
// GET /satellite
GetSatellites(ctx context.Context) (*GetSatellitesOK, error)
// GetStations invokes GetStations operation.
//
// Get available stations.
//
// GET /station
GetStations(ctx context.Context) (*GetStationsOK, error)
// GetSubscriptions invokes GetSubscriptions operation.
//
// Get current subscriptions.
//
// GET /subscription
GetSubscriptions(ctx context.Context) (*GetSubscriptionsOK, error)
// SubscribeSatellite invokes SubscribeSatellite operation.
//
// Subscribe to a given station.
//
// POST /satellite/subscribe
SubscribeSatellite(ctx context.Context, request *SubscribeSatelliteReq) (*SubscribeSatelliteOK, error)
// SubscribeStation invokes SubscribeStation operation.
//
// Subscribe to a given station.
//
// POST /station/subscribe
SubscribeStation(ctx context.Context, request *SubscribeStationReq) (*SubscribeStationOK, error)
// Unsubscribe invokes Unsubscribe operation.
//
// Remove subscription by subscription ID.
//
// DELETE /subscription
Unsubscribe(ctx context.Context, params UnsubscribeParams) error
}
// Client implements OAS client.
type Client struct {
serverURL *url.URL
baseClient
}
type errorHandler interface {
NewError(ctx context.Context, err error) *ErrorStatusCode
}
var _ Handler = struct {
errorHandler
*Client
}{}
// NewClient initializes new Client defined by OAS.
func NewClient(serverURL string, opts ...ClientOption) (*Client, error) {
u, err := url.Parse(serverURL)
if err != nil {
return nil, err
}
trimTrailingSlashes(u)
c, err := newClientConfig(opts...).baseClient()
if err != nil {
return nil, err
}
return &Client{
serverURL: u,
baseClient: c,
}, nil
}
type serverURLKey struct{}
// WithServerURL sets context key to override server URL.
func WithServerURL(ctx context.Context, u *url.URL) context.Context {
return context.WithValue(ctx, serverURLKey{}, u)
}
func (c *Client) requestURL(ctx context.Context) *url.URL {
u, ok := ctx.Value(serverURLKey{}).(*url.URL)
if !ok {
return c.serverURL
}
return u
}
// GetSatellites invokes GetSatellites operation.
//
// Get available satellites.
//
// GET /satellite
func (c *Client) GetSatellites(ctx context.Context) (*GetSatellitesOK, error) {
res, err := c.sendGetSatellites(ctx)
return res, err
}
func (c *Client) sendGetSatellites(ctx context.Context) (res *GetSatellitesOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetSatellites"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/satellite"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, GetSatellitesOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/satellite"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "GET", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeGetSatellitesResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// GetStations invokes GetStations operation.
//
// Get available stations.
//
// GET /station
func (c *Client) GetStations(ctx context.Context) (*GetStationsOK, error) {
res, err := c.sendGetStations(ctx)
return res, err
}
func (c *Client) sendGetStations(ctx context.Context) (res *GetStationsOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetStations"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/station"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, GetStationsOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/station"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "GET", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeGetStationsResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// GetSubscriptions invokes GetSubscriptions operation.
//
// Get current subscriptions.
//
// GET /subscription
func (c *Client) GetSubscriptions(ctx context.Context) (*GetSubscriptionsOK, error) {
res, err := c.sendGetSubscriptions(ctx)
return res, err
}
func (c *Client) sendGetSubscriptions(ctx context.Context) (res *GetSubscriptionsOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetSubscriptions"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/subscription"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, GetSubscriptionsOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/subscription"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "GET", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeGetSubscriptionsResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// SubscribeSatellite invokes SubscribeSatellite operation.
//
// Subscribe to a given station.
//
// POST /satellite/subscribe
func (c *Client) SubscribeSatellite(ctx context.Context, request *SubscribeSatelliteReq) (*SubscribeSatelliteOK, error) {
res, err := c.sendSubscribeSatellite(ctx, request)
return res, err
}
func (c *Client) sendSubscribeSatellite(ctx context.Context, request *SubscribeSatelliteReq) (res *SubscribeSatelliteOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("SubscribeSatellite"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/satellite/subscribe"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, SubscribeSatelliteOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/satellite/subscribe"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "POST", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
if err := encodeSubscribeSatelliteRequest(request, r); err != nil {
return res, errors.Wrap(err, "encode request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeSubscribeSatelliteResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// SubscribeStation invokes SubscribeStation operation.
//
// Subscribe to a given station.
//
// POST /station/subscribe
func (c *Client) SubscribeStation(ctx context.Context, request *SubscribeStationReq) (*SubscribeStationOK, error) {
res, err := c.sendSubscribeStation(ctx, request)
return res, err
}
func (c *Client) sendSubscribeStation(ctx context.Context, request *SubscribeStationReq) (res *SubscribeStationOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("SubscribeStation"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/station/subscribe"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, SubscribeStationOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/station/subscribe"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "POST", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
if err := encodeSubscribeStationRequest(request, r); err != nil {
return res, errors.Wrap(err, "encode request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeSubscribeStationResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// Unsubscribe invokes Unsubscribe operation.
//
// Remove subscription by subscription ID.
//
// DELETE /subscription
func (c *Client) Unsubscribe(ctx context.Context, params UnsubscribeParams) error {
_, err := c.sendUnsubscribe(ctx, params)
return err
}
func (c *Client) sendUnsubscribe(ctx context.Context, params UnsubscribeParams) (res *UnsubscribeOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("Unsubscribe"),
semconv.HTTPRequestMethodKey.String("DELETE"),
semconv.HTTPRouteKey.String("/subscription"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, UnsubscribeOperation,
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/subscription"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "id" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "id",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := params.ID.Get(); ok {
return e.EncodeValue(conv.UUIDToString(val))
}
return nil
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "DELETE", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeUnsubscribeResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}

View file

@ -0,0 +1,868 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"context"
"net/http"
"time"
"github.com/go-faster/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/otelogen"
)
type codeRecorder struct {
http.ResponseWriter
status int
}
func (c *codeRecorder) WriteHeader(status int) {
c.status = status
c.ResponseWriter.WriteHeader(status)
}
// handleGetSatellitesRequest handles GetSatellites operation.
//
// Get available satellites.
//
// GET /satellite
func (s *Server) handleGetSatellitesRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetSatellites"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/satellite"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), GetSatellitesOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
)
var response *GetSatellitesOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: GetSatellitesOperation,
OperationSummary: "Get available satellites",
OperationID: "GetSatellites",
Body: nil,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = struct{}
Params = struct{}
Response = *GetSatellitesOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.GetSatellites(ctx)
return response, err
},
)
} else {
response, err = s.h.GetSatellites(ctx)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeGetSatellitesResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleGetStationsRequest handles GetStations operation.
//
// Get available stations.
//
// GET /station
func (s *Server) handleGetStationsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetStations"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/station"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), GetStationsOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
)
var response *GetStationsOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: GetStationsOperation,
OperationSummary: "Get available stations",
OperationID: "GetStations",
Body: nil,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = struct{}
Params = struct{}
Response = *GetStationsOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.GetStations(ctx)
return response, err
},
)
} else {
response, err = s.h.GetStations(ctx)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeGetStationsResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleGetSubscriptionsRequest handles GetSubscriptions operation.
//
// Get current subscriptions.
//
// GET /subscription
func (s *Server) handleGetSubscriptionsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("GetSubscriptions"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/subscription"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), GetSubscriptionsOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
)
var response *GetSubscriptionsOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: GetSubscriptionsOperation,
OperationSummary: "Get current subscriptions",
OperationID: "GetSubscriptions",
Body: nil,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = struct{}
Params = struct{}
Response = *GetSubscriptionsOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.GetSubscriptions(ctx)
return response, err
},
)
} else {
response, err = s.h.GetSubscriptions(ctx)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeGetSubscriptionsResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleSubscribeSatelliteRequest handles SubscribeSatellite operation.
//
// Subscribe to a given station.
//
// POST /satellite/subscribe
func (s *Server) handleSubscribeSatelliteRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("SubscribeSatellite"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/satellite/subscribe"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), SubscribeSatelliteOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: SubscribeSatelliteOperation,
ID: "SubscribeSatellite",
}
)
request, close, err := s.decodeSubscribeSatelliteRequest(r)
if err != nil {
err = &ogenerrors.DecodeRequestError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeRequest", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
defer func() {
if err := close(); err != nil {
recordError("CloseRequest", err)
}
}()
var response *SubscribeSatelliteOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: SubscribeSatelliteOperation,
OperationSummary: "Subscribe to a given station",
OperationID: "SubscribeSatellite",
Body: request,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = *SubscribeSatelliteReq
Params = struct{}
Response = *SubscribeSatelliteOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.SubscribeSatellite(ctx, request)
return response, err
},
)
} else {
response, err = s.h.SubscribeSatellite(ctx, request)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeSubscribeSatelliteResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleSubscribeStationRequest handles SubscribeStation operation.
//
// Subscribe to a given station.
//
// POST /station/subscribe
func (s *Server) handleSubscribeStationRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("SubscribeStation"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/station/subscribe"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), SubscribeStationOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: SubscribeStationOperation,
ID: "SubscribeStation",
}
)
request, close, err := s.decodeSubscribeStationRequest(r)
if err != nil {
err = &ogenerrors.DecodeRequestError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeRequest", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
defer func() {
if err := close(); err != nil {
recordError("CloseRequest", err)
}
}()
var response *SubscribeStationOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: SubscribeStationOperation,
OperationSummary: "Subscribe to a given station",
OperationID: "SubscribeStation",
Body: request,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = *SubscribeStationReq
Params = struct{}
Response = *SubscribeStationOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.SubscribeStation(ctx, request)
return response, err
},
)
} else {
response, err = s.h.SubscribeStation(ctx, request)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeSubscribeStationResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleUnsubscribeRequest handles Unsubscribe operation.
//
// Remove subscription by subscription ID.
//
// DELETE /subscription
func (s *Server) handleUnsubscribeRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("Unsubscribe"),
semconv.HTTPRequestMethodKey.String("DELETE"),
semconv.HTTPRouteKey.String("/subscription"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), UnsubscribeOperation,
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
code := statusWriter.status
if code != 0 {
codeAttr := semconv.HTTPResponseStatusCode(code)
attrs = append(attrs, codeAttr)
span.SetAttributes(codeAttr)
}
attrOpt := metric.WithAttributes(attrs...)
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
// max redirects exceeded), in which case status MUST be set to Error.
code := statusWriter.status
if code >= 100 && code < 500 {
span.SetStatus(codes.Error, stage)
}
attrSet := labeler.AttributeSet()
attrs := attrSet.ToSlice()
if code != 0 {
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
}
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: UnsubscribeOperation,
ID: "Unsubscribe",
}
)
params, err := decodeUnsubscribeParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response *UnsubscribeOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: UnsubscribeOperation,
OperationSummary: "Remove subscription by subscription ID",
OperationID: "Unsubscribe",
Body: nil,
Params: middleware.Parameters{
{
Name: "id",
In: "query",
}: params.ID,
},
Raw: r,
}
type (
Request = struct{}
Params = UnsubscribeParams
Response = *UnsubscribeOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackUnsubscribeParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.Unsubscribe(ctx, params)
return response, err
},
)
} else {
err = s.h.Unsubscribe(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeUnsubscribeResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}

1362
pkg/rest/oas_json_gen.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"context"
"go.opentelemetry.io/otel/attribute"
)
// Labeler is used to allow adding custom attributes to the server request metrics.
type Labeler struct {
attrs []attribute.KeyValue
}
// Add attributes to the Labeler.
func (l *Labeler) Add(attrs ...attribute.KeyValue) {
l.attrs = append(l.attrs, attrs...)
}
// AttributeSet returns the attributes added to the Labeler as an attribute.Set.
func (l *Labeler) AttributeSet() attribute.Set {
return attribute.NewSet(l.attrs...)
}
type labelerContextKey struct{}
// LabelerFromContext retrieves the Labeler from the provided context, if present.
//
// If no Labeler was found in the provided context a new, empty Labeler is returned and the second
// return value is false. In this case it is safe to use the Labeler but any attributes added to
// it will not be used.
func LabelerFromContext(ctx context.Context) (*Labeler, bool) {
if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok {
return l, true
}
return &Labeler{}, false
}
func contextWithLabeler(ctx context.Context, l *Labeler) context.Context {
return context.WithValue(ctx, labelerContextKey{}, l)
}

View file

@ -0,0 +1,10 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"github.com/ogen-go/ogen/middleware"
)
// Middleware is middleware type.
type Middleware = middleware.Middleware

View file

@ -0,0 +1,15 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
// OperationName is the ogen operation name
type OperationName = string
const (
GetSatellitesOperation OperationName = "GetSatellites"
GetStationsOperation OperationName = "GetStations"
GetSubscriptionsOperation OperationName = "GetSubscriptions"
SubscribeSatelliteOperation OperationName = "SubscribeSatellite"
SubscribeStationOperation OperationName = "SubscribeStation"
UnsubscribeOperation OperationName = "Unsubscribe"
)

View file

@ -0,0 +1,78 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"net/http"
"github.com/google/uuid"
"github.com/ogen-go/ogen/conv"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/uri"
)
// UnsubscribeParams is parameters of Unsubscribe operation.
type UnsubscribeParams struct {
ID OptUUID
}
func unpackUnsubscribeParams(packed middleware.Parameters) (params UnsubscribeParams) {
{
key := middleware.ParameterKey{
Name: "id",
In: "query",
}
if v, ok := packed[key]; ok {
params.ID = v.(OptUUID)
}
}
return params
}
func decodeUnsubscribeParams(args [0]string, argsEscaped bool, r *http.Request) (params UnsubscribeParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode query: id.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "id",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
var paramsDotIDVal uuid.UUID
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToUUID(val)
if err != nil {
return err
}
paramsDotIDVal = c
return nil
}(); err != nil {
return err
}
params.ID.SetTo(paramsDotIDVal)
return nil
}); err != nil {
return err
}
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "id",
In: "query",
Err: err,
}
}
return params, nil
}

View file

@ -0,0 +1,142 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"io"
"mime"
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"go.uber.org/multierr"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/validate"
)
func (s *Server) decodeSubscribeSatelliteRequest(r *http.Request) (
req *SubscribeSatelliteReq,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request SubscribeSatelliteReq
if err := func() error {
if err := request.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return req, close, err
}
return &request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeSubscribeStationRequest(r *http.Request) (
req *SubscribeStationReq,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request SubscribeStationReq
if err := func() error {
if err := request.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return req, close, err
}
return &request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}

View file

@ -0,0 +1,40 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"bytes"
"net/http"
"github.com/go-faster/jx"
ht "github.com/ogen-go/ogen/http"
)
func encodeSubscribeSatelliteRequest(
req *SubscribeSatelliteReq,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeSubscribeStationRequest(
req *SubscribeStationReq,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}

View file

@ -0,0 +1,508 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"io"
"mime"
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/validate"
)
func decodeGetSatellitesResponse(resp *http.Response) (res *GetSatellitesOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response GetSatellitesOK
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeGetStationsResponse(resp *http.Response) (res *GetStationsOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response GetStationsOK
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeGetSubscriptionsResponse(resp *http.Response) (res *GetSubscriptionsOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response GetSubscriptionsOK
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeSubscribeSatelliteResponse(resp *http.Response) (res *SubscribeSatelliteOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response SubscribeSatelliteOK
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeSubscribeStationResponse(resp *http.Response) (res *SubscribeStationOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response SubscribeStationOK
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeUnsubscribeResponse(resp *http.Response) (res *UnsubscribeOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
return &UnsubscribeOK{}, nil
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}

View file

@ -0,0 +1,118 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
)
func encodeGetSatellitesResponse(response *GetSatellitesOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeGetStationsResponse(response *GetStationsOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeGetSubscriptionsResponse(response *GetSubscriptionsOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeSubscribeSatelliteResponse(response *SubscribeSatelliteOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeSubscribeStationResponse(response *SubscribeStationOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeUnsubscribeResponse(response *UnsubscribeOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
return nil
}
func encodeErrorResponse(response *ErrorStatusCode, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
code := response.StatusCode
if code == 0 {
// Set default status code.
code = http.StatusOK
}
w.WriteHeader(code)
if st := http.StatusText(code); code >= http.StatusBadRequest {
span.SetStatus(codes.Error, st)
} else {
span.SetStatus(codes.Ok, st)
}
e := new(jx.Encoder)
response.Response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
if code >= http.StatusInternalServerError {
return errors.Wrapf(ht.ErrInternalServerErrorResponse, "code: %d, message: %s", code, http.StatusText(code))
}
return nil
}

396
pkg/rest/oas_router_gen.go Normal file
View file

@ -0,0 +1,396 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"net/http"
"net/url"
"strings"
"github.com/ogen-go/ogen/uri"
)
func (s *Server) cutPrefix(path string) (string, bool) {
prefix := s.cfg.Prefix
if prefix == "" {
return path, true
}
if !strings.HasPrefix(path, prefix) {
// Prefix doesn't match.
return "", false
}
// Cut prefix from the path.
return strings.TrimPrefix(path, prefix), true
}
// ServeHTTP serves http request as defined by OpenAPI v3 specification,
// calling handler that matches the path or returning not found error.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
elem := r.URL.Path
elemIsEscaped := false
if rawPath := r.URL.RawPath; rawPath != "" {
if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
elem = normalized
elemIsEscaped = strings.ContainsRune(elem, '%')
}
}
elem, ok := s.cutPrefix(elem)
if !ok || len(elem) == 0 {
s.notFound(w, r)
return
}
// Static code generated router with unwrapped path search.
switch {
default:
if len(elem) == 0 {
break
}
switch elem[0] {
case '/': // Prefix: "/s"
if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'a': // Prefix: "atellite"
if l := len("atellite"); len(elem) >= l && elem[0:l] == "atellite" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch r.Method {
case "GET":
s.handleGetSatellitesRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
}
return
}
switch elem[0] {
case '/': // Prefix: "/subscribe"
if l := len("/subscribe"); len(elem) >= l && elem[0:l] == "/subscribe" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleSubscribeSatelliteRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
}
case 't': // Prefix: "tation"
if l := len("tation"); len(elem) >= l && elem[0:l] == "tation" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch r.Method {
case "GET":
s.handleGetStationsRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
}
return
}
switch elem[0] {
case '/': // Prefix: "/subscribe"
if l := len("/subscribe"); len(elem) >= l && elem[0:l] == "/subscribe" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleSubscribeStationRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
}
case 'u': // Prefix: "ubscription"
if l := len("ubscription"); len(elem) >= l && elem[0:l] == "ubscription" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "DELETE":
s.handleUnsubscribeRequest([0]string{}, elemIsEscaped, w, r)
case "GET":
s.handleGetSubscriptionsRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "DELETE,GET")
}
return
}
}
}
}
s.notFound(w, r)
}
// Route is route object.
type Route struct {
name string
summary string
operationID string
pathPattern string
count int
args [0]string
}
// Name returns ogen operation name.
//
// It is guaranteed to be unique and not empty.
func (r Route) Name() string {
return r.name
}
// Summary returns OpenAPI summary.
func (r Route) Summary() string {
return r.summary
}
// OperationID returns OpenAPI operationId.
func (r Route) OperationID() string {
return r.operationID
}
// PathPattern returns OpenAPI path.
func (r Route) PathPattern() string {
return r.pathPattern
}
// Args returns parsed arguments.
func (r Route) Args() []string {
return r.args[:r.count]
}
// FindRoute finds Route for given method and path.
//
// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
func (s *Server) FindRoute(method, path string) (Route, bool) {
return s.FindPath(method, &url.URL{Path: path})
}
// FindPath finds Route for given method and URL.
func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
var (
elem = u.Path
args = r.args
)
if rawPath := u.RawPath; rawPath != "" {
if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
elem = normalized
}
defer func() {
for i, arg := range r.args[:r.count] {
if unescaped, err := url.PathUnescape(arg); err == nil {
r.args[i] = unescaped
}
}
}()
}
elem, ok := s.cutPrefix(elem)
if !ok {
return r, false
}
// Static code generated router with unwrapped path search.
switch {
default:
if len(elem) == 0 {
break
}
switch elem[0] {
case '/': // Prefix: "/s"
if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'a': // Prefix: "atellite"
if l := len("atellite"); len(elem) >= l && elem[0:l] == "atellite" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch method {
case "GET":
r.name = GetSatellitesOperation
r.summary = "Get available satellites"
r.operationID = "GetSatellites"
r.pathPattern = "/satellite"
r.args = args
r.count = 0
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/subscribe"
if l := len("/subscribe"); len(elem) >= l && elem[0:l] == "/subscribe" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = SubscribeSatelliteOperation
r.summary = "Subscribe to a given station"
r.operationID = "SubscribeSatellite"
r.pathPattern = "/satellite/subscribe"
r.args = args
r.count = 0
return r, true
default:
return
}
}
}
case 't': // Prefix: "tation"
if l := len("tation"); len(elem) >= l && elem[0:l] == "tation" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch method {
case "GET":
r.name = GetStationsOperation
r.summary = "Get available stations"
r.operationID = "GetStations"
r.pathPattern = "/station"
r.args = args
r.count = 0
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/subscribe"
if l := len("/subscribe"); len(elem) >= l && elem[0:l] == "/subscribe" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = SubscribeStationOperation
r.summary = "Subscribe to a given station"
r.operationID = "SubscribeStation"
r.pathPattern = "/station/subscribe"
r.args = args
r.count = 0
return r, true
default:
return
}
}
}
case 'u': // Prefix: "ubscription"
if l := len("ubscription"); len(elem) >= l && elem[0:l] == "ubscription" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "DELETE":
r.name = UnsubscribeOperation
r.summary = "Remove subscription by subscription ID"
r.operationID = "Unsubscribe"
r.pathPattern = "/subscription"
r.args = args
r.count = 0
return r, true
case "GET":
r.name = GetSubscriptionsOperation
r.summary = "Get current subscriptions"
r.operationID = "GetSubscriptions"
r.pathPattern = "/subscription"
r.args = args
r.count = 0
return r, true
default:
return
}
}
}
}
}
return r, false
}

519
pkg/rest/oas_schemas_gen.go Normal file
View file

@ -0,0 +1,519 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"fmt"
"time"
"github.com/go-faster/errors"
"github.com/google/uuid"
)
func (s *ErrorStatusCode) Error() string {
return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response)
}
// 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
}
// GetMessage returns the value of Message.
func (s *Error) GetMessage() string {
return s.Message
}
// SetCode sets the value of Code.
func (s *Error) SetCode(val int) {
s.Code = val
}
// SetMessage sets the value of Message.
func (s *Error) SetMessage(val string) {
s.Message = val
}
// ErrorStatusCode wraps Error with StatusCode.
type ErrorStatusCode struct {
StatusCode int
Response Error
}
// GetStatusCode returns the value of StatusCode.
func (s *ErrorStatusCode) GetStatusCode() int {
return s.StatusCode
}
// GetResponse returns the value of Response.
func (s *ErrorStatusCode) GetResponse() Error {
return s.Response
}
// SetStatusCode sets the value of StatusCode.
func (s *ErrorStatusCode) SetStatusCode(val int) {
s.StatusCode = val
}
// SetResponse sets the value of Response.
func (s *ErrorStatusCode) SetResponse(val Error) {
s.Response = val
}
type GetSatellitesOK struct {
Satellites []GetSatellitesOKSatellitesItem `json:"satellites"`
}
// GetSatellites returns the value of Satellites.
func (s *GetSatellitesOK) GetSatellites() []GetSatellitesOKSatellitesItem {
return s.Satellites
}
// SetSatellites sets the value of Satellites.
func (s *GetSatellitesOK) SetSatellites(val []GetSatellitesOKSatellitesItem) {
s.Satellites = val
}
type GetSatellitesOKSatellitesItem struct {
ID uuid.UUID `json:"id"`
DisplayName string `json:"display_name"`
Status GetSatellitesOKSatellitesItemStatus `json:"status"`
}
// GetID returns the value of ID.
func (s *GetSatellitesOKSatellitesItem) GetID() uuid.UUID {
return s.ID
}
// GetDisplayName returns the value of DisplayName.
func (s *GetSatellitesOKSatellitesItem) GetDisplayName() string {
return s.DisplayName
}
// GetStatus returns the value of Status.
func (s *GetSatellitesOKSatellitesItem) GetStatus() GetSatellitesOKSatellitesItemStatus {
return s.Status
}
// SetID sets the value of ID.
func (s *GetSatellitesOKSatellitesItem) SetID(val uuid.UUID) {
s.ID = val
}
// SetDisplayName sets the value of DisplayName.
func (s *GetSatellitesOKSatellitesItem) SetDisplayName(val string) {
s.DisplayName = val
}
// SetStatus sets the value of Status.
func (s *GetSatellitesOKSatellitesItem) SetStatus(val GetSatellitesOKSatellitesItemStatus) {
s.Status = val
}
type GetSatellitesOKSatellitesItemStatus string
const (
GetSatellitesOKSatellitesItemStatusActive GetSatellitesOKSatellitesItemStatus = "active"
GetSatellitesOKSatellitesItemStatusOffline GetSatellitesOKSatellitesItemStatus = "offline"
GetSatellitesOKSatellitesItemStatusBusy GetSatellitesOKSatellitesItemStatus = "busy"
)
// AllValues returns all GetSatellitesOKSatellitesItemStatus values.
func (GetSatellitesOKSatellitesItemStatus) AllValues() []GetSatellitesOKSatellitesItemStatus {
return []GetSatellitesOKSatellitesItemStatus{
GetSatellitesOKSatellitesItemStatusActive,
GetSatellitesOKSatellitesItemStatusOffline,
GetSatellitesOKSatellitesItemStatusBusy,
}
}
// MarshalText implements encoding.TextMarshaler.
func (s GetSatellitesOKSatellitesItemStatus) MarshalText() ([]byte, error) {
switch s {
case GetSatellitesOKSatellitesItemStatusActive:
return []byte(s), nil
case GetSatellitesOKSatellitesItemStatusOffline:
return []byte(s), nil
case GetSatellitesOKSatellitesItemStatusBusy:
return []byte(s), nil
default:
return nil, errors.Errorf("invalid value: %q", s)
}
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (s *GetSatellitesOKSatellitesItemStatus) UnmarshalText(data []byte) error {
switch GetSatellitesOKSatellitesItemStatus(data) {
case GetSatellitesOKSatellitesItemStatusActive:
*s = GetSatellitesOKSatellitesItemStatusActive
return nil
case GetSatellitesOKSatellitesItemStatusOffline:
*s = GetSatellitesOKSatellitesItemStatusOffline
return nil
case GetSatellitesOKSatellitesItemStatusBusy:
*s = GetSatellitesOKSatellitesItemStatusBusy
return nil
default:
return errors.Errorf("invalid value: %q", data)
}
}
type GetStationsOK struct {
Stations []GetStationsOKStationsItem `json:"stations"`
}
// GetStations returns the value of Stations.
func (s *GetStationsOK) GetStations() []GetStationsOKStationsItem {
return s.Stations
}
// SetStations sets the value of Stations.
func (s *GetStationsOK) SetStations(val []GetStationsOKStationsItem) {
s.Stations = val
}
type GetStationsOKStationsItem struct {
ID uuid.UUID `json:"id"`
Slug string `json:"slug"`
Status GetStationsOKStationsItemStatus `json:"status"`
}
// GetID returns the value of ID.
func (s *GetStationsOKStationsItem) GetID() uuid.UUID {
return s.ID
}
// GetSlug returns the value of Slug.
func (s *GetStationsOKStationsItem) GetSlug() string {
return s.Slug
}
// GetStatus returns the value of Status.
func (s *GetStationsOKStationsItem) GetStatus() GetStationsOKStationsItemStatus {
return s.Status
}
// SetID sets the value of ID.
func (s *GetStationsOKStationsItem) SetID(val uuid.UUID) {
s.ID = val
}
// SetSlug sets the value of Slug.
func (s *GetStationsOKStationsItem) SetSlug(val string) {
s.Slug = val
}
// SetStatus sets the value of Status.
func (s *GetStationsOKStationsItem) SetStatus(val GetStationsOKStationsItemStatus) {
s.Status = val
}
type GetStationsOKStationsItemStatus string
const (
GetStationsOKStationsItemStatusActive GetStationsOKStationsItemStatus = "active"
GetStationsOKStationsItemStatusOffline GetStationsOKStationsItemStatus = "offline"
GetStationsOKStationsItemStatusBusy GetStationsOKStationsItemStatus = "busy"
)
// AllValues returns all GetStationsOKStationsItemStatus values.
func (GetStationsOKStationsItemStatus) AllValues() []GetStationsOKStationsItemStatus {
return []GetStationsOKStationsItemStatus{
GetStationsOKStationsItemStatusActive,
GetStationsOKStationsItemStatusOffline,
GetStationsOKStationsItemStatusBusy,
}
}
// MarshalText implements encoding.TextMarshaler.
func (s GetStationsOKStationsItemStatus) MarshalText() ([]byte, error) {
switch s {
case GetStationsOKStationsItemStatusActive:
return []byte(s), nil
case GetStationsOKStationsItemStatusOffline:
return []byte(s), nil
case GetStationsOKStationsItemStatusBusy:
return []byte(s), nil
default:
return nil, errors.Errorf("invalid value: %q", s)
}
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (s *GetStationsOKStationsItemStatus) UnmarshalText(data []byte) error {
switch GetStationsOKStationsItemStatus(data) {
case GetStationsOKStationsItemStatusActive:
*s = GetStationsOKStationsItemStatusActive
return nil
case GetStationsOKStationsItemStatusOffline:
*s = GetStationsOKStationsItemStatusOffline
return nil
case GetStationsOKStationsItemStatusBusy:
*s = GetStationsOKStationsItemStatusBusy
return nil
default:
return errors.Errorf("invalid value: %q", data)
}
}
type GetSubscriptionsOK struct {
Subscriptions []GetSubscriptionsOKSubscriptionsItem `json:"subscriptions"`
}
// GetSubscriptions returns the value of Subscriptions.
func (s *GetSubscriptionsOK) GetSubscriptions() []GetSubscriptionsOKSubscriptionsItem {
return s.Subscriptions
}
// SetSubscriptions sets the value of Subscriptions.
func (s *GetSubscriptionsOK) SetSubscriptions(val []GetSubscriptionsOKSubscriptionsItem) {
s.Subscriptions = val
}
type GetSubscriptionsOKSubscriptionsItem struct {
ID uuid.UUID `json:"id"`
Type GetSubscriptionsOKSubscriptionsItemType `json:"type"`
Status GetSubscriptionsOKSubscriptionsItemStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
// GetID returns the value of ID.
func (s *GetSubscriptionsOKSubscriptionsItem) GetID() uuid.UUID {
return s.ID
}
// GetType returns the value of Type.
func (s *GetSubscriptionsOKSubscriptionsItem) GetType() GetSubscriptionsOKSubscriptionsItemType {
return s.Type
}
// GetStatus returns the value of Status.
func (s *GetSubscriptionsOKSubscriptionsItem) GetStatus() GetSubscriptionsOKSubscriptionsItemStatus {
return s.Status
}
// GetCreatedAt returns the value of CreatedAt.
func (s *GetSubscriptionsOKSubscriptionsItem) GetCreatedAt() time.Time {
return s.CreatedAt
}
// SetID sets the value of ID.
func (s *GetSubscriptionsOKSubscriptionsItem) SetID(val uuid.UUID) {
s.ID = val
}
// SetType sets the value of Type.
func (s *GetSubscriptionsOKSubscriptionsItem) SetType(val GetSubscriptionsOKSubscriptionsItemType) {
s.Type = val
}
// SetStatus sets the value of Status.
func (s *GetSubscriptionsOKSubscriptionsItem) SetStatus(val GetSubscriptionsOKSubscriptionsItemStatus) {
s.Status = val
}
// SetCreatedAt sets the value of CreatedAt.
func (s *GetSubscriptionsOKSubscriptionsItem) SetCreatedAt(val time.Time) {
s.CreatedAt = val
}
type GetSubscriptionsOKSubscriptionsItemStatus string
const (
GetSubscriptionsOKSubscriptionsItemStatusActive GetSubscriptionsOKSubscriptionsItemStatus = "active"
GetSubscriptionsOKSubscriptionsItemStatusOffline GetSubscriptionsOKSubscriptionsItemStatus = "offline"
GetSubscriptionsOKSubscriptionsItemStatusBusy GetSubscriptionsOKSubscriptionsItemStatus = "busy"
)
// AllValues returns all GetSubscriptionsOKSubscriptionsItemStatus values.
func (GetSubscriptionsOKSubscriptionsItemStatus) AllValues() []GetSubscriptionsOKSubscriptionsItemStatus {
return []GetSubscriptionsOKSubscriptionsItemStatus{
GetSubscriptionsOKSubscriptionsItemStatusActive,
GetSubscriptionsOKSubscriptionsItemStatusOffline,
GetSubscriptionsOKSubscriptionsItemStatusBusy,
}
}
// MarshalText implements encoding.TextMarshaler.
func (s GetSubscriptionsOKSubscriptionsItemStatus) MarshalText() ([]byte, error) {
switch s {
case GetSubscriptionsOKSubscriptionsItemStatusActive:
return []byte(s), nil
case GetSubscriptionsOKSubscriptionsItemStatusOffline:
return []byte(s), nil
case GetSubscriptionsOKSubscriptionsItemStatusBusy:
return []byte(s), nil
default:
return nil, errors.Errorf("invalid value: %q", s)
}
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (s *GetSubscriptionsOKSubscriptionsItemStatus) UnmarshalText(data []byte) error {
switch GetSubscriptionsOKSubscriptionsItemStatus(data) {
case GetSubscriptionsOKSubscriptionsItemStatusActive:
*s = GetSubscriptionsOKSubscriptionsItemStatusActive
return nil
case GetSubscriptionsOKSubscriptionsItemStatusOffline:
*s = GetSubscriptionsOKSubscriptionsItemStatusOffline
return nil
case GetSubscriptionsOKSubscriptionsItemStatusBusy:
*s = GetSubscriptionsOKSubscriptionsItemStatusBusy
return nil
default:
return errors.Errorf("invalid value: %q", data)
}
}
type GetSubscriptionsOKSubscriptionsItemType string
const (
GetSubscriptionsOKSubscriptionsItemTypeStation GetSubscriptionsOKSubscriptionsItemType = "station"
GetSubscriptionsOKSubscriptionsItemTypeSatellite GetSubscriptionsOKSubscriptionsItemType = "satellite"
)
// AllValues returns all GetSubscriptionsOKSubscriptionsItemType values.
func (GetSubscriptionsOKSubscriptionsItemType) AllValues() []GetSubscriptionsOKSubscriptionsItemType {
return []GetSubscriptionsOKSubscriptionsItemType{
GetSubscriptionsOKSubscriptionsItemTypeStation,
GetSubscriptionsOKSubscriptionsItemTypeSatellite,
}
}
// MarshalText implements encoding.TextMarshaler.
func (s GetSubscriptionsOKSubscriptionsItemType) MarshalText() ([]byte, error) {
switch s {
case GetSubscriptionsOKSubscriptionsItemTypeStation:
return []byte(s), nil
case GetSubscriptionsOKSubscriptionsItemTypeSatellite:
return []byte(s), nil
default:
return nil, errors.Errorf("invalid value: %q", s)
}
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (s *GetSubscriptionsOKSubscriptionsItemType) UnmarshalText(data []byte) error {
switch GetSubscriptionsOKSubscriptionsItemType(data) {
case GetSubscriptionsOKSubscriptionsItemTypeStation:
*s = GetSubscriptionsOKSubscriptionsItemTypeStation
return nil
case GetSubscriptionsOKSubscriptionsItemTypeSatellite:
*s = GetSubscriptionsOKSubscriptionsItemTypeSatellite
return nil
default:
return errors.Errorf("invalid value: %q", data)
}
}
// NewOptUUID returns new OptUUID with value set to v.
func NewOptUUID(v uuid.UUID) OptUUID {
return OptUUID{
Value: v,
Set: true,
}
}
// OptUUID is optional uuid.UUID.
type OptUUID struct {
Value uuid.UUID
Set bool
}
// IsSet returns true if OptUUID was set.
func (o OptUUID) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptUUID) Reset() {
var v uuid.UUID
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptUUID) SetTo(v uuid.UUID) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptUUID) Get() (v uuid.UUID, 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 OptUUID) Or(d uuid.UUID) uuid.UUID {
if v, ok := o.Get(); ok {
return v
}
return d
}
type SubscribeSatelliteOK struct {
ID uuid.UUID `json:"id"`
}
// GetID returns the value of ID.
func (s *SubscribeSatelliteOK) GetID() uuid.UUID {
return s.ID
}
// SetID sets the value of ID.
func (s *SubscribeSatelliteOK) SetID(val uuid.UUID) {
s.ID = val
}
type SubscribeSatelliteReq struct {
ID uuid.UUID `json:"id"`
}
// GetID returns the value of ID.
func (s *SubscribeSatelliteReq) GetID() uuid.UUID {
return s.ID
}
// SetID sets the value of ID.
func (s *SubscribeSatelliteReq) SetID(val uuid.UUID) {
s.ID = val
}
type SubscribeStationOK struct {
ID uuid.UUID `json:"id"`
}
// GetID returns the value of ID.
func (s *SubscribeStationOK) GetID() uuid.UUID {
return s.ID
}
// SetID sets the value of ID.
func (s *SubscribeStationOK) SetID(val uuid.UUID) {
s.ID = val
}
type SubscribeStationReq struct {
// Subscription ID.
ID uuid.UUID `json:"id"`
}
// GetID returns the value of ID.
func (s *SubscribeStationReq) GetID() uuid.UUID {
return s.ID
}
// SetID sets the value of ID.
func (s *SubscribeStationReq) SetID(val uuid.UUID) {
s.ID = val
}
// UnsubscribeOK is response for Unsubscribe operation.
type UnsubscribeOK struct{}

View file

@ -0,0 +1,70 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"context"
)
// Handler handles operations described by OpenAPI v3 specification.
type Handler interface {
// GetSatellites implements GetSatellites operation.
//
// Get available satellites.
//
// GET /satellite
GetSatellites(ctx context.Context) (*GetSatellitesOK, error)
// GetStations implements GetStations operation.
//
// Get available stations.
//
// GET /station
GetStations(ctx context.Context) (*GetStationsOK, error)
// GetSubscriptions implements GetSubscriptions operation.
//
// Get current subscriptions.
//
// GET /subscription
GetSubscriptions(ctx context.Context) (*GetSubscriptionsOK, error)
// SubscribeSatellite implements SubscribeSatellite operation.
//
// Subscribe to a given station.
//
// POST /satellite/subscribe
SubscribeSatellite(ctx context.Context, req *SubscribeSatelliteReq) (*SubscribeSatelliteOK, error)
// SubscribeStation implements SubscribeStation operation.
//
// Subscribe to a given station.
//
// POST /station/subscribe
SubscribeStation(ctx context.Context, req *SubscribeStationReq) (*SubscribeStationOK, error)
// Unsubscribe implements Unsubscribe operation.
//
// Remove subscription by subscription ID.
//
// DELETE /subscription
Unsubscribe(ctx context.Context, params UnsubscribeParams) error
// NewError creates *ErrorStatusCode from error returned by handler.
//
// Used for common default response.
NewError(ctx context.Context, err error) *ErrorStatusCode
}
// Server implements http server based on OpenAPI v3 specification and
// calls Handler to handle requests.
type Server struct {
h Handler
baseServer
}
// NewServer creates new Server.
func NewServer(h Handler, opts ...ServerOption) (*Server, error) {
s, err := newServerConfig(opts...).baseServer()
if err != nil {
return nil, err
}
return &Server{
h: h,
baseServer: s,
}, nil
}

View file

@ -0,0 +1,76 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"context"
ht "github.com/ogen-go/ogen/http"
)
// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented.
type UnimplementedHandler struct{}
var _ Handler = UnimplementedHandler{}
// GetSatellites implements GetSatellites operation.
//
// Get available satellites.
//
// GET /satellite
func (UnimplementedHandler) GetSatellites(ctx context.Context) (r *GetSatellitesOK, _ error) {
return r, ht.ErrNotImplemented
}
// GetStations implements GetStations operation.
//
// Get available stations.
//
// GET /station
func (UnimplementedHandler) GetStations(ctx context.Context) (r *GetStationsOK, _ error) {
return r, ht.ErrNotImplemented
}
// GetSubscriptions implements GetSubscriptions operation.
//
// Get current subscriptions.
//
// GET /subscription
func (UnimplementedHandler) GetSubscriptions(ctx context.Context) (r *GetSubscriptionsOK, _ error) {
return r, ht.ErrNotImplemented
}
// SubscribeSatellite implements SubscribeSatellite operation.
//
// Subscribe to a given station.
//
// POST /satellite/subscribe
func (UnimplementedHandler) SubscribeSatellite(ctx context.Context, req *SubscribeSatelliteReq) (r *SubscribeSatelliteOK, _ error) {
return r, ht.ErrNotImplemented
}
// SubscribeStation implements SubscribeStation operation.
//
// Subscribe to a given station.
//
// POST /station/subscribe
func (UnimplementedHandler) SubscribeStation(ctx context.Context, req *SubscribeStationReq) (r *SubscribeStationOK, _ error) {
return r, ht.ErrNotImplemented
}
// Unsubscribe implements Unsubscribe operation.
//
// Remove subscription by subscription ID.
//
// DELETE /subscription
func (UnimplementedHandler) Unsubscribe(ctx context.Context, params UnsubscribeParams) error {
return ht.ErrNotImplemented
}
// NewError creates *ErrorStatusCode from error returned by handler.
//
// Used for common default response.
func (UnimplementedHandler) NewError(ctx context.Context, err error) (r *ErrorStatusCode) {
r = new(ErrorStatusCode)
return r
}

View file

@ -0,0 +1,258 @@
// Code generated by ogen, DO NOT EDIT.
package gsn
import (
"fmt"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/validate"
)
func (s *GetSatellitesOK) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
var failures []validate.FieldError
for i, elem := range s.Satellites {
if err := func() error {
if err := elem.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: fmt.Sprintf("[%d]", i),
Error: err,
})
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "satellites",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *GetSatellitesOKSatellitesItem) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := s.Status.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "status",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s GetSatellitesOKSatellitesItemStatus) Validate() error {
switch s {
case "active":
return nil
case "offline":
return nil
case "busy":
return nil
default:
return errors.Errorf("invalid value: %v", s)
}
}
func (s *GetStationsOK) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if s.Stations == nil {
return errors.New("nil is invalid value")
}
var failures []validate.FieldError
for i, elem := range s.Stations {
if err := func() error {
if err := elem.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: fmt.Sprintf("[%d]", i),
Error: err,
})
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "stations",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *GetStationsOKStationsItem) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := s.Status.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "status",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s GetStationsOKStationsItemStatus) Validate() error {
switch s {
case "active":
return nil
case "offline":
return nil
case "busy":
return nil
default:
return errors.Errorf("invalid value: %v", s)
}
}
func (s *GetSubscriptionsOK) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if s.Subscriptions == nil {
return errors.New("nil is invalid value")
}
var failures []validate.FieldError
for i, elem := range s.Subscriptions {
if err := func() error {
if err := elem.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: fmt.Sprintf("[%d]", i),
Error: err,
})
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "subscriptions",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *GetSubscriptionsOKSubscriptionsItem) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := s.Type.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "type",
Error: err,
})
}
if err := func() error {
if err := s.Status.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "status",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s GetSubscriptionsOKSubscriptionsItemStatus) Validate() error {
switch s {
case "active":
return nil
case "offline":
return nil
case "busy":
return nil
default:
return errors.Errorf("invalid value: %v", s)
}
}
func (s GetSubscriptionsOKSubscriptionsItemType) Validate() error {
switch s {
case "station":
return nil
case "satellite":
return nil
default:
return errors.Errorf("invalid value: %v", s)
}
}