initial commit

This commit is contained in:
Arnaud Delcasse 2025-04-29 06:31:39 +02:00
commit 5f63e312c9
19 changed files with 1458 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
config.yaml
.env
.vscode
__debug_bin

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
FROM git.coopgo.io/coopgo-platform/libvalhalla-go:main AS builder
# Install Golang
RUN curl -LO https://go.dev/dl/go1.23.4.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
ARG ACCESS_TOKEN_USR="nothing"
ARG ACCESS_TOKEN_PWD="nothing"
RUN printf "machine git.coopgo.io\n\
login ${ACCESS_TOKEN_USR}\n\
password ${ACCESS_TOKEN_PWD}\n"\
>> ~/.netrc
RUN chmod 600 ~/.netrc
RUN ls .
COPY . .
ENV PATH=$PATH:/usr/local/go/bin
RUN go mod download & CGO_ENABLED=1 go build -o /server
#RUN go build -a -ldflags "-linkmode external -extldflags '-static' -s -w" -o /server
#RUN go mod download & CGO_ENABLED=1 GOOS=linux go build -x -ldflags '-extldflags "-L/usr/local/lib/"' -o /server
FROM alpine:latest
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /usr/local/lib/libvalhalla-go.so /usr/local/lib
COPY --from=builder /server /
EXPOSE 8080
ENTRYPOINT ["/server"]

17
README.md Normal file
View File

