feat: initialize golang invite service project
This commit is contained in:
commit
ca828818cf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.DS_Store
|
||||
target/
|
||||
42
cmd/api/main.go
Normal file
42
cmd/api/main.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"chatapp3-golang/internal/config"
|
||||
invitehttp "chatapp3-golang/internal/http"
|
||||
"chatapp3-golang/internal/integration"
|
||||
"chatapp3-golang/internal/repo"
|
||||
"chatapp3-golang/internal/service"
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
repository, err := repo.New(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("init repository failed: %v", err)
|
||||
}
|
||||
|
||||
if cfg.AutoMigrate {
|
||||
if err := repository.AutoMigrate(); err != nil {
|
||||
log.Fatalf("auto migrate failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := repository.Ping(ctx); err != nil {
|
||||
log.Fatalf("ping dependencies failed: %v", err)
|
||||
}
|
||||
|
||||
javaClient := integration.New(cfg)
|
||||
inviteService := service.NewInviteService(cfg, repository, javaClient)
|
||||
baishunService := service.NewBaishunService(cfg, repository, javaClient)
|
||||
router := invitehttp.NewRouter(cfg, repository, javaClient, inviteService, baishunService)
|
||||
|
||||
log.Printf("chatapp3-golang invite api listening on %s", cfg.ListenAddr)
|
||||
if err := router.Run(cfg.ListenAddr); err != nil {
|
||||
log.Fatalf("run server failed: %v", err)
|
||||
}
|
||||
}
|
||||
45
go.mod
Normal file
45
go.mod
Normal file
@ -0,0 +1,45 @@
|
||||
module chatapp3-golang
|
||||
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/snowflake v0.3.0
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/redis/go-redis/v9 v9.7.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.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.20.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // 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.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // 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.2 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
112
go.sum
Normal file
112
go.sum
Normal file
@ -0,0 +1,112 @@
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
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/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
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.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.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.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
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-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.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
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/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/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=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
102
internal/config/config.go
Normal file
102
internal/config/config.go
Normal file
@ -0,0 +1,102 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ListenAddr string
|
||||
PublicBaseURL string
|
||||
MySQLDSN string
|
||||
RedisAddr string
|
||||
RedisPassword string
|
||||
RedisDB int
|
||||
AutoMigrate bool
|
||||
JavaAuthBaseURL string
|
||||
JavaDeviceBaseURL string
|
||||
JavaAppBaseURL string
|
||||
JavaBridgeBaseURL string
|
||||
JavaOtherBaseURL string
|
||||
JavaWalletBaseURL string
|
||||
BaishunPlatformBaseURL string
|
||||
BaishunAppID int64
|
||||
BaishunAppChannel string
|
||||
BaishunAppKey string
|
||||
BaishunGSP int
|
||||
BaishunLaunchCodeTTLSeconds int
|
||||
BaishunSSTokenTTLSeconds int
|
||||
InternalCallbackSecret string
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func Load() Config {
|
||||
return Config{
|
||||
ListenAddr: getEnv("INVITE_HTTP_ADDR", ":2900"),
|
||||
PublicBaseURL: getEnv("INVITE_PUBLIC_BASE_URL", "http://localhost:2900"),
|
||||
MySQLDSN: getEnv("INVITE_MYSQL_DSN", "root:root@tcp(127.0.0.1:3306)/chatapp3?charset=utf8mb4&parseTime=True&loc=Local"),
|
||||
RedisAddr: getEnv("INVITE_REDIS_ADDR", "127.0.0.1:6379"),
|
||||
RedisPassword: getEnv("INVITE_REDIS_PASSWORD", ""),
|
||||
RedisDB: getEnvInt("INVITE_REDIS_DB", 0),
|
||||
AutoMigrate: getEnvBool("INVITE_AUTO_MIGRATE", false),
|
||||
JavaAuthBaseURL: getEnv("INVITE_JAVA_AUTH_BASE_URL", "http://127.0.0.1:2100"),
|
||||
JavaDeviceBaseURL: getEnv("INVITE_JAVA_DEVICE_BASE_URL", "http://127.0.0.1:2400"),
|
||||
JavaAppBaseURL: getEnv("INVITE_JAVA_APP_BASE_URL", "http://127.0.0.1:2400"),
|
||||
JavaBridgeBaseURL: getEnv("INVITE_JAVA_BRIDGE_BASE_URL", "http://127.0.0.1:2200"),
|
||||
JavaOtherBaseURL: getEnv("GAME_JAVA_OTHER_BASE_URL", getEnv("INVITE_JAVA_APP_BASE_URL", "http://127.0.0.1:2400")),
|
||||
JavaWalletBaseURL: getEnv("GAME_JAVA_WALLET_BASE_URL", "http://127.0.0.1:2300"),
|
||||
BaishunPlatformBaseURL: getEnv("BAISHUN_PLATFORM_BASE_URL", ""),
|
||||
BaishunAppID: getEnvInt64("BAISHUN_APP_ID", 0),
|
||||
BaishunAppChannel: getEnv("BAISHUN_APP_CHANNEL", ""),
|
||||
BaishunAppKey: getEnv("BAISHUN_APP_KEY", ""),
|
||||
BaishunGSP: getEnvInt("BAISHUN_GSP", 101),
|
||||
BaishunLaunchCodeTTLSeconds: getEnvInt("BAISHUN_LAUNCH_CODE_TTL_SECONDS", 300),
|
||||
BaishunSSTokenTTLSeconds: getEnvInt("BAISHUN_SS_TOKEN_TTL_SECONDS", 86400),
|
||||
InternalCallbackSecret: getEnv("GAME_INTERNAL_CALLBACK_SECRET", ""),
|
||||
Timeout: time.Duration(getEnvInt("INVITE_HTTP_TIMEOUT_SECONDS", 8)) * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func getEnvInt(key string, fallback int) int {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func getEnvInt64(key string, fallback int64) int64 {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func getEnvBool(key string, fallback bool) bool {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
277
internal/http/baishun_handler.go
Normal file
277
internal/http/baishun_handler.go
Normal file
@ -0,0 +1,277 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"chatapp3-golang/internal/config"
|
||||
"chatapp3-golang/internal/integration"
|
||||
"chatapp3-golang/internal/service"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerBaishunRoutes(
|
||||
router *gin.Engine,
|
||||
cfg config.Config,
|
||||
javaClient *integration.Client,
|
||||
baishunService *service.BaishunService,
|
||||
) {
|
||||
appGroup := router.Group("/app/game")
|
||||
appGroup.Use(authMiddleware(javaClient))
|
||||
appGroup.GET("/room/shortcut", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
resp, err := baishunService.ListShortcutGames(c.Request.Context(), user, c.Query("roomId"))
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
appGroup.GET("/room/list", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
resp, err := baishunService.ListRoomGames(c.Request.Context(), user, c.Query("roomId"), c.Query("category"))
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
appGroup.GET("/baishun/state", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
resp, err := baishunService.GetRoomState(c.Request.Context(), user, c.Query("roomId"))
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
appGroup.POST("/baishun/launch", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
var req service.BaishunLaunchAppRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := baishunService.LaunchGame(c.Request.Context(), user, req, resolveClientIP(c))
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
appGroup.POST("/baishun/close", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
var req service.BaishunCloseAppRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := baishunService.CloseGame(c.Request.Context(), user, req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
|
||||
internalGroup := router.Group("/internal/game/baishun")
|
||||
internalGroup.Use(internalSecretMiddleware(cfg.InternalCallbackSecret))
|
||||
internalGroup.POST("/sync-catalog", func(c *gin.Context) {
|
||||
var req service.SyncCatalogRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := baishunService.SyncCatalog(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
internalGroup.POST("/refresh-room-state", func(c *gin.Context) {
|
||||
var req struct {
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
RoomID string `json:"roomId"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := baishunService.RefreshRoomState(c.Request.Context(), req.SysOrigin, req.RoomID)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
|
||||
callbackGroup := router.Group("/game/baishun")
|
||||
callbackGroup.POST("/token", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleToken(c.Request.Context(), mapToTokenRequest(payload), raw))
|
||||
})
|
||||
callbackGroup.POST("/profile", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleProfile(c.Request.Context(), mapToProfileRequest(payload), raw))
|
||||
})
|
||||
callbackGroup.POST("/update-token", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleUpdateToken(c.Request.Context(), mapToUpdateTokenRequest(payload), raw))
|
||||
})
|
||||
callbackGroup.POST("/change-balance", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleChangeBalance(c.Request.Context(), mapToChangeBalanceRequest(payload), raw))
|
||||
})
|
||||
callbackGroup.POST("/report", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleReport(c.Request.Context(), payload, raw))
|
||||
})
|
||||
callbackGroup.POST("/balance-info", func(c *gin.Context) {
|
||||
raw, payload := readRawPayload(c)
|
||||
writeBaishunJSON(c, http.StatusOK, baishunService.HandleBalanceInfo(c.Request.Context(), mapToBalanceInfoRequest(payload), raw))
|
||||
})
|
||||
}
|
||||
|
||||
func internalSecretMiddleware(secret string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if strings.TrimSpace(secret) == "" {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
token := strings.TrimSpace(c.GetHeader("X-Internal-Token"))
|
||||
if token != secret {
|
||||
writeError(c, service.NewAppError(http.StatusUnauthorized, "invalid_internal_token", "internal token is invalid"))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func writeBaishunJSON(c *gin.Context, status int, payload any) {
|
||||
c.JSON(status, payload)
|
||||
}
|
||||
|
||||
func readRawPayload(c *gin.Context) (string, map[string]any) {
|
||||
rawBytes, _ := c.GetRawData()
|
||||
raw := string(rawBytes)
|
||||
payload := map[string]any{}
|
||||
if len(rawBytes) > 0 {
|
||||
_ = json.Unmarshal(rawBytes, &payload)
|
||||
}
|
||||
return raw, payload
|
||||
}
|
||||
|
||||
func mapToTokenRequest(payload map[string]any) service.BaishunTokenRequest {
|
||||
return service.BaishunTokenRequest{
|
||||
AppID: asInt64(payload["app_id"]),
|
||||
UserID: asString(payload["user_id"]),
|
||||
Code: asString(payload["code"]),
|
||||
Signature: asString(payload["signature"]),
|
||||
SignatureNonce: asString(payload["signature_nonce"]),
|
||||
Timestamp: asInt64(payload["timestamp"]),
|
||||
}
|
||||
}
|
||||
|
||||
func mapToProfileRequest(payload map[string]any) service.BaishunProfileRequest {
|
||||
return service.BaishunProfileRequest{
|
||||
AppID: asInt64(payload["app_id"]),
|
||||
UserID: asString(payload["user_id"]),
|
||||
SSToken: asString(payload["ss_token"]),
|
||||
ClientIP: asString(payload["client_ip"]),
|
||||
GameID: int(asInt64(payload["game_id"])),
|
||||
Signature: asString(payload["signature"]),
|
||||
SignatureNonce: asString(payload["signature_nonce"]),
|
||||
Timestamp: asInt64(payload["timestamp"]),
|
||||
}
|
||||
}
|
||||
|
||||
func mapToUpdateTokenRequest(payload map[string]any) service.BaishunUpdateTokenRequest {
|
||||
return service.BaishunUpdateTokenRequest{
|
||||
AppID: asInt64(payload["app_id"]),
|
||||
UserID: asString(payload["user_id"]),
|
||||
SSToken: asString(payload["ss_token"]),
|
||||
GameID: int(asInt64(payload["game_id"])),
|
||||
Signature: asString(payload["signature"]),
|
||||
SignatureNonce: asString(payload["signature_nonce"]),
|
||||
Timestamp: asInt64(payload["timestamp"]),
|
||||
}
|
||||
}
|
||||
|
||||
func mapToChangeBalanceRequest(payload map[string]any) service.BaishunChangeBalanceRequest {
|
||||
var currencyType *int
|
||||
if rawValue, exists := payload["currency_type"]; exists && rawValue != nil {
|
||||
parsed := int(asInt64(rawValue))
|
||||
currencyType = &parsed
|
||||
}
|
||||
return service.BaishunChangeBalanceRequest{
|
||||
AppID: asInt64(payload["app_id"]),
|
||||
UserID: asString(payload["user_id"]),
|
||||
SSToken: asString(payload["ss_token"]),
|
||||
CurrencyDiff: asInt64(payload["currency_diff"]),
|
||||
DiffMsg: asString(payload["diff_msg"]),
|
||||
GameID: int(asInt64(payload["game_id"])),
|
||||
GameRoundID: asString(payload["game_round_id"]),
|
||||
RoomID: asString(payload["room_id"]),
|
||||
ChangeTimeAt: asInt64(payload["change_time_at"]),
|
||||
OrderID: asString(payload["order_id"]),
|
||||
Extend: asString(payload["extend"]),
|
||||
MsgType: asString(payload["msg_type"]),
|
||||
CurrencyType: currencyType,
|
||||
Signature: asString(payload["signature"]),
|
||||
SignatureNonce: asString(payload["signature_nonce"]),
|
||||
Timestamp: asInt64(payload["timestamp"]),
|
||||
}
|
||||
}
|
||||
|
||||
func mapToBalanceInfoRequest(payload map[string]any) service.BaishunBalanceInfoRequest {
|
||||
return service.BaishunBalanceInfoRequest{
|
||||
UserID: asString(payload["user_id"]),
|
||||
AppID: asInt64(payload["app_id"]),
|
||||
AppChannel: asString(payload["app_channel"]),
|
||||
Signature: asString(payload["signature"]),
|
||||
SignatureNonce: asString(payload["signature_nonce"]),
|
||||
Timestamp: asInt64(payload["timestamp"]),
|
||||
}
|
||||
}
|
||||
|
||||
func asString(value any) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
return strings.TrimSpace(typed)
|
||||
case json.Number:
|
||||
return typed.String()
|
||||
default:
|
||||
return strings.TrimSpace(fmt.Sprint(typed))
|
||||
}
|
||||
}
|
||||
|
||||
func asInt64(value any) int64 {
|
||||
if value == nil {
|
||||
return 0
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case int64:
|
||||
return typed
|
||||
case int:
|
||||
return int64(typed)
|
||||
case float64:
|
||||
return int64(typed)
|
||||
case json.Number:
|
||||
parsed, _ := typed.Int64()
|
||||
return parsed
|
||||
case string:
|
||||
parsed, _ := strconv.ParseInt(strings.TrimSpace(typed), 10, 64)
|
||||
return parsed
|
||||
default:
|
||||
parsed, _ := strconv.ParseInt(strings.TrimSpace(fmt.Sprint(typed)), 10, 64)
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
204
internal/http/router.go
Normal file
204
internal/http/router.go
Normal file
@ -0,0 +1,204 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"chatapp3-golang/internal/config"
|
||||
"chatapp3-golang/internal/integration"
|
||||
"chatapp3-golang/internal/repo"
|
||||
"chatapp3-golang/internal/service"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const authUserContextKey = "auth_user"
|
||||
|
||||
func NewRouter(
|
||||
cfg config.Config,
|
||||
repository *repo.Repository,
|
||||
javaClient *integration.Client,
|
||||
inviteService *service.InviteService,
|
||||
baishunService *service.BaishunService,
|
||||
) *gin.Engine {
|
||||
router := gin.New()
|
||||
router.Use(gin.Logger(), gin.Recovery())
|
||||
|
||||
router.GET("/health", func(c *gin.Context) {
|
||||
ctx, cancel := context.WithTimeout(c.Request.Context(), cfg.Timeout)
|
||||
defer cancel()
|
||||
if err := repository.Ping(ctx); err != nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{
|
||||
"code": "dependency_unavailable",
|
||||
"message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"code": "ok", "message": "success"})
|
||||
})
|
||||
|
||||
router.GET("/public/h5/invite-campaign/landing", func(c *gin.Context) {
|
||||
resp, err := inviteService.GetLanding(c.Request.Context(), c.Query("code"))
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
|
||||
internal := router.Group("/internal/invite-campaign")
|
||||
internal.POST("/recharge-success", func(c *gin.Context) {
|
||||
var req service.RechargeSuccessRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := inviteService.HandleRechargeSuccess(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
|
||||
authenticated := router.Group("/app/h5/invite-campaign")
|
||||
authenticated.Use(authMiddleware(javaClient))
|
||||
authenticated.GET("/home", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
resp, err := inviteService.GetHome(c.Request.Context(), user)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
authenticated.POST("/bind-code", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
var req service.BindCodeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := inviteService.BindCode(c.Request.Context(), user, resolveClientIP(c), req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
authenticated.POST("/tasks/claim", func(c *gin.Context) {
|
||||
user := mustAuthUser(c)
|
||||
var req service.TaskClaimRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
||||
return
|
||||
}
|
||||
resp, err := inviteService.ClaimTask(c.Request.Context(), user, req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeOK(c, resp)
|
||||
})
|
||||
|
||||
registerBaishunRoutes(router, cfg, javaClient, baishunService)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func authMiddleware(javaClient *integration.Client) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
authorization := strings.TrimSpace(c.GetHeader("Authorization"))
|
||||
if authorization == "" {
|
||||
writeError(c, service.NewAppError(http.StatusUnauthorized, "missing_authorization", "authorization is required"))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
token := trimBearer(authorization)
|
||||
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
credential, err := javaClient.AuthenticateToken(ctx, token)
|
||||
if err != nil {
|
||||
writeError(c, service.NewAppError(http.StatusUnauthorized, "invalid_token", err.Error()))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Set(authUserContextKey, service.AuthUser{
|
||||
UserID: int64(credential.UserID),
|
||||
SysOrigin: credential.SysOrigin,
|
||||
Token: token,
|
||||
Authorization: authorization,
|
||||
})
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func mustAuthUser(c *gin.Context) service.AuthUser {
|
||||
value, exists := c.Get(authUserContextKey)
|
||||
if !exists {
|
||||
return service.AuthUser{}
|
||||
}
|
||||
user, _ := value.(service.AuthUser)
|
||||
return user
|
||||
}
|
||||
|
||||
func writeOK(c *gin.Context, data any) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": true,
|
||||
"errorCode": 0,
|
||||
"errorMsg": "success",
|
||||
"body": data,
|
||||
"code": "success",
|
||||
"message": "success",
|
||||
"data": data,
|
||||
"time": time.Now().UnixMilli(),
|
||||
})
|
||||
}
|
||||
|
||||
func writeError(c *gin.Context, err error) {
|
||||
var appErr *service.AppError
|
||||
if errors.As(err, &appErr) {
|
||||
c.JSON(appErr.Status, gin.H{
|
||||
"status": false,
|
||||
"errorCode": appErr.Status,
|
||||
"errorCodeName": appErr.Code,
|
||||
"errorMsg": appErr.Message,
|
||||
"body": nil,
|
||||
"code": appErr.Code,
|
||||
"message": appErr.Message,
|
||||
"data": nil,
|
||||
"time": time.Now().UnixMilli(),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": false,
|
||||
"errorCode": http.StatusInternalServerError,
|
||||
"errorCodeName": "internal_error",
|
||||
"errorMsg": err.Error(),
|
||||
"body": nil,
|
||||
"code": "internal_error",
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
"time": time.Now().UnixMilli(),
|
||||
})
|
||||
}
|
||||
|
||||
func trimBearer(authorization string) string {
|
||||
if strings.HasPrefix(strings.ToLower(authorization), "bearer ") {
|
||||
return strings.TrimSpace(authorization[7:])
|
||||
}
|
||||
return authorization
|
||||
}
|
||||
|
||||
func resolveClientIP(c *gin.Context) string {
|
||||
if forwarded := strings.TrimSpace(c.GetHeader("X-Forwarded-For")); forwarded != "" {
|
||||
parts := strings.Split(forwarded, ",")
|
||||
if len(parts) > 0 {
|
||||
return strings.TrimSpace(parts[0])
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(c.ClientIP())
|
||||
}
|
||||
304
internal/integration/java.go
Normal file
304
internal/integration/java.go
Normal file
@ -0,0 +1,304 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"chatapp3-golang/internal/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
cfg config.Config
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
type UserCredential struct {
|
||||
UserID Int64Value `json:"userId"`
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
}
|
||||
|
||||
type UserProfile struct {
|
||||
ID Int64Value `json:"id"`
|
||||
UserAvatar string `json:"userAvatar"`
|
||||
UserNickname string `json:"userNickname"`
|
||||
}
|
||||
|
||||
type GoldReceiptCommand struct {
|
||||
ReceiptType string `json:"receiptType"`
|
||||
UserID int64 `json:"userId"`
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
EventID string `json:"eventId"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
Amount int64 `json:"amount"`
|
||||
CloseDelayAsset bool `json:"closeDelayAsset"`
|
||||
OpUserType string `json:"opUserType"`
|
||||
CustomizeOrigin string `json:"customizeOrigin,omitempty"`
|
||||
CustomizeOriginDesc string `json:"customizeOriginDesc,omitempty"`
|
||||
}
|
||||
|
||||
type TestGoldReceiptCommand struct {
|
||||
ReceiptType string `json:"receiptType"`
|
||||
UserID int64 `json:"userId"`
|
||||
EventType string `json:"eventType"`
|
||||
EventDesc string `json:"eventDesc"`
|
||||
EventID string `json:"eventId"`
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
Amount int64 `json:"amount"`
|
||||
CloseDelayAsset bool `json:"closeDelayAsset"`
|
||||
}
|
||||
|
||||
type InviteCode struct {
|
||||
UserID Int64Value `json:"userId"`
|
||||
InviteCode string `json:"inviteCode"`
|
||||
HasBound bool `json:"hasBound"`
|
||||
}
|
||||
|
||||
type GrantGoldRequest struct {
|
||||
UserID int64 `json:"userId"`
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
EventID string `json:"eventId"`
|
||||
Origin string `json:"origin"`
|
||||
GoldAmount int64 `json:"goldAmount"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type GrantPropsRequest struct {
|
||||
TrackID int64 `json:"trackId"`
|
||||
AcceptUserID int64 `json:"acceptUserId"`
|
||||
SysOrigin string `json:"sysOrigin"`
|
||||
Origin string `json:"origin"`
|
||||
SourceGroupID int64 `json:"sourceGroupId"`
|
||||
}
|
||||
|
||||
type resultResponse[T any] struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Body T `json:"body"`
|
||||
Success *bool `json:"success"`
|
||||
}
|
||||
|
||||
type Int64Value int64
|
||||
|
||||
func (v *Int64Value) UnmarshalJSON(data []byte) error {
|
||||
raw := strings.TrimSpace(string(data))
|
||||
if raw == "" || raw == "null" {
|
||||
*v = 0
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(raw, "\"") && strings.HasSuffix(raw, "\"") {
|
||||
raw = strings.Trim(raw, "\"")
|
||||
}
|
||||
parsed, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = Int64Value(parsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
func New(cfg config.Config) *Client {
|
||||
return &Client{
|
||||
cfg: cfg,
|
||||
httpClient: &http.Client{
|
||||
Timeout: cfg.Timeout,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) AuthenticateToken(ctx context.Context, token string) (UserCredential, error) {
|
||||
endpoint := c.cfg.JavaAuthBaseURL + "/auth/client/getUserCredentialByToken?token=" + url.QueryEscape(token)
|
||||
var resp resultResponse[UserCredential]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return UserCredential{}, err
|
||||
}
|
||||
if int64(resp.Body.UserID) == 0 {
|
||||
return UserCredential{}, fmt.Errorf("empty credential response")
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetDeviceFingerprint(ctx context.Context, userID int64) (string, error) {
|
||||
endpoint := c.cfg.JavaDeviceBaseURL + "/user/device/fingerprint?userId=" + url.QueryEscape(strconv.FormatInt(userID, 10))
|
||||
var resp resultResponse[string]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(resp.Body), nil
|
||||
}
|
||||
|
||||
func (c *Client) EnsureInviteCode(ctx context.Context, authorization string) (InviteCode, error) {
|
||||
endpoint := c.cfg.JavaAppBaseURL + "/activity/invite/user/my/invite/code"
|
||||
headers := http.Header{}
|
||||
if authorization != "" {
|
||||
headers.Set("Authorization", authorization)
|
||||
}
|
||||
var resp InviteCode
|
||||
if err := c.getJSON(ctx, endpoint, headers, &resp); err != nil {
|
||||
return InviteCode{}, err
|
||||
}
|
||||
if strings.TrimSpace(resp.InviteCode) == "" {
|
||||
return InviteCode{}, fmt.Errorf("invite code response is empty")
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) GrantGold(ctx context.Context, req GrantGoldRequest) error {
|
||||
return c.postJSON(ctx, c.cfg.JavaBridgeBaseURL+"/internal/resident-activity/invite/grant-gold", req, nil, nil)
|
||||
}
|
||||
|
||||
func (c *Client) GrantProps(ctx context.Context, req GrantPropsRequest) error {
|
||||
return c.postJSON(ctx, c.cfg.JavaBridgeBaseURL+"/internal/resident-activity/invite/grant-props", req, nil, nil)
|
||||
}
|
||||
|
||||
func (c *Client) GetUserProfile(ctx context.Context, userID int64) (UserProfile, error) {
|
||||
endpoint := c.cfg.JavaOtherBaseURL + "/user-profile/client/getByUserId?userId=" + url.QueryEscape(strconv.FormatInt(userID, 10))
|
||||
var resp resultResponse[UserProfile]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return UserProfile{}, err
|
||||
}
|
||||
if int64(resp.Body.ID) == 0 {
|
||||
return UserProfile{}, fmt.Errorf("empty user profile response")
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetUserLanguage(ctx context.Context, userID int64) (string, error) {
|
||||
endpoint := c.cfg.JavaOtherBaseURL + "/user-profile/client/getLanguage?userId=" + url.QueryEscape(strconv.FormatInt(userID, 10))
|
||||
var resp resultResponse[string]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(resp.Body), nil
|
||||
}
|
||||
|
||||
func (c *Client) MapGoldBalance(ctx context.Context, userIDs []int64) (map[int64]int64, error) {
|
||||
endpoint := c.cfg.JavaWalletBaseURL + "/wallet/gold/client/mapBalance"
|
||||
var resp resultResponse[map[string]int64]
|
||||
if err := c.postJSON(ctx, endpoint, userIDs, nil, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make(map[int64]int64, len(resp.Body))
|
||||
for key, value := range resp.Body {
|
||||
userID, err := strconv.ParseInt(key, 10, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
result[userID] = value
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Client) ExistsGoldEvent(ctx context.Context, eventID string) (bool, error) {
|
||||
endpoint := c.cfg.JavaWalletBaseURL + "/wallet/gold/client/existsEventId?eventId=" + url.QueryEscape(eventID)
|
||||
var resp resultResponse[bool]
|
||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
func (c *Client) ChangeGoldBalance(ctx context.Context, cmd GoldReceiptCommand) error {
|
||||
endpoint := c.cfg.JavaWalletBaseURL + "/wallet/gold/client/balance/change"
|
||||
if err := c.postJSON(ctx, endpoint, cmd, nil, nil); err == nil {
|
||||
return nil
|
||||
} else if !shouldFallbackToGoldTestEndpoint(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Some local environments only expose the lighter test endpoint payload.
|
||||
testCmd := TestGoldReceiptCommand{
|
||||
ReceiptType: cmd.ReceiptType,
|
||||
UserID: cmd.UserID,
|
||||
EventType: cmd.CustomizeOrigin,
|
||||
EventDesc: cmd.CustomizeOriginDesc,
|
||||
EventID: cmd.EventID,
|
||||
SysOrigin: cmd.SysOrigin,
|
||||
Remark: cmd.Remark,
|
||||
Amount: cmd.Amount,
|
||||
CloseDelayAsset: cmd.CloseDelayAsset,
|
||||
}
|
||||
return c.postJSON(ctx, c.cfg.JavaWalletBaseURL+"/wallet/gold/client/balance/change/test", testCmd, nil, nil)
|
||||
}
|
||||
|
||||
func shouldFallbackToGoldTestEndpoint(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
message := strings.ToLower(strings.TrimSpace(err.Error()))
|
||||
switch {
|
||||
case strings.Contains(message, "status=404"),
|
||||
strings.Contains(message, "status=405"),
|
||||
strings.Contains(message, "status=501"),
|
||||
strings.Contains(message, "connection refused"),
|
||||
strings.Contains(message, "no such host"),
|
||||
strings.Contains(message, "unsupported protocol"):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) getJSON(ctx context.Context, endpoint string, headers http.Header, out any) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applyHeaders(req.Header, headers)
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return decodeResponse(resp, out)
|
||||
}
|
||||
|
||||
func (c *Client) postJSON(ctx context.Context, endpoint string, payload any, headers http.Header, out any) error {
|
||||
data, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
applyHeaders(req.Header, headers)
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return decodeResponse(resp, out)
|
||||
}
|
||||
|
||||
func decodeResponse(resp *http.Response, out any) error {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("java api failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(body)))
|
||||
}
|
||||
if out == nil || len(body) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(body, out); err != nil {
|
||||
return fmt.Errorf("decode response failed: %w body=%s", err, strings.TrimSpace(string(body)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyHeaders(dst http.Header, src http.Header) {
|
||||
for key, values := range src {
|
||||
for _, value := range values {
|
||||
dst.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
162
internal/model/baishun_models.go
Normal file
162
internal/model/baishun_models.go
Normal file
@ -0,0 +1,162 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type SysGameListConfig struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32"`
|
||||
GameOrigin string `gorm:"column:game_origin;size:32"`
|
||||
GameID string `gorm:"column:game_id;size:64"`
|
||||
Name string `gorm:"column:name;size:128"`
|
||||
Category string `gorm:"column:category;size:64"`
|
||||
GameCode string `gorm:"column:game_code;size:512"`
|
||||
Cover string `gorm:"column:cover;size:1024"`
|
||||
Showcase bool `gorm:"column:is_showcase"`
|
||||
Sort int64 `gorm:"column:sort"`
|
||||
FullScreen bool `gorm:"column:full_screen"`
|
||||
ClientOrigin string `gorm:"column:client_origin;size:32"`
|
||||
Regions string `gorm:"column:regions;size:255"`
|
||||
GameMode string `gorm:"column:game_mode;size:255"`
|
||||
}
|
||||
|
||||
func (SysGameListConfig) TableName() string { return "sys_game_list_config" }
|
||||
|
||||
type SysGameListVendorExt struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
GameListConfigID int64 `gorm:"column:game_list_config_id;uniqueIndex:uk_game_vendor_ext_cfg_vendor,priority:1"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;index:idx_game_vendor_ext_sys_vendor,priority:1"`
|
||||
VendorType string `gorm:"column:vendor_type;size:32;uniqueIndex:uk_game_vendor_ext_cfg_vendor,priority:2;index:idx_game_vendor_ext_sys_vendor,priority:2"`
|
||||
VendorGameID string `gorm:"column:vendor_game_id;size:64"`
|
||||
LaunchMode string `gorm:"column:launch_mode;size:32"`
|
||||
PackageVersion string `gorm:"column:package_version;size:32"`
|
||||
PackageURL string `gorm:"column:package_url;size:1024"`
|
||||
PreviewURL string `gorm:"column:preview_url;size:1024"`
|
||||
Orientation *int `gorm:"column:orientation"`
|
||||
SafeHeight int `gorm:"column:safe_height"`
|
||||
GSP string `gorm:"column:gsp;size:64"`
|
||||
BridgeSchemaVersion string `gorm:"column:bridge_schema_version;size:16"`
|
||||
CurrencyType *int `gorm:"column:currency_type"`
|
||||
CurrencyIcon string `gorm:"column:currency_icon;size:1024"`
|
||||
ExtraJSON string `gorm:"column:extra_json;type:text"`
|
||||
Enabled bool `gorm:"column:enabled;index:idx_game_vendor_ext_sys_vendor,priority:3"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (SysGameListVendorExt) TableName() string { return "sys_game_list_vendor_ext" }
|
||||
|
||||
type BaishunGameCatalog struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_baishun_catalog_sys_vendor_game,priority:1;index:idx_baishun_catalog_internal_game,priority:1"`
|
||||
InternalGameID string `gorm:"column:internal_game_id;size:64;index:idx_baishun_catalog_internal_game,priority:2"`
|
||||
VendorGameID int `gorm:"column:vendor_game_id;uniqueIndex:uk_baishun_catalog_sys_vendor_game,priority:2"`
|
||||
Name string `gorm:"column:name;size:128"`
|
||||
Cover string `gorm:"column:cover;size:1024"`
|
||||
PreviewURL string `gorm:"column:preview_url;size:1024"`
|
||||
DownloadURL string `gorm:"column:download_url;size:1024"`
|
||||
PackageVersion string `gorm:"column:package_version;size:32"`
|
||||
GameModeJSON string `gorm:"column:game_mode_json;size:64"`
|
||||
Orientation *int `gorm:"column:orientation"`
|
||||
SafeHeight int `gorm:"column:safe_height"`
|
||||
VenueLevelJSON string `gorm:"column:venue_level_json;size:64"`
|
||||
GSP string `gorm:"column:gsp;size:64"`
|
||||
RawJSON string `gorm:"column:raw_json;type:longtext"`
|
||||
Status string `gorm:"column:status;size:32;index:idx_baishun_catalog_internal_game,priority:3"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (BaishunGameCatalog) TableName() string { return "baishun_game_catalog" }
|
||||
|
||||
type BaishunLaunchSession struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;index:idx_baishun_session_room_user,priority:1"`
|
||||
RoomID string `gorm:"column:room_id;size:64;index:idx_baishun_session_room_user,priority:2"`
|
||||
UserID int64 `gorm:"column:user_id;index:idx_baishun_session_room_user,priority:3"`
|
||||
InternalGameID string `gorm:"column:internal_game_id;size:64"`
|
||||
VendorGameID int `gorm:"column:vendor_game_id"`
|
||||
GameSessionID string `gorm:"column:game_session_id;size:64;uniqueIndex:uk_baishun_game_session"`
|
||||
LaunchCode string `gorm:"column:launch_code;size:128;uniqueIndex:uk_baishun_launch_code"`
|
||||
LaunchCodeExpireTime time.Time `gorm:"column:launch_code_expire_time"`
|
||||
SSToken *string `gorm:"column:ss_token;size:255;uniqueIndex:uk_baishun_ss_token"`
|
||||
SSTokenExpireTime *time.Time `gorm:"column:ss_token_expire_time;index:idx_baishun_session_token_expire"`
|
||||
Language string `gorm:"column:language;size:16"`
|
||||
GSP int `gorm:"column:gsp"`
|
||||
CurrencyType int `gorm:"column:currency_type"`
|
||||
CurrencyIcon string `gorm:"column:currency_icon;size:1024"`
|
||||
SceneMode int `gorm:"column:scene_mode"`
|
||||
GameMode int `gorm:"column:game_mode"`
|
||||
PackageVersion string `gorm:"column:package_version;size:32"`
|
||||
ClientIP string `gorm:"column:client_ip;size:64"`
|
||||
ClientOrigin string `gorm:"column:client_origin;size:16"`
|
||||
Status string `gorm:"column:status;size:32;index:idx_baishun_session_room_user,priority:4"`
|
||||
ClosedReason string `gorm:"column:closed_reason;size:64"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (BaishunLaunchSession) TableName() string { return "baishun_launch_session" }
|
||||
|
||||
type BaishunOrderIdempotency struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_baishun_order,priority:1;index:idx_baishun_order_user_time,priority:1"`
|
||||
OrderID string `gorm:"column:order_id;size:128;uniqueIndex:uk_baishun_order,priority:2"`
|
||||
GameRoundID string `gorm:"column:game_round_id;size:128;index:idx_baishun_round"`
|
||||
RoomID string `gorm:"column:room_id;size:64"`
|
||||
UserID int64 `gorm:"column:user_id;index:idx_baishun_order_user_time,priority:2"`
|
||||
VendorGameID int `gorm:"column:vendor_game_id"`
|
||||
CurrencyDiff int64 `gorm:"column:currency_diff"`
|
||||
DiffMsg string `gorm:"column:diff_msg;size:32"`
|
||||
MsgType string `gorm:"column:msg_type;size:64"`
|
||||
CurrencyType *int `gorm:"column:currency_type"`
|
||||
WalletEventID string `gorm:"column:wallet_event_id;size:160;uniqueIndex:uk_baishun_wallet_event"`
|
||||
WalletAssetRecordID *int64 `gorm:"column:wallet_asset_record_id"`
|
||||
Status string `gorm:"column:status;size:32"`
|
||||
RequestJSON string `gorm:"column:request_json;type:longtext"`
|
||||
ResponseJSON string `gorm:"column:response_json;type:longtext"`
|
||||
CreateTime time.Time `gorm:"column:create_time;index:idx_baishun_order_user_time,priority:3"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (BaishunOrderIdempotency) TableName() string { return "baishun_order_idempotency" }
|
||||
|
||||
type BaishunCallbackLog struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32"`
|
||||
RequestType string `gorm:"column:request_type;size:32;index:idx_baishun_log_type_time,priority:1"`
|
||||
OrderID string `gorm:"column:order_id;size:128;index:idx_baishun_log_order"`
|
||||
GameRoundID string `gorm:"column:game_round_id;size:128"`
|
||||
RoomID string `gorm:"column:room_id;size:64;index:idx_baishun_log_room_user,priority:1"`
|
||||
UserID *int64 `gorm:"column:user_id;index:idx_baishun_log_room_user,priority:2"`
|
||||
VendorGameID *int `gorm:"column:vendor_game_id"`
|
||||
RequestJSON string `gorm:"column:request_json;type:longtext"`
|
||||
ResponseJSON string `gorm:"column:response_json;type:longtext"`
|
||||
BizCode string `gorm:"column:biz_code;size:32"`
|
||||
BizMessage string `gorm:"column:biz_message;size:255"`
|
||||
Status string `gorm:"column:status;size:32"`
|
||||
CreateTime time.Time `gorm:"column:create_time;index:idx_baishun_log_type_time,priority:2"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (BaishunCallbackLog) TableName() string { return "baishun_callback_log" }
|
||||
|
||||
type BaishunRoomState struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_baishun_room_state,priority:1"`
|
||||
RoomID string `gorm:"column:room_id;size:64;uniqueIndex:uk_baishun_room_state,priority:2"`
|
||||
HostUserID int64 `gorm:"column:host_user_id"`
|
||||
CurrentGameID string `gorm:"column:current_game_id;size:64"`
|
||||
CurrentVendorGameID *int `gorm:"column:current_vendor_game_id"`
|
||||
CurrentGameName string `gorm:"column:current_game_name;size:128"`
|
||||
CurrentGameCover string `gorm:"column:current_game_cover;size:1024"`
|
||||
GameSessionID string `gorm:"column:game_session_id;size:64;index:idx_baishun_room_state_session"`
|
||||
LaunchUserID *int64 `gorm:"column:launch_user_id"`
|
||||
State string `gorm:"column:state;size:32"`
|
||||
ExtraJSON string `gorm:"column:extra_json;type:text"`
|
||||
StartTime *time.Time `gorm:"column:start_time"`
|
||||
EndTime *time.Time `gorm:"column:end_time"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (BaishunRoomState) TableName() string { return "baishun_room_state" }
|
||||
149
internal/model/models.go
Normal file
149
internal/model/models.go
Normal file
@ -0,0 +1,149 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type InviteCodeMapping struct {
|
||||
UserID int64 `gorm:"column:user_id;primaryKey"`
|
||||
InviteCode string `gorm:"column:invite_code;size:32;uniqueIndex:uk_invite_code"`
|
||||
Account string `gorm:"column:account;size:64"`
|
||||
}
|
||||
|
||||
func (InviteCodeMapping) TableName() string { return "invite_code_mapping" }
|
||||
|
||||
type UserBaseInfo struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
Account string `gorm:"column:account;size:64"`
|
||||
UserAvatar string `gorm:"column:user_avatar;size:255"`
|
||||
UserNickname string `gorm:"column:user_nickname;size:255"`
|
||||
OriginSys string `gorm:"column:origin_sys;size:32"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
}
|
||||
|
||||
func (UserBaseInfo) TableName() string { return "user_base_info" }
|
||||
|
||||
type InviteCampaignConfig struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_invite_campaign_sys_origin"`
|
||||
Enabled bool `gorm:"column:enabled"`
|
||||
DownloadURL string `gorm:"column:download_url;size:512"`
|
||||
ShareTitle string `gorm:"column:share_title;size:255"`
|
||||
ShareDesc string `gorm:"column:share_desc;size:255"`
|
||||
ServiceContact string `gorm:"column:service_contact;size:255"`
|
||||
Timezone string `gorm:"column:timezone;size:64"`
|
||||
AntiCheatSameIPOnce bool `gorm:"column:anti_cheat_same_ip_once"`
|
||||
AntiCheatSameDeviceOnce bool `gorm:"column:anti_cheat_same_device_once"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignConfig) TableName() string { return "invite_campaign_config" }
|
||||
|
||||
type InviteCampaignRewardRule struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;index:idx_invite_rule_sys_type_sort,priority:1"`
|
||||
RuleType string `gorm:"column:rule_type;size:32;index:idx_invite_rule_sys_type_sort,priority:2"`
|
||||
ThresholdValue int64 `gorm:"column:threshold_value"`
|
||||
GoldAmount int64 `gorm:"column:gold_amount"`
|
||||
RewardGroupID *int64 `gorm:"column:reward_group_id"`
|
||||
Enabled bool `gorm:"column:enabled"`
|
||||
Sort int `gorm:"column:sort;index:idx_invite_rule_sys_type_sort,priority:3"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignRewardRule) TableName() string { return "invite_campaign_reward_rule" }
|
||||
|
||||
type InviteCampaignRelation struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;index:idx_invite_relation_sys_inviter,priority:1;index:uk_invite_relation_invitee,priority:1,unique"`
|
||||
InviterUserID int64 `gorm:"column:inviter_user_id;index:idx_invite_relation_sys_inviter,priority:2"`
|
||||
InviteeUserID int64 `gorm:"column:invitee_user_id;index:uk_invite_relation_invitee,priority:2,unique"`
|
||||
InviteCode string `gorm:"column:invite_code;size:32"`
|
||||
BindIP string `gorm:"column:bind_ip;size:128;index:idx_invite_relation_ip"`
|
||||
DeviceFingerprint string `gorm:"column:device_fingerprint;size:255;index:idx_invite_relation_device"`
|
||||
EligibleStatus string `gorm:"column:eligible_status;size:32"`
|
||||
BlockReason string `gorm:"column:block_reason;size:255"`
|
||||
BindTime time.Time `gorm:"column:bind_time"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignRelation) TableName() string { return "invite_campaign_relation" }
|
||||
|
||||
type InviteCampaignInviteeProgress struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
RelationID int64 `gorm:"column:relation_id;uniqueIndex:uk_invitee_progress_relation"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32"`
|
||||
InviterUserID int64 `gorm:"column:inviter_user_id;index:idx_invitee_progress_inviter"`
|
||||
InviteeUserID int64 `gorm:"column:invitee_user_id;uniqueIndex:uk_invitee_progress_invitee"`
|
||||
TotalRecharge int64 `gorm:"column:total_recharge_coins"`
|
||||
ValidUser bool `gorm:"column:valid_user"`
|
||||
ValidTime *time.Time `gorm:"column:valid_time"`
|
||||
RewardedRuleIDs string `gorm:"column:rewarded_rule_ids;size:255"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignInviteeProgress) TableName() string { return "invite_campaign_invitee_progress" }
|
||||
|
||||
type InviteCampaignMonthlyProgress struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_invite_monthly_progress,priority:1"`
|
||||
InviterUserID int64 `gorm:"column:inviter_user_id;uniqueIndex:uk_invite_monthly_progress,priority:2"`
|
||||
MonthKey string `gorm:"column:month_key;size:6;uniqueIndex:uk_invite_monthly_progress,priority:3"`
|
||||
InviteCount int64 `gorm:"column:invite_count"`
|
||||
ValidUserCount int64 `gorm:"column:valid_user_count"`
|
||||
TotalRecharge int64 `gorm:"column:total_recharge_coins"`
|
||||
RewardGoldCoins int64 `gorm:"column:reward_gold_coins"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignMonthlyProgress) TableName() string { return "invite_campaign_monthly_progress" }
|
||||
|
||||
type InviteCampaignTaskClaim struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;uniqueIndex:uk_invite_task_claim,priority:1"`
|
||||
InviterUserID int64 `gorm:"column:inviter_user_id;uniqueIndex:uk_invite_task_claim,priority:2"`
|
||||
MonthKey string `gorm:"column:month_key;size:6;uniqueIndex:uk_invite_task_claim,priority:3"`
|
||||
RuleID int64 `gorm:"column:rule_id;uniqueIndex:uk_invite_task_claim,priority:4"`
|
||||
ClaimTime time.Time `gorm:"column:claim_time"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignTaskClaim) TableName() string { return "invite_campaign_task_claim" }
|
||||
|
||||
type InviteCampaignRewardLog struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32;index:idx_invite_reward_target"`
|
||||
RelationID *int64 `gorm:"column:relation_id"`
|
||||
InviterUserID *int64 `gorm:"column:inviter_user_id"`
|
||||
InviteeUserID *int64 `gorm:"column:invitee_user_id"`
|
||||
TargetUserID int64 `gorm:"column:target_user_id;index:idx_invite_reward_target"`
|
||||
RuleID *int64 `gorm:"column:rule_id"`
|
||||
RewardScene string `gorm:"column:reward_scene;size:32"`
|
||||
BusinessKey string `gorm:"column:business_key;size:128;uniqueIndex:uk_invite_reward_business"`
|
||||
GoldAmount int64 `gorm:"column:gold_amount"`
|
||||
RewardGroupID *int64 `gorm:"column:reward_group_id"`
|
||||
Status string `gorm:"column:status;size:32"`
|
||||
ErrorMessage string `gorm:"column:error_message;size:255"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignRewardLog) TableName() string { return "invite_campaign_reward_log" }
|
||||
|
||||
type InviteCampaignRechargeEvent struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
SysOrigin string `gorm:"column:sys_origin;size:32"`
|
||||
OrderID string `gorm:"column:order_id;size:128;uniqueIndex:uk_invite_recharge_order"`
|
||||
InviterUserID *int64 `gorm:"column:inviter_user_id"`
|
||||
InviteeUserID int64 `gorm:"column:invitee_user_id"`
|
||||
RechargeCoins int64 `gorm:"column:recharge_coins"`
|
||||
PayTime time.Time `gorm:"column:pay_time"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
UpdateTime time.Time `gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
func (InviteCampaignRechargeEvent) TableName() string { return "invite_campaign_recharge_event" }
|
||||
62
internal/repo/repo.go
Normal file
62
internal/repo/repo.go
Normal file
@ -0,0 +1,62 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"chatapp3-golang/internal/config"
|
||||
"chatapp3-golang/internal/model"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
DB *gorm.DB
|
||||
Redis *redis.Client
|
||||
}
|
||||
|
||||
func New(cfg config.Config) (*Repository, error) {
|
||||
db, err := gorm.Open(mysql.Open(cfg.MySQLDSN), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.RedisAddr,
|
||||
Password: cfg.RedisPassword,
|
||||
DB: cfg.RedisDB,
|
||||
})
|
||||
|
||||
return &Repository{DB: db, Redis: client}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) Ping(ctx context.Context) error {
|
||||
if err := r.Redis.Ping(ctx).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
sqlDB, err := r.DB.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDB.PingContext(ctx)
|
||||
}
|
||||
|
||||
func (r *Repository) AutoMigrate() error {
|
||||
return r.DB.AutoMigrate(
|
||||
&model.InviteCampaignConfig{},
|
||||
&model.InviteCampaignRewardRule{},
|
||||
&model.InviteCampaignRelation{},
|
||||
&model.InviteCampaignInviteeProgress{},
|
||||
&model.InviteCampaignMonthlyProgress{},
|
||||
&model.InviteCampaignTaskClaim{},
|
||||
&model.InviteCampaignRewardLog{},
|
||||
&model.InviteCampaignRechargeEvent{},
|
||||
&model.SysGameListVendorExt{},
|
||||
&model.BaishunGameCatalog{},
|
||||
&model.BaishunLaunchSession{},
|
||||
&model.BaishunOrderIdempotency{},
|
||||
&model.BaishunCallbackLog{},
|
||||
&model.BaishunRoomState{},
|
||||
)
|
||||
}
|
||||
1403
internal/service/baishun.go
Normal file
1403
internal/service/baishun.go
Normal file
File diff suppressed because it is too large
Load Diff
1527
internal/service/invite.go
Normal file
1527
internal/service/invite.go
Normal file
File diff suppressed because it is too large
Load Diff
23
internal/util/id.go
Normal file
23
internal/util/id.go
Normal file
@ -0,0 +1,23 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/bwmarrin/snowflake"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeOnce sync.Once
|
||||
node *snowflake.Node
|
||||
nodeErr error
|
||||
)
|
||||
|
||||
func NextID() (int64, error) {
|
||||
nodeOnce.Do(func() {
|
||||
node, nodeErr = snowflake.NewNode(1)
|
||||
})
|
||||
if nodeErr != nil {
|
||||
return 0, nodeErr
|
||||
}
|
||||
return node.Generate().Int64(), nil
|
||||
}
|
||||
124
migrations/001_invite_campaign.sql
Normal file
124
migrations/001_invite_campaign.sql
Normal file
@ -0,0 +1,124 @@
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_config (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
||||
download_url VARCHAR(512) DEFAULT NULL,
|
||||
share_title VARCHAR(255) DEFAULT NULL,
|
||||
share_desc VARCHAR(255) DEFAULT NULL,
|
||||
service_contact VARCHAR(255) DEFAULT NULL,
|
||||
timezone VARCHAR(64) NOT NULL DEFAULT 'Asia/Riyadh',
|
||||
anti_cheat_same_ip_once TINYINT(1) NOT NULL DEFAULT 1,
|
||||
anti_cheat_same_device_once TINYINT(1) NOT NULL DEFAULT 1,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_campaign_sys_origin (sys_origin)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_reward_rule (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
rule_type VARCHAR(32) NOT NULL,
|
||||
threshold_value BIGINT NOT NULL DEFAULT 0,
|
||||
gold_amount BIGINT NOT NULL DEFAULT 0,
|
||||
reward_group_id BIGINT DEFAULT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
sort INT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_invite_rule_sys_type_sort (sys_origin, rule_type, sort)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_relation (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
inviter_user_id BIGINT NOT NULL,
|
||||
invitee_user_id BIGINT NOT NULL,
|
||||
invite_code VARCHAR(32) NOT NULL,
|
||||
bind_ip VARCHAR(128) DEFAULT NULL,
|
||||
device_fingerprint VARCHAR(255) DEFAULT NULL,
|
||||
eligible_status VARCHAR(32) NOT NULL DEFAULT 'ELIGIBLE',
|
||||
block_reason VARCHAR(255) DEFAULT NULL,
|
||||
bind_time DATETIME NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_relation_invitee (sys_origin, invitee_user_id),
|
||||
KEY idx_invite_relation_sys_inviter (sys_origin, inviter_user_id),
|
||||
KEY idx_invite_relation_ip (bind_ip),
|
||||
KEY idx_invite_relation_device (device_fingerprint)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_invitee_progress (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
relation_id BIGINT NOT NULL,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
inviter_user_id BIGINT NOT NULL,
|
||||
invitee_user_id BIGINT NOT NULL,
|
||||
total_recharge_coins BIGINT NOT NULL DEFAULT 0,
|
||||
valid_user TINYINT(1) NOT NULL DEFAULT 0,
|
||||
valid_time DATETIME DEFAULT NULL,
|
||||
rewarded_rule_ids VARCHAR(255) DEFAULT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invitee_progress_relation (relation_id),
|
||||
UNIQUE KEY uk_invitee_progress_invitee (invitee_user_id),
|
||||
KEY idx_invitee_progress_inviter (inviter_user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_monthly_progress (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
inviter_user_id BIGINT NOT NULL,
|
||||
month_key VARCHAR(6) NOT NULL,
|
||||
invite_count BIGINT NOT NULL DEFAULT 0,
|
||||
valid_user_count BIGINT NOT NULL DEFAULT 0,
|
||||
total_recharge_coins BIGINT NOT NULL DEFAULT 0,
|
||||
reward_gold_coins BIGINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_monthly_progress (sys_origin, inviter_user_id, month_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_task_claim (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
inviter_user_id BIGINT NOT NULL,
|
||||
month_key VARCHAR(6) NOT NULL,
|
||||
rule_id BIGINT NOT NULL,
|
||||
claim_time DATETIME NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_task_claim (sys_origin, inviter_user_id, month_key, rule_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_reward_log (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
relation_id BIGINT DEFAULT NULL,
|
||||
inviter_user_id BIGINT DEFAULT NULL,
|
||||
invitee_user_id BIGINT DEFAULT NULL,
|
||||
target_user_id BIGINT NOT NULL,
|
||||
rule_id BIGINT DEFAULT NULL,
|
||||
reward_scene VARCHAR(32) NOT NULL,
|
||||
business_key VARCHAR(128) NOT NULL,
|
||||
gold_amount BIGINT NOT NULL DEFAULT 0,
|
||||
reward_group_id BIGINT DEFAULT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
error_message VARCHAR(255) DEFAULT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_reward_business (business_key),
|
||||
KEY idx_invite_reward_target (sys_origin, target_user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invite_campaign_recharge_event (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
order_id VARCHAR(128) NOT NULL,
|
||||
inviter_user_id BIGINT DEFAULT NULL,
|
||||
invitee_user_id BIGINT NOT NULL,
|
||||
recharge_coins BIGINT NOT NULL DEFAULT 0,
|
||||
pay_time DATETIME NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_invite_recharge_order (order_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
145
migrations/002_baishun_game.sql
Normal file
145
migrations/002_baishun_game.sql
Normal file
@ -0,0 +1,145 @@
|
||||
CREATE TABLE IF NOT EXISTS sys_game_list_vendor_ext (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
game_list_config_id BIGINT NOT NULL,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
vendor_type VARCHAR(32) NOT NULL,
|
||||
vendor_game_id VARCHAR(64) NOT NULL,
|
||||
launch_mode VARCHAR(32) NOT NULL DEFAULT 'H5_REMOTE',
|
||||
package_version VARCHAR(32) DEFAULT NULL,
|
||||
package_url VARCHAR(1024) DEFAULT NULL,
|
||||
preview_url VARCHAR(1024) DEFAULT NULL,
|
||||
orientation TINYINT DEFAULT NULL,
|
||||
safe_height INT NOT NULL DEFAULT 0,
|
||||
gsp VARCHAR(64) DEFAULT NULL,
|
||||
bridge_schema_version VARCHAR(16) NOT NULL DEFAULT '1.0',
|
||||
currency_type INT DEFAULT NULL,
|
||||
currency_icon VARCHAR(1024) DEFAULT NULL,
|
||||
extra_json TEXT DEFAULT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_game_vendor_ext_cfg_vendor (game_list_config_id, vendor_type),
|
||||
KEY idx_game_vendor_ext_sys_vendor (sys_origin, vendor_type, enabled)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS baishun_game_catalog (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
internal_game_id VARCHAR(64) NOT NULL,
|
||||
vendor_game_id INT NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
cover VARCHAR(1024) DEFAULT NULL,
|
||||
preview_url VARCHAR(1024) DEFAULT NULL,
|
||||
download_url VARCHAR(1024) DEFAULT NULL,
|
||||
package_version VARCHAR(32) DEFAULT NULL,
|
||||
game_mode_json VARCHAR(64) DEFAULT NULL,
|
||||
orientation TINYINT DEFAULT NULL,
|
||||
safe_height INT NOT NULL DEFAULT 0,
|
||||
venue_level_json VARCHAR(64) DEFAULT NULL,
|
||||
gsp VARCHAR(64) DEFAULT NULL,
|
||||
raw_json LONGTEXT DEFAULT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ENABLED',
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_baishun_catalog_sys_vendor_game (sys_origin, vendor_game_id),
|
||||
KEY idx_baishun_catalog_internal_game (sys_origin, internal_game_id, status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS baishun_launch_session (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
room_id VARCHAR(64) NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
internal_game_id VARCHAR(64) NOT NULL,
|
||||
vendor_game_id INT NOT NULL,
|
||||
game_session_id VARCHAR(64) NOT NULL,
|
||||
launch_code VARCHAR(128) NOT NULL,
|
||||
launch_code_expire_time DATETIME NOT NULL,
|
||||
ss_token VARCHAR(255) DEFAULT NULL,
|
||||
ss_token_expire_time DATETIME DEFAULT NULL,
|
||||
language VARCHAR(16) NOT NULL DEFAULT '0',
|
||||
gsp INT NOT NULL DEFAULT 0,
|
||||
currency_type INT NOT NULL DEFAULT 0,
|
||||
currency_icon VARCHAR(1024) DEFAULT NULL,
|
||||
scene_mode INT NOT NULL DEFAULT 0,
|
||||
game_mode INT NOT NULL DEFAULT 3,
|
||||
package_version VARCHAR(32) DEFAULT NULL,
|
||||
client_ip VARCHAR(64) DEFAULT NULL,
|
||||
client_origin VARCHAR(16) DEFAULT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'INIT',
|
||||
closed_reason VARCHAR(64) DEFAULT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_baishun_launch_code (launch_code),
|
||||
UNIQUE KEY uk_baishun_ss_token (ss_token),
|
||||
UNIQUE KEY uk_baishun_game_session (game_session_id),
|
||||
KEY idx_baishun_session_room_user (sys_origin, room_id, user_id, status),
|
||||
KEY idx_baishun_session_token_expire (ss_token_expire_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS baishun_order_idempotency (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
order_id VARCHAR(128) NOT NULL,
|
||||
game_round_id VARCHAR(128) DEFAULT NULL,
|
||||
room_id VARCHAR(64) NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
vendor_game_id INT NOT NULL,
|
||||
currency_diff BIGINT NOT NULL DEFAULT 0,
|
||||
diff_msg VARCHAR(32) NOT NULL,
|
||||
msg_type VARCHAR(64) DEFAULT NULL,
|
||||
currency_type INT DEFAULT NULL,
|
||||
wallet_event_id VARCHAR(160) NOT NULL,
|
||||
wallet_asset_record_id BIGINT DEFAULT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'INIT',
|
||||
request_json LONGTEXT DEFAULT NULL,
|
||||
response_json LONGTEXT DEFAULT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_baishun_order (sys_origin, order_id),
|
||||
UNIQUE KEY uk_baishun_wallet_event (wallet_event_id),
|
||||
KEY idx_baishun_round (game_round_id),
|
||||
KEY idx_baishun_order_user_time (sys_origin, user_id, create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS baishun_callback_log (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) DEFAULT NULL,
|
||||
request_type VARCHAR(32) NOT NULL,
|
||||
order_id VARCHAR(128) DEFAULT NULL,
|
||||
game_round_id VARCHAR(128) DEFAULT NULL,
|
||||
room_id VARCHAR(64) DEFAULT NULL,
|
||||
user_id BIGINT DEFAULT NULL,
|
||||
vendor_game_id INT DEFAULT NULL,
|
||||
request_json LONGTEXT DEFAULT NULL,
|
||||
response_json LONGTEXT DEFAULT NULL,
|
||||
biz_code VARCHAR(32) DEFAULT NULL,
|
||||
biz_message VARCHAR(255) DEFAULT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'SUCCESS',
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_baishun_log_type_time (request_type, create_time),
|
||||
KEY idx_baishun_log_order (order_id),
|
||||
KEY idx_baishun_log_room_user (room_id, user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS baishun_room_state (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
sys_origin VARCHAR(32) NOT NULL,
|
||||
room_id VARCHAR(64) NOT NULL,
|
||||
host_user_id BIGINT NOT NULL,
|
||||
current_game_id VARCHAR(64) DEFAULT NULL,
|
||||
current_vendor_game_id INT DEFAULT NULL,
|
||||
current_game_name VARCHAR(128) DEFAULT NULL,
|
||||
current_game_cover VARCHAR(1024) DEFAULT NULL,
|
||||
game_session_id VARCHAR(64) DEFAULT NULL,
|
||||
launch_user_id BIGINT DEFAULT NULL,
|
||||
state VARCHAR(32) NOT NULL DEFAULT 'IDLE',
|
||||
extra_json TEXT DEFAULT NULL,
|
||||
start_time DATETIME DEFAULT NULL,
|
||||
end_time DATETIME DEFAULT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_baishun_room_state (sys_origin, room_id),
|
||||
KEY idx_baishun_room_state_session (game_session_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
Loading…
x
Reference in New Issue
Block a user