app: added one api connection between backend and frontend

This commit is contained in:
Tigor Hutasuhut 2024-08-06 22:13:37 +07:00
parent efd2b6b187
commit 261361e5a7
15 changed files with 211 additions and 9 deletions

View file

@ -8,6 +8,13 @@ export GOOSE_MIGRATION_DIR ?= schemas/migrations
build: generate-go generate-web build: generate-go generate-web
go build -o bin/bluemage ./go/cmd/bluemage/main.go go build -o bin/bluemage ./go/cmd/bluemage/main.go
run: build
ARGS=$${ARGS:-serve}
./bin/bluemage $$ARGS
run-web: generate-web
cd web && npm run dev
generate-go: migrate generate-go: migrate
rm -rf go/gen rm -rf go/gen
(cd ./schemas/proto && buf generate --template buf.gen.go.yaml .) (cd ./schemas/proto && buf generate --template buf.gen.go.yaml .)

6
go.mod
View file

@ -5,11 +5,15 @@ go 1.22.5
require ( require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2
connectrpc.com/connect v1.16.2 connectrpc.com/connect v1.16.2
connectrpc.com/cors v0.1.0
github.com/aarondl/opt v0.0.0-20240623220848-083f18ab9536 github.com/aarondl/opt v0.0.0-20240623220848-083f18ab9536
github.com/bufbuild/protovalidate-go v0.6.3 github.com/bufbuild/protovalidate-go v0.6.3
github.com/jaswdr/faker/v2 v2.3.0 github.com/jaswdr/faker/v2 v2.3.0
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16
github.com/rs/cors v1.11.0
github.com/spf13/cobra v1.8.1
github.com/stephenafamo/bob v0.28.1 github.com/stephenafamo/bob v0.28.1
golang.org/x/net v0.23.0
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
) )
@ -17,7 +21,9 @@ require (
github.com/aarondl/json v0.0.0-20221020222930-8b0db17ef1bf // indirect github.com/aarondl/json v0.0.0-20221020222930-8b0db17ef1bf // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/google/cel-go v0.20.1 // indirect github.com/google/cel-go v0.20.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stephenafamo/scan v0.4.2 // indirect github.com/stephenafamo/scan v0.4.2 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect

16
go.sum
View file

@ -2,6 +2,8 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-2024071716455
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2/go.mod h1:ylS4c28ACSI59oJrOdW4pHS4n0Hw4TgSPHn8rpHl4Yw= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2/go.mod h1:ylS4c28ACSI59oJrOdW4pHS4n0Hw4TgSPHn8rpHl4Yw=
connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE=
connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc=
connectrpc.com/cors v0.1.0 h1:f3gTXJyDZPrDIZCQ567jxfD9PAIpopHiRDnJRt3QuOQ=
connectrpc.com/cors v0.1.0/go.mod h1:v8SJZCPfHtGH1zsm+Ttajpozd4cYIUryl4dFB6QEpfg=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
@ -18,6 +20,7 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZdSUWRY7Fv0= github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZdSUWRY7Fv0=
github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U= github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -37,6 +40,8 @@ github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jaswdr/faker/v2 v2.3.0 h1:jgQ9UmU2Eb5tSQ8JkUS4tPoyTM2OtThQpOpwk7Fa9RY= github.com/jaswdr/faker/v2 v2.3.0 h1:jgQ9UmU2Eb5tSQ8JkUS4tPoyTM2OtThQpOpwk7Fa9RY=
github.com/jaswdr/faker/v2 v2.3.0/go.mod h1:ROK8xwQV0hYOLDUtxCQgHGcl10jbVzIvqHxcIDdwY2Q= github.com/jaswdr/faker/v2 v2.3.0/go.mod h1:ROK8xwQV0hYOLDUtxCQgHGcl10jbVzIvqHxcIDdwY2Q=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
@ -63,10 +68,17 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc=
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stephenafamo/bob v0.28.1 h1:yQaHuhP9HoCldoRIrhB7SwcHKMCCSw5499h7ETFcBLs= github.com/stephenafamo/bob v0.28.1 h1:yQaHuhP9HoCldoRIrhB7SwcHKMCCSw5499h7ETFcBLs=
github.com/stephenafamo/bob v0.28.1/go.mod h1:S/D3dAbBZjBOcts9iv4ywsJDApFK86s3bUBulCoT6kE= github.com/stephenafamo/bob v0.28.1/go.mod h1:S/D3dAbBZjBOcts9iv4ywsJDApFK86s3bUBulCoT6kE=
github.com/stephenafamo/fakedb v0.0.0-20221230081958-0b86f816ed97 h1:XItoZNmhOih06TC02jK7l3wlpZ0XT/sPQYutDcGOQjg= github.com/stephenafamo/fakedb v0.0.0-20221230081958-0b86f816ed97 h1:XItoZNmhOih06TC02jK7l3wlpZ0XT/sPQYutDcGOQjg=
@ -90,8 +102,8 @@ github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwv
github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA=
github.com/volatiletech/strmangle v0.0.6 h1:AdOYE3B2ygRDq4rXDij/MMwq6KVK/pWAYxpC7CLrkKQ= github.com/volatiletech/strmangle v0.0.6 h1:AdOYE3B2ygRDq4rXDij/MMwq6KVK/pWAYxpC7CLrkKQ=
github.com/volatiletech/strmangle v0.0.6/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0= github.com/volatiletech/strmangle v0.0.6/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=

View file

@ -8,7 +8,7 @@ import (
type API struct { type API struct {
mu sync.Mutex mu sync.Mutex
db bob.Executor DB bob.Executor
} }
func (api *API) lockf(f func()) { func (api *API) lockf(f func()) {

View file

@ -15,7 +15,7 @@ import (
func (api *API) DevicesCreate(ctx context.Context, params *models.Device) (device *models.Device, err error) { func (api *API) DevicesCreate(ctx context.Context, params *models.Device) (device *models.Device, err error) {
now := time.Now() now := time.Now()
api.lockf(func() { api.lockf(func() {
device, err = models.Devices.Insert(ctx, api.db, &models.DeviceSetter{ device, err = models.Devices.Insert(ctx, api.DB, &models.DeviceSetter{
Slug: omit.From(params.Slug), Slug: omit.From(params.Slug),
Name: omit.From(params.Name), Name: omit.From(params.Name),
ResolutionX: omit.From(params.ResolutionX), ResolutionX: omit.From(params.ResolutionX),

View file

@ -9,7 +9,7 @@ import (
) )
func (api *API) GetDevice(ctx context.Context, slug string) (device *models.Device, err error) { func (api *API) GetDevice(ctx context.Context, slug string) (device *models.Device, err error) {
device, err = models.FindDevice(ctx, api.db, slug) device, err = models.FindDevice(ctx, api.DB, slug)
if err != nil { if err != nil {
if err.Error() == "sql: no rows in result set" { if err.Error() == "sql: no rows in result set" {
return device, errs.Wrapw(err, "device not found", "slug", slug).Code(connect.CodeNotFound) return device, errs.Wrapw(err, "device not found", "slug", slug).Code(connect.CodeNotFound)

View file

@ -1,7 +1,28 @@
package main package main
import "time" import (
"context"
"os"
"os/signal"
"github.com/spf13/cobra"
"github.com/tigorlazuardi/bluemage/go/cmd/bluemage/serve"
)
var Cmd = &cobra.Command{
Use: "bluemage",
Short: "Bluemage is a reddit image downloader",
}
func init() {
Cmd.AddCommand(serve.Cmd)
}
func main() { func main() {
time.Now().Unix() ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
if err := Cmd.ExecuteContext(ctx); err != nil {
os.Exit(1)
}
} }

View file

@ -0,0 +1,63 @@
package serve
import (
"context"
"errors"
"log/slog"
"net/http"
"time"
"connectrpc.com/connect"
"github.com/spf13/cobra"
"github.com/stephenafamo/bob"
"github.com/tigorlazuardi/bluemage/go/api"
"github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1/v1connect"
"github.com/tigorlazuardi/bluemage/go/pkg/errs"
"github.com/tigorlazuardi/bluemage/go/server"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
var Cmd = &cobra.Command{
Use: "serve",
RunE: func(cmd *cobra.Command, args []string) error {
db, err := bob.Open("sqlite3", "file:go/data.db")
if err != nil {
return errs.Wrap(err, "failed to open database")
}
api := &api.API{
DB: db,
}
handler := &server.Server{
DeviceHandler: server.DeviceHandler{
API: api,
},
}
mux := http.NewServeMux()
mux.Handle(v1connect.NewDeviceServiceHandler(handler, connect.WithInterceptors(server.LogInterceptor())))
server := &http.Server{
Addr: ":8080",
Handler: h2c.NewHandler(server.WithCORS(mux), &http2.Server{}),
}
go func() {
<-cmd.Context().Done()
slog.Info("Exit signal received. Shutting down server")
shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
_ = server.Shutdown(shutdownCtx)
}()
slog.Info("ConnectRPC server started", "addr", server.Addr)
err = server.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
return errs.Wrap(err, "failed to serve")
}
return errors.Join(db.Close())
},
SilenceUsage: true,
}

View file

@ -229,3 +229,11 @@ func FindError(err error) Error {
return nil return nil
} }
} }
func DrillToError(err error) error {
e := FindError(err)
if e != nil {
return e
}
return err
}

21
go/server/cors.go Normal file
View file

@ -0,0 +1,21 @@
package server
import (
"net/http"
connectcors "connectrpc.com/cors"
"github.com/rs/cors"
)
// WithCORS adds CORS support to a Connect HTTP handler.
func WithCORS(h http.Handler) http.Handler {
middleware := cors.New(cors.Options{
// TODO: AllowedOrigins will need to be limited when
// the client is embedded to the binary.
AllowedOrigins: []string{"*"},
AllowedMethods: connectcors.AllowedMethods(),
AllowedHeaders: connectcors.AllowedHeaders(),
ExposedHeaders: connectcors.ExposedHeaders(),
})
return middleware.Handler(h)
}

39
go/server/interceptor.go Normal file
View file

@ -0,0 +1,39 @@
package server
import (
"context"
"fmt"
"log/slog"
"time"
"connectrpc.com/connect"
"github.com/tigorlazuardi/bluemage/go/pkg/errs"
)
func LogInterceptor() connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, ar connect.AnyRequest) (connect.AnyResponse, error) {
start := time.Now()
resp, err := next(ctx, ar)
dur := time.Since(start)
millisecondsFloat := float64(dur) / float64(time.Millisecond)
if err != nil {
slog.Error("RPC Error",
"procedure", ar.Spec().Procedure,
"method", ar.HTTPMethod(),
"duration", fmt.Sprintf("%.3fs", millisecondsFloat),
"error", errs.DrillToError(err),
)
} else {
slog.Info("RPC Call",
"procedure", ar.Spec().Procedure,
"method", ar.HTTPMethod(),
"duration", fmt.Sprintf("%.3fs", millisecondsFloat),
)
}
return resp, err
}
}
return connect.UnaryInterceptorFunc(interceptor)
}

View file

@ -1,8 +1,8 @@
version: v2 version: v2
plugins: plugins:
- local: protoc-gen-es - local: protoc-gen-es
out: ../../web/gen/proto out: ../../web/src/gen/proto
opt: target=ts opt: target=ts
- local: protoc-gen-connect-es - local: protoc-gen-connect-es
out: ../../web/gen/proto out: ../../web/src/gen/proto
opt: target=ts opt: target=ts

1
web/.env Normal file
View file

@ -0,0 +1 @@
VITE_BLUEMAGE_API_URL=http://localhost:8080

View file

@ -2,6 +2,13 @@
import svelteLogo from './assets/svelte.svg' import svelteLogo from './assets/svelte.svg'
import viteLogo from '/vite.svg' import viteLogo from '/vite.svg'
import Counter from './lib/Counter.svelte' import Counter from './lib/Counter.svelte'
import { client } from './client/client';
function getDevice() {
return client.getDevice({slug: 'test'})
}
let promise = getDevice()
</script> </script>
<main> <main>
@ -26,6 +33,14 @@
<p class="read-the-docs"> <p class="read-the-docs">
Click on the Vite and Svelte logos to learn more Click on the Vite and Svelte logos to learn more
</p> </p>
{#await promise}
<p>loading...</p>
{:then device}
<p>{device.name}</p>
{:catch error}
<p>{error.message}</p>
{/await}
</main> </main>
<style> <style>

9
web/src/client/client.ts Normal file
View file

@ -0,0 +1,9 @@
import { createPromiseClient } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import { DeviceService } from "../gen/proto/device/v1/device_connect";
const transport = createConnectTransport({
baseUrl: import.meta.env.VITE_BLUEMAGE_API_URL,
});
export const client = createPromiseClient(DeviceService, transport);