@ -0,0 +1,17 @@
# COOPGO multimodal routing service
COOPGO Multimodal routing service handles routing through different mobility modes :
- [X] Public transit
- [X] Carpool
- [X] Walking
- [X] Driving
## Notes on public transit
Public transit routing is built with [Valhalla](https://github.com/valhalla/valhalla) routing engine. In the future, we may implement our own.
Valhalla C++ library (libvalhalla.so) is embedded within Go using the CGO.
Bindings are available in [libs/transit/valhalla/bindings](libs/transit/valhalla/bindings). This is largely inspired by [https://github.com/pufferffish/valhalla-go](https://github.com/pufferffish/valhalla-go), except that we build with Docker and integrate it directly within the project.

41
config.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"strings"
"github.com/spf13/viper"
)
func ReadConfig() (*viper.Viper, error) {
defaults := map[string]any{
"name": "COOPGO Multimodal Routing",
"dev_env": false,
"modes": map[string]any{
"carpool": map[string]any{
"enabled": true,
"operators": []map[string]any{},
},
},
"services": map[string]any{
"grpc": map[string]any{
"enable": true,
"port": 8080,
},
"http": map[string]any{
"enable": false,
"port": 80,
},
},
}
v := viper.New()
for key, value := range defaults {
v.SetDefault(key, value)
}
v.SetConfigName("config")
v.AddConfigPath(".")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.AutomaticEnv()
err := v.ReadInConfig()
return v, err
}

43
go.mod Normal file
View File

@ -0,0 +1,43 @@
module git.coopgo.io/coopgo-platform/multimodal-routing
go 1.23.3
require (
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20240919052743-201e803c6a4e // indirect
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230164352-d46c349d51d7 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/schema v1.2.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/paulmach/orb v0.9.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.mongodb.org/mongo-driver v1.11.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/grpc v1.68.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

165
go.sum Normal file
View File

@ -0,0 +1,165 @@
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20240919052743-201e803c6a4e h1:grG21iRInke5CjRyHs9I+38ZVeDXRG82xB654+vqeVc=
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20240919052743-201e803c6a4e/go.mod h1:c9aJwNtY4PJuqAFYZ9afnx46UAZtWJ3P8ICZM02/DBA=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230105518-1d3838339ae6 h1:8vCeARJDo7GUhN4wLiQQeKETssGpjhewMnPuzhZfFE4=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230105518-1d3838339ae6/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230113846-3c63ee618ed8 h1:DlPSwmrt805bn506sL7BVH382QNSuJIl1SCsGE3i754=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230113846-3c63ee618ed8/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230132247-cad8e7ac3e3f h1:PPQmjthw6QrPjCHifbNj+ePC1nWkKUVulzK1+Nqofa4=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230132247-cad8e7ac3e3f/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230143710-0139ebdf72ce h1:XTsveayxA6DPtDWkTYdSCCYaCEBxi9rbdclZgfyPSrw=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230143710-0139ebdf72ce/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230161647-11405e2a9959 h1:GmWcNby1OTaKUnmayrBtvFHkQIvAbgNYdlYtLBsU/ck=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230161647-11405e2a9959/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230163259-b858b0fb1932 h1:W644/JN5JdS2HZWX1wFsR2PsFc2zlaB5ET1x80/l4ds=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230163259-b858b0fb1932/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230164352-d46c349d51d7 h1:yPiQrN0BxU+tLsDKojZv3sI/A3RtnrSd7hOJhBHZyqg=
git.coopgo.io/coopgo-platform/libvalhalla-go v0.0.0-20241230164352-d46c349d51d7/go.mod h1:VH5hNBKEZQlr1cgFd7sDMh9iGtoaINbyDmT++sUkTx0=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/paulmach/orb v0.9.0 h1:MwA1DqOKtvCgm7u9RZ/pnYejTeDJPnr0+0oFajBbJqk=
github.com/paulmach/orb v0.9.0/go.mod h1:SudmOk85SXtmXAB3sLGyJ6tZy/8pdfrV0o6ef98Xc30=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
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/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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=

103
handlers/carpool.go Normal file
View File

@ -0,0 +1,103 @@
package handlers
import (
"errors"
"fmt"
"sync"
"time"
"git.coopgo.io/coopgo-platform/multimodal-routing/libs/carpool"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
type CarpoolRoutingHandler struct {
OperatorAPIs []carpool.CarpoolOperatorAPI
}
func NewCarpoolRoutingHandler(cfg *viper.Viper) (*CarpoolRoutingHandler, error) {
operatorApis := []carpool.CarpoolOperatorAPI{}
operators := cfg.Get("operators").([]any)
for _, operator := range operators {
o := operator.(map[string]any)
operatorType, ok := o["type"].(string)
if !ok {
return nil, errors.New("missing operator type")
}
if operatorType == "blablacardaily" {
operatorId, ok := o["operator_id"].(string)
if !ok {
return nil, errors.New("missing operator_id")
}
apiKey, ok := o["api_key"].(string)
if !ok {
return nil, errors.New("missing api_key")
}
baseUrl, ok := o["base_url"].(string)
if !ok {
return nil, errors.New("missing base_url")
}
operatorapi, err := carpool.NewBBCDailyCarpoolAPI(operatorId, apiKey, baseUrl)
if err != nil {
return nil, fmt.Errorf("could not create Blablacar Daily API: %w", err)
}
operatorApis = append(operatorApis, operatorapi)
}
}
return &CarpoolRoutingHandler{
OperatorAPIs: operatorApis,
}, nil
}
// TODO add options (WithTimeDelta, etc...)
func (h CarpoolRoutingHandler) Search(results chan *geojson.FeatureCollection, wg *sync.WaitGroup, departure geojson.Feature, destination geojson.Feature, departureDate time.Time) error {
defer wg.Done()
defaultTimeDelta := 3600 * time.Second
defaultDepartureRadius := int64(10)
defaultDestinationRadius := int64(10)
defaultCount := int64(10)
var wg2 sync.WaitGroup
for _, api := range h.OperatorAPIs {
wg2.Add(1)
go func(results chan *geojson.FeatureCollection, wg2 *sync.WaitGroup) {
defer wg2.Done()
r, err := api.GetDriverJourneys(departure.Point().Lat(), departure.Point().Lon(), destination.Point().Lat(), destination.Point().Lon(), departureDate, &defaultTimeDelta, defaultDepartureRadius, defaultDestinationRadius, defaultCount)
if err != nil {
log.Error().Err(err).Str("operator", api.GetOperatorId()).Msg("error in carpool api request")
}
for _, journey := range r {
// Departure
geo := geojson.NewFeatureCollection()
dep := geojson.NewFeature(orb.Point{journey.PassengerPickupLng, journey.PassengerPickupLat})
dep.Properties["type"] = "departure"
dep.Properties["label"] = journey.PassengerPickupAddress
// TODO Polyline to GeoJSON LineString
// Destination
dest := geojson.NewFeature(orb.Point{journey.PassengerDropLng, journey.PassengerDropLat})
dest.Properties["type"] = "destination"
dest.Properties["label"] = journey.PassengerDropAddress
// Carpool GeoJSON definition
geo.Features = append(geo.Features, dep)
geo.Features = append(geo.Features, dest)
geo.ExtraMembers = geojson.Properties{
"journey_type": "carpool",
"ocss": journey,
}
results <- geo
}
}(results, &wg2)
}
wg2.Wait()
return nil
}

47
handlers/handlers.go Normal file
View File

@ -0,0 +1,47 @@
package handlers
import (
"fmt"
"sync"
"time"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
type MultimodalRoutingHandler struct {
Carpool *CarpoolRoutingHandler
}
func NewMultimodalRoutingHandler(cfg *viper.Viper) (*MultimodalRoutingHandler, error) {
carpoolHandler, err := NewCarpoolRoutingHandler(cfg.Sub("carpool"))
if err != nil {
return nil, fmt.Errorf("could not initialize carpool handler : %w", err)
}
return &MultimodalRoutingHandler{
Carpool: carpoolHandler,
}, nil
}
func (h *MultimodalRoutingHandler) Search(departure geojson.Feature, destination geojson.Feature, departureDate time.Time) ([]*geojson.FeatureCollection, error) {
ch := make(chan *geojson.FeatureCollection)
journeys := []*geojson.FeatureCollection{}
var wg sync.WaitGroup
// Carpool
wg.Add(1)
go h.Carpool.Search(ch, &wg, departure, destination, departureDate)
go func() {
wg.Wait()
close(ch)
}()
for journey := range ch {
log.Debug().Any("journey", journey).Msg("Received from channel")
journeys = append(journeys, journey)
}
return journeys, nil
}

29
handlers/transit.go Normal file
View File

@ -0,0 +1,29 @@
package handlers
// import (
// "sync"
// "time"
//
// "git.coopgo.io/coopgo-platform/multimodal-routing/libs/transit"
// "github.com/paulmach/orb/geojson"
// "github.com/spf13/viper"
// )
//
// type TransitHandler struct {
// Routing *transit.TransitRouting
// }
//
// func NewTransitHandler(cfg *viper.Viper) (*TransitHandler, error) {
// routing, err := transit.NewTransitRouting(cfg)
// if err != nil {
// return nil, err
// }
// return &TransitHandler{
// Routing: routing,
// }, nil
// }
//
// func (h TransitHandler) Search(results chan *geojson.FeatureCollection, wg *sync.WaitGroup, departure geojson.Feature, destination geojson.Feature, departureDate time.Time) error {
// defer wg.Done()
// return nil
// }

View File

@ -0,0 +1,192 @@
package carpool
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"time"
"git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
)
type BBCDailyCarpoolAPI struct {
OperatorId string
APIKey string
BaseURL string
}
func NewBBCDailyCarpoolAPI(operatorId string, api_key string, baseURL string) (*BBCDailyCarpoolAPI, error) {
return &BBCDailyCarpoolAPI{
OperatorId: operatorId,
APIKey: api_key,
BaseURL: baseURL,
}, nil
}
type BBCDailyResult struct {
ID *string `json:"id"`
Duration *time.Duration `json:"duration"`
Distance *int64 `json:"distance"`
PickupLatitude *float64 `json:"pickup_latitude"`
PickupLongitude *float64 `json:"pickup_longitude"`
PickupDatetime time.Time `json:"pickup_datetime"`
DropoffLatitude *float64 `json:"dropoff_latitude"`
DropoffLongitude *float64 `json:"dropoff_longitude"`
DropoffDatetime *string `json:"dropoff_datetime"`
WebURL *string `json:"web_url"`
DepartureToPickupWalkingTime *time.Duration `json:"departure_to_pickup_walking_time"`
DropoffToArrivalWalkingTime *time.Duration `json:"dropoff_to_arrival_walking_time"`
JourneyPolyline *string `json:"journey_polyline"`
Price *struct {
Currency string `json:"currency"`
Amount float64 `json:"amount"`
} `json:"price"`
AvailableSeats *int64 `json:"available_seats"`
}
func (api *BBCDailyCarpoolAPI) GetOperatorId() string {
return api.OperatorId
}
func (api *BBCDailyCarpoolAPI) GetDriverJourneys(
departureLat float64,
departureLng float64,
arrivalLat float64,
arrivalLng float64,
departureDate time.Time,
timeDelta *time.Duration,
departureRadius int64,
arrivalRadius int64,
count int64,
) ([]ocss.DriverJourney, error) {
td := 1 * time.Hour
if timeDelta != nil {
td = *timeDelta
}
results, err := blablacarDailySearch(
api.BaseURL+"/search",
api.APIKey,
departureLat,
departureLng,
arrivalLat,
arrivalLng,
departureDate,
td,
)
if err != nil {
log.Error().Err(err).Msg("error in blablacarDailySearch")
return nil, err
}
journeys := []ocss.DriverJourney{}
for _, r := range results {
var price *ocss.Price
if r.Price != nil {
paying := ocss.Paying
price = &ocss.Price{
Type: &paying,
Amount: &r.Price.Amount,
Currency: &r.Price.Currency,
}
}
driverJourney := ocss.DriverJourney{
DriverTrip: ocss.DriverTrip{
Driver: ocss.User{
ID: uuid.NewString(),
Operator: api.OperatorId,
Alias: "Utilisateur BlablacarDaily",
},
DepartureToPickupWalkingDuration: r.DepartureToPickupWalkingTime,
DropoffToArrivalWalkingDuration: r.DropoffToArrivalWalkingTime,
Trip: ocss.Trip{
Operator: api.OperatorId,
PassengerPickupLat: nilCheck(r.PickupLatitude),
PassengerPickupLng: nilCheck(r.PickupLongitude),
PassengerDropLat: nilCheck(r.DropoffLatitude),
PassengerDropLng: nilCheck(r.DropoffLongitude),
Duration: nilCheck(r.Duration),
Distance: r.Distance,
JourneyPolyline: r.JourneyPolyline,
},
},
JourneySchedule: ocss.JourneySchedule{
ID: r.ID,
PassengerPickupDate: ocss.OCSSTime(r.PickupDatetime),
WebUrl: r.WebURL,
},
AvailableSteats: r.AvailableSeats,
Price: price,
}
journeys = append(journeys, driverJourney)
}
return journeys, nil
}
func (api *BBCDailyCarpoolAPI) GetPassengerJourneys(
departureLat float64,
departureLng float64,
arrivalLat float64,
arrivalLng float64,
departureDate time.Time,
timeDelta *time.Duration,
departureRadius int64,
arrivalRadius int64,
count int64,
) ([]ocss.PassengerJourney, error) {
return nil, errors.New("not implemented")
}
func blablacarDailySearch(url string, access_token string, departure_latitude float64, departure_longitude float64, arrival_latitude float64, arrival_longitude float64, departure_time time.Time, departure_timedelta time.Duration) ([]BBCDailyResult, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Error().Err(err).Msg("new request issue")
return nil, err
}
req.Header.Set("Content-Type", "application/json")
q := req.URL.Query()
q.Add("access_token", access_token)
q.Add("departure_latitude", fmt.Sprintf("%f", departure_latitude))
q.Add("departure_longitude", fmt.Sprintf("%f", departure_longitude))
q.Add("arrival_latitude", fmt.Sprintf("%f", arrival_latitude))
q.Add("arrival_longitude", fmt.Sprintf("%f", arrival_longitude))
q.Add("departure_epoch", strconv.FormatInt(departure_time.Unix(), 10))
q.Add("departure_timedelta", fmt.Sprintf("%v", departure_timedelta.Abs().Seconds()))
req.URL.RawQuery = q.Encode()
log.Debug().Str("url", req.URL.String()).Msg("Request to BBCDaily")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Error().Err(err).Msg("error in BBCDaily request")
return nil, err
}
response := []BBCDailyResult{}
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
body, err2 := io.ReadAll(resp.Body)
if err2 != nil {
log.Error().Err(err2).Msg("error reading json string")
}
log.Error().Err(err).Any("resp body", body).Msg("cannot read json response to blablacardaily API")
return nil, err
}
return response, nil
}
func nilCheck[T any](a *T) T {
var t T
if a == nil {
return t
}
return *a
}

