From 0110e4113c890124a104044254cdd906d5cdee01 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:18:39 -0800 Subject: [PATCH 01/95] gr25: ingest skeleton --- gr25/.gitignore | 168 +++++++++++++++++++++++++++++++++++++++ gr25/Makefile | 15 ++++ gr25/api/api.go | 28 +++++++ gr25/api/ping.go | 12 +++ gr25/config/banner.go | 20 +++++ gr25/config/config.go | 37 +++++++++ gr25/database/db.go | 37 +++++++++ gr25/go.mod | 50 ++++++++++++ gr25/go.sum | 100 +++++++++++++++++++++++ gr25/main.go | 24 ++++++ gr25/scripts/deploy.sh | 22 +++++ gr25/scripts/run.sh | 19 +++++ gr25/scripts/test-env.sh | 1 + gr25/scripts/test.sh | 17 ++++ gr25/utils/config.go | 26 ++++++ gr25/utils/logger.go | 18 +++++ gr25/utils/time.go | 11 +++ 17 files changed, 605 insertions(+) create mode 100644 gr25/.gitignore create mode 100644 gr25/Makefile create mode 100644 gr25/api/api.go create mode 100644 gr25/api/ping.go create mode 100644 gr25/config/banner.go create mode 100644 gr25/config/config.go create mode 100644 gr25/database/db.go create mode 100644 gr25/go.mod create mode 100644 gr25/go.sum create mode 100644 gr25/main.go create mode 100644 gr25/scripts/deploy.sh create mode 100755 gr25/scripts/run.sh create mode 100644 gr25/scripts/test-env.sh create mode 100755 gr25/scripts/test.sh create mode 100644 gr25/utils/config.go create mode 100644 gr25/utils/logger.go create mode 100644 gr25/utils/time.go diff --git a/gr25/.gitignore b/gr25/.gitignore new file mode 100644 index 00000000..a0300d6c --- /dev/null +++ b/gr25/.gitignore @@ -0,0 +1,168 @@ +.env + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +coverage.html + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/ + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk \ No newline at end of file diff --git a/gr25/Makefile b/gr25/Makefile new file mode 100644 index 00000000..ba9bd5d3 --- /dev/null +++ b/gr25/Makefile @@ -0,0 +1,15 @@ +.PHONY: clean run test + +clean: + go clean + go mod tidy + rm *.out + rm coverage.html + +run: + chmod +x scripts/run.sh + ./scripts/run.sh + +test: + chmod +x scripts/test.sh + ./scripts/test.sh diff --git a/gr25/api/api.go b/gr25/api/api.go new file mode 100644 index 00000000..47a48519 --- /dev/null +++ b/gr25/api/api.go @@ -0,0 +1,28 @@ +package api + +import ( + "gr25/config" + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func SetupRouter() *gin.Engine { + if config.Env == "PROD" { + gin.SetMode(gin.ReleaseMode) + } + r := gin.Default() + r.Use(cors.New(cors.Config{ + AllowAllOrigins: true, + AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}, + AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"}, + MaxAge: 12 * time.Hour, + AllowCredentials: true, + })) + return r +} + +func InitializeRoutes(router *gin.Engine) { + router.GET("/ping", Ping) +} diff --git a/gr25/api/ping.go b/gr25/api/ping.go new file mode 100644 index 00000000..954e1f16 --- /dev/null +++ b/gr25/api/ping.go @@ -0,0 +1,12 @@ +package api + +import ( + "gr25/config" + "net/http" + + "github.com/gin-gonic/gin" +) + +func Ping(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{"message": config.Service.FormattedNameWithVersion() + " is online!"}) +} diff --git a/gr25/config/banner.go b/gr25/config/banner.go new file mode 100644 index 00000000..f9d028a3 --- /dev/null +++ b/gr25/config/banner.go @@ -0,0 +1,20 @@ +package config + +import "github.com/fatih/color" + +var Banner = ` +███╗ ███╗ █████╗ ██████╗ █████╗ ██████╗██╗ ██╗███████╗ +████╗ ████║██╔══██╗██╔══██╗██╔══██╗██╔════╝██║ ██║██╔════╝ +██╔████╔██║███████║██████╔╝███████║██║ ███████║█████╗ +██║╚██╔╝██║██╔══██║██╔═══╝ ██╔══██║██║ ██╔══██║██╔══╝ +██║ ╚═╝ ██║██║ ██║██║ ██║ ██║╚██████╗██║ ██║███████╗ +╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ +` + +func PrintStartupBanner() { + banner := color.New(color.Bold, color.FgHiMagenta).PrintlnFunc() + banner(Banner) + version := color.New(color.Bold, color.FgMagenta).PrintlnFunc() + version("Running " + Service.FormattedNameWithVersion() + " [ENV: " + Env + "]") + println() +} diff --git a/gr25/config/config.go b/gr25/config/config.go new file mode 100644 index 00000000..7383667f --- /dev/null +++ b/gr25/config/config.go @@ -0,0 +1,37 @@ +package config + +import ( + "os" + + "github.com/bk1031/rincon-go/v2" +) + +var Service rincon.Service = rincon.Service{ + Name: "GR25", + Version: "1.0.0", +} + +var Routes = []rincon.Route{ + { + Route: "/gr25/**", + Method: "*", + }, +} + +var Env = os.Getenv("ENV") +var Port = os.Getenv("PORT") + +var DatabaseHost = os.Getenv("DATABASE_HOST") +var DatabasePort = os.Getenv("DATABASE_PORT") +var DatabaseUser = os.Getenv("DATABASE_USER") +var DatabasePassword = os.Getenv("DATABASE_PASSWORD") +var DatabaseName = os.Getenv("DATABASE_NAME") + +var RinconClient *rincon.Client +var RinconUser = os.Getenv("RINCON_USER") +var RinconPassword = os.Getenv("RINCON_PASSWORD") + +var MQTTHost = os.Getenv("MQTT_HOST") +var MQTTPort = os.Getenv("MQTT_PORT") +var MQTTUser = os.Getenv("MQTT_USER") +var MQTTPassword = os.Getenv("MQTT_PASSWORD") diff --git a/gr25/database/db.go b/gr25/database/db.go new file mode 100644 index 00000000..6c20374a --- /dev/null +++ b/gr25/database/db.go @@ -0,0 +1,37 @@ +package database + +import ( + "fmt" + "gr25/config" + "gr25/utils" + + "time" + + singlestore "github.com/singlestore-labs/gorm-singlestore" + "gorm.io/gorm" +) + +var DB *gorm.DB + +var dbRetries = 0 + +func InitializeDB() error { + dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=UTC", config.DatabaseUser, config.DatabasePassword, config.DatabaseHost, config.DatabasePort, config.DatabaseName) + db, err := gorm.Open(singlestore.Open(dsn), &gorm.Config{}) + if err != nil { + if dbRetries < 5 { + dbRetries++ + utils.SugarLogger.Errorln("failed to connect database, retrying in 5s... ") + time.Sleep(time.Second * 5) + InitializeDB() + } else { + return fmt.Errorf("failed to connect database after 5 attempts") + } + } else { + utils.SugarLogger.Infoln("Connected to database") + db.AutoMigrate() + utils.SugarLogger.Infoln("AutoMigration complete") + DB = db + } + return nil +} diff --git a/gr25/go.mod b/gr25/go.mod new file mode 100644 index 00000000..3cbe6729 --- /dev/null +++ b/gr25/go.mod @@ -0,0 +1,50 @@ +module gr25 + +go 1.23.6 + +require ( + github.com/bk1031/rincon-go/v2 v2.0.0 + go.uber.org/zap v1.27.0 +) + +require ( + github.com/bytedance/sonic v1.12.6 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.4 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.12.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/gorm v1.25.7 // indirect +) + +require ( + github.com/fatih/color v1.18.0 + github.com/gin-contrib/cors v1.7.3 + github.com/singlestore-labs/gorm-singlestore v1.2.0 + go.uber.org/multierr v1.10.0 // indirect +) diff --git a/gr25/go.sum b/gr25/go.sum new file mode 100644 index 00000000..999c0a42 --- /dev/null +++ b/gr25/go.sum @@ -0,0 +1,100 @@ +github.com/bk1031/rincon-go/v2 v2.0.0 h1:nmDHQNZI/AFfW+ZGTGoxpNPrv3OYXQ09anX+fCoiQsQ= +github.com/bk1031/rincon-go/v2 v2.0.0/go.mod h1:287Zc8PvUNnJuAwpt9XVuYUL8k4wrXg3Fa3L0KEmAB4= +github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= +github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= +github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +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/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= +github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/singlestore-labs/gorm-singlestore v1.2.0 h1:mccrEa5tyZDvq7LdEl7oIVfizVC0gxkcf2MHoZG1TWQ= +github.com/singlestore-labs/gorm-singlestore v1.2.0/go.mod h1:Bxq1nC7Gr1I7Hb0tS4bF/aLp3/EqD64kY79LeBKYKBQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= +golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/gr25/main.go b/gr25/main.go new file mode 100644 index 00000000..15eef9bb --- /dev/null +++ b/gr25/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "gr25/api" + "gr25/config" + "gr25/database" + "gr25/utils" +) + +func main() { + config.PrintStartupBanner() + utils.InitializeLogger() + utils.VerifyConfig() + defer utils.Logger.Sync() + + database.InitializeDB() + + router := api.SetupRouter() + api.InitializeRoutes(router) + err := router.Run(":" + config.Port) + if err != nil { + utils.SugarLogger.Fatalln(err) + } +} diff --git a/gr25/scripts/deploy.sh b/gr25/scripts/deploy.sh new file mode 100644 index 00000000..67c4b10f --- /dev/null +++ b/gr25/scripts/deploy.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +service_name=$(basename $(dirname $(dirname "$(readlink -f "$0")"))) + +# Extract version from config.go +VERSION=$(grep 'Version: ' config/config.go | cut -d '"' -f 2) + +if [ -z "$VERSION" ] + then + echo "Error: Unable to extract version from config/config.go" + exit 1 +fi + +# Check if docker is installed +if ! [ -x "$(command -v docker)" ]; then + echo 'Error: docker is not installed.' >&2 + exit 1 +fi + +echo "Building container for $service_name v$VERSION" +# Build the docker container +docker build -t gauchoracing/mp_$service_name:"$VERSION" -t gauchoracing/mp_$service_name:latest --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 --push --progress=plain . \ No newline at end of file diff --git a/gr25/scripts/run.sh b/gr25/scripts/run.sh new file mode 100755 index 00000000..1c37094a --- /dev/null +++ b/gr25/scripts/run.sh @@ -0,0 +1,19 @@ +# check if go.mod exists in current directory +if [ ! -f go.mod ]; then + echo "go.mod not found" + echo "Please make sure you are in the root service directory" + exit 1 +fi + +# check if .env exists in current directory +if [ ! -f .env ]; then + echo ".env not found" + echo "Please make sure the .env file is present in the current directory" + exit 1 +fi + + +set -a +. .env +go get . +go run main.go \ No newline at end of file diff --git a/gr25/scripts/test-env.sh b/gr25/scripts/test-env.sh new file mode 100644 index 00000000..3027f954 --- /dev/null +++ b/gr25/scripts/test-env.sh @@ -0,0 +1 @@ +export ENV=PROD \ No newline at end of file diff --git a/gr25/scripts/test.sh b/gr25/scripts/test.sh new file mode 100755 index 00000000..fde6e316 --- /dev/null +++ b/gr25/scripts/test.sh @@ -0,0 +1,17 @@ +# check if go.mod exists in current directory +if [ ! -f go.mod ]; then + echo "go.mod not found" + echo "Please make sure you are in the root ingest directory" + exit 1 +fi + +# check if test-env.sh exists in scripts directory +if [ ! -f scripts/test-env.sh ]; then + echo "scripts/test-env.sh not found" + echo "Please make sure you are in the root ingest directory" + exit 1 +fi + +. scripts/test-env.sh +go test ./... -race -covermode=atomic -coverprofile=coverage.out -v +go tool cover -html coverage.out -o coverage.html \ No newline at end of file diff --git a/gr25/utils/config.go b/gr25/utils/config.go new file mode 100644 index 00000000..240a9a0a --- /dev/null +++ b/gr25/utils/config.go @@ -0,0 +1,26 @@ +package utils + +import "gr25/config" + +func VerifyConfig() { + if config.Port == "" { + config.Port = "9999" + SugarLogger.Infof("PORT is not set, defaulting to %s", config.Port) + } + if config.DatabaseHost == "" { + config.DatabaseHost = "localhost" + SugarLogger.Infof("DATABASE_HOST is not set, defaulting to %s", config.DatabaseHost) + } + if config.DatabasePort == "" { + config.DatabasePort = "3306" + SugarLogger.Infof("DATABASE_PORT is not set, defaulting to %s", config.DatabasePort) + } + if config.DatabaseUser == "" { + config.DatabaseUser = "root" + SugarLogger.Infof("DATABASE_USER is not set, defaulting to %s", config.DatabaseUser) + } + if config.DatabasePassword == "" { + config.DatabasePassword = "password" + SugarLogger.Infof("DATABASE_PASSWORD is not set, defaulting to %s", config.DatabasePassword) + } +} diff --git a/gr25/utils/logger.go b/gr25/utils/logger.go new file mode 100644 index 00000000..0e5c42e3 --- /dev/null +++ b/gr25/utils/logger.go @@ -0,0 +1,18 @@ +package utils + +import ( + "gr25/config" + + "go.uber.org/zap" +) + +var Logger *zap.Logger +var SugarLogger *zap.SugaredLogger + +func InitializeLogger() { + Logger = zap.Must(zap.NewProduction()) + if config.Env == "DEV" { + Logger = zap.Must(zap.NewDevelopment()) + } + SugarLogger = Logger.Sugar() +} diff --git a/gr25/utils/time.go b/gr25/utils/time.go new file mode 100644 index 00000000..d6899ed0 --- /dev/null +++ b/gr25/utils/time.go @@ -0,0 +1,11 @@ +package utils + +import ( + "math" + "time" +) + +func WithPrecision(t time.Time) time.Time { + round := time.Second / time.Duration(math.Pow10(6)) + return t.Round(round) +} From 597cd6267400b62dd5e5e62ec0042598266ae936 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:21:25 -0800 Subject: [PATCH 02/95] add gr25 to gh actions --- .github/workflows/build.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 605ed4a7..c58790ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,8 +76,26 @@ jobs: go get . go build + gr25: + runs-on: ubuntu-latest + name: gr25 + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: true + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: '1.22.0' + - name: Build GR25 + run: | + cd gr25 + go get . + go build + all: - needs: [dashboard, auth, jeddah, gr24] + needs: [dashboard, auth, jeddah, gr24, gr25] runs-on: ubuntu-latest name: all steps: From 7c05f76bc7fa87abfb0b5ad729d168bbc43b18e8 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:27:10 -0800 Subject: [PATCH 03/95] gr25: rincon registration --- gr25/go.mod | 4 +-- gr25/main.go | 2 ++ gr25/service/rincon.go | 71 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 gr25/service/rincon.go diff --git a/gr25/go.mod b/gr25/go.mod index 3cbe6729..fb52dbde 100644 --- a/gr25/go.mod +++ b/gr25/go.mod @@ -4,7 +4,9 @@ go 1.23.6 require ( github.com/bk1031/rincon-go/v2 v2.0.0 + github.com/gin-gonic/gin v1.10.0 go.uber.org/zap v1.27.0 + gorm.io/gorm v1.25.7 ) require ( @@ -14,7 +16,6 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.23.0 // indirect @@ -39,7 +40,6 @@ require ( golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/gorm v1.25.7 // indirect ) require ( diff --git a/gr25/main.go b/gr25/main.go index 15eef9bb..6269a15f 100644 --- a/gr25/main.go +++ b/gr25/main.go @@ -4,6 +4,7 @@ import ( "gr25/api" "gr25/config" "gr25/database" + "gr25/service" "gr25/utils" ) @@ -13,6 +14,7 @@ func main() { utils.VerifyConfig() defer utils.Logger.Sync() + service.RegisterRincon() database.InitializeDB() router := api.SetupRouter() diff --git a/gr25/service/rincon.go b/gr25/service/rincon.go new file mode 100644 index 00000000..7d1c3d49 --- /dev/null +++ b/gr25/service/rincon.go @@ -0,0 +1,71 @@ +package service + +import ( + "gr25/config" + "gr25/utils" + "strings" + "time" + + "github.com/bk1031/rincon-go/v2" +) + +var rinconRetries = 0 +var isRunningInDocker = false + +func RegisterRincon() { + if config.RinconUser == "" || config.RinconPassword == "" { + utils.SugarLogger.Debugln("Rincon user or password is not set, skipping registration") + return + } + rinconEndpoint := "http://rincon:10311" + client, err := rincon.NewClient(rincon.Config{ + BaseURL: rinconEndpoint, + HeartbeatMode: rincon.ServerHeartbeat, + HeartbeatInterval: 60, + AuthUser: config.RinconUser, + AuthPassword: config.RinconPassword, + }) + if err != nil { + utils.SugarLogger.Errorf("Failed to create Rincon client with %s: %v", rinconEndpoint, err) + rinconEndpoint = "http://localhost:10311" + client, err = rincon.NewClient(rincon.Config{ + BaseURL: rinconEndpoint, + HeartbeatMode: rincon.ServerHeartbeat, + HeartbeatInterval: 60, + AuthUser: config.RinconUser, + AuthPassword: config.RinconPassword, + }) + if err != nil { + if rinconRetries < 5 { + utils.SugarLogger.Errorf("Failed to create Rincon client with %s: %v, retrying in 5s...", rinconEndpoint, err) + rinconRetries++ + time.Sleep(time.Second * 5) + RegisterRincon() + } else { + utils.SugarLogger.Fatalln("Failed to create Rincon client after 5 attempts") + return + } + } else { + utils.SugarLogger.Infof("Created Rincon client with endpoint %s", rinconEndpoint) + isRunningInDocker = false + } + } else { + utils.SugarLogger.Infof("Created Rincon client with endpoint %s", rinconEndpoint) + isRunningInDocker = true + } + config.RinconClient = client + if isRunningInDocker { + config.Service.Endpoint = "http://gr25:" + config.Port + config.Service.HealthCheck = "http://gr25:" + config.Port + "/" + strings.ToLower(config.Service.Name) + "/ping" + } else { + config.Service.Endpoint = "http://host.docker.internal:" + config.Port + config.Service.HealthCheck = "http://host.docker.internal:" + config.Port + "/" + strings.ToLower(config.Service.Name) + "/ping" + } + id, err := config.RinconClient.Register(config.Service, config.Routes) + if err != nil { + utils.SugarLogger.Errorf("Failed to register service with Rincon: %v", err) + return + } + config.Service = *config.RinconClient.Service() + utils.SugarLogger.Infof("Registered service with ID: %d", id) +} From f3cb270d506eb49034b31a3f3dede053b476ee2a Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:33:41 -0800 Subject: [PATCH 04/95] update docker compose --- docker-compose.yaml | 68 +++++++++++++------------------------------- singlestore/init.sql | 1 + 2 files changed, 20 insertions(+), 49 deletions(-) create mode 100644 singlestore/init.sql diff --git a/docker-compose.yaml b/docker-compose.yaml index 0364f24c..1db25dab 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -33,62 +33,32 @@ services: HEARTBEAT_TYPE: "server" HEARTBEAT_INTERVAL: "60" DB_DRIVER: "mysql" - DB_HOST: ${DB_HOST} - DB_PORT: ${DB_PORT} - DB_NAME: ${DB_NAME} - DB_USER: ${DB_USER} - DB_PASSWORD: ${DB_PASSWORD} + DB_HOST: ${DATABASE_HOST} + DB_PORT: ${DATABASE_PORT} + DB_NAME: ${DATABASE_NAME} + DB_USER: ${DATABASE_USER} + DB_PASSWORD: ${DATABASE_PASSWORD} ports: - "10311:10311" - bahrain: - image: gauchoracing/mp_bahrain:latest - container_name: bahrain - restart: unless-stopped - depends_on: - - rincon - environment: - ENV: ${ENV} - PORT: "7002" - AUTH_SIGNING_KEY: ${AUTH_SIGNING_KEY} - DB_HOST: ${DB_HOST} - DB_PORT: ${DB_PORT} - DB_NAME: ${DB_NAME} - DB_USER: ${DB_USER} - DB_PASSWORD: ${DB_PASSWORD} - RINCON_USER: ${RINCON_USER} - RINCON_PASSWORD: ${RINCON_PASSWORD} - ports: - - "7002" - - gr24: - image: gauchoracing/mp_gr24:latest - container_name: gr24 - restart: unless-stopped - depends_on: - - rincon - environment: - ENV: ${ENV} - PORT: "7004" - MQTT_HOST: ${MQTT_HOST} - MQTT_PORT: ${MQTT_PORT} - MQTT_USER: ${MQTT_USER} - MQTT_PASSWORD: ${MQTT_PASSWORD} - DB_HOST: ${DB_HOST} - DB_PORT: ${DB_PORT} - DB_NAME: ${DB_NAME} - DB_USER: ${DB_USER} - DB_PASSWORD: ${DB_PASSWORD} - RINCON_USER: ${RINCON_USER} - RINCON_PASSWORD: ${RINCON_PASSWORD} - ports: - - "7004" - nanomq: image: emqx/nanomq:latest restart: unless-stopped ports: - "1883:1883" + db: + image: ghcr.io/singlestore-labs/singlestoredb-dev:latest + restart: unless-stopped + volumes: + - s2data:/data + - ./singlestore/init.sql:/init.sql + ports: + - "3306:3306" + - "3380:8080" + - "3381:9000" + environment: + ROOT_PASSWORD: "${DATABASE_PASSWORD}" + volumes: - mysql: + s2data: \ No newline at end of file diff --git a/singlestore/init.sql b/singlestore/init.sql new file mode 100644 index 00000000..edda1fbc --- /dev/null +++ b/singlestore/init.sql @@ -0,0 +1 @@ +CREATE DATABASE IF NOT EXISTS mapache; From 07b4f30c7b79c5c9c96bb30ca9ec4a08a325f0f2 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:45:02 -0800 Subject: [PATCH 05/95] gr25: add signal db migration --- gr25/api/api.go | 2 +- gr25/database/db.go | 3 ++- gr25/go.mod | 1 + gr25/go.sum | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gr25/api/api.go b/gr25/api/api.go index 47a48519..c200c89d 100644 --- a/gr25/api/api.go +++ b/gr25/api/api.go @@ -24,5 +24,5 @@ func SetupRouter() *gin.Engine { } func InitializeRoutes(router *gin.Engine) { - router.GET("/ping", Ping) + router.GET("/gr25/ping", Ping) } diff --git a/gr25/database/db.go b/gr25/database/db.go index 6c20374a..eb8f5d26 100644 --- a/gr25/database/db.go +++ b/gr25/database/db.go @@ -7,6 +7,7 @@ import ( "time" + "github.com/gaucho-racing/mapache-go" singlestore "github.com/singlestore-labs/gorm-singlestore" "gorm.io/gorm" ) @@ -29,7 +30,7 @@ func InitializeDB() error { } } else { utils.SugarLogger.Infoln("Connected to database") - db.AutoMigrate() + db.AutoMigrate(&mapache.Signal{}) utils.SugarLogger.Infoln("AutoMigration complete") DB = db } diff --git a/gr25/go.mod b/gr25/go.mod index fb52dbde..ba1b042c 100644 --- a/gr25/go.mod +++ b/gr25/go.mod @@ -44,6 +44,7 @@ require ( require ( github.com/fatih/color v1.18.0 + github.com/gaucho-racing/mapache-go v1.6.1 github.com/gin-contrib/cors v1.7.3 github.com/singlestore-labs/gorm-singlestore v1.2.0 go.uber.org/multierr v1.10.0 // indirect diff --git a/gr25/go.sum b/gr25/go.sum index 999c0a42..b2ba6b7d 100644 --- a/gr25/go.sum +++ b/gr25/go.sum @@ -15,6 +15,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gaucho-racing/mapache-go v1.6.1 h1:VnrTyvr3tOWiMQsIj2Ij+ggNLyeddu2OKITWSGVIFXg= +github.com/gaucho-racing/mapache-go v1.6.1/go.mod h1:I8lpCGdURUpNaDX4JJSWdFDJdjT7i3fMvTvwHICDtqI= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= From d2eaec342f7e9673119d8bb62bd3c15d9db30269 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 09:48:51 -0800 Subject: [PATCH 06/95] gr25: add dockerfile --- gr25/Dockerfile | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 gr25/Dockerfile diff --git a/gr25/Dockerfile b/gr25/Dockerfile new file mode 100644 index 00000000..52376633 --- /dev/null +++ b/gr25/Dockerfile @@ -0,0 +1,29 @@ +FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS builder + +RUN apk --no-cache add ca-certificates +RUN apk add --no-cache tzdata + +WORKDIR /app + +COPY go.mod ./ +COPY go.sum ./ +RUN go mod download + +COPY . ./ +ARG TARGETOS +ARG TARGETARCH +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /gr25 + +## +## Deploy +## +FROM alpine:3.21 + +WORKDIR / + +COPY --from=builder /gr25 /gr25 + +COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo +ENV TZ=America/Los_Angeles + +ENTRYPOINT ["/gr25"] \ No newline at end of file From a729129f9047374ab26265f436bb096b8fc9fe42 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 22:27:36 -0800 Subject: [PATCH 07/95] mqtt ingest subscription and deserialization --- gr25/database/db.go | 4 +-- gr25/go.mod | 4 +++ gr25/go.sum | 8 +++++ gr25/main.go | 3 ++ gr25/model/ecu.go | 76 +++++++++++++++++++++++++++++++++++++++++ gr25/model/message.go | 14 ++++++++ gr25/mqtt/mqtt.go | 25 ++++++++++++++ gr25/service/message.go | 75 ++++++++++++++++++++++++++++++++++++++++ gr25/service/signal.go | 45 ++++++++++++++++++++++++ 9 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 gr25/model/ecu.go create mode 100644 gr25/model/message.go create mode 100644 gr25/mqtt/mqtt.go create mode 100644 gr25/service/message.go create mode 100644 gr25/service/signal.go diff --git a/gr25/database/db.go b/gr25/database/db.go index eb8f5d26..61cdb1d7 100644 --- a/gr25/database/db.go +++ b/gr25/database/db.go @@ -29,9 +29,9 @@ func InitializeDB() error { return fmt.Errorf("failed to connect database after 5 attempts") } } else { - utils.SugarLogger.Infoln("Connected to database") + utils.SugarLogger.Infoln("[DB] Connected to database") db.AutoMigrate(&mapache.Signal{}) - utils.SugarLogger.Infoln("AutoMigration complete") + utils.SugarLogger.Infoln("[DB] AutoMigration complete") DB = db } return nil diff --git a/gr25/go.mod b/gr25/go.mod index ba1b042c..a28b8832 100644 --- a/gr25/go.mod +++ b/gr25/go.mod @@ -4,6 +4,7 @@ go 1.23.6 require ( github.com/bk1031/rincon-go/v2 v2.0.0 + github.com/eclipse/paho.mqtt.golang v1.5.0 github.com/gin-gonic/gin v1.10.0 go.uber.org/zap v1.27.0 gorm.io/gorm v1.25.7 @@ -14,6 +15,7 @@ require ( github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/eclipse/paho.golang v0.22.0 // indirect github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -21,6 +23,7 @@ require ( github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.4 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -36,6 +39,7 @@ require ( golang.org/x/arch v0.12.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/gr25/go.sum b/gr25/go.sum index b2ba6b7d..e920d8dd 100644 --- a/gr25/go.sum +++ b/gr25/go.sum @@ -11,6 +11,10 @@ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/eclipse/paho.golang v0.22.0 h1:JhhUngr8TBlyUZDZw/L6WVayPi9qmSmdWeki48i5AVE= +github.com/eclipse/paho.golang v0.22.0/go.mod h1:9ZiYJ93iEfGRJri8tErNeStPKLXIGBHiqbHV74t5pqI= +github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= +github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= @@ -34,6 +38,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -83,6 +89,8 @@ golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= diff --git a/gr25/main.go b/gr25/main.go index 6269a15f..f7d31cea 100644 --- a/gr25/main.go +++ b/gr25/main.go @@ -4,6 +4,7 @@ import ( "gr25/api" "gr25/config" "gr25/database" + "gr25/mqtt" "gr25/service" "gr25/utils" ) @@ -16,6 +17,8 @@ func main() { service.RegisterRincon() database.InitializeDB() + mqtt.InitializeMQTT() + service.SubscribeTopics() router := api.SetupRouter() api.InitializeRoutes(router) diff --git a/gr25/model/ecu.go b/gr25/model/ecu.go new file mode 100644 index 00000000..a86ffe58 --- /dev/null +++ b/gr25/model/ecu.go @@ -0,0 +1,76 @@ +package model + +import mp "github.com/gaucho-racing/mapache-go" + +var ecuStatusOne = mp.Message{ + mp.NewField("ecu_state", 1, mp.Unsigned, mp.BigEndian, nil), + mp.NewField("ecu_status_flags", 3, mp.Unsigned, mp.BigEndian, func(f mp.Field) []mp.Signal { + signals := []mp.Signal{} + bitMap := []string{ + "ecu_status_acu", + "ecu_status_inv_one", + "ecu_status_inv_two", + "ecu_status_inv_three", + "ecu_status_inv_four", + "ecu_status_fan_one", + "ecu_status_fan_two", + "ecu_status_fan_three", + "ecu_status_fan_four", + "ecu_status_fan_five", + "ecu_status_fan_six", + "ecu_status_fan_seven", + "ecu_status_fan_eight", + "ecu_status_dash", + "ecu_status_steering", + } + for i := 0; i < len(bitMap); i++ { + signals = append(signals, mp.Signal{ + Name: bitMap[i], + Value: float64(f.CheckBit(i)), + RawValue: f.CheckBit(i), + }) + } + return signals + }), + mp.NewField("ecu_maps", 1, mp.Unsigned, mp.BigEndian, func(f mp.Field) []mp.Signal { + signals := []mp.Signal{} + signals = append(signals, mp.Signal{ + Name: "ecu_power_level", + Value: float64((f.Value >> 4) & 0x0F), + RawValue: (f.Value >> 4) & 0x0F, + }) + signals = append(signals, mp.Signal{ + Name: "ecu_torque_map", + Value: float64(f.Value & 0x0F), + RawValue: f.Value & 0x0F, + }) + return signals + }), + mp.NewField("ecu_max_cell_temp", 1, mp.Unsigned, mp.BigEndian, func(f mp.Field) []mp.Signal { + signals := []mp.Signal{} + signals = append(signals, mp.Signal{ + Name: "ecu_max_cell_temp", + Value: float64(f.Value) * 0.25, + RawValue: f.Value, + }) + return signals + }), + mp.NewField("ecu_acu_state_of_charge", 1, mp.Unsigned, mp.BigEndian, func(f mp.Field) []mp.Signal { + signals := []mp.Signal{} + signals = append(signals, mp.Signal{ + Name: "ecu_acu_state_of_charge", + Value: float64(f.Value) * 20 / 51, + RawValue: f.Value, + }) + return signals + }), + mp.NewField("ecu_glv_state_of_charge", 1, mp.Unsigned, mp.BigEndian, func(f mp.Field) []mp.Signal { + signals := []mp.Signal{} + signals = append(signals, mp.Signal{ + Name: "ecu_glv_state_of_charge", + Value: float64(f.Value) * 20 / 51, + RawValue: f.Value, + }) + return signals + }), +} diff --git a/gr25/model/message.go b/gr25/model/message.go new file mode 100644 index 00000000..3be674f4 --- /dev/null +++ b/gr25/model/message.go @@ -0,0 +1,14 @@ +package model + +import mp "github.com/gaucho-racing/mapache-go" + +var messageMap = map[int]mp.Message{ + 0x003: ecuStatusOne, +} + +func GetMessage(id int) mp.Message { + if msg, ok := messageMap[id]; ok { + return msg + } + return nil +} diff --git a/gr25/mqtt/mqtt.go b/gr25/mqtt/mqtt.go new file mode 100644 index 00000000..a400d8b5 --- /dev/null +++ b/gr25/mqtt/mqtt.go @@ -0,0 +1,25 @@ +package mqtt + +import ( + "fmt" + "gr25/config" + "gr25/utils" + + mq "github.com/eclipse/paho.mqtt.golang" +) + +var Client mq.Client + +func InitializeMQTT() { + opts := mq.NewClientOptions() + opts.AddBroker(fmt.Sprintf("tcp://%s:%s", config.MQTTHost, config.MQTTPort)) + opts.SetUsername(config.MQTTUser) + opts.SetPassword(config.MQTTPassword) + opts.SetAutoReconnect(true) + opts.SetClientID(fmt.Sprintf("%s-%d", config.Service.Name, config.Service.ID)) + Client = mq.NewClient(opts) + if token := Client.Connect(); token.Wait() && token.Error() != nil { + utils.SugarLogger.Fatalln("[MQ] Failed to connect to MQTT", token.Error()) + } + utils.SugarLogger.Infoln("[MQ] Connected to MQTT broker") +} diff --git a/gr25/service/message.go b/gr25/service/message.go new file mode 100644 index 00000000..a2e02e7f --- /dev/null +++ b/gr25/service/message.go @@ -0,0 +1,75 @@ +package service + +import ( + "encoding/binary" + "gr25/model" + "gr25/mqtt" + "gr25/utils" + "strconv" + "strings" + "time" + + mq "github.com/eclipse/paho.mqtt.golang" +) + +func SubscribeTopics() { + mqtt.Client.Subscribe("gr25/#", 0, func(client mq.Client, msg mq.Message) { + topic := msg.Topic() + if len(strings.Split(topic, "/")) != 3 { + utils.SugarLogger.Infof("[MQ] Received invalid topic: %s, ignoring", topic) + return + } + vehicleID := strings.Split(topic, "/")[1] + canID := strings.Split(topic, "/")[2] + message := msg.Payload() + canIDInt, err := strconv.ParseInt(canID, 16, 64) + if err != nil { + utils.SugarLogger.Infof("[MQ] Received invalid can id: %s, ignoring", canID) + return + } + utils.SugarLogger.Infof("[MQ] Received message: %s", topic) + go HandleMessage(vehicleID, int(canIDInt), message) + }) +} + +func HandleMessage(vehicleID string, canID int, message []byte) { + // First 8 bytes are timestamp + if len(message) < 10 { // Need at least timestamp (8) + upload key (2) + utils.SugarLogger.Infof("[MQ] Message too short, ignoring") + return + } + timestamp := message[:8] + uploadKey := message[8:10] + data := message[10:] + + // TODO: Check upload key + if int(binary.BigEndian.Uint16(uploadKey)) == 0 { + utils.SugarLogger.Infof("Received invalid upload key: %x, ignoring", uploadKey) + return + } + + messageStruct := model.GetMessage(canID) + if messageStruct == nil { + utils.SugarLogger.Infof("Received unknown message id: %d, ignoring", canID) + return + } + + err := messageStruct.FillFromBytes(data) + if err != nil { + utils.SugarLogger.Infof("Error deserializing message: %s", err) + return + } + + signals := messageStruct.ExportSignals() + for _, signal := range signals { + signal.Timestamp = int(binary.BigEndian.Uint64(timestamp)) + signal.VehicleID = vehicleID + signal.ProducedAt = time.UnixMicro(int64(signal.Timestamp)) + signal.CreatedAt = utils.WithPrecision(time.Now()) + + err := CreateSignal(signal) + if err != nil { + utils.SugarLogger.Infof("Error creating signal: %s", err) + } + } +} diff --git a/gr25/service/signal.go b/gr25/service/signal.go new file mode 100644 index 00000000..284a86b0 --- /dev/null +++ b/gr25/service/signal.go @@ -0,0 +1,45 @@ +package service + +import ( + "fmt" + "gr25/database" + "gr25/utils" + + "github.com/gaucho-racing/mapache-go" + "go.uber.org/zap" +) + +func GetSignal(timestamp int, vehicleID string, name string) mapache.Signal { + var signal mapache.Signal + database.DB.Where("timestamp = ?", timestamp).Where("vehicle_id = ?", vehicleID).Where("name = ?", name).First(&signal) + return signal +} + +func CreateSignal(signal mapache.Signal) error { + if signal.Timestamp == 0 { + return fmt.Errorf("signal timestamp cannot be 0") + } + if signal.VehicleID == "" { + return fmt.Errorf("signal vehicle id cannot be empty") + } + if signal.Name == "" { + return fmt.Errorf("signal name cannot be empty") + } + if database.DB.Where("timestamp = ?", signal.Timestamp).Where("vehicle_id = ?", signal.VehicleID).Where("name = ?", signal.Name).Updates(&signal).RowsAffected == 0 { + utils.SugarLogger.Infow("[DB] New signal created", []zap.Field{ + zap.Int("timestamp", signal.Timestamp), + zap.String("vehicle_id", signal.VehicleID), + zap.String("name", signal.Name), + }) + if result := database.DB.Create(&signal); result.Error != nil { + return result.Error + } + } else { + utils.SugarLogger.Infow("[DB] Existing signal updated", []zap.Field{ + zap.Int("timestamp", signal.Timestamp), + zap.String("vehicle_id", signal.VehicleID), + zap.String("name", signal.Name), + }) + } + return nil +} From ec4a64b247b4378a132f434a85aca770d6ce22a1 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 13 Feb 2025 23:06:56 -0800 Subject: [PATCH 08/95] fixed logging in createsignal func --- gr25/service/signal.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/gr25/service/signal.go b/gr25/service/signal.go index 284a86b0..f59f6bba 100644 --- a/gr25/service/signal.go +++ b/gr25/service/signal.go @@ -6,7 +6,6 @@ import ( "gr25/utils" "github.com/gaucho-racing/mapache-go" - "go.uber.org/zap" ) func GetSignal(timestamp int, vehicleID string, name string) mapache.Signal { @@ -26,20 +25,20 @@ func CreateSignal(signal mapache.Signal) error { return fmt.Errorf("signal name cannot be empty") } if database.DB.Where("timestamp = ?", signal.Timestamp).Where("vehicle_id = ?", signal.VehicleID).Where("name = ?", signal.Name).Updates(&signal).RowsAffected == 0 { - utils.SugarLogger.Infow("[DB] New signal created", []zap.Field{ - zap.Int("timestamp", signal.Timestamp), - zap.String("vehicle_id", signal.VehicleID), - zap.String("name", signal.Name), - }) + utils.SugarLogger.Infow("[DB] New signal created", + "timestamp", signal.Timestamp, + "vehicle_id", signal.VehicleID, + "name", signal.Name, + ) if result := database.DB.Create(&signal); result.Error != nil { return result.Error } } else { - utils.SugarLogger.Infow("[DB] Existing signal updated", []zap.Field{ - zap.Int("timestamp", signal.Timestamp), - zap.String("vehicle_id", signal.VehicleID), - zap.String("name", signal.Name), - }) + utils.SugarLogger.Infow("[DB] Existing signal updated", + "timestamp", signal.Timestamp, + "vehicle_id", signal.VehicleID, + "name", signal.Name, + ) } return nil } From cb53c4716bbb9f0ce5f06731da19c801946be79b Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Sat, 15 Feb 2025 15:26:37 -0800 Subject: [PATCH 09/95] update docker compose --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1db25dab..dbed25cf 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,4 @@ -version: "3.9" +name: mapache services: kerbecs: From 23f7300190a62b605733b0eb4e73a0e026af88ff Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Sat, 15 Feb 2025 15:35:42 -0800 Subject: [PATCH 10/95] Trigger Build From 04315fe2caf526ddb0128bd77cd6b49249926cec Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Sat, 15 Feb 2025 15:36:21 -0800 Subject: [PATCH 11/95] Trigger Build From 3f7b97ebd7aed762989d842314691ed0796d72c1 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Sat, 15 Feb 2025 15:41:04 -0800 Subject: [PATCH 12/95] Trigger Build From 2e0584e0a816638c0491309f19bc402148303291 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 11:37:10 -0800 Subject: [PATCH 13/95] Trigger Build From 21f31365a6fe7ea23bfb117c6b39dcd6254a8489 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 11:39:06 -0800 Subject: [PATCH 14/95] Trigger Build From 0790d9549b37d293a36e3d9e1a7d7865abec5fa6 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 11:42:04 -0800 Subject: [PATCH 15/95] Trigger Build From 0c879cd27ca331e084d30ea443b932533e44e846 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 11:53:01 -0800 Subject: [PATCH 16/95] Trigger Build From bffd7488ab818ec02f50df7d9581fda9de659959 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:02:41 -0800 Subject: [PATCH 17/95] Trigger Build From cee132d6c85d3d3959308f5c340ee5a5feff4352 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:06:07 -0800 Subject: [PATCH 18/95] Trigger Build From c0958f66e3511446a6678b5af75ebd0677ee1730 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:13:48 -0800 Subject: [PATCH 19/95] Trigger Build From 125c27d68f54caa4319ff366ddf8cfb971ab0e4e Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:15:04 -0800 Subject: [PATCH 20/95] Trigger Build From c96930aa2f78c271de85c850115cd5e2b06a0f86 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:18:54 -0800 Subject: [PATCH 21/95] Trigger Build From df25430d62be73379fe7b1cf18ca164a1daa3f1b Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:28:11 -0800 Subject: [PATCH 22/95] Trigger Build From 125e763d7b2034593abd671de0a69751d9fe0741 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:28:42 -0800 Subject: [PATCH 23/95] Trigger Build From 4478ed2e3421804ba2ee20d169e0b3fd113ebe10 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:29:13 -0800 Subject: [PATCH 24/95] Trigger Build From c20891ff0b89d2c584671551af62eea606b39c70 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:31:00 -0800 Subject: [PATCH 25/95] Trigger Build From 36a80fa81f7ee90ebdc9a9c46fe8a69f59ed2e7f Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 12:38:18 -0800 Subject: [PATCH 26/95] Trigger Build From 53043a16ab71a63b8464f02b68ea81a60bc1d3de Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 19:44:08 -0800 Subject: [PATCH 27/95] Trigger Build From 10e15e38c862ee9533a7ed90ba9a28d8cecc77dd Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 20:21:33 -0800 Subject: [PATCH 28/95] Trigger Build From 48d11e439a48fe44f486385759c53ed1cdb7b77b Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 20:38:14 -0800 Subject: [PATCH 29/95] Trigger Build From f2177c8e6f17e5520ca228123a70a54c673fa380 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 20:42:41 -0800 Subject: [PATCH 30/95] Trigger Build From fe086368cdd785dd56e70a51ee3a0e0cad53b697 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 20:43:25 -0800 Subject: [PATCH 31/95] Trigger Build From ec95c739a7882981e2a992d7749abf97696395c7 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:09:11 -0800 Subject: [PATCH 32/95] Trigger Build From 3cc635af6f4b069f760b381e1e8844ca6f2d8eee Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:11:25 -0800 Subject: [PATCH 33/95] Trigger Build From f7f06cb197d1ca6cf0d49cf18060a9da7266ff60 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:13:27 -0800 Subject: [PATCH 34/95] Trigger Build From 86721fce6566f2972dfa99b2c23754758fa9d143 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:22:03 -0800 Subject: [PATCH 35/95] Trigger Build From e00debffdb3d4a4f2784925a2eb0dc7e91d2758e Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:29:31 -0800 Subject: [PATCH 36/95] Trigger Build From b2cc6c9cc7bc1629548380bb9149ebd036556188 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:35:36 -0800 Subject: [PATCH 37/95] Trigger Build From c73625a0aeb9f8fc3225071b2ad0afb414384e19 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:39:55 -0800 Subject: [PATCH 38/95] Trigger Build From db8168a551d4a7ce7ede6463e8c8b33177341fd9 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:44:59 -0800 Subject: [PATCH 39/95] Trigger Build From e783c5c2187f88205ce6b99de016a38829fd7a32 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Tue, 18 Feb 2025 21:51:56 -0800 Subject: [PATCH 40/95] Trigger Build From f43b06775e5b5419bf77192876149f34e87b4fcc Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 10:50:41 -0800 Subject: [PATCH 41/95] Trigger Build From cafa9febbbaab277abf22cff233767235b640d21 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 10:55:12 -0800 Subject: [PATCH 42/95] Trigger Build From 2f6581478affecdc4b03c29bbfca13774fd40b16 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 10:58:55 -0800 Subject: [PATCH 43/95] Trigger Build From 140221775c69adc925779d6768283eac3b6087d4 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:04:37 -0800 Subject: [PATCH 44/95] Trigger Build From 9c1218c7954b64b9650dcbb29e3ca7abb6d72520 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:25:49 -0800 Subject: [PATCH 45/95] Trigger Build From 77838d19605bae95c97448e3a89dc9964b8af32c Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:09 -0800 Subject: [PATCH 46/95] Trigger Build From 903943b55e901e6284fc20aac216f39132e48931 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:24 -0800 Subject: [PATCH 47/95] Trigger Build From e28408ac0d3989d089eac05c41e9fd8c15e864c7 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:27 -0800 Subject: [PATCH 48/95] Trigger Build From 2d4b45caadfdd89cd01c7205f3e75665bf0fa11a Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:30 -0800 Subject: [PATCH 49/95] Trigger Build From 210111a70dc152de7bdd8617a6296fd6af9f1245 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:35 -0800 Subject: [PATCH 50/95] Trigger Build From 5abd6ee163173cd996a72e19fd243cf56fb5c907 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:43 -0800 Subject: [PATCH 51/95] Trigger Build From 8df13eecdc6152d10b20c3c113a57ead62ddcc0e Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:45 -0800 Subject: [PATCH 52/95] Trigger Build From 420f46c72762b6819b40dccab1ca28ef9642e930 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:46 -0800 Subject: [PATCH 53/95] Trigger Build From dc69438f5aafd43eb3cb035ee466509bd1e91488 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:48 -0800 Subject: [PATCH 54/95] Trigger Build From d79d3985836f69ac2eadf9c99343dbe191dbd137 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:27:50 -0800 Subject: [PATCH 55/95] Trigger Build From 570e3ce2fda07724dc9820319a13407c34cb473d Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:16 -0800 Subject: [PATCH 56/95] Trigger Build From 53269b42ea392437878d16e187ba43eb078052ef Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:19 -0800 Subject: [PATCH 57/95] Trigger Build From 1253ee16d298774e3d14f36de9b7025fe9fc518a Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:23 -0800 Subject: [PATCH 58/95] Trigger Build From ceffd549989d80b17fb9088cfbb3efb5196b94b0 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:39 -0800 Subject: [PATCH 59/95] Trigger Build From 3bf54f6f0287d805b171b1225c78c48116506396 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:42 -0800 Subject: [PATCH 60/95] Trigger Build From a980e9e9bd7b9ea17bb9511e6ac5ed02b7eaaf6f Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:44 -0800 Subject: [PATCH 61/95] Trigger Build From 63419bef2a901c98e7216c0193956d2108910a4c Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:47 -0800 Subject: [PATCH 62/95] Trigger Build From a425fd208c3abb6248385c00e9bde0b7e08846d8 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:50 -0800 Subject: [PATCH 63/95] Trigger Build From 5b7a1e23eed96ace3447240bd33cf46d956d1793 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:55 -0800 Subject: [PATCH 64/95] Trigger Build From a7b1ec7d771c59d1604b2436f3c3f29f597b931e Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:28:58 -0800 Subject: [PATCH 65/95] Trigger Build From 2339466e4a52aa9184ae4f2dc13d3f7fb45da43e Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:29:06 -0800 Subject: [PATCH 66/95] Trigger Build From e872b84b77811f9749deb130696b207bdded8824 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:29:11 -0800 Subject: [PATCH 67/95] Trigger Build From 16086e2f34cb3b0df20ae480af5403fdeaca77dc Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:29:17 -0800 Subject: [PATCH 68/95] Trigger Build From a473b560e750fcf0d9ec2bfad46566dcfc8e8bd4 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:02 -0800 Subject: [PATCH 69/95] Trigger Build From 16abf8a874a78d96c7e2e563b1353ae4215d6c50 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:04 -0800 Subject: [PATCH 70/95] Trigger Build From c99dd9011447ac21c629bdeaaaa20e8b696f0dab Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:06 -0800 Subject: [PATCH 71/95] Trigger Build From b76ea1042353b0519109dc611c9981ee136883ca Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:09 -0800 Subject: [PATCH 72/95] Trigger Build From 72502bb170acbced0c7aaf48aa81f56c829c2451 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:13 -0800 Subject: [PATCH 73/95] Trigger Build From ca29a0b5d06f4d617d0f6d0088ae39ab47e4f3ab Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:30:43 -0800 Subject: [PATCH 74/95] Trigger Build From 03465b37bf77b373aca1a62ea42710617e0fa1c9 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:31:49 -0800 Subject: [PATCH 75/95] Trigger Build From 9997513c9c934cde5447ff04ca8c628aaef67ea3 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 11:32:53 -0800 Subject: [PATCH 76/95] Trigger Build From 07f05fdabee16f22f6110c31905922393cd9cb65 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 12:45:19 -0800 Subject: [PATCH 77/95] Trigger Build From bb9003310832250c203b9acf3ce4051c5ff25819 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 12:56:21 -0800 Subject: [PATCH 78/95] Trigger Build From 2e630918d10085722eb62d0eae77ea2bf0574aa8 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 12:58:26 -0800 Subject: [PATCH 79/95] Trigger Build From ba9edbcd8d3dce89cd1861c76d7c50ab0eb56291 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:04:47 -0800 Subject: [PATCH 80/95] Trigger Build From f7863d7ad26a2af8adf3e598250e558593cdf4e4 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:20:13 -0800 Subject: [PATCH 81/95] Trigger Build From df237c6abd18a160bbf68b02816eba5fcb7a23bf Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:32:49 -0800 Subject: [PATCH 82/95] Trigger Build From 4171357087d6df753533a0fd5ae5558f829c1e6d Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:40:06 -0800 Subject: [PATCH 83/95] Trigger Build From 94bb72ee1c7b24bdeb7a9582bcb357e59e02a9f6 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:45:33 -0800 Subject: [PATCH 84/95] Trigger Build From dabc00809a084847057d8d5439b7fe3d8244a8a8 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:51:15 -0800 Subject: [PATCH 85/95] Trigger Build From d35593c9e26379c82d902267a336a96b87dea017 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 13:54:43 -0800 Subject: [PATCH 86/95] Trigger Build From 07476fcd627281d24002220b9e6a80185adde47f Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 14:22:20 -0800 Subject: [PATCH 87/95] Trigger Build From 4a52a79a9c106caf593518592445438485f243f8 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 14:27:59 -0800 Subject: [PATCH 88/95] Trigger Build From 1b2611d30990f3f4127f7a11a482c7b9c3a02ae6 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 14:29:49 -0800 Subject: [PATCH 89/95] Trigger Build From c9df2f66ad7e4374992d6808d41b27c2e2a80510 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 15:04:16 -0800 Subject: [PATCH 90/95] Trigger Build From b666ce7ec0ef07ebb4cb9d2dfa82955328a415bc Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 15:08:00 -0800 Subject: [PATCH 91/95] Trigger Build From 4f19f56f86836db010bd9f1e6ea60707eb3a05b9 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 15:52:59 -0800 Subject: [PATCH 92/95] Trigger Build From 92eef2008ed745c0d3fb2faf62e4e752b1e557af Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 15:58:37 -0800 Subject: [PATCH 93/95] Trigger Build From 5d110f675d5b14f96f3dcacb1a25be4a7684508c Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 16:08:26 -0800 Subject: [PATCH 94/95] Trigger Build From 82bf4b16f70396dd19ce60d85cd02df3112d9efc Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Wed, 19 Feb 2025 16:29:04 -0800 Subject: [PATCH 95/95] Trigger Build