From 04a8fa23444d1c732d84dc7f27a09a311c7d8151 Mon Sep 17 00:00:00 2001 From: "DESKTOP-V763RJ7\\Administrator" <835606593@qq.com> Date: Sat, 3 Jan 2026 14:26:11 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app.go | 55 ++++++++++++++++++ app/base.go | 33 +++++++++++ app/pprof.go | 44 ++++++++++++++ app/websocket.go | 31 ++++++++++ config/config.dev.yaml | 17 ++++++ config/config.go | 28 +++++++++ config/config.prod.yaml | 16 +++++ deploy/Dockerfile | 11 ++++ go.mod | 37 ++++++++++++ go.sum | 77 ++++++++++++++++++++++++ internal/ws/client.go | 126 ++++++++++++++++++++++++++++++++++++++++ internal/ws/handler.go | 70 ++++++++++++++++++++++ internal/ws/manager.go | 28 +++++++++ internal/ws/router.go | 15 +++++ main.go | 14 +++++ 15 files changed, 602 insertions(+) create mode 100644 app/app.go create mode 100644 app/base.go create mode 100644 app/pprof.go create mode 100644 app/websocket.go create mode 100644 config/config.dev.yaml create mode 100644 config/config.go create mode 100644 config/config.prod.yaml create mode 100644 deploy/Dockerfile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/ws/client.go create mode 100644 internal/ws/handler.go create mode 100644 internal/ws/manager.go create mode 100644 internal/ws/router.go create mode 100644 main.go diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000..b6df441 --- /dev/null +++ b/app/app.go @@ -0,0 +1,55 @@ +package app + +import ( + "common/log" + "fmt" + "github.com/judwhite/go-svc" + "robot/config" +) + +type Program struct { + moduleList []Module // 模块列表 +} + +type Module interface { + init() error + start() error + stop() error +} + +func (p *Program) Init(_ svc.Environment) error { + p.moduleList = append(p.moduleList, &ModuleBase{}) + p.moduleList = append(p.moduleList, &ModuleWebsocket{}) + p.moduleList = append(p.moduleList, &ModulePprof{}) + + for _, module := range p.moduleList { + if err := module.init(); err != nil { + return err + } + } + log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name)) + return nil +} + +func (p *Program) Start() error { + for _, module := range p.moduleList { + if err := module.start(); err != nil { + return err + } + } + + log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name)) + return nil +} + +func (p *Program) Stop() error { + for i := len(p.moduleList) - 1; i >= 0; i-- { + module := p.moduleList[i] + if err := module.stop(); err != nil { + log.Errorf("module stop error: %v", err) + } + } + + log.Infof(fmt.Sprintf("%v Stop successful...", config.Get().App.Name)) + return nil +} diff --git a/app/base.go b/app/base.go new file mode 100644 index 0000000..97c9e12 --- /dev/null +++ b/app/base.go @@ -0,0 +1,33 @@ +package app + +import ( + "common/log" + "common/utils" + "math/rand" + "robot/config" +) + +// ModuleBase 基础模块,或者一些零散的模块 +type ModuleBase struct { +} + +func (p *ModuleBase) init() error { + // 配置 + if err := config.LoadConfig(); err != nil { + return err + } + cfg := config.Get() + // 日志 + log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level) + // 雪花 + utils.InitSnowflake(int64(rand.Intn(1000))) + return nil +} + +func (p *ModuleBase) start() error { + return nil +} + +func (p *ModuleBase) stop() error { + return nil +} diff --git a/app/pprof.go b/app/pprof.go new file mode 100644 index 0000000..35840fe --- /dev/null +++ b/app/pprof.go @@ -0,0 +1,44 @@ +package app + +import ( + "common/log" + "context" + "errors" + "net/http" + _ "net/http/pprof" + "sync" +) + +// ModulePprof pprof模块 +type ModulePprof struct { + wg *sync.WaitGroup + server *http.Server +} + +func (m *ModulePprof) init() error { + m.wg = &sync.WaitGroup{} + return nil +} + +func (m *ModulePprof) start() error { + m.wg.Add(1) + go func() { + defer m.wg.Done() + m.server = &http.Server{ + Addr: "localhost:6060", + } + if err := m.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Errorf("pprof server failed: %v", err.Error()) + } + log.Infof("pprof server stop.") + }() + return nil +} + +func (m *ModulePprof) stop() error { + if err := m.server.Shutdown(context.Background()); err != nil { + log.Errorf("stop pprof server failed: %v", err) + } + m.wg.Wait() + return nil +} diff --git a/app/websocket.go b/app/websocket.go new file mode 100644 index 0000000..192cf28 --- /dev/null +++ b/app/websocket.go @@ -0,0 +1,31 @@ +package app + +import ( + "fmt" + "robot/config" + "robot/internal/ws" +) + +// ModuleWebsocket Websocket客户端模块 +type ModuleWebsocket struct { + manager *ws.Manager +} + +func (p *ModuleWebsocket) init() error { + cfg := config.Get().Client + addr := fmt.Sprintf("%s:%d", cfg.Websocket.Address, cfg.Websocket.Port) + if cfg.Websocket.Port == 0 { + addr = cfg.Websocket.Address + } + p.manager = ws.NewManager(addr) + return nil +} + +func (p *ModuleWebsocket) start() error { + p.manager.Start() + return nil +} + +func (p *ModuleWebsocket) stop() error { + return nil +} diff --git a/config/config.dev.yaml b/config/config.dev.yaml new file mode 100644 index 0000000..9b4157a --- /dev/null +++ b/config/config.dev.yaml @@ -0,0 +1,17 @@ +app: + name: "robot-dev" + +log: + debug: true + level: "debug" + maxSize: 10 + maxBackups: 100 + maxAge: 7 + +client: + count: 1100 + usn: [ 1,1000000 ] + websocket: +# address: "ws://47.108.184.184/ws/" + address: "ws://127.0.0.1" + port: 8501 \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..9c9b182 --- /dev/null +++ b/config/config.go @@ -0,0 +1,28 @@ +package config + +import "common/config" + +const path = "./config" + +type Config struct { + App *config.AppConfig `yaml:"app"` + Log *config.LogConfig `yaml:"log"` + Client *struct { + Count int32 `yaml:"count"` + USN []int64 `yaml:"usn"` + Websocket *config.AddressConfig `yaml:"websocket"` + } `yaml:"client"` +} + +var cfg *Config + +// LoadConfig 加载应用配置 +func LoadConfig() error { + c, err := config.LoadConfig(path, cfg) + cfg = c + return err +} + +func Get() *Config { + return cfg +} diff --git a/config/config.prod.yaml b/config/config.prod.yaml new file mode 100644 index 0000000..739efa8 --- /dev/null +++ b/config/config.prod.yaml @@ -0,0 +1,16 @@ +app: + name: "robot-prod" + +log: + debug: false + level: "debug" + maxSize: 10 + maxBackups: 100 + maxAge: 7 + +client: + count: 100 + usn: [ 1,1000000 ] + websocket: + address: "ws://172.18.28.0" + port: 8501 diff --git a/deploy/Dockerfile b/deploy/Dockerfile new file mode 100644 index 0000000..25632c6 --- /dev/null +++ b/deploy/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:latest + +RUN apk add --no-cache tzdata && \ + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone + +COPY robot/ /app/ +RUN chmod 777 /app/server-robot + +WORKDIR /app +CMD ["./server-robot"] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a06864f --- /dev/null +++ b/go.mod @@ -0,0 +1,37 @@ +module robot + +go 1.23.1 + +require ( + common v0.0.0-00010101000000-000000000000 + github.com/gorilla/websocket v1.5.3 + github.com/judwhite/go-svc v1.2.1 + google.golang.org/protobuf v1.36.9 +) + +require ( + github.com/bwmarrin/snowflake v0.3.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/grpc v1.71.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +) + +replace common => ../common diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bc87b1d --- /dev/null +++ b/go.sum @@ -0,0 +1,77 @@ +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +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/judwhite/go-svc v1.2.1 h1:a7fsJzYUa33sfDJRF2N/WXhA+LonCEEY8BJb1tuS5tA= +github.com/judwhite/go-svc v1.2.1/go.mod h1:mo/P2JNX8C07ywpP9YtO2gnBgnUiFTHqtsZekJrUuTk= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +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/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.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= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/ws/client.go b/internal/ws/client.go new file mode 100644 index 0000000..fc30974 --- /dev/null +++ b/internal/ws/client.go @@ -0,0 +1,126 @@ +package ws + +import ( + "common/log" + "common/proto/sc/sc_pb" + "context" + "crypto/tls" + "errors" + "fmt" + "github.com/gorilla/websocket" + "google.golang.org/protobuf/proto" +) + +type Client struct { + addr string + token string + + conn *websocket.Conn + ctx context.Context + cancel context.CancelFunc + writeChaen chan []byte +} + +func NewClient(addr string, token string) *Client { + c := &Client{ + addr: addr, + token: token, + writeChaen: make(chan []byte, 1024), + } + c.ctx, c.cancel = context.WithCancel(context.Background()) + return c +} + +func (c *Client) Start() { + go func() { + dialer := websocket.DefaultDialer + dialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + conn, _, err := dialer.Dial(fmt.Sprintf("%v?token=%v", c.addr, c.token), nil) + if err != nil { + log.Errorf("connect error %v", err.Error()) + return + } + c.conn = conn + _ = c.WriteMessage(sc_pb.MessageID_MESSAGE_ID_ENTER_INSTANCE, &sc_pb.C2S_EnterInstance{ + InstanceID: 1, + }) + go c.startReader() + go c.startWriter() + select { + case <-c.ctx.Done(): + c.onStop() + return + } + }() +} + +func (c *Client) startReader() { + for { + select { + case <-c.ctx.Done(): + return + default: + _, msgByte, err := c.conn.ReadMessage() + if err != nil { + log.Errorf("read error quit %s", err) + c.Stop() + return + } + + msg := &sc_pb.Message{} + if err = proto.Unmarshal(msgByte, msg); err != nil { + continue + } + if r, ok := router[msg.ID]; ok { + r.Handle(msg.Payload, c) + } + } + } +} + +func (c *Client) startWriter() { + for { + select { + case data, ok := <-c.writeChaen: + if ok { + if err := c.conn.WriteMessage(websocket.BinaryMessage, data); err != nil { + log.Errorf("Send Buff Data error:, %s Conn Writer exit", err) + return + } + } else { + log.Errorf("msgBuffChan is Closed") + } + case <-c.ctx.Done(): + return + } + } +} + +// WriteMessage 发送消息给服务器 +func (c *Client) WriteMessage(msgID sc_pb.MessageID, data proto.Message) error { + d, err := proto.Marshal(data) + if err != nil { + return err + } + p := &sc_pb.Message{ + ID: msgID, + Payload: d, + } + marshal, _ := proto.Marshal(p) + select { + case c.writeChaen <- marshal: + default: + return errors.New("send buff chan is full") + } + return nil +} + +func (c *Client) Stop() { + c.cancel() +} + +func (c *Client) onStop() { + if err := c.conn.Close(); err != nil { + log.Errorf("close client error %v", err) + } +} diff --git a/internal/ws/handler.go b/internal/ws/handler.go new file mode 100644 index 0000000..2b67377 --- /dev/null +++ b/internal/ws/handler.go @@ -0,0 +1,70 @@ +package ws + +import ( + "common/log" + "common/proto/sc/sc_pb" + "google.golang.org/protobuf/proto" + "math" + "math/rand" + "sync" + "time" +) + +type EnterInstance struct { +} + +func (_ *EnterInstance) Handle(data []byte, client *Client) { + msg := &sc_pb.S2C_EnterInstance{} + if err := proto.Unmarshal(data, msg); err != nil { + log.Errorf("handle msg error") + client.Stop() + return + } + + randDir := func() (float64, float64) { + randX := float64(rand.Intn(201) - 100) + randY := float64(rand.Intn(201) - 100) + + var normalizedX, normalizedY float64 + if length := math.Sqrt(randX*randX + randY*randY); length > 0 { + normalizedX = randX / length + normalizedY = randY / length + } + + return normalizedX, normalizedY + } + + go func() { + for { + x, y := randDir() + _ = client.WriteMessage(sc_pb.MessageID_MESSAGE_ID_ACTION, &sc_pb.C2S_Action{ + Sequence: 0, + Timestamp: 0, + Action: sc_pb.ActionID_ACTION_ID_MOVE, + DirX: int32(x * 100), + DirY: int32(y * 100), + SkillID: 0, + }) + time.Sleep(500 * time.Millisecond) + } + }() +} + +var s2cPositionPool = sync.Pool{ + New: func() interface{} { + return &sc_pb.Message{} + }, +} + +type Position struct { +} + +func (_ *Position) Handle(data []byte, client *Client) { + //msg := s2cPositionPool.Get().(*sc_pb.Message) + //if err := proto.Unmarshal(data, msg); err != nil { + // log.Errorf("handle msg error") + // client.Stop() + // return + //} + //s2cPositionPool.Put(msg) +} diff --git a/internal/ws/manager.go b/internal/ws/manager.go new file mode 100644 index 0000000..cab6b4c --- /dev/null +++ b/internal/ws/manager.go @@ -0,0 +1,28 @@ +package ws + +import ( + "common/utils" + "robot/config" + "strconv" + "time" +) + +type Manager struct { + addr string +} + +func NewManager(addr string) *Manager { + c := &Manager{ + addr: addr, + } + return c +} + +func (c *Manager) Start() { + cfg := config.Get().Client + for i := int32(0); i < cfg.Count; i++ { + client := NewClient(c.addr, strconv.Itoa(utils.RandInt(int(cfg.USN[0]), int(cfg.USN[1])))) + client.Start() + time.Sleep(time.Millisecond * 10) + } +} diff --git a/internal/ws/router.go b/internal/ws/router.go new file mode 100644 index 0000000..cc0bc43 --- /dev/null +++ b/internal/ws/router.go @@ -0,0 +1,15 @@ +package ws + +import "common/proto/sc/sc_pb" + +var router map[sc_pb.MessageID]BaseRouter + +type BaseRouter interface { + Handle(data []byte, client *Client) +} + +func init() { + router = make(map[sc_pb.MessageID]BaseRouter) + router[sc_pb.MessageID_MESSAGE_ID_ENTER_INSTANCE] = &EnterInstance{} + router[sc_pb.MessageID_MESSAGE_ID_POSITION] = &Position{} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..8cc2bdf --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "github.com/judwhite/go-svc" + "robot/app" + "syscall" +) + +func main() { + if err := svc.Run(&app.Program{}, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL); err != nil { + fmt.Println(err) + } +}