13
libs/carpool/carpool.go Normal file
View File

@ -0,0 +1,13 @@
package carpool
import (
"time"
"git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
)
type CarpoolOperatorAPI interface {
GetOperatorId() string
GetDriverJourneys(departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius int64, arrivalRadius int64, count int64) ([]ocss.DriverJourney, error)
GetPassengerJourneys(departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius int64, arrivalRadius int64, count int64) ([]ocss.PassengerJourney, error)
}

23
libs/transit/transit.go Normal file
View File

@ -0,0 +1,23 @@
package transit
import (
"fmt"
valhalla "git.coopgo.io/coopgo-platform/libvalhalla-go"
"github.com/spf13/viper"
)
type TransitRouting struct {
Valhalla *valhalla.Actor
}
func NewTransitRouting(cfg *viper.Viper) (*TransitRouting, error) {
config := valhalla.DefaultConfig()
actor, err := valhalla.NewActorFromConfig(config)
if err != nil {
return nil, fmt.Errorf("could not initiate valhalla library : %w", err)
}
return &TransitRouting{
Valhalla: actor,
}, nil
}

47
main.go Normal file
View File

@ -0,0 +1,47 @@
//go:build cgo
package main
import (
"C"
"os"
"git.coopgo.io/coopgo-platform/multimodal-routing/handlers"
grpcserver "git.coopgo.io/coopgo-platform/multimodal-routing/servers/grpc/server"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
cfg, err := ReadConfig()
if err != nil {
log.Error().Err(err).Msg("issue reading config file")
}
var (
service_name = cfg.GetString("name")
dev_env = cfg.GetBool("dev_env")
grpc_enable = cfg.GetBool("services.grpc.enable")
)
if dev_env {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}
handler, err := handlers.NewMultimodalRoutingHandler(cfg.Sub("modes"))
if err != nil {
log.Fatal().Err(err).Msg("error creating handlers")
return
}
log.Info().Str("service_name", service_name).Msg("Running service")
failed := make(chan error)
if grpc_enable {
grpcserver.Run(failed, cfg, handler)
}
err = <-failed
log.Fatal().Err(err).Str("service_name", service_name).Msg("Terminating service")
}

