feat: initial http bulk data collector
This commit is contained in:
parent
29375417ae
commit
145c5e9426
1
backend/services/bulkdata/.gitignore
vendored
Normal file
1
backend/services/bulkdata/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/.env.local
|
||||||
0
backend/services/bulkdata/README.md
Normal file
0
backend/services/bulkdata/README.md
Normal file
8
backend/services/bulkdata/build/Dockerfile
Normal file
8
backend/services/bulkdata/build/Dockerfile
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
FROM golang:1.22@sha256:82e07063a1ac3ee59e6f38b1222e32ce88469e4431ff6496cc40fb9a0fc18229 as builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ../ .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o bulkdata cmd/bulkdata/main.go
|
||||||
|
|
||||||
|
FROM alpine:3.14@sha256:0f2d5c38dd7a4f4f733e688e3a6733cb5ab1ac6e3cb4603a5dd564e5bfb80eed
|
||||||
|
COPY --from=builder /app/bulkdata /
|
||||||
|
ENTRYPOINT ["/bulkdata"]
|
||||||
61
backend/services/bulkdata/build/Makefile
Normal file
61
backend/services/bulkdata/build/Makefile
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
.PHONY: help build push start stop release remove delete run logs bash
|
||||||
|
|
||||||
|
DOCKER_USER ?= oktopusp
|
||||||
|
DOCKER_APP ?= bulkdata
|
||||||
|
DOCKER_TAG ?= $(shell git log --format="%h" -n 1)
|
||||||
|
CONTAINER_SHELL ?= /bin/sh
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Makefile arguments:"
|
||||||
|
@echo ""
|
||||||
|
@echo "DOCKER_USER - docker user to build image"
|
||||||
|
@echo "DOCKER_APP - docker image name"
|
||||||
|
@echo "DOCKER_TAG - docker image tag"
|
||||||
|
@echo "CONTAINER_SHELL - container shell e.g:'/bin/bash'"
|
||||||
|
@echo ""
|
||||||
|
@echo "Makefile commands:"
|
||||||
|
@echo ""
|
||||||
|
@echo "build - docker image build"
|
||||||
|
@echo "push - push docker iamge to registry"
|
||||||
|
@echo "run - create and start docker container with the image"
|
||||||
|
@echo "start - start existent docker container with the image"
|
||||||
|
@echo "stop - stop docker container running the image"
|
||||||
|
@echo "remove - remove docker container running the image"
|
||||||
|
@echo "delete - delete docker image"
|
||||||
|
@echo "logs - show logs of docker container"
|
||||||
|
@echo "bash - access container shell"
|
||||||
|
@echo "release - tag image as latest and push to registry"
|
||||||
|
|
||||||
|
build:
|
||||||
|
@docker build -t ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG} -f Dockerfile ../
|
||||||
|
|
||||||
|
run:
|
||||||
|
@docker run -d --name ${DOCKER_USER}-${DOCKER_APP} ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
|
||||||
|
|
||||||
|
stop:
|
||||||
|
@docker stop ${DOCKER_USER}-${DOCKER_APP}
|
||||||
|
|
||||||
|
remove: stop
|
||||||
|
@docker rm ${DOCKER_USER}-${DOCKER_APP}
|
||||||
|
|
||||||
|
delete:
|
||||||
|
@docker rmi ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
|
||||||
|
|
||||||
|
start:
|
||||||
|
@docker start ${DOCKER_USER}-${DOCKER_APP}
|
||||||
|
|
||||||
|
push:
|
||||||
|
@docker push ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
|
||||||
|
|
||||||
|
logs:
|
||||||
|
@docker logs -f ${DOCKER_USER}-${DOCKER_APP}
|
||||||
|
|
||||||
|
bash:
|
||||||
|
@docker exec -it ${DOCKER_USER}-${DOCKER_APP} ${CONTAINER_SHELL}
|
||||||
|
|
||||||
|
release: build
|
||||||
|
@docker push ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
|
||||||
|
@docker tag ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG} ${DOCKER_USER}/${DOCKER_APP}:latest
|
||||||
|
@docker push ${DOCKER_USER}/${DOCKER_APP}:latest
|
||||||
29
backend/services/bulkdata/cmd/bulkdata/main.go
Normal file
29
backend/services/bulkdata/cmd/bulkdata/main.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/api"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/nats"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
done := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(done, syscall.SIGINT)
|
||||||
|
|
||||||
|
c := config.NewConfig()
|
||||||
|
|
||||||
|
js, nc, kv := nats.StartNatsClient(c.Nats)
|
||||||
|
|
||||||
|
server := api.NewApi(c.RestApi, js, nc, kv)
|
||||||
|
|
||||||
|
server.StartApi()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
log.Println("bulk data collector is saying adios ...")
|
||||||
|
}
|
||||||
19
backend/services/bulkdata/go.mod
Normal file
19
backend/services/bulkdata/go.mod
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
module github.com/oktopUSP/backend/services/bulkdata
|
||||||
|
|
||||||
|
go 1.22.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/mux v1.8.1
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/nats-io/nats.go v1.34.1
|
||||||
|
github.com/rs/cors v1.11.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/klauspost/compress v1.17.2 // indirect
|
||||||
|
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||||
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
|
golang.org/x/crypto v0.18.0 // indirect
|
||||||
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
)
|
||||||
20
backend/services/bulkdata/go.sum
Normal file
20
backend/services/bulkdata/go.sum
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||||
|
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4=
|
||||||
|
github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||||
|
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||||
|
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||||
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
|
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
|
||||||
|
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||||
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
58
backend/services/bulkdata/internal/api/api.go
Normal file
58
backend/services/bulkdata/internal/api/api.go
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/nats-io/nats.go/jetstream"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/api/cors"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/api/handler"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/api/middleware"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
port string
|
||||||
|
handler handler.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
const REQUEST_TIMEOUT = time.Second * 30
|
||||||
|
|
||||||
|
func NewApi(c config.RestApi, js jetstream.JetStream, nc *nats.Conn, kv jetstream.KeyValue) Api {
|
||||||
|
return Api{
|
||||||
|
port: c.Port,
|
||||||
|
handler: handler.NewHandler(js, nc, kv),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) StartApi() {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/healthcheck", a.handler.Healthcheck).Methods("GET")
|
||||||
|
r.HandleFunc("/", a.handler.Data).Methods("POST")
|
||||||
|
|
||||||
|
/* ----- Middleware for requests which requires user to be authenticated ---- */
|
||||||
|
r.Use(func(handler http.Handler) http.Handler {
|
||||||
|
return middleware.Middleware(handler)
|
||||||
|
})
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
corsOpts := cors.GetCorsConfig()
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: "0.0.0.0:" + a.port,
|
||||||
|
WriteTimeout: time.Second * 60,
|
||||||
|
ReadTimeout: time.Second * 60,
|
||||||
|
IdleTimeout: time.Second * 60,
|
||||||
|
Handler: corsOpts.Handler(r),
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := srv.ListenAndServe(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
log.Println("Running Bulk Data Collector HTTP Server at port", a.port)
|
||||||
|
}
|
||||||
39
backend/services/bulkdata/internal/api/cors/cors.go
Normal file
39
backend/services/bulkdata/internal/api/cors/cors.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package cors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/cors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetCorsConfig() cors.Cors {
|
||||||
|
allowedOrigins := getCorsEnvConfig()
|
||||||
|
log.Println("API CORS - AllowedOrigins:", allowedOrigins)
|
||||||
|
return *cors.New(cors.Options{
|
||||||
|
AllowedOrigins: allowedOrigins,
|
||||||
|
AllowedMethods: []string{
|
||||||
|
http.MethodGet,
|
||||||
|
http.MethodPost,
|
||||||
|
http.MethodPut,
|
||||||
|
http.MethodPatch,
|
||||||
|
http.MethodDelete,
|
||||||
|
http.MethodOptions,
|
||||||
|
http.MethodHead,
|
||||||
|
},
|
||||||
|
|
||||||
|
AllowedHeaders: []string{
|
||||||
|
"*", //or you can your header key values which you are using in your application
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCorsEnvConfig() []string {
|
||||||
|
val, _ := os.LookupEnv("REST_API_CORS")
|
||||||
|
if val == "" {
|
||||||
|
return []string{"*"}
|
||||||
|
}
|
||||||
|
return strings.Split(val, ",")
|
||||||
|
}
|
||||||
31
backend/services/bulkdata/internal/api/handler/data.go
Normal file
31
backend/services/bulkdata/internal/api/handler/data.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) Data(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
oui := r.URL.Query().Get("oui")
|
||||||
|
pc := r.URL.Query().Get("pc")
|
||||||
|
sn := r.URL.Query().Get("sn")
|
||||||
|
eid := r.URL.Query().Get("eid")
|
||||||
|
|
||||||
|
log.Println("oui: ", oui)
|
||||||
|
log.Println("pc: ", pc)
|
||||||
|
log.Println("sn: ", sn)
|
||||||
|
log.Println("eid: ", eid)
|
||||||
|
|
||||||
|
var body map[string]interface{}
|
||||||
|
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&body)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Body: ", body)
|
||||||
|
}
|
||||||
23
backend/services/bulkdata/internal/api/handler/handler.go
Normal file
23
backend/services/bulkdata/internal/api/handler/handler.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/nats-io/nats.go/jetstream"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
js jetstream.JetStream
|
||||||
|
nc *nats.Conn
|
||||||
|
kv jetstream.KeyValue
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(js jetstream.JetStream, nc *nats.Conn, kv jetstream.KeyValue) Handler {
|
||||||
|
return Handler{
|
||||||
|
js: js,
|
||||||
|
nc: nc,
|
||||||
|
kv: kv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func (h *Handler) Healthcheck(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("I'm Alive"))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Middleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
// tokenString := r.Header.Get("Authorization")
|
||||||
|
// if tokenString == "" {
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// email, err := auth.ValidateToken(tokenString)
|
||||||
|
// if err != nil {
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//ctx := context.WithValue(r.Context(), "email", email)
|
||||||
|
next.ServeHTTP(w, r.WithContext(r.Context()))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
105
backend/services/bulkdata/internal/config/config.go
Normal file
105
backend/services/bulkdata/internal/config/config.go
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const LOCAL_ENV = ".env.local"
|
||||||
|
|
||||||
|
type Nats struct {
|
||||||
|
Url string
|
||||||
|
Name string
|
||||||
|
VerifyCertificates bool
|
||||||
|
Ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type RestApi struct {
|
||||||
|
Port string
|
||||||
|
Ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
RestApi RestApi
|
||||||
|
Nats Nats
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig() *Config {
|
||||||
|
|
||||||
|
loadEnvVariables()
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|
||||||
|
natsUrl := flag.String("nats_url", lookupEnvOrString("NATS_URL", "nats://localhost:4222"), "url for nats server")
|
||||||
|
natsName := flag.String("nats_name", lookupEnvOrString("NATS_NAME", "adapter"), "name for nats client")
|
||||||
|
natsVerifyCertificates := flag.Bool("nats_verify_certificates", lookupEnvOrBool("NATS_VERIFY_CERTIFICATES", false), "verify validity of certificates from nats server")
|
||||||
|
flApiPort := flag.String("api_port", lookupEnvOrString("REST_API_PORT", "4000"), "Rest api port")
|
||||||
|
flHelp := flag.Bool("help", false, "Help")
|
||||||
|
|
||||||
|
/*
|
||||||
|
App variables priority:
|
||||||
|
1º - Flag through command line.
|
||||||
|
2º - Env variables.
|
||||||
|
3º - Default flag value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *flHelp {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
return &Config{
|
||||||
|
RestApi: RestApi{
|
||||||
|
Port: *flApiPort,
|
||||||
|
Ctx: ctx,
|
||||||
|
},
|
||||||
|
Nats: Nats{
|
||||||
|
Url: *natsUrl,
|
||||||
|
Name: *natsName,
|
||||||
|
VerifyCertificates: *natsVerifyCertificates,
|
||||||
|
Ctx: ctx,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadEnvVariables() {
|
||||||
|
err := godotenv.Load()
|
||||||
|
|
||||||
|
if _, err := os.Stat(LOCAL_ENV); err == nil {
|
||||||
|
_ = godotenv.Overload(LOCAL_ENV)
|
||||||
|
log.Printf("Loaded variables from '%s'", LOCAL_ENV)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error to load environment variables:", err)
|
||||||
|
} else {
|
||||||
|
log.Println("Loaded variables from '.env'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupEnvOrString(key string, defaultVal string) string {
|
||||||
|
if val, _ := os.LookupEnv(key); val != "" {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupEnvOrBool(key string, defaultVal bool) bool {
|
||||||
|
if val, _ := os.LookupEnv(key); val != "" {
|
||||||
|
v, err := strconv.ParseBool(val)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("LookupEnvOrBool[%s]: %v", key, err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
74
backend/services/bulkdata/internal/nats/nats.go
Normal file
74
backend/services/bulkdata/internal/nats/nats.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package nats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/nats-io/nats.go/jetstream"
|
||||||
|
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BUCKET_NAME = "devices-auth"
|
||||||
|
BUCKET_DESCRIPTION = "Devices authentication"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartNatsClient(c config.Nats) (jetstream.JetStream, *nats.Conn, jetstream.KeyValue) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
nc *nats.Conn
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
opts := defineOptions(c)
|
||||||
|
|
||||||
|
log.Printf("Connecting to NATS server %s", c.Url)
|
||||||
|
|
||||||
|
for {
|
||||||
|
nc, err = nats.Connect(c.Url, opts...)
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("Successfully connected to NATS server %s", c.Url)
|
||||||
|
|
||||||
|
js, err := jetstream.New(nc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create JetStream client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kv, err := js.CreateOrUpdateKeyValue(c.Ctx, jetstream.KeyValueConfig{
|
||||||
|
Bucket: BUCKET_NAME,
|
||||||
|
Description: BUCKET_DESCRIPTION,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create KeyValue store: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return js, nc, kv
|
||||||
|
}
|
||||||
|
|
||||||
|
func defineOptions(c config.Nats) []nats.Option {
|
||||||
|
var opts []nats.Option
|
||||||
|
|
||||||
|
opts = append(opts, nats.Name(c.Name))
|
||||||
|
opts = append(opts, nats.MaxReconnects(-1))
|
||||||
|
opts = append(opts, nats.ReconnectWait(5*time.Second))
|
||||||
|
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
|
||||||
|
log.Printf("Got disconnected! Reason: %q\n", err)
|
||||||
|
}))
|
||||||
|
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
|
||||||
|
log.Printf("Got reconnected to %v!\n", nc.ConnectedUrl())
|
||||||
|
}))
|
||||||
|
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
|
||||||
|
log.Printf("Connection closed. Reason: %q\n", nc.LastError())
|
||||||
|
}))
|
||||||
|
if c.VerifyCertificates {
|
||||||
|
opts = append(opts, nats.RootCAs())
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
@ -64,6 +64,7 @@ func (a *Api) StartApi() {
|
||||||
iot.HandleFunc("/{sn}/{mtp}/add", a.deviceCreateMsg).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/add", a.deviceCreateMsg).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/{mtp}/del", a.deviceDeleteMsg).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/del", a.deviceDeleteMsg).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/{mtp}/set", a.deviceUpdateMsg).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/set", a.deviceUpdateMsg).Methods("PUT")
|
||||||
|
iot.HandleFunc("/{sn}/{mtp}/notify", a.deviceNotifyMsg).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/{mtp}/parameters", a.deviceGetSupportedParametersMsg).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/parameters", a.deviceGetSupportedParametersMsg).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/{mtp}/instances", a.deviceGetParameterInstances).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/instances", a.deviceGetParameterInstances).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/{mtp}/operate", a.deviceOperateMsg).Methods("PUT")
|
iot.HandleFunc("/{sn}/{mtp}/operate", a.deviceOperateMsg).Methods("PUT")
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/leandrofars/oktopus/internal/bridge"
|
"github.com/leandrofars/oktopus/internal/bridge"
|
||||||
local "github.com/leandrofars/oktopus/internal/nats"
|
local "github.com/leandrofars/oktopus/internal/nats"
|
||||||
"github.com/leandrofars/oktopus/internal/usp/usp_msg"
|
"github.com/leandrofars/oktopus/internal/usp/usp_msg"
|
||||||
|
|
@ -165,6 +167,44 @@ func (a *Api) deviceOperateMsg(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Api) deviceNotifyMsg(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
sn := getSerialNumberFromRequest(r)
|
||||||
|
mtp, err := getMtpFromRequest(r, w)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if mtp == "" {
|
||||||
|
var ok bool
|
||||||
|
mtp, ok = deviceStateOK(w, a.nc, sn)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// var notify usp_msg.Notify
|
||||||
|
notify := usp_msg.Notify{
|
||||||
|
SubscriptionId: uuid.NewString(),
|
||||||
|
SendResp: true,
|
||||||
|
Notification: &usp_msg.Notify_Event_{
|
||||||
|
Event: &usp_msg.Notify_Event{
|
||||||
|
EventName: "Push!",
|
||||||
|
ObjPath: "Device.BulkData.Profile.1.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Notify %s:", notify.String())
|
||||||
|
|
||||||
|
msg := usp_utils.NewNotifyMsg(notify)
|
||||||
|
|
||||||
|
err = sendUspMsg(msg, sn, w, a.nc, mtp)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Api) deviceUpdateMsg(w http.ResponseWriter, r *http.Request) {
|
func (a *Api) deviceUpdateMsg(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
sn := getSerialNumberFromRequest(r)
|
sn := getSerialNumberFromRequest(r)
|
||||||
|
|
|
||||||
|
|
@ -145,3 +145,21 @@ func NewOperateMsg(getStuff usp_msg.Operate) usp_msg.Msg {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewNotifyMsg(notify usp_msg.Notify) usp_msg.Msg {
|
||||||
|
return usp_msg.Msg{
|
||||||
|
Header: &usp_msg.Header{
|
||||||
|
MsgId: uuid.NewString(),
|
||||||
|
MsgType: usp_msg.Header_NOTIFY,
|
||||||
|
},
|
||||||
|
Body: &usp_msg.Body{
|
||||||
|
MsgBody: &usp_msg.Body_Request{
|
||||||
|
Request: &usp_msg.Request{
|
||||||
|
ReqType: &usp_msg.Request_Notify{
|
||||||
|
Notify: ¬ify,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
reactStrictMode: true
|
reactStrictMode: false
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -655,7 +655,7 @@ const getDeviceParameterInstances = async (raw) =>{
|
||||||
let paramsInfo = {}
|
let paramsInfo = {}
|
||||||
let commandsInfo = {}
|
let commandsInfo = {}
|
||||||
|
|
||||||
let supportedParams = content.req_obj_results[0].supported_objs[0].supported_params
|
let supportedParams = content.req_obj_results[0].supported_objs[0].supported_params //TODO: fixme when more then one supported_objs
|
||||||
let supportedCommands = content.req_obj_results[0].supported_objs[0].supported_commands
|
let supportedCommands = content.req_obj_results[0].supported_objs[0].supported_commands
|
||||||
|
|
||||||
let parametersToFetch = () => {
|
let parametersToFetch = () => {
|
||||||
|
|
@ -725,7 +725,7 @@ const getDeviceParameterInstances = async (raw) =>{
|
||||||
// console.log(y.result_params[key])
|
// console.log(y.result_params[key])
|
||||||
// console.log({[key]:paramsInfo[key]})
|
// console.log({[key]:paramsInfo[key]})
|
||||||
|
|
||||||
console.log("Take a look here mate: ",{...paramsInfo[key], value: y.result_params[key]})
|
//console.log("Take a look here mate: ",{...paramsInfo[key], value: y.result_params[key]})
|
||||||
if (!values[y.resolved_path]){
|
if (!values[y.resolved_path]){
|
||||||
values[y.resolved_path] = []
|
values[y.resolved_path] = []
|
||||||
}
|
}
|
||||||
|
|
@ -751,12 +751,13 @@ const getDeviceParameterInstances = async (raw) =>{
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("values:", values)
|
//console.log("values:", values)
|
||||||
setDeviceParametersValue(values)
|
setDeviceParametersValue(values)
|
||||||
console.log("commands:", commandsInfo)
|
//console.log("commands:", commandsInfo)
|
||||||
setDeviceCommands(commandsInfo)
|
setDeviceCommands(commandsInfo)
|
||||||
})
|
})
|
||||||
|
console.log("values:", values)
|
||||||
|
console.log("commands:", commandsInfo)
|
||||||
console.log("/-------------------------------------------------------/")
|
console.log("/-------------------------------------------------------/")
|
||||||
setDeviceParameters(content)
|
setDeviceParameters(content)
|
||||||
}else{
|
}else{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user