View File

@ -0,0 +1,208 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.1
// protoc v4.24.4
// source: geojson.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type FeatureCollection struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Serialized string `protobuf:"bytes,1,opt,name=serialized,proto3" json:"serialized,omitempty"`
}
func (x *FeatureCollection) Reset() {
*x = FeatureCollection{}
if protoimpl.UnsafeEnabled {
mi := &file_geojson_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FeatureCollection) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FeatureCollection) ProtoMessage() {}
func (x *FeatureCollection) ProtoReflect() protoreflect.Message {
mi := &file_geojson_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FeatureCollection.ProtoReflect.Descriptor instead.
func (*FeatureCollection) Descriptor() ([]byte, []int) {
return file_geojson_proto_rawDescGZIP(), []int{0}
}
func (x *FeatureCollection) GetSerialized() string {
if x != nil {
return x.Serialized
}
return ""
}
type Feature struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Serialized string `protobuf:"bytes,1,opt,name=serialized,proto3" json:"serialized,omitempty"`
}
func (x *Feature) Reset() {
*x = Feature{}
if protoimpl.UnsafeEnabled {
mi := &file_geojson_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Feature) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Feature) ProtoMessage() {}
func (x *Feature) ProtoReflect() protoreflect.Message {
mi := &file_geojson_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Feature.ProtoReflect.Descriptor instead.
func (*Feature) Descriptor() ([]byte, []int) {
return file_geojson_proto_rawDescGZIP(), []int{1}
}
func (x *Feature) GetSerialized() string {
if x != nil {
return x.Serialized
}
return ""
}
var File_geojson_proto protoreflect.FileDescriptor
var file_geojson_proto_rawDesc = []byte{
0x0a, 0x0d, 0x67, 0x65, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0x33, 0x0a, 0x11, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12,
0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x42,
0x45, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x2e, 0x63, 0x6f, 0x6f, 0x70, 0x67, 0x6f, 0x2e, 0x69, 0x6f,
0x2f, 0x63, 0x6f, 0x6f, 0x70, 0x67, 0x6f, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x2d, 0x72, 0x6f, 0x75, 0x74,
0x69, 0x6e, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x67, 0x72, 0x70, 0x63,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_geojson_proto_rawDescOnce sync.Once
file_geojson_proto_rawDescData = file_geojson_proto_rawDesc
)
func file_geojson_proto_rawDescGZIP() []byte {
file_geojson_proto_rawDescOnce.Do(func() {
file_geojson_proto_rawDescData = protoimpl.X.CompressGZIP(file_geojson_proto_rawDescData)
})
return file_geojson_proto_rawDescData
}
var file_geojson_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_geojson_proto_goTypes = []interface{}{
(*FeatureCollection)(nil), // 0: FeatureCollection
(*Feature)(nil), // 1: Feature
}
var file_geojson_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_geojson_proto_init() }
func file_geojson_proto_init() {
if File_geojson_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_geojson_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FeatureCollection); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_geojson_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Feature); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_geojson_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_geojson_proto_goTypes,
DependencyIndexes: file_geojson_proto_depIdxs,
MessageInfos: file_geojson_proto_msgTypes,
}.Build()
File_geojson_proto = out.File
file_geojson_proto_rawDesc = nil
file_geojson_proto_goTypes = nil
file_geojson_proto_depIdxs = nil
}

View File

@ -0,0 +1,13 @@
syntax = "proto3";
option go_package = "git.coopgo.io/coopgo-platform/multimodal-routing/servers/grpc/proto";
// import "google/protobuf/timestamp.proto";
message FeatureCollection {
string serialized = 1;
}
message Feature {
string serialized = 1;
}

View File

@ -0,0 +1,264 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.1
// protoc v4.24.4
// source: multimodal-routing.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SearchRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Departure *Feature `protobuf:"bytes,1,opt,name=departure,proto3" json:"departure,omitempty"`
Destination *Feature `protobuf:"bytes,2,opt,name=destination,proto3" json:"destination,omitempty"`
DepartureDate *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=departure_date,json=departureDate,proto3" json:"departure_date,omitempty"`
TimeDelta *int64 `protobuf:"varint,4,opt,name=time_delta,json=timeDelta,proto3,oneof" json:"time_delta,omitempty"`
}
func (x *SearchRequest) Reset() {
*x = SearchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_multimodal_routing_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SearchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SearchRequest) ProtoMessage() {}
func (x *SearchRequest) ProtoReflect() protoreflect.Message {
mi := &file_multimodal_routing_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SearchRequest.ProtoReflect.Descriptor instead.
func (*SearchRequest) Descriptor() ([]byte, []int) {
return file_multimodal_routing_proto_rawDescGZIP(), []int{0}
}
func (x *SearchRequest) GetDeparture() *Feature {
if x != nil {
return x.Departure
}
return nil
}
func (x *SearchRequest) GetDestination() *Feature {
if x != nil {
return x.Destination
}
return nil
}
func (x *SearchRequest) GetDepartureDate() *timestamppb.Timestamp {
if x != nil {
return x.DepartureDate
}
return nil
}
func (x *SearchRequest) GetTimeDelta() int64 {
if x != nil && x.TimeDelta != nil {
return *x.TimeDelta
}
return 0
}
type SearchResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Results []*FeatureCollection `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"`
}
func (x *SearchResponse) Reset() {
*x = SearchResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_multimodal_routing_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SearchResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SearchResponse) ProtoMessage() {}
func (x *SearchResponse) ProtoReflect() protoreflect.Message {
mi := &file_multimodal_routing_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SearchResponse.ProtoReflect.Descriptor instead.
func (*SearchResponse) Descriptor() ([]byte, []int) {
return file_multimodal_routing_proto_rawDescGZIP(), []int{1}
}
func (x *SearchResponse) GetResults() []*FeatureCollection {
if x != nil {
return x.Results
}
return nil
}
var File_multimodal_routing_proto protoreflect.FileDescriptor
var file_multimodal_routing_proto_rawDesc = []byte{
0x0a, 0x18, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x2d, 0x72, 0x6f, 0x75,
0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x67, 0x65, 0x6f,
0x6a, 0x73, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x01, 0x0a, 0x0d, 0x53,
0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x09,
0x64, 0x65, 0x70, 0x61, 0x72, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x08, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x64, 0x65, 0x70, 0x61, 0x72,
0x74, 0x75, 0x72, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x46, 0x65, 0x61, 0x74,
0x75, 0x72, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x41, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x61, 0x72, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x64, 0x61,
0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x61, 0x72, 0x74, 0x75, 0x72, 0x65, 0x44,
0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74,
0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x44,
0x65, 0x6c, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, 0x65,
0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x46, 0x65, 0x61, 0x74,
0x75, 0x72, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x32, 0x40, 0x0a, 0x11, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x6d,
0x6f, 0x64, 0x61, 0x6c, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x06, 0x53,
0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x0e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x45, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x2e,
0x63, 0x6f, 0x6f, 0x70, 0x67, 0x6f, 0x2e, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x6f, 0x70, 0x67, 0x6f,
0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6d,
0x6f, 0x64, 0x61, 0x6c, 0x2d, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x73, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_multimodal_routing_proto_rawDescOnce sync.Once
file_multimodal_routing_proto_rawDescData = file_multimodal_routing_proto_rawDesc
)
func file_multimodal_routing_proto_rawDescGZIP() []byte {
file_multimodal_routing_proto_rawDescOnce.Do(func() {
file_multimodal_routing_proto_rawDescData = protoimpl.X.CompressGZIP(file_multimodal_routing_proto_rawDescData)
})
return file_multimodal_routing_proto_rawDescData
}
var file_multimodal_routing_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_multimodal_routing_proto_goTypes = []interface{}{
(*SearchRequest)(nil), // 0: SearchRequest
(*SearchResponse)(nil), // 1: SearchResponse
(*Feature)(nil), // 2: Feature
(*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp
(*FeatureCollection)(nil), // 4: FeatureCollection
}
var file_multimodal_routing_proto_depIdxs = []int32{
2, // 0: SearchRequest.departure:type_name -> Feature
2, // 1: SearchRequest.destination:type_name -> Feature
3, // 2: SearchRequest.departure_date:type_name -> google.protobuf.Timestamp
4, // 3: SearchResponse.results:type_name -> FeatureCollection
0, // 4: MultimodalRouting.Search:input_type -> SearchRequest
1, // 5: MultimodalRouting.Search:output_type -> SearchResponse
5, // [5:6] is the sub-list for method output_type
4, // [4:5] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_multimodal_routing_proto_init() }
func file_multimodal_routing_proto_init() {
if File_multimodal_routing_proto != nil {
return
}
file_geojson_proto_init()
if !protoimpl.UnsafeEnabled {
file_multimodal_routing_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SearchRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_multimodal_routing_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SearchResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_multimodal_routing_proto_msgTypes[0].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_multimodal_routing_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_multimodal_routing_proto_goTypes,
DependencyIndexes: file_multimodal_routing_proto_depIdxs,
MessageInfos: file_multimodal_routing_proto_msgTypes,
}.Build()
File_multimodal_routing_proto = out.File
file_multimodal_routing_proto_rawDesc = nil
file_multimodal_routing_proto_goTypes = nil
file_multimodal_routing_proto_depIdxs = nil
}

View File

@ -0,0 +1,21 @@
syntax = "proto3";
option go_package = "git.coopgo.io/coopgo-platform/multimodal-routing/servers/grpc/proto";
import "google/protobuf/timestamp.proto";
import "geojson.proto";
service MultimodalRouting {
rpc Search(SearchRequest) returns (SearchResponse) {}
}
message SearchRequest {
Feature departure = 1;
Feature destination = 2;
google.protobuf.Timestamp departure_date = 3;
optional int64 time_delta = 4;
}
message SearchResponse {
repeated FeatureCollection results = 1;
}

View File

@ -0,0 +1,109 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.24.4
// source: multimodal-routing.proto
package proto
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
MultimodalRouting_Search_FullMethodName = "/MultimodalRouting/Search"
)
// MultimodalRoutingClient is the client API for MultimodalRouting service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type MultimodalRoutingClient interface {
Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error)
}
type multimodalRoutingClient struct {
cc grpc.ClientConnInterface
}
func NewMultimodalRoutingClient(cc grpc.ClientConnInterface) MultimodalRoutingClient {
return &multimodalRoutingClient{cc}
}
func (c *multimodalRoutingClient) Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error) {
out := new(SearchResponse)
err := c.cc.Invoke(ctx, MultimodalRouting_Search_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// MultimodalRoutingServer is the server API for MultimodalRouting service.
// All implementations must embed UnimplementedMultimodalRoutingServer
// for forward compatibility
type MultimodalRoutingServer interface {
Search(context.Context, *SearchRequest) (*SearchResponse, error)
mustEmbedUnimplementedMultimodalRoutingServer()
}
// UnimplementedMultimodalRoutingServer must be embedded to have forward compatible implementations.
type UnimplementedMultimodalRoutingServer struct {
}
func (UnimplementedMultimodalRoutingServer) Search(context.Context, *SearchRequest) (*SearchResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Search not implemented")
}
func (UnimplementedMultimodalRoutingServer) mustEmbedUnimplementedMultimodalRoutingServer() {}
// UnsafeMultimodalRoutingServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MultimodalRoutingServer will
// result in compilation errors.
type UnsafeMultimodalRoutingServer interface {
mustEmbedUnimplementedMultimodalRoutingServer()
}
func RegisterMultimodalRoutingServer(s grpc.ServiceRegistrar, srv MultimodalRoutingServer) {
s.RegisterService(&MultimodalRouting_ServiceDesc, srv)
}
func _MultimodalRouting_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MultimodalRoutingServer).Search(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MultimodalRouting_Search_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MultimodalRoutingServer).Search(ctx, req.(*SearchRequest))
}
return interceptor(ctx, in, info, handler)
}
// MultimodalRouting_ServiceDesc is the grpc.ServiceDesc for MultimodalRouting service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var MultimodalRouting_ServiceDesc = grpc.ServiceDesc{
ServiceName: "MultimodalRouting",
HandlerType: (*MultimodalRoutingServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Search",
Handler: _MultimodalRouting_Search_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "multimodal-routing.proto",
}

View File

@ -0,0 +1,87 @@
package grpcserver
import (
"context"
"fmt"
"net"
"git.coopgo.io/coopgo-platform/multimodal-routing/handlers"
"git.coopgo.io/coopgo-platform/multimodal-routing/servers/grpc/proto"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/status"
)
type MultimodalRoutingServer struct {
Handler *handlers.MultimodalRoutingHandler
proto.UnimplementedMultimodalRoutingServer
}
func NewMultimodalRoutingServer(handler *handlers.MultimodalRoutingHandler) *MultimodalRoutingServer {
return &MultimodalRoutingServer{
Handler: handler,
}
}
func (s *MultimodalRoutingServer) Search(ctx context.Context, req *proto.SearchRequest) (*proto.SearchResponse, error) {
departure, err := geojson.UnmarshalFeature([]byte(req.Departure.Serialized))
if err != nil {
log.Error().Err(err).Msg("error decoding departure")
return nil, status.Errorf(codes.Internal, "could not read departure: %w", err)
}
destination, err := geojson.UnmarshalFeature([]byte(req.Destination.Serialized))
if err != nil {
log.Error().Err(err).Msg("error decoding destination")
return nil, status.Errorf(codes.Internal, "could not read destination: %w", err)
}
departureDate := req.DepartureDate.AsTime()
journeys, err := s.Handler.Search(*departure, *destination, departureDate)
if err != nil {
log.Error().Err(err).Any("departure", departure).Any("destination", destination).Time("departure date", departureDate).Msg("error retrieving carpools")
}
results := []*proto.FeatureCollection{}
for _, c := range journeys {
serialized, err := c.MarshalJSON()
if err != nil {
log.Error().Err(err).Any("carpool object", c).Msg("could not serialize carpool response")
continue
}
results = append(results, &proto.FeatureCollection{Serialized: string(serialized)})
}
return &proto.SearchResponse{
Results: results,
}, nil
}
func Run(failed chan error, cfg *viper.Viper, handler *handlers.MultimodalRoutingHandler) {
var (
dev_env = cfg.GetBool("dev_env")
address = fmt.Sprintf(":%s", cfg.GetString("services.grpc.port"))
)
server := grpc.NewServer()
proto.RegisterMultimodalRoutingServer(server, NewMultimodalRoutingServer(handler))
l, err := net.Listen("tcp", address)
if err != nil {
failed <- fmt.Errorf("error trying to listen to network port : %w", err)
return
}
if dev_env {
log.Info().Msg("gRPC server reflexion activated")
reflection.Register(server)
}
log.Info().Str("address", address).Msg("running gRPC server")
if err := server.Serve(l); err != nil {
failed <- fmt.Errorf("error in grpc server : %w", err)
}
}