├── demo ├── logs │ ├── log │ ├── log.20191109.log │ └── log.20191106.log ├── toml │ └── user.toml ├── swaggerui │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── index.html │ ├── oauth2-redirect.html │ └── swagger.json ├── docker │ ├── build.sh │ ├── docker-compose.yml │ └── Dockerfile ├── test │ ├── di_test │ │ ├── demo │ │ │ ├── people_interface.go │ │ │ └── man.go │ │ └── di_test.go │ ├── str_test │ │ └── str_test.go │ ├── timer │ │ └── timer_test.go │ ├── toml │ │ └── toml_test.go │ ├── client │ │ └── client_test.go │ ├── json_demo │ │ └── json_test.go │ ├── ctx │ │ └── ctx_test.go │ ├── token │ │ └── token_test.go │ ├── mytest │ │ └── my_test.go │ ├── mqtt │ │ └── mqtt_test.go │ ├── extends │ │ └── extend_test.go │ ├── queue │ │ └── queue_test.go │ ├── num │ │ └── num_test.go │ ├── ctl │ │ └── controller_test.go │ ├── json_str │ │ └── json_test.go │ ├── conver │ │ └── conver_test.go │ ├── mgo │ │ └── mgo_test.go │ ├── reflect_test │ │ └── reflect_test.go │ └── xorm │ │ └── xorm_test.go ├── src │ ├── service │ │ ├── two_service.go │ │ ├── one_service.go │ │ ├── parallel_two.go │ │ ├── parallel_one.go │ │ └── sql_service.go │ ├── controller │ │ ├── sleep_controller.go │ │ ├── auth_controller.go │ │ ├── sql_controller.go │ │ ├── event_controller.go │ │ ├── queue_controller.go │ │ ├── publish_controller.go │ │ ├── queue2_controller.go │ │ ├── cache_set_controller.go │ │ ├── consul_controller.go │ │ ├── valid_controller.go │ │ ├── cache_get_controller.go │ │ ├── redis_controller.go │ │ ├── mqtt_event_controller.go │ │ ├── parallel_controller.go │ │ ├── two_controller.go │ │ ├── post_controller.go │ │ └── one_controller.go │ ├── model │ │ ├── comm_demo.go │ │ └── comm_user_info.go │ ├── router │ │ ├── command_router.go │ │ ├── cron_router.go │ │ ├── queue_router.go │ │ ├── websocket_router.go │ │ ├── grpc_router.go │ │ ├── timer_router.go │ │ ├── subscribe_router.go │ │ └── http_router.go │ ├── dto │ │ ├── queue_dto.go │ │ └── test_dto.go │ ├── fsm │ │ └── user_fsm.go │ └── provider │ │ └── demo_provider.go ├── go.mod ├── env.toml └── main.go ├── constants ├── dto.go ├── code.go ├── time_format.go └── error.go ├── contracts ├── mock_interface.go ├── valid_interface.go ├── service_interface.go ├── provider_interface.go ├── router_interface.go ├── filter_interface.go ├── controller_interface.go ├── logger_interface.go ├── message_struct.go └── context.go ├── servers ├── queues │ ├── job.go │ ├── payload.go │ ├── signal_stop.go │ ├── client.go │ ├── signals.go │ ├── helper.go │ └── server.go ├── events │ ├── helper.go │ ├── event.go │ └── server.go ├── transports │ ├── protobuf │ │ └── message.go.proto │ ├── cron_transport.go │ ├── timer_transport.go │ ├── command_transport.go │ ├── queue_transport.go │ ├── grpc_transport.go │ ├── websocket_transport.go │ ├── http_transport.go │ ├── mqtt_subscribe_transport.go │ └── codecs │ │ ├── timer_codec.go │ │ ├── queue_codec.go │ │ ├── websocket_codec.go │ │ ├── cron_codec.go │ │ ├── command_codec.go │ │ ├── mqtt_codec.go │ │ ├── gprc_codec.go │ │ └── http_codec.go ├── commons │ ├── comm_handler.go │ └── Server.go ├── mqtts │ ├── publish.go │ ├── ins.go │ └── subscribe_server.go ├── cronjobs │ └── server.go ├── command_comm_server.go ├── gateway_comm_server.go ├── timer_comm_server.go ├── event_comm_server.go ├── websocket_comm_server.go ├── mqtt_subscribe_comm_server.go ├── commands │ └── server.go ├── queue_comm_server.go ├── cron_comm_server.go ├── gateways │ ├── maxBytesReader.go │ ├── server.go │ └── codec.go ├── timers │ └── server.go ├── http_comm_server.go ├── websockets │ └── server.go └── grpc_comm_server.go ├── tools ├── idwork │ ├── helper.go │ └── worker.go ├── jwt │ ├── claims.go │ └── token.go ├── util │ └── md5.go ├── errors │ └── error.go ├── tests │ └── test.go ├── helpers.go ├── convert │ └── convert.go └── local_time.go ├── container ├── ins.go └── container.go ├── loggers ├── logger.go ├── ins.go └── logrus_log.go ├── configs ├── cache_config.go ├── token_config.go ├── event_config.go ├── grpc_config.go ├── http_config.go ├── log_config.go ├── websocket_config.go ├── queue_config.go ├── redis_config.go ├── mqtt_config.go ├── mongo_config.go ├── mysql_config.go └── init.go ├── filters ├── helpers.go ├── health_endpoint.go ├── filter.go ├── limit_endpoint.go ├── Jwt_endpoint.go ├── gateway_endpoint.go ├── response_endpoint.go └── comm_endpoint.go ├── clients ├── helpers.go ├── mysql │ ├── ins.go │ └── helper.go ├── http.go ├── service.go ├── mongo │ └── session.go ├── redis │ └── pool_ins.go ├── grpc.go └── consul.go ├── validations ├── helpers.go └── util.go ├── args └── init.go ├── providers └── consul_registy_provider.go ├── cache └── ins.go ├── services └── service.go ├── go.mod └── wego.go /demo/logs/log: -------------------------------------------------------------------------------- 1 | logs/log.20191109.log -------------------------------------------------------------------------------- /demo/toml/user.toml: -------------------------------------------------------------------------------- 1 | [type] 2 | register ="注册用户" 3 | -------------------------------------------------------------------------------- /constants/dto.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const RequestDto = "REQUEST_DTO" 4 | -------------------------------------------------------------------------------- /constants/code.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | type Code struct { 4 | Code string 5 | Msg string 6 | } 7 | -------------------------------------------------------------------------------- /contracts/mock_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IMock interface { 4 | Mock() interface{} 5 | } 6 | -------------------------------------------------------------------------------- /demo/swaggerui/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9299381/wego/HEAD/demo/swaggerui/favicon-16x16.png -------------------------------------------------------------------------------- /demo/swaggerui/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/9299381/wego/HEAD/demo/swaggerui/favicon-32x32.png -------------------------------------------------------------------------------- /contracts/valid_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IValid interface { 4 | GetRules() interface{} 5 | } 6 | -------------------------------------------------------------------------------- /servers/queues/job.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | type Job struct { 4 | Queue string 5 | Payload Payload 6 | } 7 | -------------------------------------------------------------------------------- /contracts/service_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IService interface { 4 | Handle(ctx Context) error 5 | } 6 | -------------------------------------------------------------------------------- /demo/docker/build.sh: -------------------------------------------------------------------------------- 1 | GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o main main.go && 2 | docker image build -t demo_app ./docker -------------------------------------------------------------------------------- /demo/test/di_test/demo/people_interface.go: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | type IPeople interface { 4 | Work() 5 | Write(string) string 6 | } 7 | -------------------------------------------------------------------------------- /contracts/provider_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IProvider interface { 4 | Register() //在这里注册路由 5 | Boot() //加载配置文件等 6 | } 7 | -------------------------------------------------------------------------------- /contracts/router_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IRouter interface { 4 | Boot() 5 | Load() 6 | Register() 7 | Start() error 8 | Close() 9 | } 10 | -------------------------------------------------------------------------------- /demo/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | demo_app: 4 | build: 5 | context: . 6 | ports: 7 | - 8341:8341 8 | command: /home/main 9 | -------------------------------------------------------------------------------- /demo/logs/log.20191109.log: -------------------------------------------------------------------------------- 1 | {"level":"info","msg":"Http Server Start :8341","time":"2019-11-09 15:52:26"} 2 | {"level":"info","msg":"interrupt","time":"2019-11-09 15:53:02"} 3 | -------------------------------------------------------------------------------- /servers/queues/payload.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | type Payload struct { 4 | Route string `json:"route"` 5 | Params map[string]interface{} `json:"params"` 6 | } 7 | -------------------------------------------------------------------------------- /constants/time_format.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const YmdHis = "2006-01-02 15:04:05" 4 | const YmdHi = "2006-01-02 15:04" 5 | const YmdH = "2006-01-02 15" 6 | const Ymd = "2006-01-02" 7 | -------------------------------------------------------------------------------- /tools/idwork/helper.go: -------------------------------------------------------------------------------- 1 | package idwork 2 | 3 | import ( 4 | "github.com/9299381/wego/configs" 5 | ) 6 | 7 | func ID() string { 8 | return getID(int64(configs.EnvInt("server_id", 512))) 9 | } 10 | -------------------------------------------------------------------------------- /contracts/filter_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | import "github.com/go-kit/kit/endpoint" 4 | 5 | type IFilter interface { 6 | Next(next endpoint.Endpoint) IFilter 7 | Make() endpoint.Endpoint 8 | } 9 | -------------------------------------------------------------------------------- /servers/queues/signal_stop.go: -------------------------------------------------------------------------------- 1 | // +build go1.1 2 | 3 | package queues 4 | 5 | import ( 6 | "os" 7 | "os/signal" 8 | ) 9 | 10 | func signalStop(c chan<- os.Signal) { 11 | signal.Stop(c) 12 | } 13 | -------------------------------------------------------------------------------- /tools/jwt/claims.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | type Claims struct { 4 | Id string `json:"id"` 5 | Name string `json:"name"` 6 | Role string `json:"role"` 7 | Iat int64 `json:"iat"` 8 | Exp int64 `json:"exp"` 9 | } 10 | -------------------------------------------------------------------------------- /container/ins.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import "sync" 4 | 5 | var ins *Container 6 | var once sync.Once 7 | 8 | func GetIns() *Container { 9 | once.Do(func() { 10 | ins = NewContainer() 11 | }) 12 | return ins 13 | } 14 | -------------------------------------------------------------------------------- /demo/test/str_test/str_test.go: -------------------------------------------------------------------------------- 1 | package str_test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestString(t *testing.T) { 9 | str := "a.b.c" 10 | ret := strings.ReplaceAll(str, ".", "/") 11 | t.Log(ret) 12 | } 13 | -------------------------------------------------------------------------------- /tools/util/md5.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | ) 7 | 8 | func Md5(plain string) string { 9 | h := md5.New() 10 | h.Write([]byte(plain)) 11 | return hex.EncodeToString(h.Sum(nil)) 12 | } 13 | -------------------------------------------------------------------------------- /loggers/logger.go: -------------------------------------------------------------------------------- 1 | package loggers 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | ) 6 | 7 | type logger struct { 8 | *logrus.Logger 9 | } 10 | 11 | func (s logger) Log(keyvals ...interface{}) error { 12 | s.Info(keyvals) 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /configs/cache_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type CacheConfig struct { 4 | Size int `json:"size"` 5 | } 6 | 7 | func LoadCacheConfig() *CacheConfig { 8 | 9 | config := &CacheConfig{ 10 | Size: EnvInt("cache.size", 1048576), 11 | } 12 | return config 13 | } 14 | -------------------------------------------------------------------------------- /container/container.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import "github.com/go-macaron/inject" 4 | 5 | type Container struct { 6 | inject.Injector 7 | } 8 | 9 | func NewContainer() *Container { 10 | injector := inject.New() 11 | return &Container{ 12 | Injector: injector, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demo/test/timer/timer_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/tools" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestTimer(t *testing.T) { 11 | now := tools.LocalTime(time.Now()) 12 | n := fmt.Sprintf("%s", now) 13 | fmt.Println(n) 14 | } 15 | -------------------------------------------------------------------------------- /demo/src/service/two_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | ) 6 | 7 | type TwoService struct { 8 | } 9 | 10 | func (s *TwoService) Handle(ctx contracts.Context) error { 11 | 12 | ctx.Set("one", "tow") 13 | ctx.Log.Info("two......") 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /demo/test/toml/toml_test.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego" 6 | "testing" 7 | ) 8 | 9 | func TestToml(t *testing.T) { 10 | // 加载过程 11 | wego.Toml("user", "user") 12 | // 读取过程 13 | level := wego.Toml("user").GetString("type.register") 14 | fmt.Println(level) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /servers/events/helper.go: -------------------------------------------------------------------------------- 1 | package events 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | ) 6 | 7 | func Fire(payload *contracts.Payload) { 8 | //发送事件需要判断是否有处理器,否则不处理 9 | _, isExist := Handlers[payload.Route] 10 | if isExist { 11 | event := newEvent(payload) 12 | addEvent(event) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demo/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 基础镜像 2 | FROM scratch 3 | # 镜像作者 4 | MAINTAINER 9299381@qq.com 5 | 6 | # 复制文件或目录到容器指定路径中 7 | COPY . /home 8 | 9 | # 容器对外映射的本地端口,需要在 docker run 的时候使用-p或者-P选项生效 10 | EXPOSE 8341 11 | 12 | 13 | # 为后续的RUN、CMD、ENTRYPOINT指令配置工作目录 14 | WORKDIR /home 15 | 16 | # 在启动容器时提供一个命令执行选项,这里运行我们的应用 17 | #CMD ["/home/main"] -------------------------------------------------------------------------------- /demo/test/client/client_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "testing" 6 | ) 7 | 8 | func TestClientService(t *testing.T) { 9 | param := make(map[string]interface{}) 10 | resp := clients.Service("demo"). 11 | Api("demo.post"). 12 | Params(param). 13 | Run() 14 | 15 | t.Log(resp) 16 | } 17 | -------------------------------------------------------------------------------- /servers/transports/protobuf/message.go.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package protobuf; 4 | 5 | service Service{ 6 | rpc Handle(Request) returns (Response) {} 7 | } 8 | 9 | message Request { 10 | string id = 1; 11 | string param = 2; 12 | } 13 | message Response { 14 | string code = 1; 15 | string msg = 2; 16 | string data = 3; 17 | } -------------------------------------------------------------------------------- /configs/token_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type TokenConfig struct { 4 | Key string `json:"key"` 5 | Exp int64 `json:"exp"` 6 | } 7 | 8 | func LoadTokenConfig() *TokenConfig { 9 | config := &TokenConfig{ 10 | Key: EnvString("token.key", "EHKHHP54PXKYTS2E"), 11 | Exp: int64(EnvInt("token.exp", 2592000)), 12 | } 13 | return config 14 | } 15 | -------------------------------------------------------------------------------- /demo/test/di_test/demo/man.go: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type Man struct { 9 | } 10 | 11 | func (s *Man) Work() { 12 | fmt.Println("man working") 13 | } 14 | func (s *Man) Write(content string) string { 15 | str := "man write something" 16 | ret := strings.Join([]string{str, content}, ":") 17 | return ret 18 | } 19 | -------------------------------------------------------------------------------- /filters/helpers.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/go-kit/kit/endpoint" 6 | ) 7 | 8 | func Chain(endpoints ...contracts.IFilter) endpoint.Endpoint { 9 | len := len(endpoints) - 1 10 | for i := 0; i < len; i++ { 11 | endpoints[i].Next(endpoints[i+1].Make()) 12 | } 13 | return endpoints[0].Make() 14 | } 15 | -------------------------------------------------------------------------------- /configs/event_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type EventConfig struct { 4 | Concurrency int `json:"concurrency"` 5 | After int `json:"after"` 6 | } 7 | 8 | func LoadEventConfig() *EventConfig { 9 | 10 | config := &EventConfig{ 11 | Concurrency: EnvInt("event.concurrency", 1), 12 | After: EnvInt("event.after", 1), 13 | } 14 | return config 15 | } 16 | -------------------------------------------------------------------------------- /demo/test/json_demo/json_test.go: -------------------------------------------------------------------------------- 1 | package json_demo 2 | 3 | import ( 4 | "github.com/tidwall/gjson" 5 | "testing" 6 | ) 7 | 8 | /** 9 | https://www.jianshu.com/p/623f8ca5ec12 10 | */ 11 | func TestJson(t *testing.T) { 12 | const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}` 13 | value := gjson.Get(json, "name.last").Str 14 | println(value) 15 | } 16 | -------------------------------------------------------------------------------- /demo/test/ctx/ctx_test.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | "testing" 7 | ) 8 | 9 | func TestContext(t *testing.T) { 10 | ctx := &contracts.Context{ 11 | Keys: make(map[string]interface{}), 12 | } 13 | 14 | ctx.Set("a", "1") 15 | ctx.Set("a.b", "2") 16 | //ctx.Set("a", "2") 17 | fmt.Println(ctx.Get("a")) 18 | } 19 | -------------------------------------------------------------------------------- /configs/grpc_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type GrpcConfig struct { 4 | GrpcHost string `json:"grpc_host"` 5 | GrpcPort string `json:"grpc_port"` 6 | } 7 | 8 | func LoadGrpcConfig() *GrpcConfig { 9 | config := &GrpcConfig{ 10 | GrpcHost: EnvString("server.grpc_host", "127.0.0.1"), 11 | GrpcPort: EnvString("server.grpc_port", "9341"), 12 | } 13 | return config 14 | } 15 | -------------------------------------------------------------------------------- /configs/http_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type HttpConfig struct { 4 | HttpHost string `json:"http_host"` 5 | HttpPort string `json:"http_port"` 6 | } 7 | 8 | func LoadHttpConfig() *HttpConfig { 9 | config := &HttpConfig{ 10 | HttpHost: EnvString("server.http_host", "127.0.0.1"), 11 | HttpPort: EnvString("server.http_port", "8341"), 12 | } 13 | return config 14 | } 15 | -------------------------------------------------------------------------------- /configs/log_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type LogConfig struct { 4 | LogFilePath string `json:"log_file_path"` 5 | LogFileName string `json:"log_file_name"` 6 | } 7 | 8 | func LoadLogConfig() *LogConfig { 9 | config := &LogConfig{ 10 | LogFilePath: EnvString("log.file_path", "./logs"), 11 | LogFileName: EnvString("log.file_name", "log"), 12 | } 13 | 14 | return config 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/service/one_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | ) 6 | 7 | type OneService struct { 8 | } 9 | 10 | func (s *OneService) Handle(ctx contracts.Context) error { 11 | ctx.Log.Info("one....") 12 | ctx.Set("k.a", "a") 13 | ctx.Set("k.b", "b") 14 | ctx.Set("k.a", "b") 15 | 16 | ctx.Log.Info(ctx.Get("k")) 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/controller/sleep_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "time" 6 | ) 7 | 8 | //用于测试并行,串行 9 | type SleepController struct { 10 | } 11 | 12 | func (s *SleepController) Handle(ctx contracts.Context) (interface{}, error) { 13 | 14 | time.Sleep(10 * time.Second) 15 | ctx.Log.Info("sleep ......") 16 | 17 | return nil, nil 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/controller/auth_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | type AuthController struct { 9 | } 10 | 11 | func (s *AuthController) Handle(ctx contracts.Context) (interface{}, error) { 12 | 13 | fmt.Println(ctx.Get("request.claim.Id")) 14 | fmt.Println(ctx.Get("request.claim.Name")) 15 | 16 | return nil, nil 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/service/parallel_two.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | type ParallelTwo struct { 9 | } 10 | 11 | func (s *ParallelTwo) Handle(ctx contracts.Context) error { 12 | ctx.Log.Info(ctx.Get("controller")) 13 | fmt.Println("two~~~~~~~~~~~~") 14 | ctx.Set("aaa", "ccc") 15 | ctx.Set("two", "two") 16 | 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/model/comm_demo.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CommDemoModel struct { 4 | Id string `xorm:"pk varchar(21) notnull unique 'id'" json:"id"` 5 | NumInt1 int `xorm:"int(11)" json:"num_int1"` 6 | NumInt2 int `xorm:"bigint(20)" json:"num_int2"` 7 | NumBig int64 `xorm:"bigint(20)" json:"num_big"` 8 | } 9 | 10 | func (s *CommDemoModel) TableName() string { 11 | return "comm_demo" 12 | } 13 | -------------------------------------------------------------------------------- /tools/errors/error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import "strings" 4 | 5 | func Code(code string, text string) error { 6 | return &Error{Code: code, Message: text} 7 | } 8 | 9 | // errorString is a trivial implementation of error. 10 | type Error struct { 11 | Code string 12 | Message string 13 | } 14 | 15 | func (e *Error) Error() string { 16 | return strings.Join([]string{e.Code, e.Message}, "::") 17 | } 18 | -------------------------------------------------------------------------------- /servers/transports/cron_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewCronJob(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.CronDecodeRequest, 13 | codecs.CronEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /servers/transports/timer_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewTimer(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.TimerDecodeRequest, 13 | codecs.TimerEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /contracts/controller_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type IController interface { 4 | Handle(ctx Context) (interface{}, error) 5 | } 6 | 7 | type Controller struct { 8 | } 9 | 10 | func (s *Controller) Handle(ctx Context) (interface{}, error) { 11 | return nil, nil 12 | } 13 | func (s *Controller) GetRules() interface{} { 14 | return nil 15 | } 16 | func (s *Controller) Mock() interface{} { 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/service/parallel_one.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | type ParallelOne struct { 9 | } 10 | 11 | func (s *ParallelOne) Handle(ctx contracts.Context) error { 12 | ctx.Log.Info(ctx.Get("controller")) 13 | fmt.Println("one~~~~~~~~~~~~") 14 | ctx.Set("aaa", "bbb") 15 | ctx.Set("one", "one") 16 | //return errors.New("error") 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /servers/transports/command_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewCommand(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.CommandDecodeRequest, 13 | codecs.CommandEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /servers/transports/queue_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewQueue(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.QueueServerDecodeRequest, 13 | codecs.QueueServerEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /servers/transports/grpc_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/transports/codecs" 5 | "github.com/go-kit/kit/endpoint" 6 | GrpcTransport "github.com/go-kit/kit/transport/grpc" 7 | ) 8 | 9 | func NewGRPC(endpoint endpoint.Endpoint) *GrpcTransport.Server { 10 | return GrpcTransport.NewServer( 11 | endpoint, 12 | codecs.GprcDecodeRequest, 13 | codecs.GprcEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /servers/transports/websocket_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewWebSocket(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.WebSocketDecodeRequest, 13 | codecs.WebSocketEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /servers/transports/http_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/transports/codecs" 5 | "github.com/go-kit/kit/endpoint" 6 | HttpTransport "github.com/go-kit/kit/transport/http" 7 | ) 8 | 9 | func NewHTTP(endpoint endpoint.Endpoint) *HttpTransport.Server { 10 | return HttpTransport.NewServer( 11 | endpoint, 12 | codecs.HttpFormDecodeRequest, 13 | codecs.HttpEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /clients/helpers.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "github.com/9299381/wego/clients/mysql" 5 | "github.com/9299381/wego/clients/redis" 6 | redigo "github.com/gomodule/redigo/redis" 7 | "xorm.io/xorm" 8 | ) 9 | 10 | func DB() *xorm.Engine { 11 | return mysql.GetDB() 12 | } 13 | 14 | func Redis() redigo.Conn { 15 | return redis.GetRedisPool().Get() 16 | } 17 | 18 | func RedisPool() *redigo.Pool { 19 | return redis.GetRedisPool() 20 | } 21 | -------------------------------------------------------------------------------- /loggers/ins.go: -------------------------------------------------------------------------------- 1 | package loggers 2 | 3 | import ( 4 | "github.com/go-kit/kit/log" 5 | "github.com/sirupsen/logrus" 6 | "sync" 7 | ) 8 | 9 | var ins *logrus.Logger 10 | var once sync.Once 11 | 12 | func GetLog() *logrus.Logger { 13 | once.Do(func() { 14 | ins = newLogrus() 15 | }) 16 | return ins 17 | } 18 | 19 | // log.logger 接口的一种实现,用以注入 go-kit 的服务注册 20 | func NewKitLog() log.Logger { 21 | return logger{ 22 | Logger: GetLog(), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /servers/transports/mqtt_subscribe_transport.go: -------------------------------------------------------------------------------- 1 | package transports 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/transports/codecs" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | func NewMqttSubscribe(endpoint endpoint.Endpoint) *commons.Server { 10 | return commons.NewServer( 11 | endpoint, 12 | codecs.MqttSubscribeDecodeRequest, 13 | codecs.MqttSubscribeEncodeResponse, 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /demo/test/token/token_test.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/tools/jwt" 6 | "testing" 7 | ) 8 | 9 | func TestToken(t *testing.T) { 10 | token := jwt.New(). 11 | SetId("123"). 12 | SetName("abc"). 13 | SetRole("p1101"). 14 | GetToken() 15 | //eyJpZCI6IjEyMyIsIm5hbWUiOiJhYmMiLCJyb2xlIjoicDExMDEiLCJpYXQiOjE1Njk1NzkwOTQsImV4cCI6MTU3MjE3MTA5NH0=.228a1c01bdce8cd3405d2295d7a2eb30 16 | fmt.Println(token) 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/router/command_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type CommandRouter struct { 9 | *servers.CommandCommServer 10 | } 11 | 12 | func (s *CommandRouter) Boot() { 13 | s.CommandCommServer = servers.NewCommandCommServer() 14 | } 15 | 16 | //todo 写个队列server 编解码,路由等 17 | 18 | func (s *CommandRouter) Register() { 19 | s.Route("cmd_test", wego.Handler("two")) 20 | } 21 | -------------------------------------------------------------------------------- /servers/queues/client.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/gomodule/redigo/redis" 7 | ) 8 | 9 | func Enqueue(conn redis.Conn, job *Job, prefix string) error { 10 | buffer, err := json.Marshal(job.Payload) 11 | if err != nil { 12 | return err 13 | } 14 | err = conn.Send("RPUSH", fmt.Sprintf("%s_queue:%s", prefix, job.Queue), buffer) 15 | if err != nil { 16 | return err 17 | } 18 | return conn.Flush() 19 | } 20 | -------------------------------------------------------------------------------- /servers/queues/signals.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "syscall" 7 | ) 8 | 9 | func signals() <-chan bool { 10 | quit := make(chan bool) 11 | 12 | go func() { 13 | signals := make(chan os.Signal) 14 | defer close(signals) 15 | 16 | signal.Notify(signals, syscall.SIGQUIT, syscall.SIGTERM, os.Interrupt) 17 | defer signalStop(signals) 18 | 19 | <-signals 20 | quit <- true 21 | }() 22 | 23 | return quit 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/controller/sql_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/demo/src/service" 6 | "github.com/9299381/wego/services" 7 | ) 8 | 9 | type SqlController struct { 10 | } 11 | 12 | func (s *SqlController) Handle(ctx contracts.Context) (interface{}, error) { 13 | _ = services.Pipe().Middle(&service.SqlService{}).Line(ctx) 14 | ret := ctx.Get("user") 15 | return ret, nil 16 | 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/router/cron_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type CronRouter struct { 9 | *servers.CronCommServer 10 | } 11 | 12 | func (s *CronRouter) Boot() { 13 | s.CronCommServer = servers.NewCronCommServer() 14 | } 15 | 16 | func (s *CronRouter) Register() { 17 | 18 | s.Route("*/5 * * * * *", wego.Handler("one")) 19 | s.Route("*/2 * * * * *", wego.Handler("two")) 20 | } 21 | -------------------------------------------------------------------------------- /demo/src/router/queue_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type QueueRouter struct { 9 | *servers.QueueCommServer 10 | } 11 | 12 | func (s *QueueRouter) Boot() { 13 | s.QueueCommServer = servers.NewQueueCommServer() 14 | } 15 | 16 | func (s *QueueRouter) Register() { 17 | s.Route("queue_test", wego.Handler("two")) 18 | s.Route("queue2", wego.Handler("queue2")) 19 | 20 | } 21 | -------------------------------------------------------------------------------- /demo/src/router/websocket_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | //websocket 服务器尽量采用 emqx mqtt broker 9 | type WebSocketRouter struct { 10 | *servers.WebSocketCommServer 11 | } 12 | 13 | func (s *WebSocketRouter) Boot() { 14 | s.WebSocketCommServer = servers.NewWebSocketCommServer() 15 | } 16 | 17 | func (s *WebSocketRouter) Register() { 18 | s.Route("Two", wego.Handler("two")) 19 | } 20 | -------------------------------------------------------------------------------- /validations/helpers.go: -------------------------------------------------------------------------------- 1 | package validations 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | func Valid(obj interface{}) error { 9 | //如何验证嵌套的问题 10 | valid := Validation{} 11 | b, _ := valid.Valid(obj) 12 | if !b { 13 | var msg string 14 | for _, err := range valid.Errors { 15 | m := strings.Join([]string{err.Field, err.Message}, ":") 16 | msg = strings.Join([]string{m, msg}, ";") 17 | } 18 | return errors.New(msg) 19 | } 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/controller/event_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/servers/events" 6 | ) 7 | 8 | type EventController struct { 9 | } 10 | 11 | func (s *EventController) Handle(ctx contracts.Context) (interface{}, error) { 12 | params := make(map[string]interface{}) 13 | payload := &contracts.Payload{ 14 | Route: "two", 15 | Params: params, 16 | } 17 | events.Fire(payload) 18 | return nil, nil 19 | } 20 | -------------------------------------------------------------------------------- /demo/test/mytest/my_test.go: -------------------------------------------------------------------------------- 1 | package mytest 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/tools/idwork" 6 | "testing" 7 | ) 8 | 9 | func TestDoSomething(t *testing.T) { 10 | fmt.Println("here") 11 | } 12 | func BenchmarkDoSomething(b *testing.B) { 13 | b.StopTimer() //调用该函数停止压力测试的时间计数 14 | //做一些初始化的工作,例如读取文件数据,数据库连接之类的, 15 | //这样这些时间不影响我们测试函数本身的性能 16 | b.StartTimer() //重新开始时间 17 | for i := 0; i < b.N; i++ { //use b.N for looping 18 | idwork.ID() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo/test/mqtt/mqtt_test.go: -------------------------------------------------------------------------------- 1 | package mqtt 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/servers/mqtts" 6 | "strconv" 7 | "testing" 8 | ) 9 | 10 | func TestMqtt(t *testing.T) { 11 | 12 | m := make(map[string]interface{}) 13 | m["pub"] = "pub" 14 | m["sub"] = "sub" 15 | err := mqtts.Publish("sub_test3", m) 16 | 17 | fmt.Println(err) 18 | } 19 | func TestByte(t *testing.T) { 20 | s := 2 21 | data := []byte(strconv.Itoa(s)) 22 | b := data[0] 23 | fmt.Println(string(b)) 24 | } 25 | -------------------------------------------------------------------------------- /configs/websocket_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type WebSocketConfig struct { 4 | WebSocketHost string `json:"web_socket_host"` 5 | WebSocketPort string `json:"web_socket_port"` 6 | Path string 7 | } 8 | 9 | func LoadWebSocketConfig() *WebSocketConfig { 10 | config := &WebSocketConfig{ 11 | Path: "/ws", 12 | WebSocketPort: EnvString("server.websocket_port", "8342"), 13 | WebSocketHost: EnvString("server.websocket_host", "127.0.0.1"), 14 | } 15 | return config 16 | } 17 | -------------------------------------------------------------------------------- /servers/events/event.go: -------------------------------------------------------------------------------- 1 | package events 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | ) 6 | 7 | func addEvent(event *contracts.Payload) { 8 | go func() { 9 | eventChan <- event 10 | }() 11 | } 12 | 13 | func newEvent(event *contracts.Payload) *contracts.Payload { 14 | e := eventPool.Get() 15 | if e == nil { 16 | return event 17 | } else { 18 | ret := e.(*contracts.Payload) 19 | (*ret).Route = event.Route 20 | (*ret).Params = event.Params 21 | return ret 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/controller/queue_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/servers/queues" 6 | ) 7 | 8 | type QueueController struct { 9 | } 10 | 11 | func (s *QueueController) Handle(ctx contracts.Context) (interface{}, error) { 12 | 13 | msg := make(map[string]interface{}) 14 | msg["aaa"] = "bbb" 15 | 16 | err := queues.Fire("demo1", "queue_test", msg) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return nil, nil 21 | } 22 | -------------------------------------------------------------------------------- /servers/transports/codecs/timer_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | func TimerDecodeRequest(ctx context.Context, req interface{}) (interface{}, error) { 9 | request := req.(map[string]interface{}) 10 | return contracts.Request{ 11 | Id: request["request_id"].(string), 12 | Data: request, 13 | }, nil 14 | } 15 | 16 | func TimerEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 17 | return rsp, nil 18 | } 19 | -------------------------------------------------------------------------------- /servers/queues/helper.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "github.com/9299381/wego/configs" 6 | ) 7 | 8 | func Fire(name string, router string, params map[string]interface{}) error { 9 | conn := clients.Redis() 10 | defer conn.Close() 11 | job := &Job{ 12 | Queue: name, 13 | Payload: Payload{ 14 | Route: router, 15 | Params: params, 16 | }, 17 | } 18 | prefix := configs.EnvString("queue.prefix", "wego") 19 | return Enqueue(conn, job, prefix) 20 | 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/controller/publish_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/servers/mqtts" 6 | ) 7 | 8 | type PublishController struct { 9 | } 10 | 11 | func (s *PublishController) Handle(ctx contracts.Context) (interface{}, error) { 12 | 13 | m := make(map[string]interface{}) 14 | m["pub"] = "pub" 15 | m["sub"] = "sub" 16 | err := mqtts.Publish("sub_test", m) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return nil, nil 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/router/grpc_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type GrpcRouter struct { 9 | *servers.GrpcCommServer 10 | } 11 | 12 | func (s *GrpcRouter) Boot() { 13 | s.GrpcCommServer = servers.NewGrpcCommServer() 14 | } 15 | 16 | //这里注册路由 17 | func (s *GrpcRouter) Register() { 18 | 19 | s.Route("demo.two", wego.Handler("two")) 20 | s.Route("demo.one", wego.Handler("one")) 21 | s.Route("demo.post", wego.Handler("post")) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /filters/health_endpoint.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | type HealthEndpoint struct { 10 | } 11 | 12 | func (s *HealthEndpoint) Next(next endpoint.Endpoint) contracts.IFilter { 13 | return s 14 | } 15 | 16 | func (s *HealthEndpoint) Make() endpoint.Endpoint { 17 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 18 | return contracts.ResponseSucess("SERVING"), nil 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /servers/transports/codecs/queue_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/tools/idwork" 7 | ) 8 | 9 | func QueueServerDecodeRequest(ctx context.Context, req interface{}) (interface{}, error) { 10 | id := idwork.ID() 11 | return contracts.Request{ 12 | Id: id, 13 | Data: req.(map[string]interface{}), 14 | }, nil 15 | } 16 | 17 | func QueueServerEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 18 | return rsp, nil 19 | } 20 | -------------------------------------------------------------------------------- /servers/transports/codecs/websocket_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/tools/idwork" 7 | ) 8 | 9 | func WebSocketDecodeRequest(ctx context.Context, req interface{}) (interface{}, error) { 10 | id := idwork.ID() 11 | return contracts.Request{ 12 | Id: id, 13 | Data: req.(map[string]interface{}), 14 | }, nil 15 | } 16 | 17 | func WebSocketEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 18 | return rsp, nil 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/controller/queue2_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/demo/src/dto" 7 | ) 8 | 9 | type Queue2Controller struct { 10 | } 11 | 12 | func (s *Queue2Controller) Handle(ctx contracts.Context) (interface{}, error) { 13 | req := ctx.Request().(*dto.TaskRequest) 14 | for _, v := range req.OrderList { 15 | fmt.Print(v) 16 | } 17 | return nil, nil 18 | } 19 | func (s *Queue2Controller) GetRules() interface{} { 20 | return &dto.TaskRequest{} 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/controller/cache_set_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/cache" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | type CacheSetController struct { 9 | } 10 | 11 | func (s *CacheSetController) Handle(ctx contracts.Context) (interface{}, error) { 12 | 13 | v := make(map[string]interface{}) 14 | v["aaa"] = "bbb" 15 | 16 | dd := make(map[string]interface{}) 17 | dd["a"] = "111" 18 | dd["b"] = "222" 19 | 20 | v["ccc"] = dd 21 | _ = cache.Set("key", v, 60) 22 | 23 | return nil, nil 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/router/timer_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type TimerRouter struct { 9 | *servers.TimerCommServer 10 | } 11 | 12 | func (s *TimerRouter) Boot() { 13 | s.TimerCommServer = servers.NewTimerCommServer() 14 | } 15 | 16 | func (s *TimerRouter) Register() { 17 | 18 | params := make(map[string]interface{}) 19 | params["timer"] = "test" 20 | s.Route("one", 2, wego.Handler("one"), params) 21 | s.Route("two", 5, wego.Handler("two"), params) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /servers/commons/comm_handler.go: -------------------------------------------------------------------------------- 1 | package commons 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type CommHandler struct { 8 | Handler Handler 9 | } 10 | 11 | func (s *CommHandler) Handle(ctx context.Context, req interface{}) (interface{}, error) { 12 | rsp, err := s.Handler.ServeHandle(ctx, req) 13 | if err != nil { 14 | return nil, err 15 | } 16 | return rsp, err 17 | } 18 | 19 | //该接口的实现是为了 cronjob 20 | func (s *CommHandler) Run() { 21 | ctx := context.Background() 22 | req := make(map[string]interface{}) 23 | _, _ = s.Handler.ServeHandle(ctx, req) 24 | } 25 | -------------------------------------------------------------------------------- /contracts/logger_interface.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | type ILogger interface { 4 | Info(keyvals ...interface{}) 5 | Error(keyvals ...interface{}) 6 | Fatal(keyvals ...interface{}) 7 | Trace(keyvals ...interface{}) 8 | Debug(keyvals ...interface{}) 9 | Panic(keyvals ...interface{}) 10 | 11 | Infof(format string, args ...interface{}) 12 | Errorf(format string, args ...interface{}) 13 | Fatalf(format string, args ...interface{}) 14 | Tracef(format string, args ...interface{}) 15 | Debugf(format string, args ...interface{}) 16 | Panicf(format string, args ...interface{}) 17 | } 18 | -------------------------------------------------------------------------------- /servers/transports/codecs/cron_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/tools/idwork" 7 | ) 8 | 9 | func CronDecodeRequest(ctx context.Context, req interface{}) (interface{}, error) { 10 | request := req.(map[string]interface{}) 11 | request["request_id"] = idwork.ID() 12 | return contracts.Request{ 13 | Id: request["request_id"].(string), 14 | Data: request, 15 | }, nil 16 | } 17 | 18 | func CronEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 19 | return rsp, nil 20 | } 21 | -------------------------------------------------------------------------------- /configs/queue_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type QueueConfig struct { 8 | Prefix string 9 | Listen []string 10 | Interval time.Duration 11 | Concurrency int 12 | } 13 | 14 | func LoadQueueConfig() *QueueConfig { 15 | interval := EnvInt("queue.interval", 1) 16 | config := &QueueConfig{ 17 | Prefix: EnvString("queue.prefix", "wego"), 18 | Listen: EnvStringSlice("queue.listen", []string{}), 19 | Interval: time.Duration(interval) * time.Second, 20 | Concurrency: EnvInt("queue.concurrency", 1), 21 | } 22 | return config 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/controller/consul_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/args" 5 | "github.com/9299381/wego/clients" 6 | "github.com/9299381/wego/contracts" 7 | ) 8 | 9 | type ConsulController struct { 10 | } 11 | 12 | func (s *ConsulController) Handle(ctx contracts.Context) (interface{}, error) { 13 | 14 | entity, _ := clients.GetConsulService(args.Name) 15 | ctx.Log.Info(entity.Service.Service) 16 | ctx.Log.Info(entity.Service.Address) 17 | ctx.Log.Info(entity.Service.Port) 18 | tag := entity.Service.Tags[0] 19 | ctx.Log.Info(tag) 20 | 21 | return nil, nil 22 | } 23 | -------------------------------------------------------------------------------- /servers/mqtts/publish.go: -------------------------------------------------------------------------------- 1 | package mqtts 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "github.com/9299381/wego/configs" 7 | "github.com/9299381/wego/constants" 8 | ) 9 | 10 | func Publish(topic string, payload interface{}) error { 11 | if GetIns() == nil { 12 | return errors.New(constants.ErrMQTTConnect) 13 | } 14 | param, err := json.Marshal(payload) 15 | if err != nil { 16 | return err 17 | } 18 | config := configs.LoadMqttConfig() 19 | token := GetIns().Publish(topic, config.PublishQos, false, param) 20 | if token.Wait() && token.Error() != nil { 21 | return token.Error() 22 | } 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/router/subscribe_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/servers" 6 | ) 7 | 8 | type SubscribeRouter struct { 9 | *servers.MqttSubscribeCommCommServer 10 | } 11 | 12 | func (s *SubscribeRouter) Boot() { 13 | s.MqttSubscribeCommCommServer = servers.NewMqttSubscribeCommCommServer() 14 | } 15 | 16 | func (s *SubscribeRouter) Register() { 17 | //topic -> handler 18 | s.Route("sub_test", wego.Handler("two")) 19 | s.Route("sub_test2", wego.Handler("two")) 20 | s.Route("sub_test3", wego.Handler("sleep")) 21 | s.Route("$SYS/brokers/+/clients/+/+", wego.Handler("mqtt_event")) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /clients/mysql/ins.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "github.com/9299381/wego/configs" 5 | _ "github.com/go-sql-driver/mysql" 6 | "sync" 7 | "xorm.io/xorm" 8 | ) 9 | 10 | var db *xorm.Engine 11 | var onceMysql sync.Once 12 | 13 | func GetDB() *xorm.Engine { 14 | onceMysql.Do(func() { 15 | db = newMySql() 16 | }) 17 | return db 18 | } 19 | func newMySql() *xorm.Engine { 20 | conf := configs.LoadMySqlConfig() 21 | engine, _ := xorm.NewEngine( 22 | conf.Driver, 23 | conf.DataSource, 24 | ) 25 | engine.SetMaxIdleConns(conf.MaxIdleConns) 26 | engine.SetMaxOpenConns(conf.MaxOpenConns) 27 | engine.ShowSQL(conf.ShowSQL) 28 | return engine 29 | } 30 | -------------------------------------------------------------------------------- /servers/cronjobs/server.go: -------------------------------------------------------------------------------- 1 | package cronjobs 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/robfig/cron/v3" 6 | "time" 7 | ) 8 | 9 | type Server struct { 10 | Serv *cron.Cron 11 | } 12 | 13 | func NewServer() *Server { 14 | nyc, _ := time.LoadLocation("Asia/Shanghai") 15 | ss := &Server{ 16 | Serv: cron.New(cron.WithSeconds(), cron.WithLocation(nyc)), 17 | } 18 | return ss 19 | } 20 | 21 | func (s *Server) Register(spec string, job *commons.CommHandler) { 22 | _, _ = s.Serv.AddJob(spec, job) 23 | } 24 | 25 | func (s *Server) Serve() error { 26 | s.Serv.Start() 27 | select {} 28 | } 29 | func (s *Server) Close() { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/9299381/wego/demo 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/9299381/wego v0.2.0 7 | github.com/gomodule/redigo v2.0.0+incompatible 8 | github.com/looplab/fsm v0.1.0 9 | github.com/mitchellh/mapstructure v1.1.2 10 | github.com/satori/go.uuid v1.2.0 // indirect 11 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 12 | github.com/tidwall/gjson v1.3.4 13 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65 // indirect 14 | golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 // indirect 15 | gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 16 | xorm.io/builder v0.3.7 17 | ) 18 | 19 | replace github.com/9299381/wego => ../ 20 | -------------------------------------------------------------------------------- /demo/test/extends/extend_test.go: -------------------------------------------------------------------------------- 1 | package extends 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestExtend(t *testing.T) { 9 | p := &pc{} 10 | testInterface(p) 11 | } 12 | 13 | func testInterface(usb usbInterface) { 14 | usb.SayHello() 15 | usb.DoSth() 16 | } 17 | 18 | type usbInterface interface { 19 | SayHello() 20 | DoSth() 21 | } 22 | type usb struct { 23 | } 24 | 25 | func (i *usb) SayHello() { 26 | fmt.Println("usb....sayhello") 27 | } 28 | 29 | func (i *usb) DoSth() { 30 | fmt.Println("usb....do ") 31 | } 32 | 33 | type pc struct { 34 | *usb //可以直接引用usb的 dosth 无需new 35 | } 36 | 37 | func (i *pc) SayHello() { 38 | fmt.Println("pc....sayhello") 39 | } 40 | -------------------------------------------------------------------------------- /configs/redis_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type RedisConfig struct { 8 | Uri string 9 | Auth string 10 | Db int 11 | MaxActive int 12 | MaxIdle int 13 | IdleTimeout time.Duration 14 | } 15 | 16 | func LoadRedisConfig() *RedisConfig { 17 | config := &RedisConfig{ 18 | Uri: EnvString("redis.uri", "127.0.0.1:6937"), 19 | Auth: EnvString("redis.auth", "password"), 20 | Db: EnvInt("redis.db", 0), 21 | MaxActive: EnvInt("redis.max_active", 50), 22 | MaxIdle: EnvInt("redis.max_idle", 5), 23 | IdleTimeout: time.Duration(EnvInt("redis.timeout", 10)) * time.Second, 24 | } 25 | return config 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/controller/valid_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/demo/src/dto" 6 | ) 7 | 8 | type ValidController struct { 9 | } 10 | 11 | // swagger:route Post /demo/valid 分组2 validController 12 | // Test swagger 13 | // This will ....... 14 | // Responses: 15 | // 200: postResponse 16 | func (s *ValidController) Handle(ctx contracts.Context) (interface{}, error) { 17 | st := ctx.Request().(*dto.TestDto) 18 | resp := &dto.ValidResponse{ 19 | Age: st.Age, 20 | List: st.DemoList, 21 | } 22 | return resp, nil 23 | } 24 | 25 | func (s *ValidController) GetRules() interface{} { 26 | return &dto.TestDto{} 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/controller/cache_get_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/cache" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/tidwall/gjson" 7 | ) 8 | 9 | type CacheGetController struct { 10 | } 11 | 12 | func (s *CacheGetController) Handle(ctx contracts.Context) (interface{}, error) { 13 | //GetByte 方式 14 | jsonBytes, _ := cache.GetByte("key") 15 | // Get方式 16 | obj := make(map[string]interface{}) 17 | _ = cache.Get("key", &obj) 18 | 19 | //使用gjson 更方便 直接从json字符串中取值 20 | return map[string]interface{}{ 21 | "ccc": gjson.Get(string(jsonBytes), "ccc.a").Str, 22 | "aaa": obj["aaa"], 23 | "gaaa": gjson.Get(string(jsonBytes), "aaa").String(), 24 | }, nil 25 | } 26 | -------------------------------------------------------------------------------- /filters/filter.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/go-kit/kit/endpoint" 6 | ) 7 | 8 | func New(controller contracts.IController) endpoint.Endpoint { 9 | return Chain( 10 | &ResponseEndpoint{}, 11 | &CommEndpoint{Controller: controller}, 12 | ) 13 | } 14 | 15 | func Auth(controller contracts.IController) endpoint.Endpoint { 16 | return Chain( 17 | &ResponseEndpoint{}, 18 | &JwtEndpoint{}, 19 | &CommEndpoint{Controller: controller}, 20 | ) 21 | } 22 | 23 | func Limit(controller contracts.IController) endpoint.Endpoint { 24 | return Chain( 25 | &ResponseEndpoint{}, 26 | &LimitEndpoint{}, 27 | &CommEndpoint{Controller: controller}, 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /demo/test/queue/queue_test.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/9299381/wego/demo/src/dto" 6 | "github.com/9299381/wego/servers/queues" 7 | "github.com/9299381/wego/tools/idwork" 8 | "testing" 9 | ) 10 | 11 | func TestQueue(t *testing.T) { 12 | var orders []*dto.Order 13 | orders = append(orders, &dto.Order{ 14 | Id: idwork.ID(), 15 | Name: "one", 16 | }) 17 | orders = append(orders, &dto.Order{ 18 | Id: idwork.ID(), 19 | Name: "two", 20 | }) 21 | orderJson, _ := json.Marshal(orders) 22 | 23 | _ = queues.Fire( 24 | "demo1", 25 | "queue2", 26 | map[string]interface{}{ 27 | "task_id": idwork.ID(), 28 | "order_json": string(orderJson), 29 | }, 30 | ) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /servers/transports/codecs/command_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "github.com/9299381/wego/constants" 8 | "github.com/9299381/wego/contracts" 9 | "github.com/9299381/wego/tools/idwork" 10 | ) 11 | 12 | func CommandDecodeRequest(_ context.Context, req interface{}) (interface{}, error) { 13 | var mapResult map[string]interface{} 14 | err := json.Unmarshal([]byte(req.(string)), &mapResult) 15 | if err != nil { 16 | return nil, errors.New(constants.ErrJson) 17 | } 18 | return contracts.Request{ 19 | Id: idwork.ID(), 20 | Data: mapResult, 21 | }, nil 22 | } 23 | 24 | func CommandEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 25 | return rsp, nil 26 | } 27 | -------------------------------------------------------------------------------- /servers/mqtts/ins.go: -------------------------------------------------------------------------------- 1 | package mqtts 2 | 3 | import ( 4 | "github.com/9299381/wego/configs" 5 | "github.com/9299381/wego/tools/idwork" 6 | mqtt "github.com/eclipse/paho.mqtt.golang" 7 | "sync" 8 | ) 9 | 10 | var ins mqtt.Client 11 | var once sync.Once 12 | 13 | func GetIns() mqtt.Client { 14 | once.Do(func() { 15 | ins = init_mc() 16 | }) 17 | return ins 18 | } 19 | func init_mc() mqtt.Client { 20 | config := configs.LoadMqttConfig() 21 | opts := mqtt.NewClientOptions().AddBroker(config.Host) 22 | opts.SetUsername(config.UserName) 23 | opts.SetPassword(config.PassWord) 24 | opts.SetClientID(idwork.ID()) 25 | mc := mqtt.NewClient(opts) 26 | if token := mc.Connect(); token.Wait() && token.Error() != nil { 27 | return nil 28 | } 29 | return mc 30 | } 31 | -------------------------------------------------------------------------------- /filters/limit_endpoint.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/9299381/wego/contracts" 7 | "github.com/go-kit/kit/endpoint" 8 | "github.com/juju/ratelimit" 9 | "time" 10 | ) 11 | 12 | type LimitEndpoint struct { 13 | next endpoint.Endpoint 14 | } 15 | 16 | func (s *LimitEndpoint) Next(next endpoint.Endpoint) contracts.IFilter { 17 | s.next = next 18 | return s 19 | } 20 | 21 | func (s *LimitEndpoint) Make() endpoint.Endpoint { 22 | limit := ratelimit.NewBucket(time.Second*1, 3) 23 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 24 | if limit.TakeAvailable(1) == 0 { 25 | return nil, errors.New("Rate limit exceed!") 26 | } 27 | return s.next(ctx, request) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /configs/mqtt_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | type MqttConfig struct { 4 | Host string `json:"host"` 5 | UserName string `json:"user_name"` 6 | PassWord string `json:"pass_word"` 7 | Parallel bool `json:"parallel"` 8 | SubscribeQos uint8 `json:"subscribe_qos"` 9 | PublishQos uint8 `json:"publish_qos"` 10 | } 11 | 12 | func LoadMqttConfig() *MqttConfig { 13 | config := &MqttConfig{ 14 | Host: EnvString("mqtt.host", "tcp://127.0.0.1:1883"), 15 | UserName: EnvString("mqtt.username", ""), 16 | PassWord: EnvString("mqtt.password", ""), 17 | Parallel: EnvBool("mqtt.parallel", false), 18 | SubscribeQos: uint8(EnvInt("mqtt.subscribe_qos", 2)), 19 | PublishQos: uint8(EnvInt("mqtt.publish_qos", 2)), 20 | } 21 | return config 22 | } 23 | -------------------------------------------------------------------------------- /demo/src/model/comm_user_info.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/9299381/wego/tools" 5 | ) 6 | 7 | type CommUser struct { 8 | Id string `xorm:"pk varchar(21) notnull unique 'id'" json:"id"` 9 | UserName string `xorm:"varchar(50) not null 'user_name'" json:"user_name"` 10 | LoginName string `xorm:"varchar(20) 'login_name'" json:"login_name"` 11 | Status string `xorm:"varchar(2) 'status'" json:"status"` 12 | CreateTime tools.LocalTime `xorm:"datetime created 'create_time'" json:"create_time"` 13 | UpdateTime tools.LocalTime `xorm:"datetime updated 'update_time'" json:"update_time"` 14 | } 15 | 16 | func (s *CommUser) TableName() string { 17 | return "comm_user_info" 18 | 19 | //return "comm_user_info_copy1" 20 | } 21 | -------------------------------------------------------------------------------- /args/init.go: -------------------------------------------------------------------------------- 1 | package args 2 | 3 | import ( 4 | "flag" 5 | "testing" 6 | ) 7 | 8 | var Name string 9 | var Mode string 10 | 11 | var Registy string 12 | 13 | var Server string 14 | var Config string 15 | 16 | var Cmd string 17 | var Args string 18 | 19 | func init() { 20 | 21 | flag.StringVar(&Name, "name", "app", "服务名称") 22 | flag.StringVar(&Mode, "mode", "dev", "开发模式") 23 | flag.StringVar(&Registy, "registy", "", "consul服务注册中心") 24 | 25 | flag.StringVar(&Server, "server", "http,event", "需要启动的服务器") 26 | flag.StringVar(&Config, "config", "env,consul", "顺序1环境配置") 27 | 28 | flag.StringVar(&Cmd, "cmd", "cmd", "cli命令") 29 | flag.StringVar(&Args, "args", "{}", "json参数") 30 | var _ = func() bool { 31 | testing.Init() 32 | return true 33 | }() 34 | if !flag.Parsed() { 35 | flag.Parse() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/controller/redis_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/gomodule/redigo/redis" 7 | ) 8 | 9 | type RedisController struct { 10 | } 11 | 12 | func (s *RedisController) Handle(ctx contracts.Context) (interface{}, error) { 13 | 14 | client := clients.Redis() //从pool中获取一个链接 15 | defer client.Close() //延时释放链接,本方法执行完毕时释放 16 | _, _ = client.Do("SET", "go_key", "value") 17 | res, _ := redis.String(client.Do("GET", "go_key")) 18 | exists, _ := redis.Bool(client.Do("EXISTS", "foo")) 19 | if exists { 20 | ctx.Log.Info("foo 存在") 21 | } else { 22 | _, _ = client.Do("SET", "foo", "value") 23 | ctx.Log.Info("foo 不存在") 24 | 25 | } 26 | ctx.Log.Info("redis-go_key 的值:", res) 27 | 28 | return nil, nil 29 | } 30 | -------------------------------------------------------------------------------- /constants/error.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const Err string = "9999::错误" 4 | const ErrStop string = "9990::暂停服务" 5 | const ErrMQTTConnect string = "9991::MQTT链接失败" 6 | const ErrCacheInit string = "9992::Cache初始化错误" 7 | const ErrLoadEnv string = "9993::ENV环境加载失败" 8 | const ErrSign string = "9994::数据签名错误" 9 | const ErrBalance = "9995::金额不可为负值" 10 | 11 | const ErrNotExist string = "9000::数据不存在" 12 | const ErrIsExist string = "9001::数据已存在" 13 | const ErrSaveFailed string = "9002::数据保存失败" 14 | 15 | const ErrConvert string = "9010::类型转换错误" 16 | const ErrJson string = "9011::JSON报文解析错误" 17 | 18 | const ErrNoToken string = "9020::缺少authToken" 19 | const ErrTokenFmt string = "9021::Token格式错误" 20 | const ErrTokenExp string = "9022::Token过期,请重新登录" 21 | const ErrTokenSign string = "9023::签名错误,请重新登录" 22 | 23 | const ErrRoute string = "9030::路由解析错误" 24 | -------------------------------------------------------------------------------- /demo/src/controller/mqtt_event_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "time" 6 | ) 7 | 8 | type MqttEventController struct { 9 | } 10 | 11 | func (s *MqttEventController) Handle(ctx contracts.Context) (interface{}, error) { 12 | if ctx.Get("request.connected_at") != nil { 13 | connect := int64(ctx.Get("request.connected_at").(float64)) 14 | var conn string = time.Unix(connect, 0).Format("2006-01-02 15:04:05") 15 | println(ctx.Get("request.clientid").(string), "connect_at", conn) 16 | } 17 | if ctx.Get("request.disconnected_at") != nil { 18 | connect := int64(ctx.Get("request.disconnected_at").(float64)) 19 | var disconn string = time.Unix(connect, 0).Format("2006-01-02 15:04:05") 20 | println(ctx.Get("request.clientid").(string), "disconnect_at", disconn) 21 | } 22 | return nil, nil 23 | } 24 | -------------------------------------------------------------------------------- /servers/transports/codecs/mqtt_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "github.com/9299381/wego/constants" 8 | "github.com/9299381/wego/contracts" 9 | "github.com/9299381/wego/tools/idwork" 10 | ) 11 | 12 | func MqttSubscribeDecodeRequest(_ context.Context, req interface{}) (interface{}, error) { 13 | var mapResult map[string]interface{} 14 | err := json.Unmarshal(req.([]byte), &mapResult) 15 | if err != nil { 16 | return nil, errors.New(constants.ErrJson) 17 | } 18 | requestId, ok := mapResult["request_id"].(string) 19 | if ok == false { 20 | requestId = idwork.ID() 21 | } 22 | return contracts.Request{ 23 | Id: requestId, 24 | Data: mapResult, 25 | }, nil 26 | } 27 | 28 | func MqttSubscribeEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 29 | return rsp, nil 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/controller/parallel_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/demo/src/service" 6 | "github.com/9299381/wego/services" 7 | ) 8 | 9 | type ParallelController struct { 10 | } 11 | 12 | func (s *ParallelController) Handle(ctx contracts.Context) (interface{}, error) { 13 | ctx.Set("controller", "parallel") 14 | 15 | //并行service中间件 16 | err := services.Pipe(). 17 | Middle(&service.ParallelOne{}). 18 | Middle(&service.ParallelTwo{}). 19 | Parallel(ctx) 20 | if err != nil { 21 | return nil, err 22 | } 23 | m := make(map[string]interface{}) 24 | m["aaa"] = ctx.Get("aaa") //不确定值, 25 | m["one"] = ctx.Get("one") //one中设置 26 | m["two"] = ctx.Get("two") //two中设置 27 | m["controller"] = ctx.Get("controller") //controller中设置 28 | 29 | return m, nil 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/service/sql_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/demo/src/fsm" 7 | "github.com/9299381/wego/demo/src/model" 8 | ) 9 | 10 | type SqlService struct { 11 | } 12 | 13 | func (s *SqlService) Handle(ctx contracts.Context) error { 14 | 15 | user := &model.CommUser{Id: "1189164474851006208"} 16 | _, _ = clients.DB().Get(user) 17 | ctx.Log.Info(user) 18 | 19 | ////初始化状态机 20 | sm := fsm.NewUserFSM(ctx, user) 21 | ctx.Log.Info(user.Status) 22 | //发送状态转换的事件 23 | if sm.Can("login") { 24 | err := sm.Event("login") 25 | if err != nil { 26 | return err 27 | } 28 | user.UserName = "aaaaaaaaa" 29 | ctx.Log.Info(user.Status) 30 | _, _ = clients.DB().Update(user, &model.CommUser{Id: user.Id}) 31 | } 32 | ctx.Set("user", user) 33 | 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /clients/mysql/helper.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "errors" 5 | "github.com/9299381/wego/constants" 6 | ) 7 | 8 | func First(query interface{}, args []interface{}, bean interface{}) error { 9 | has, err := GetDB().SQL(query, args...).Get(bean) 10 | if err != nil { 11 | return err 12 | } 13 | if !has { 14 | return errors.New(constants.ErrNotExist) 15 | } 16 | return nil 17 | } 18 | 19 | func Fetch(query interface{}, args []interface{}, bean interface{}) error { 20 | return GetDB().SQL(query, args...).Find(bean) 21 | } 22 | 23 | func Insert(bean interface{}) bool { 24 | affected, _ := GetDB().Insert(bean) 25 | if affected == 1 { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func Update(bean interface{}, cond interface{}) bool { 32 | affected, _ := GetDB().Update(bean, cond) 33 | if affected == 1 { 34 | return true 35 | } 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/dto/queue_dto.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/9299381/wego/constants" 6 | "github.com/9299381/wego/validations" 7 | ) 8 | 9 | type TaskRequest struct { 10 | TaskId string `json:"task_id" valid:"Required"` 11 | OrderJson string `json:"order_json" valid:"Required"` 12 | OrderList []*Order `json:"-" valid:"Custom(CheckOrder)"` 13 | } 14 | 15 | func (s *TaskRequest) CheckOrder(v *validations.Validation) { 16 | err := json.Unmarshal([]byte(s.OrderJson), &s.OrderList) 17 | if err != nil { 18 | _ = v.SetError("order_json", constants.ErrJson) 19 | return 20 | } 21 | for _, order := range s.OrderList { 22 | err := validations.Valid(order) 23 | if err != nil { 24 | _ = v.SetError("list_json", err.Error()) 25 | } 26 | } 27 | } 28 | 29 | type Order struct { 30 | Id string `json:"id" valid:"Required" ` 31 | Name string `json:"name" valid:"Required"` 32 | } 33 | -------------------------------------------------------------------------------- /servers/transports/codecs/gprc_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "github.com/9299381/wego/contracts" 7 | protobuf2 "github.com/9299381/wego/servers/transports/protobuf" 8 | ) 9 | 10 | // TCP请求数据解码函数 11 | func GprcDecodeRequest(ctx context.Context, req interface{}) (interface{}, error) { 12 | request := req.(*protobuf2.Request) 13 | data := make(map[string]interface{}) 14 | _ = json.Unmarshal([]byte(request.Param), &data) 15 | 16 | return contracts.Request{ 17 | Id: request.Id, 18 | Data: data, 19 | }, nil 20 | } 21 | 22 | // TCP返回数据编码函数 23 | func GprcEncodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { 24 | response := rsp.(contracts.Response) 25 | data, _ := json.Marshal(response.Data) 26 | resp := &protobuf2.Response{ 27 | Code: response.Code, 28 | Data: string(data), 29 | Msg: response.Message, 30 | } 31 | return resp, nil 32 | } 33 | -------------------------------------------------------------------------------- /configs/mongo_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | import "time" 4 | 5 | type MongoConfig struct { 6 | Address []string 7 | Database string 8 | Username string 9 | Password string 10 | MaxIdleTime time.Duration 11 | MinPoolSize int 12 | } 13 | 14 | /** 15 | 每次有连接被重置到空闲池时,打一个时间戳。 16 | 在轮询 goroutine 中每隔一段时间 review 空闲连接的空闲时长, 17 | 当时长大于maxIdleTimeMS时,就释放连接,将空闲池的大小控制在minPoolSize。 18 | 若maxIdleTimeMS不设置或为 0,则默认为不进行释放 19 | */ 20 | func LoadMongoConfig() *MongoConfig { 21 | idle := EnvInt("mongo.max_idle_time", 30) 22 | config := &MongoConfig{ 23 | Address: EnvStringSlice("mongo.uri", []string{"127.0.0.1:27017"}), 24 | Database: EnvString("mongo.database", "base"), 25 | Username: EnvString("mongo.username", ""), 26 | Password: EnvString("mongo.password", ""), 27 | MinPoolSize: EnvInt("mongo.min_pool_size", 10), 28 | MaxIdleTime: time.Duration(idle) * time.Second, 29 | } 30 | return config 31 | } 32 | -------------------------------------------------------------------------------- /demo/test/num/num_test.go: -------------------------------------------------------------------------------- 1 | package num 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "github.com/9299381/wego/demo/src/model" 6 | "github.com/9299381/wego/tools/idwork" 7 | "testing" 8 | ) 9 | 10 | func TestNum(t *testing.T) { 11 | 12 | } 13 | 14 | func TestDemoTestModel(t *testing.T) { 15 | err := clients.DB().Sync2(new(model.CommDemoModel)) 16 | if err != nil { 17 | t.Error(err) 18 | } 19 | } 20 | func TestInsert(t *testing.T) { 21 | demo := &model.CommDemoModel{ 22 | Id: idwork.ID(), 23 | NumInt1: 9876543210, 24 | NumInt2: 0, 25 | NumBig: 1111111111111111111, 26 | } 27 | _, _ = clients.DB().Insert(demo) 28 | } 29 | func TestUpdate(t *testing.T) { 30 | demo := &model.CommDemoModel{Id: "1298580054575415296"} 31 | _, _ = clients.DB().Get(demo) 32 | demo.NumInt1 = 0 33 | demo.NumInt2 = 123 34 | _, _ = clients.DB(). 35 | Id(demo.Id). 36 | Cols("num_int1", "num_int2"). 37 | Update(demo) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /demo/test/ctl/controller_test.go: -------------------------------------------------------------------------------- 1 | package ctl 2 | 3 | import ( 4 | "github.com/9299381/wego/demo/src/controller" 5 | "github.com/9299381/wego/tools" 6 | "testing" 7 | ) 8 | 9 | func TestOneController(t *testing.T) { 10 | resp, err := tools.Test(). 11 | Controller(&controller.OneController{}). 12 | Request(nil). 13 | Run() 14 | 15 | if err != nil { 16 | t.Error(err) 17 | } else { 18 | t.Log(resp.Data) 19 | } 20 | 21 | } 22 | func TestTwoController(t *testing.T) { 23 | resp, err := tools.Test(). 24 | Controller(&controller.TwoController{}). 25 | Request(nil). 26 | Run() 27 | 28 | if err != nil { 29 | t.Error(err) 30 | } else { 31 | t.Log(resp.Data) 32 | } 33 | 34 | } 35 | func TestParallelController(t *testing.T) { 36 | resp, err := tools.Test(). 37 | Controller(&controller.ParallelController{}). 38 | Request(nil). 39 | Run() 40 | 41 | if err != nil { 42 | t.Error(err) 43 | } else { 44 | t.Log(resp.Data) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /configs/mysql_config.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/args" 6 | ) 7 | 8 | type MySqlConfig struct { 9 | Driver string 10 | DataSource string 11 | MaxIdleConns int 12 | MaxOpenConns int 13 | ShowSQL bool 14 | } 15 | 16 | func LoadMySqlConfig() *MySqlConfig { 17 | driver := EnvString("db.connection", "mysql") 18 | dataSource := fmt.Sprintf( 19 | "%s:%s@(%s:%s)/%s"+"?charset=utf8&collation=utf8_general_ci", 20 | EnvString("db.username", "root"), 21 | EnvString("db.password", "root"), 22 | EnvString("db.host", "127.0.0.1"), 23 | EnvString("db.port", "3306"), 24 | EnvString("db.database", "default"), 25 | ) 26 | show := false 27 | if args.Mode != "prod" { 28 | show = true 29 | } 30 | config := &MySqlConfig{ 31 | Driver: driver, 32 | DataSource: dataSource, 33 | ShowSQL: show, 34 | MaxIdleConns: EnvInt("db.max_idle", 5), 35 | MaxOpenConns: EnvInt("db.max_open", 50), 36 | } 37 | return config 38 | } 39 | -------------------------------------------------------------------------------- /servers/command_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/loggers" 5 | "github.com/9299381/wego/servers/commands" 6 | "github.com/9299381/wego/servers/commons" 7 | "github.com/9299381/wego/servers/transports" 8 | "github.com/go-kit/kit/endpoint" 9 | ) 10 | 11 | type CommandCommServer struct { 12 | *commands.Server 13 | } 14 | 15 | func NewCommandCommServer() *CommandCommServer { 16 | ss := &CommandCommServer{ 17 | Server: commands.NewServer(), 18 | } 19 | ss.Logger = loggers.GetLog() 20 | return ss 21 | } 22 | 23 | func (s *CommandCommServer) Route(name string, endpoint endpoint.Endpoint) { 24 | 25 | handler := &commons.CommHandler{ 26 | Handler: transports.NewCommand(endpoint), 27 | } 28 | s.Register(name, handler) 29 | } 30 | 31 | func (s *CommandCommServer) Load() { 32 | 33 | //注册通用路由 34 | } 35 | 36 | func (s *CommandCommServer) Start() error { 37 | return s.Serve() 38 | 39 | } 40 | func (s *CommandCommServer) Close() { 41 | s.Server.Close() 42 | } 43 | -------------------------------------------------------------------------------- /clients/http.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/tools/convert" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func NewHttpPostCall(host, service string, params map[string]interface{}) (ret contracts.Response) { 14 | 15 | path := "http://" + host + "/" + strings.Replace(service, ".", "/", -1) 16 | client := &http.Client{ 17 | Timeout: 10 * time.Second, 18 | } 19 | resp, err := client.PostForm(path, convert.FormEncode(params)) 20 | if err != nil { 21 | ret = contracts.ResponseFailed(err) 22 | return 23 | } 24 | defer resp.Body.Close() 25 | body, err := ioutil.ReadAll(resp.Body) 26 | 27 | response := &contracts.Response{} 28 | err = json.Unmarshal(body, response) 29 | if err != nil { 30 | ret = contracts.ResponseFailed(err) 31 | } else { 32 | m := response.Data.(map[string]interface{}) 33 | m["call_method"] = "http" 34 | response.Data = m 35 | ret = *response 36 | } 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /servers/gateway_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/filters" 5 | "github.com/9299381/wego/loggers" 6 | "github.com/9299381/wego/servers/gateways" 7 | "github.com/go-kit/kit/endpoint" 8 | ) 9 | 10 | type GateWayCommServer struct { 11 | *gateways.Server 12 | } 13 | 14 | func NewGateWayCommServer() *GateWayCommServer { 15 | ss := &GateWayCommServer{ 16 | Server: gateways.NewServer(), 17 | } 18 | ss.Logger = loggers.GetLog() 19 | return ss 20 | } 21 | 22 | func (s *GateWayCommServer) Route(method, path string, endpoint endpoint.Endpoint) { 23 | //如果有本地注册的路由,则跑本地,2种情况组合endpoint filter 24 | //1 跑本地服务 25 | //2 只跑本地endpoint filter 26 | s.Register(method, path, endpoint) 27 | } 28 | 29 | func (s *GateWayCommServer) Load() { 30 | //注册通用路由,consul 心跳检测 31 | s.Route("GET", "/health", (&filters.HealthEndpoint{}).Make()) 32 | 33 | } 34 | 35 | func (s *GateWayCommServer) Start() error { 36 | return s.Serve() 37 | } 38 | func (s *GateWayCommServer) Close() { 39 | s.Server.Close() 40 | } 41 | -------------------------------------------------------------------------------- /filters/Jwt_endpoint.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/9299381/wego/constants" 7 | "github.com/9299381/wego/contracts" 8 | "github.com/9299381/wego/tools/convert" 9 | "github.com/9299381/wego/tools/jwt" 10 | "github.com/go-kit/kit/endpoint" 11 | ) 12 | 13 | type JwtEndpoint struct { 14 | next endpoint.Endpoint 15 | } 16 | 17 | func (s *JwtEndpoint) Next(next endpoint.Endpoint) contracts.IFilter { 18 | s.next = next 19 | return s 20 | } 21 | 22 | func (s *JwtEndpoint) Make() endpoint.Endpoint { 23 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 24 | req := request.(contracts.Request) 25 | token := req.Data["authToken"] 26 | if token == nil || token == "" { 27 | return nil, errors.New(constants.ErrNoToken) 28 | } 29 | claim, err := jwt.New().VerifyToken(token.(string)) 30 | if err != nil { 31 | return nil, err 32 | } 33 | req.Data["claim"] = convert.Struct2Map(claim) 34 | //这里进行token的jwt认证 35 | return s.next(ctx, req) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /servers/timer_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/loggers" 5 | "github.com/9299381/wego/servers/commons" 6 | "github.com/9299381/wego/servers/timers" 7 | "github.com/9299381/wego/servers/transports" 8 | "github.com/go-kit/kit/endpoint" 9 | ) 10 | 11 | /** 12 | 定时器 13 | */ 14 | type TimerCommServer struct { 15 | *timers.Server 16 | } 17 | 18 | func NewTimerCommServer() *TimerCommServer { 19 | ss := &TimerCommServer{ 20 | Server: timers.NewServer(), 21 | } 22 | ss.Logger = loggers.GetLog() 23 | return ss 24 | } 25 | 26 | func (s *TimerCommServer) Load() { 27 | 28 | //注册通用路由 29 | } 30 | 31 | func (s *TimerCommServer) Route(name string, freq int, endpoint endpoint.Endpoint, params map[string]interface{}) { 32 | 33 | handler := &commons.CommHandler{ 34 | Handler: transports.NewTimer(endpoint), 35 | } 36 | s.Register(name, freq, handler, params) 37 | } 38 | 39 | func (s *TimerCommServer) Start() error { 40 | return s.Serve() 41 | } 42 | func (s *TimerCommServer) Close() { 43 | s.Server.Close() 44 | } 45 | -------------------------------------------------------------------------------- /filters/gateway_endpoint.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/go-kit/kit/endpoint" 7 | ) 8 | 9 | type GateWayEndpoint struct { 10 | next endpoint.Endpoint 11 | } 12 | 13 | func (s *GateWayEndpoint) Next(next endpoint.Endpoint) contracts.IFilter { 14 | s.next = next 15 | return s 16 | } 17 | 18 | func (s *GateWayEndpoint) Make() endpoint.Endpoint { 19 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 20 | req := request.(contracts.Request) 21 | req.Data["GATEWAY"] = "GATEWAY" 22 | if s.next == nil { 23 | response = contracts.ResponseSucess(req.Data) 24 | } else { 25 | response, err = s.next(ctx, req) 26 | res := response.(contracts.Response) 27 | if res.Code == "0000" { 28 | m, b := res.Data.(map[string]interface{}) 29 | if b && m != nil { 30 | for k, v := range m { 31 | req.Data[k] = v 32 | } 33 | response = contracts.ResponseSucess(req.Data) 34 | } 35 | } 36 | } 37 | return 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /servers/event_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/configs" 6 | "github.com/9299381/wego/loggers" 7 | "github.com/9299381/wego/servers/events" 8 | "time" 9 | ) 10 | 11 | type EventCommServer struct { 12 | *events.Server 13 | } 14 | 15 | func NewEventCommServer() *EventCommServer { 16 | config := configs.LoadEventConfig() 17 | ss := &EventCommServer{ 18 | Server: events.NewServer(), 19 | } 20 | ss.Logger = loggers.GetLog() 21 | ss.Concurrency = config.Concurrency 22 | ss.After = time.After(time.Duration(config.After) * time.Second) 23 | events.Handlers = wego.App.Handlers 24 | return ss 25 | } 26 | func (s *EventCommServer) Boot() { 27 | 28 | } 29 | 30 | func (s *EventCommServer) Load() { 31 | 32 | //注册通用路由 33 | } 34 | func (s *EventCommServer) Register() { 35 | } 36 | 37 | func (s *EventCommServer) Route() { 38 | 39 | } 40 | 41 | func (s *EventCommServer) Start() error { 42 | return s.Serve() 43 | } 44 | func (s *EventCommServer) Close() { 45 | s.Server.Close() 46 | } 47 | -------------------------------------------------------------------------------- /servers/websocket_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/loggers" 5 | "github.com/9299381/wego/servers/commons" 6 | "github.com/9299381/wego/servers/transports" 7 | "github.com/9299381/wego/servers/websockets" 8 | "github.com/go-kit/kit/endpoint" 9 | ) 10 | 11 | //websocket 服务器尽量采用 emqx mqtt broker 12 | type WebSocketCommServer struct { 13 | *websockets.Server 14 | } 15 | 16 | func NewWebSocketCommServer() *WebSocketCommServer { 17 | 18 | ss := &WebSocketCommServer{ 19 | Server: websockets.NewServer(), 20 | } 21 | ss.Logger = loggers.GetLog() 22 | return ss 23 | } 24 | 25 | func (s *WebSocketCommServer) Route(name string, endpoint endpoint.Endpoint) { 26 | 27 | handler := &commons.CommHandler{ 28 | Handler: transports.NewWebSocket(endpoint), 29 | } 30 | s.Register(name, handler) 31 | } 32 | 33 | func (s *WebSocketCommServer) Load() { 34 | //注册通用路由 35 | } 36 | 37 | func (s *WebSocketCommServer) Start() error { 38 | return s.Serve() 39 | } 40 | func (s *WebSocketCommServer) Close() { 41 | s.Server.Close() 42 | } 43 | -------------------------------------------------------------------------------- /filters/response_endpoint.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/9299381/wego" 7 | "github.com/9299381/wego/constants" 8 | "github.com/9299381/wego/contracts" 9 | "github.com/9299381/wego/loggers" 10 | "github.com/go-kit/kit/endpoint" 11 | ) 12 | 13 | type ResponseEndpoint struct { 14 | next endpoint.Endpoint 15 | } 16 | 17 | func (s *ResponseEndpoint) Next(next endpoint.Endpoint) contracts.IFilter { 18 | s.next = next 19 | return s 20 | } 21 | 22 | func (s *ResponseEndpoint) Make() endpoint.Endpoint { 23 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 24 | //全局扑捉错误 25 | defer func() { 26 | if err := recover(); err != nil { 27 | loggers.GetLog().Info(err) 28 | response = contracts.MakeResponse(nil, err.(error)) 29 | } 30 | }() 31 | if wego.App.Status == false { 32 | err := errors.New(constants.ErrStop) 33 | return contracts.MakeResponse(nil, err), nil 34 | } 35 | response, err = s.next(ctx, request) 36 | return contracts.MakeResponse(response, err), nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /servers/mqtt_subscribe_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/loggers" 5 | "github.com/9299381/wego/servers/commons" 6 | "github.com/9299381/wego/servers/mqtts" 7 | "github.com/9299381/wego/servers/transports" 8 | "github.com/go-kit/kit/endpoint" 9 | ) 10 | 11 | type MqttSubscribeCommCommServer struct { 12 | *mqtts.Server 13 | } 14 | 15 | func NewMqttSubscribeCommCommServer() *MqttSubscribeCommCommServer { 16 | ss := &MqttSubscribeCommCommServer{ 17 | Server: mqtts.NewServer(), 18 | } 19 | ss.Logger = loggers.GetLog() 20 | return ss 21 | } 22 | 23 | func (s *MqttSubscribeCommCommServer) Route(name string, endpoint endpoint.Endpoint) { 24 | 25 | handler := &commons.CommHandler{ 26 | Handler: transports.NewMqttSubscribe(endpoint), 27 | } 28 | s.Register(name, handler) 29 | } 30 | 31 | func (s *MqttSubscribeCommCommServer) Load() { 32 | 33 | //注册通用路由 34 | } 35 | 36 | func (s *MqttSubscribeCommCommServer) Start() error { 37 | return s.Serve() 38 | 39 | } 40 | 41 | func (s *MqttSubscribeCommCommServer) Close() { 42 | s.Server.Close() 43 | } 44 | -------------------------------------------------------------------------------- /demo/test/di_test/di_test.go: -------------------------------------------------------------------------------- 1 | package di_test 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/demo/test/di_test/demo" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | func TestOne(t *testing.T) { 11 | str := "aaaaaaa" 12 | people := &demo.Man{} 13 | wego.DI().MapTo(people, (*demo.IPeople)(nil)) 14 | ret, _ := wego.DI().Invoke(func(p demo.IPeople) string { 15 | return p.Write(str) 16 | }) 17 | t.Log(ret) 18 | } 19 | 20 | func TestTwo(t *testing.T) { 21 | str := "aaaaaaa" 22 | people := &demo.Man{} 23 | wego.DI().Map(people) 24 | ret, _ := wego.DI().Invoke(func(p *demo.Man) string { 25 | return p.Write(str) 26 | }) 27 | t.Log(ret) 28 | } 29 | 30 | func TestThree(t *testing.T) { 31 | people := &demo.Man{} 32 | wego.DI().MapTo(people, (*demo.IPeople)(nil)) 33 | _, _ = wego.DI().Invoke(MyFastInvoker(nil)) 34 | } 35 | 36 | type MyFastInvoker func(people demo.IPeople) 37 | 38 | func (invoker MyFastInvoker) Invoke(args []interface{}) ([]reflect.Value, error) { 39 | if people, ok := args[0].(demo.IPeople); ok { 40 | people.Work() 41 | } 42 | return nil, nil 43 | } 44 | -------------------------------------------------------------------------------- /demo/test/json_str/json_test.go: -------------------------------------------------------------------------------- 1 | package json_str 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/9299381/wego/contracts" 7 | "github.com/9299381/wego/tools/idwork" 8 | "testing" 9 | ) 10 | 11 | type DemoStruct struct { 12 | Id string `json:"id"` 13 | Name string `json:"name"` 14 | } 15 | 16 | func TestDemoStruct(t *testing.T) { 17 | var records []*DemoStruct 18 | records = append(records, &DemoStruct{ 19 | Id: idwork.ID(), 20 | Name: "one", 21 | }) 22 | records = append(records, &DemoStruct{ 23 | Id: idwork.ID(), 24 | Name: "two", 25 | }) 26 | args, _ := json.Marshal(records) 27 | fmt.Println(string(args)) 28 | params := map[string]interface{}{ 29 | "args": string(args), 30 | } 31 | 32 | payload := &contracts.Payload{ 33 | Route: "route", 34 | Params: params, 35 | } 36 | jb, _ := json.Marshal(payload) 37 | 38 | p := &contracts.Payload{} 39 | _ = json.Unmarshal(jb, p) 40 | fmt.Println(p) 41 | 42 | var st []*DemoStruct 43 | _ = json.Unmarshal([]byte(p.Params["args"].(string)), &st) 44 | for _, v := range st { 45 | fmt.Println(v) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/controller/two_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/demo/src/service" 6 | "github.com/9299381/wego/services" 7 | "github.com/9299381/wego/tools/idwork" 8 | ) 9 | 10 | type TwoController struct { 11 | } 12 | 13 | func (s *TwoController) Handle(ctx contracts.Context) (interface{}, error) { 14 | // swagger:route Get /demo/two 分组1 twoController 15 | // Test swagger 16 | // This will ....... 17 | // Responses: 18 | // 200: twoResponse 19 | _ = services.Pipe(). 20 | Middle(&service.TwoService{}). 21 | Line(ctx) 22 | ret := &TwoResponse{ 23 | Id: idwork.ID(), 24 | UserName: ctx.Get("one").(string), 25 | } 26 | return ret, nil 27 | } 28 | func (s *TwoController) GetRules() interface{} { 29 | return &TwoRequest{} 30 | } 31 | 32 | // swagger:parameters twoController 33 | type TwoRequest struct { 34 | // 备注 35 | Name string `json:"name"` 36 | } 37 | 38 | // swagger:response twoResponse 39 | type TwoResponse struct { 40 | Id string `json:"id"` 41 | UserName string `json:"user_name"` 42 | } 43 | -------------------------------------------------------------------------------- /servers/commands/server.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/9299381/wego/args" 7 | "github.com/9299381/wego/constants" 8 | "github.com/9299381/wego/contracts" 9 | "github.com/9299381/wego/servers/commons" 10 | ) 11 | 12 | type Server struct { 13 | handlers map[string]*commons.CommHandler 14 | Logger contracts.ILogger 15 | } 16 | 17 | func NewServer() *Server { 18 | //初始化,logger,redis池 19 | s := &Server{ 20 | handlers: make(map[string]*commons.CommHandler), 21 | } 22 | return s 23 | } 24 | 25 | func (s *Server) Register(name string, handler *commons.CommHandler) { 26 | s.handlers[name] = handler 27 | 28 | } 29 | 30 | func (s *Server) Serve() error { 31 | if args.Cmd != "" { 32 | //调用服务 33 | handler, isExist := s.handlers[args.Cmd] 34 | if isExist == false { 35 | return errors.New(constants.ErrRoute) 36 | } 37 | ctx := context.Background() 38 | response, err := handler.Handle(ctx, args.Args) 39 | if err != nil { 40 | return err 41 | } 42 | s.Logger.Info(response) 43 | } 44 | return nil 45 | } 46 | func (s *Server) Close() { 47 | 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/controller/post_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/tools/convert" 6 | "github.com/9299381/wego/tools/idwork" 7 | ) 8 | 9 | type PostController struct { 10 | } 11 | 12 | // swagger:route Post /demo/post 分组2 postController 13 | // Test swagger 14 | // This will ....... 15 | // Responses: 16 | // 200: postResponse 17 | 18 | func (s *PostController) Handle(ctx contracts.Context) (interface{}, error) { 19 | 20 | request := &postRequest{} 21 | err := convert.Map2Struct(ctx.Get("request"), request) 22 | 23 | if err != nil { 24 | return nil, err 25 | } 26 | ctx.Log.Info(request) 27 | 28 | ret := &postResponse{ 29 | Id: idwork.ID(), 30 | Resp: *request, 31 | } 32 | return ret, nil 33 | } 34 | 35 | // swagger:parameters postController 36 | type postRequest struct { 37 | Id string `json:"id"` 38 | Value string `json:"value"` 39 | Number int `json:"number"` 40 | } 41 | 42 | // swagger:response postResponse 43 | type postResponse struct { 44 | Id string `json:"id"` 45 | Resp postRequest `json:"resp"` 46 | } 47 | -------------------------------------------------------------------------------- /demo/src/router/http_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/args" 6 | "github.com/9299381/wego/servers" 7 | ) 8 | 9 | type HttpRouter struct { 10 | *servers.HttpCommServer 11 | } 12 | 13 | func (s *HttpRouter) Boot() { 14 | s.HttpCommServer = servers.NewHttpCommServer() 15 | } 16 | 17 | func (s *HttpRouter) Register() { 18 | 19 | s.Get("/demo/one", wego.Handler("one")) 20 | s.Get("/demo/two", wego.Handler("two")) 21 | s.Post("/demo/auth", wego.Handler("auth")) 22 | s.Get("/demo/sql", wego.Handler("sql")) 23 | s.Get("/demo/redis", wego.Handler("redis")) 24 | s.Post("/demo/post", wego.Handler("post")) 25 | s.Get("/demo/queue", wego.Handler("queue")) 26 | 27 | s.Get("/demo/cache_set", wego.Handler("cache_set")) 28 | s.Get("/demo/cache_get", wego.Handler("cache_get")) 29 | //验证validate 30 | s.Post("/demo/valid", wego.Handler("valid")) 31 | 32 | s.Get("/demo/consul", wego.Handler("consul")) 33 | s.Get("/demo/event", wego.Handler("event")) 34 | s.Get("/demo/publish", wego.Handler("publish")) 35 | 36 | if args.Mode != "prod" { 37 | s.HandleSwagger() 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /providers/consul_registy_provider.go: -------------------------------------------------------------------------------- 1 | package providers 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/args" 6 | "github.com/9299381/wego/clients" 7 | "github.com/9299381/wego/configs" 8 | "strings" 9 | ) 10 | 11 | type ConsulRegistyProvider struct { 12 | } 13 | 14 | func (s *ConsulRegistyProvider) Boot() { 15 | 16 | } 17 | 18 | func (s *ConsulRegistyProvider) Register() { 19 | if args.Registy != "" { 20 | s.consulHttpRegister() 21 | s.consulGrpcRegister() 22 | } 23 | } 24 | func (s *ConsulRegistyProvider) consulHttpRegister() { 25 | if strings.Contains(args.Server, "http") || strings.Contains(args.Server, "gateway") { 26 | httpConfig := configs.LoadHttpConfig() 27 | wego.App.Consul["http"] = clients.NewConsulHttpRegister( 28 | args.Name, 29 | httpConfig.HttpHost, 30 | httpConfig.HttpPort, 31 | ) 32 | } 33 | } 34 | func (s *ConsulRegistyProvider) consulGrpcRegister() { 35 | if strings.Contains(args.Server, "grpc") { 36 | grpcConfig := configs.LoadGrpcConfig() 37 | wego.App.Consul["grpc"] = clients.NewConsulGrpcRegister( 38 | args.Name, 39 | grpcConfig.GrpcHost, 40 | grpcConfig.GrpcPort, 41 | ) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /clients/service.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | // 为统一php模式而封装 9 | // micro -> service, service ->route 10 | func Service(service string) *microService { 11 | return µService{ 12 | service: service, 13 | params: make(map[string]interface{}), 14 | } 15 | } 16 | 17 | type microService struct { 18 | service string 19 | api string 20 | params map[string]interface{} 21 | } 22 | 23 | func (s *microService) Api(api string) *microService { 24 | s.api = api 25 | return s 26 | } 27 | 28 | func (s *microService) Params(params map[string]interface{}) *microService { 29 | s.params = params 30 | return s 31 | } 32 | 33 | func (s *microService) Run() (resp contracts.Response) { 34 | entity, err := GetConsulService(s.service) 35 | if err != nil { 36 | resp = contracts.ResponseFailed(err) 37 | return 38 | } 39 | tag := entity.Service.Tags[0] 40 | host := fmt.Sprintf("%s:%d", entity.Service.Address, entity.Service.Port) 41 | if tag == "http" { 42 | return NewHttpPostCall(host, s.api, s.params) 43 | } else if tag == "grpc" { 44 | resp = NewGrpcCall(host, s.api, s.params) 45 | } 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /clients/mongo/session.go: -------------------------------------------------------------------------------- 1 | package mongo 2 | 3 | import ( 4 | "github.com/9299381/wego/configs" 5 | "gopkg.in/mgo.v2" 6 | "log" 7 | ) 8 | 9 | var session *mgo.Session 10 | 11 | func Session() *mgo.Session { 12 | if session == nil { 13 | var err error 14 | conf := configs.LoadMongoConfig() 15 | info := &mgo.DialInfo{ 16 | Addrs: conf.Address, 17 | Timeout: conf.MaxIdleTime, 18 | Username: conf.Username, 19 | Password: conf.Password, 20 | Database: conf.Database, 21 | PoolLimit: conf.MinPoolSize, 22 | } 23 | session, err = mgo.DialWithInfo(info) 24 | if err != nil { 25 | log.Fatalf("MongoCreateSession: %s\n", err) 26 | } 27 | session.SetMode(mgo.Monotonic, true) 28 | } 29 | return session.Clone() 30 | } 31 | func Col(collection string, f func(*mgo.Collection)) { 32 | Table(configs.LoadMongoConfig().Database, collection, f) 33 | } 34 | func Table(database string, collection string, f func(*mgo.Collection)) { 35 | session := Session() 36 | defer func() { 37 | session.Close() 38 | if err := recover(); err != nil { 39 | log.Fatalf("MongoSessionError: %v", err) 40 | } 41 | }() 42 | c := session.DB(database).C(collection) 43 | f(c) 44 | } 45 | -------------------------------------------------------------------------------- /demo/src/fsm/user_fsm.go: -------------------------------------------------------------------------------- 1 | package fsm 2 | 3 | import ( 4 | "github.com/9299381/wego/contracts" 5 | "github.com/9299381/wego/demo/src/model" 6 | "github.com/looplab/fsm" 7 | ) 8 | 9 | const Begin = "0" 10 | const Reg = "10" 11 | const Login = "20" 12 | const Lock = "30" 13 | const Named = "60" 14 | 15 | type UserFSM struct { 16 | contracts.Context 17 | *fsm.FSM 18 | User *model.CommUser 19 | } 20 | 21 | func NewUserFSM(ctx contracts.Context, user *model.CommUser) *UserFSM { 22 | s := &UserFSM{ 23 | Context: ctx, 24 | User: user, 25 | } 26 | sm := fsm.NewFSM( 27 | Begin, 28 | fsm.Events{ 29 | {Name: "register", Src: []string{Begin}, Dst: Reg}, 30 | {Name: "login", Src: []string{Reg}, Dst: Login}, 31 | {Name: "named", Src: []string{Reg, Login}, Dst: Named}, 32 | {Name: "lock", Src: []string{Reg, Login, Named}, Dst: Lock}, 33 | }, 34 | fsm.Callbacks{ 35 | "after_event": func(e *fsm.Event) { 36 | s.Log.Infof("fsm event:%s change status to %s", e.Event, e.Dst) 37 | s.User.Status = e.Dst 38 | }, 39 | }, 40 | ) 41 | if s.User.Status != "" { 42 | sm.SetState(s.User.Status) 43 | } else { 44 | sm.SetState(Begin) 45 | } 46 | 47 | s.FSM = sm 48 | return s 49 | } 50 | -------------------------------------------------------------------------------- /demo/env.toml: -------------------------------------------------------------------------------- 1 | # dev,test,prod等优先,common通用 2 | [common] 3 | # 为避免与php发生冲突,SERVER_ID 从512开始-1023,PHP则从0-63计算 4 | server_id = 512 5 | [common.server] 6 | # 用于侦听和注册到consul服务器 7 | http_host = "" 8 | http_port = 8341 9 | grpc_host = "" 10 | grpc_port = 9341 11 | # 单机版时有意义,分布式用emqx替代 12 | websocket_host = "" 13 | websocket_port = 7341 14 | 15 | 16 | [common.db] 17 | # mysql 部分 18 | connection = "mysql" 19 | host = "192.168.0.1" 20 | port = 3306 21 | database = "base" 22 | username = "root" 23 | password = "123123" 24 | timezone = "+08:00" 25 | max_idle = 5 26 | max_open = 50 27 | 28 | [common.redis] 29 | # redis 部分 30 | uri = "127.0.0.1:6937" 31 | auth = "123123" 32 | db = 1 33 | max_active = 50 34 | max_idle = 5 35 | time_out = 10 36 | 37 | [common.queue] 38 | # 队列部分 39 | # 前缀 40 | prefix = "wego" 41 | # 侦听队列 42 | listen = ["demo1"] 43 | #扫描频率,分钟 44 | interval = 1 45 | # 并发 46 | concurrency = 10 47 | 48 | [common.cache] 49 | # 缓存设置 100*1024*1024 50 | size = 104857600 51 | 52 | [common.mqtt] 53 | host = "tcp://127.0.0.1:1883" 54 | username = "" 55 | password = "" 56 | parallel = true 57 | 58 | 59 | 60 | [dev.server] 61 | http_port = 8342 62 | [dev.db] 63 | host = "127.0.0.1" 64 | 65 | 66 | [prod.db] 67 | host = "123.123.123.123" -------------------------------------------------------------------------------- /demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/args" 6 | "github.com/9299381/wego/demo/src/provider" 7 | "github.com/9299381/wego/demo/src/router" 8 | "github.com/9299381/wego/providers" 9 | "github.com/9299381/wego/servers" 10 | ) 11 | 12 | func main() { 13 | 14 | //args.Registy = "127.0.0.1:8500" 15 | args.Server = "http,grpc" 16 | 17 | //args.Server = "http,event,subscribe" 18 | //args.Server = "subscribe" 19 | //args.Server = "queue" 20 | args.Name = "demo" 21 | args.Mode = "dev" 22 | //服务注册 23 | wego.Provider(&providers.ConsulRegistyProvider{}) 24 | // api 接口 25 | wego.Provider(new(provider.DemoProvider)) 26 | // http服务器路由 27 | wego.Router("http", &router.HttpRouter{}) 28 | // grpc_api 接口服务路由 29 | wego.Router("grpc", &router.GrpcRouter{}) 30 | wego.Router("queue", &router.QueueRouter{}) 31 | wego.Router("command", &router.CommandRouter{}) 32 | wego.Router("timer", &router.TimerRouter{}) 33 | wego.Router("cron", &router.CronRouter{}) 34 | wego.Router("websocket", &router.WebSocketRouter{}) 35 | wego.Router("subscribe", &router.SubscribeRouter{}) 36 | //内置加载事件服务,无需路由,直接调用 filter handler 37 | wego.Router("event", servers.NewEventCommServer()) 38 | 39 | wego.Start() 40 | 41 | } 42 | -------------------------------------------------------------------------------- /demo/test/conver/conver_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/mitchellh/mapstructure" 6 | "testing" 7 | ) 8 | 9 | func TestMap2Struct(t *testing.T) { 10 | 11 | m := getMap() 12 | obj := &DTOStruct{} 13 | //要去掉map中key的下划线 14 | err := mapstructure.WeakDecode(m, obj) 15 | 16 | if err != nil { 17 | t.Error(err) 18 | } else { 19 | t.Log(obj) 20 | } 21 | 22 | } 23 | 24 | func getMap() map[string]interface{} { 25 | 26 | //jjson := "[{\"id\":\"123123\",\"name\":\"abcde\"},{\"id\":\"234234\",\"name\":\"asdfasdf\"}]" 27 | 28 | m := make(map[string]interface{}) 29 | //m["name"] = "asdf" 30 | //m["age"] = "123" 31 | //m["desc"] = "随便练" 32 | //m["Username"] = string(getJson()) 33 | m["user_name"] = string(getJson()) 34 | 35 | return m 36 | } 37 | 38 | func getJson() []byte { 39 | 40 | var jj []map[string]interface{} 41 | ss1 := make(map[string]interface{}) 42 | ss1["id"] = "123123" 43 | ss1["name"] = "abcde" 44 | ss2 := make(map[string]interface{}) 45 | ss2["id"] = "234234" 46 | ss2["name"] = "asdfasdf" 47 | jj = append(jj, ss1) 48 | jj = append(jj, ss2) 49 | jjson, _ := json.Marshal(jj) 50 | return jjson 51 | 52 | } 53 | 54 | type DTOStruct struct { 55 | User_Name string `json:"user_name"` 56 | } 57 | -------------------------------------------------------------------------------- /tools/tests/test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/9299381/wego/contracts" 7 | "github.com/9299381/wego/filters" 8 | "github.com/9299381/wego/tools/idwork" 9 | ) 10 | 11 | type TestStruct struct { 12 | controller contracts.IController 13 | request map[string]interface{} 14 | } 15 | 16 | func NewTest() *TestStruct { 17 | return &TestStruct{ 18 | request: make(map[string]interface{}), 19 | } 20 | } 21 | func (s *TestStruct) Controller(controller contracts.IController) *TestStruct { 22 | s.controller = controller 23 | return s 24 | } 25 | func (s *TestStruct) Request(m map[string]interface{}) *TestStruct { 26 | if m != nil { 27 | s.request = m 28 | } 29 | return s 30 | } 31 | func (s *TestStruct) Run() (contracts.Response, error) { 32 | e := filters.Chain( 33 | &filters.ResponseEndpoint{}, 34 | &filters.CommEndpoint{Controller: s.controller}, 35 | ) 36 | request := contracts.Request{ 37 | Id: idwork.ID(), 38 | Data: s.request, 39 | } 40 | response, err := e(context.Background(), request) 41 | resp := response.(contracts.Response) 42 | if err != nil { 43 | return resp, err 44 | } 45 | if resp.Code != "0000" { 46 | return resp, errors.New(resp.Message) 47 | } 48 | return resp, nil 49 | } 50 | -------------------------------------------------------------------------------- /servers/queue_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/clients" 5 | "github.com/9299381/wego/configs" 6 | "github.com/9299381/wego/loggers" 7 | "github.com/9299381/wego/servers/commons" 8 | "github.com/9299381/wego/servers/queues" 9 | "github.com/9299381/wego/servers/transports" 10 | "github.com/go-kit/kit/endpoint" 11 | ) 12 | 13 | /** 14 | redis queue 15 | */ 16 | type QueueCommServer struct { 17 | *queues.Server 18 | } 19 | 20 | func NewQueueCommServer() *QueueCommServer { 21 | config := configs.LoadQueueConfig() 22 | ss := &QueueCommServer{ 23 | Server: queues.NewServer(&queues.Options{ 24 | Prefix: config.Prefix, 25 | Listen: config.Listen, 26 | Interval: config.Interval, 27 | UseNumber: true, 28 | Concurrency: config.Concurrency, 29 | }), 30 | } 31 | ss.RedisPool = clients.RedisPool() 32 | ss.Logger = loggers.GetLog() 33 | return ss 34 | } 35 | 36 | func (s *QueueCommServer) Route(name string, endpoint endpoint.Endpoint) { 37 | 38 | handler := &commons.CommHandler{ 39 | Handler: transports.NewQueue(endpoint), 40 | } 41 | s.Register(name, handler) 42 | } 43 | 44 | func (s *QueueCommServer) Load() { 45 | 46 | //注册通用路由 47 | } 48 | 49 | func (s *QueueCommServer) Start() error { 50 | return s.Serve() 51 | 52 | } 53 | func (s *QueueCommServer) Close() { 54 | s.Server.Close() 55 | } 56 | -------------------------------------------------------------------------------- /cache/ins.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "github.com/9299381/wego/configs" 7 | "github.com/9299381/wego/constants" 8 | "github.com/coocood/freecache" 9 | "runtime/debug" 10 | "sync" 11 | ) 12 | 13 | var ins *freecache.Cache 14 | var once sync.Once 15 | 16 | func GetIns() *freecache.Cache { 17 | once.Do(func() { 18 | ins = initCache() 19 | }) 20 | return ins 21 | } 22 | 23 | func initCache() *freecache.Cache { 24 | config := configs.LoadCacheConfig() 25 | if config.Size != 0 { 26 | c := freecache.NewCache(config.Size) 27 | //根据cache的大小进行设置 28 | debug.SetGCPercent(20) 29 | return c 30 | } 31 | return nil 32 | } 33 | 34 | func Set(key string, value interface{}, exp int) error { 35 | if GetIns() == nil { 36 | return errors.New(constants.ErrCacheInit) 37 | } 38 | 39 | k := []byte(key) 40 | v, err := json.Marshal(value) 41 | if err != nil { 42 | return err 43 | } 44 | err = GetIns().Set(k, v, exp) 45 | if err != nil { 46 | return err 47 | } 48 | return nil 49 | } 50 | func Get(key string, obj interface{}) error { 51 | b, err := GetByte(key) 52 | if err != nil { 53 | return err 54 | } 55 | err = json.Unmarshal(b, obj) 56 | if err != nil { 57 | return err 58 | } 59 | return nil 60 | } 61 | func GetByte(key string) ([]byte, error) { 62 | if GetIns() == nil { 63 | return nil, errors.New(constants.ErrCacheInit) 64 | } 65 | k := []byte(key) 66 | return GetIns().Get(k) 67 | } 68 | -------------------------------------------------------------------------------- /clients/redis/pool_ins.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/configs" 6 | "github.com/gomodule/redigo/redis" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | /** 12 | MaxActive 最大连接数,即最多的tcp连接数,一般建议往大的配置, 13 | 但不要超过操作系统文件句柄个数(centos下可以ulimit -n查看)。 14 | MaxIdle 最大空闲连接数,即会有这么多个连接提前等待着,但过了超时时间也会关闭。 15 | IdleTimeout 空闲连接超时时间, 16 | 但应该设置比redis服务器超时时间短。否则服务端超时了,客户端保持着连接也没用。 17 | Wait 这是个很有用的配置。如果超过最大连接,是报错,还是等待 18 | */ 19 | 20 | var pool *redis.Pool 21 | var onceRedis sync.Once 22 | 23 | func GetRedisPool() *redis.Pool { 24 | onceRedis.Do(func() { 25 | pool = newRedisPool() 26 | }) 27 | return pool 28 | } 29 | 30 | func newRedisPool() *redis.Pool { 31 | conf := configs.LoadRedisConfig() 32 | timeout := conf.IdleTimeout 33 | pool = &redis.Pool{ 34 | MaxActive: conf.MaxActive, 35 | MaxIdle: conf.MaxIdle, 36 | IdleTimeout: timeout, 37 | Wait: true, 38 | Dial: func() (conn redis.Conn, err error) { 39 | conn, err = redis.Dial( 40 | "tcp", 41 | conf.Uri, 42 | redis.DialPassword(conf.Auth), 43 | redis.DialDatabase(conf.Db), 44 | redis.DialConnectTimeout(timeout), 45 | redis.DialReadTimeout(timeout), 46 | redis.DialWriteTimeout(timeout), 47 | ) 48 | if err != nil { 49 | return nil, fmt.Errorf("redis connection error: %s", err) 50 | } 51 | return 52 | }, 53 | TestOnBorrow: func(c redis.Conn, t time.Time) error { 54 | _, err := c.Do("PING") 55 | return err 56 | }, 57 | } 58 | 59 | return pool 60 | 61 | } 62 | -------------------------------------------------------------------------------- /contracts/message_struct.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | import "strings" 4 | 5 | type Request struct { 6 | Id string `json:"request_id"` 7 | Data map[string]interface{} 8 | } 9 | 10 | type Response struct { 11 | Ret int `json:"ret"` 12 | Code string `json:"code"` 13 | Data interface{} `json:"data"` 14 | Message string `json:"message"` 15 | } 16 | 17 | func MakeResponse(data interface{}, err error) Response { 18 | if err != nil { 19 | return ResponseFailed(err) 20 | } else { 21 | return ResponseSucess(data) 22 | } 23 | } 24 | func ResponseSucess(data interface{}) Response { 25 | return Response{ 26 | Code: "0000", 27 | Data: data, 28 | Ret: 200, 29 | Message: "请求成功", 30 | } 31 | } 32 | func ResponseFailed(err error) Response { 33 | errMap := strings.Split(err.Error(), "::") 34 | if len(errMap) == 2 { 35 | return Response{ 36 | Code: errMap[0], 37 | Data: make(map[string]interface{}), 38 | Ret: 200, 39 | Message: errMap[1], 40 | } 41 | } else { 42 | return Response{ 43 | Code: "9999", 44 | Data: make(map[string]interface{}), 45 | Ret: 200, 46 | Message: err.Error(), 47 | } 48 | } 49 | } 50 | 51 | type Payload struct { 52 | Route string `json:"route"` 53 | Params map[string]interface{} `json:"params"` 54 | } 55 | 56 | type GateWayRequest struct { 57 | Dest string 58 | Method string 59 | Id string 60 | Service string 61 | Route string 62 | Data map[string]interface{} 63 | } 64 | -------------------------------------------------------------------------------- /clients/grpc.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "github.com/9299381/wego/contracts" 8 | "github.com/9299381/wego/servers/transports/protobuf" 9 | "github.com/9299381/wego/tools/idwork" 10 | "google.golang.org/grpc" 11 | "log" 12 | ) 13 | 14 | func NewGrpcClient(serviceAddress string, service string, params map[string]interface{}) (*protobuf.Response, error) { 15 | conn, err := grpc.Dial(serviceAddress, grpc.WithInsecure()) 16 | if err != nil { 17 | log.Fatalf("did not connect: %v", err) 18 | } 19 | defer conn.Close() 20 | 21 | jsonParam, _ := json.Marshal(params) 22 | in := &protobuf.Request{ 23 | Id: idwork.ID(), 24 | Param: string(jsonParam), 25 | } 26 | 27 | out := new(protobuf.Response) 28 | 29 | method := "/protobuf." + service + "/Handle" 30 | err = conn.Invoke(context.Background(), method, in, out) 31 | return out, err 32 | } 33 | 34 | func NewGrpcCall(host, service string, params map[string]interface{}) (ret contracts.Response) { 35 | resp, err := NewGrpcClient(host, service, params) 36 | if err != nil { 37 | ret = contracts.ResponseFailed(errors.New("没有响应的服务:" + service)) 38 | } else { 39 | m := make(map[string]interface{}) 40 | m["call_method"] = "grpc" 41 | err := json.Unmarshal([]byte(resp.GetData()), &m) 42 | if err != nil { 43 | ret = contracts.ResponseFailed(err) 44 | } else { 45 | ret.Code = resp.Code 46 | ret.Ret = 200 47 | ret.Message = resp.Msg 48 | ret.Data = m 49 | } 50 | } 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /tools/helpers.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "github.com/9299381/wego/tools/tests" 5 | "math/rand" 6 | "net" 7 | "time" 8 | ) 9 | 10 | func LocalIp() (string, error) { 11 | 12 | netInterfaces, err := net.Interfaces() 13 | if err != nil { 14 | return "", err 15 | } 16 | for i := 0; i < len(netInterfaces); i++ { 17 | if (netInterfaces[i].Flags & net.FlagUp) != 0 { 18 | addrs, _ := netInterfaces[i].Addrs() 19 | for _, address := range addrs { 20 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 21 | if ipnet.IP.To4() != nil { 22 | return ipnet.IP.String(), nil 23 | } 24 | } 25 | } 26 | } 27 | } 28 | return "", nil 29 | 30 | } 31 | 32 | func Test() *tests.TestStruct { 33 | return tests.NewTest() 34 | } 35 | 36 | // RandString 生成随机字符串 37 | func RandString(length int, opt ...string) string { 38 | str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 39 | if opt != nil { 40 | if opt[0] == "0" { 41 | str = "0123456789" 42 | } else if opt[0] == "a" { 43 | str = "abcdefghijklmnopqrstuvwxyz" 44 | } else if opt[0] == "A" { 45 | str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 46 | } else if opt[0] == "aA" { 47 | str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 48 | } 49 | } 50 | bytes := []byte(str) 51 | bytesLen := len(bytes) 52 | var result []byte 53 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 54 | for i := 0; i < length; i++ { 55 | result = append(result, bytes[r.Intn(bytesLen)]) 56 | } 57 | return string(result) 58 | } 59 | -------------------------------------------------------------------------------- /servers/cron_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "github.com/9299381/wego/servers/commons" 5 | "github.com/9299381/wego/servers/cronjobs" 6 | "github.com/9299381/wego/servers/transports" 7 | "github.com/go-kit/kit/endpoint" 8 | ) 9 | 10 | type CronCommServer struct { 11 | *cronjobs.Server 12 | } 13 | 14 | func (s *CronCommServer) Desc() { 15 | //1)星号(*) 16 | //表示 cron 表达式能匹配该字段的所有值。如在第5个字段使用星号(month),表示每个月 17 | //2)斜线(/) 18 | //表示增长间隔,如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15 19 | //3)逗号(,) 20 | //用于枚举值,如第6个字段值是 MON,WED,FRI,表示 星期一、三、五 执行 21 | //4)连字号(-) 22 | //表示一个范围,如第3个字段的值为 9-17 表示 9am 到 5pm 直接每个小时(包括9和17) 23 | //5)问号(?) 24 | //只用于日(Day of month)和星期(Day of week),\表示不指定值,可以用于代替 * 25 | //每隔5秒执行一次:*/5 * * * * ? 26 | //每隔1分钟执行一次:0 */1 * * * ? 27 | //每天23点执行一次:0 0 23 * * ? 28 | //每天凌晨1点执行一次:0 0 1 * * ? 29 | //每月1号凌晨1点执行一次:0 0 1 1 * ? 30 | //在26分、29分、33分执行一次:0 26,29,33 * * * ? 31 | //每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ? 32 | } 33 | 34 | func NewCronCommServer() *CronCommServer { 35 | ss := &CronCommServer{ 36 | Server: cronjobs.NewServer(), 37 | } 38 | return ss 39 | } 40 | 41 | func (s *CronCommServer) Route(spec string, endpoint endpoint.Endpoint) { 42 | 43 | handler := &commons.CommHandler{ 44 | Handler: transports.NewCronJob(endpoint), 45 | } 46 | s.Register(spec, handler) 47 | } 48 | 49 | func (s *CronCommServer) Load() { 50 | //通用加载 todo 51 | } 52 | 53 | func (s *CronCommServer) Start() error { 54 | 55 | return s.Serve() 56 | } 57 | func (s *CronCommServer) Close() { 58 | s.Server.Close() 59 | } 60 | -------------------------------------------------------------------------------- /servers/gateways/maxBytesReader.go: -------------------------------------------------------------------------------- 1 | package gateways 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | //copy from http.request 10 | type maxBytesReader struct { 11 | w http.ResponseWriter 12 | r io.ReadCloser // underlying reader 13 | n int64 // max bytes remaining 14 | err error // sticky error 15 | } 16 | 17 | func (l *maxBytesReader) Read(p []byte) (n int, err error) { 18 | if l.err != nil { 19 | return 0, l.err 20 | } 21 | if len(p) == 0 { 22 | return 0, nil 23 | } 24 | // If they asked for a 32KB byte read but only 5 bytes are 25 | // remaining, no need to read 32KB. 6 bytes will answer the 26 | // question of the whether we hit the limit or go past it. 27 | if int64(len(p)) > l.n+1 { 28 | p = p[:l.n+1] 29 | } 30 | n, err = l.r.Read(p) 31 | 32 | if int64(n) <= l.n { 33 | l.n -= int64(n) 34 | l.err = err 35 | return n, err 36 | } 37 | 38 | n = int(l.n) 39 | l.n = 0 40 | 41 | // The server code and client code both use 42 | // maxBytesReader. This "requestTooLarge" check is 43 | // only used by the server code. To prevent binaries 44 | // which only using the HTTP Client code (such as 45 | // cmd/go) from also linking in the HTTP server, don't 46 | // use a static type assertion to the server 47 | // "*response" type. Check this interface instead: 48 | type requestTooLarger interface { 49 | requestTooLarge() 50 | } 51 | if res, ok := l.w.(requestTooLarger); ok { 52 | res.requestTooLarge() 53 | } 54 | l.err = errors.New("http: request body too large") 55 | return n, l.err 56 | } 57 | 58 | func (l *maxBytesReader) Close() error { 59 | return l.r.Close() 60 | } 61 | -------------------------------------------------------------------------------- /demo/swaggerui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /tools/convert/convert.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "github.com/9299381/wego/constants" 7 | "github.com/9299381/wego/validations" 8 | "github.com/mitchellh/mapstructure" 9 | "net/url" 10 | "reflect" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | func Struct2Map(obj interface{}) map[string]interface{} { 16 | elem := reflect.ValueOf(obj).Elem() 17 | relType := elem.Type() 18 | 19 | var data = make(map[string]interface{}) 20 | for i := 0; i < relType.NumField(); i++ { 21 | data[relType.Field(i).Name] = elem.Field(i).Interface() 22 | } 23 | return data 24 | } 25 | 26 | func Map2Struct(req, obj interface{}) error { 27 | // map转struct时, key与struct的字段应该相同,忽略大小写, 28 | // 注意 不可随意增加_,json中可以有_ 29 | request, ok := req.(map[string]interface{}) 30 | if ok == false { 31 | return errors.New(constants.ErrConvert) 32 | } 33 | for k, v := range request { 34 | if strings.Contains(k, "_") { 35 | kk := strings.ReplaceAll(k, "_", "") 36 | request[kk] = v 37 | } 38 | } 39 | err := mapstructure.WeakDecode(request, obj) 40 | if err != nil { 41 | return errors.New(constants.ErrConvert) 42 | } 43 | err = validations.Valid(obj) 44 | if err != nil { 45 | return err 46 | } 47 | return nil 48 | } 49 | 50 | func FormEncode(params map[string]interface{}) url.Values { 51 | data := url.Values{} 52 | for k, param := range params { 53 | paramsType := reflect.TypeOf(param) 54 | switch paramsType.String() { 55 | case "string": 56 | data.Set(k, param.(string)) 57 | case "int": 58 | data.Set(k, strconv.Itoa(param.(int))) 59 | default: 60 | str, _ := json.Marshal(param) 61 | data.Set(k, string(str)) 62 | 63 | } 64 | } 65 | return data 66 | } 67 | -------------------------------------------------------------------------------- /demo/src/provider/demo_provider.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "github.com/9299381/wego" 5 | "github.com/9299381/wego/demo/src/controller" 6 | "github.com/9299381/wego/filters" 7 | ) 8 | 9 | type DemoProvider struct { 10 | } 11 | 12 | func (s *DemoProvider) Boot() { 13 | } 14 | 15 | func (s *DemoProvider) Register() { 16 | // 这种controller 可以重复再event,subscribe,queue中使用,因此注册到handler中 17 | //限速 18 | wego.Handler("one", filters.Limit(new(controller.OneController))) 19 | wego.Handler("two", filters.New(&controller.TwoController{})) 20 | wego.Handler("auth", filters.Chain( 21 | &filters.ResponseEndpoint{}, 22 | &filters.JwtEndpoint{}, 23 | &filters.LimitEndpoint{}, 24 | &filters.CommEndpoint{ 25 | Controller: &controller.AuthController{}, 26 | })) 27 | 28 | wego.Handler("post", filters.New(&controller.PostController{})) 29 | wego.Handler("sql", filters.New(&controller.SqlController{})) 30 | wego.Handler("redis", filters.New(&controller.RedisController{})) 31 | wego.Handler("queue", filters.New(&controller.QueueController{})) 32 | wego.Handler("queue2", filters.New(&controller.Queue2Controller{})) 33 | 34 | wego.Handler("cache_set", filters.New(&controller.CacheSetController{})) 35 | wego.Handler("cache_get", filters.New(&controller.CacheGetController{})) 36 | // 37 | wego.Handler("valid", filters.New(&controller.ValidController{})) 38 | // 39 | wego.Handler("consul", filters.New(&controller.ConsulController{})) 40 | 41 | wego.Handler("event", filters.New(&controller.EventController{})) 42 | // 43 | wego.Handler("publish", filters.New(&controller.PublishController{})) 44 | wego.Handler("sleep", filters.New(&controller.SleepController{})) 45 | wego.Handler("mqtt_event", filters.New(&controller.MqttEventController{})) 46 | } 47 | -------------------------------------------------------------------------------- /servers/timers/server.go: -------------------------------------------------------------------------------- 1 | package timers 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/servers/commons" 7 | "github.com/9299381/wego/tools/idwork" 8 | "time" 9 | ) 10 | 11 | type Server struct { 12 | handlers map[string]*service 13 | Logger contracts.ILogger 14 | } 15 | type service struct { 16 | freq int 17 | handler *commons.CommHandler 18 | params map[string]interface{} 19 | } 20 | 21 | func NewServer() *Server { 22 | ss := &Server{ 23 | handlers: make(map[string]*service), 24 | } 25 | 26 | return ss 27 | } 28 | func (s *Server) Register(name string, freq int, handler *commons.CommHandler, params map[string]interface{}) { 29 | 30 | s.handlers[name] = &service{ 31 | freq: freq, 32 | handler: handler, 33 | params: params, 34 | } 35 | } 36 | 37 | func (s *Server) Serve() error { 38 | errChans := make(map[string]chan error) 39 | for name, svr := range s.handlers { 40 | errChans[name] = make(chan error) 41 | ticker := time.NewTicker(time.Duration(svr.freq) * time.Second) 42 | go func(name string, svr *service, t *time.Ticker, errChan chan error) { 43 | for { 44 | select { 45 | case <-t.C: 46 | id := idwork.ID() 47 | ctx := context.Background() 48 | params := svr.params 49 | params["request_id"] = id 50 | resp, err := svr.handler.Handle(ctx, params) 51 | if err != nil { 52 | s.Logger.Info(err.Error()) 53 | } else { 54 | s.Logger.Info("定时任务:", resp) 55 | } 56 | } 57 | } 58 | }(name, svr, ticker, errChans[name]) 59 | } 60 | for _, errChan := range errChans { 61 | e := <-errChan 62 | if e != nil { 63 | return e 64 | } 65 | } 66 | return nil 67 | } 68 | 69 | func (s *Server) Close() { 70 | 71 | } 72 | -------------------------------------------------------------------------------- /servers/events/server.go: -------------------------------------------------------------------------------- 1 | package events 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/tools/idwork" 7 | "github.com/go-kit/kit/endpoint" 8 | "runtime" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | /** 14 | 通过channel方式传递event,而不是通过共享内存传递 15 | */ 16 | var Handlers map[string]endpoint.Endpoint 17 | var eventPool sync.Pool 18 | var eventChan chan *contracts.Payload 19 | 20 | type Server struct { 21 | Concurrency int 22 | After <-chan time.Time 23 | Logger contracts.ILogger 24 | } 25 | 26 | func NewServer() *Server { 27 | Handlers = make(map[string]endpoint.Endpoint) 28 | eventChan = make(chan *contracts.Payload, runtime.NumCPU()) 29 | ss := &Server{} 30 | return ss 31 | } 32 | 33 | func (s *Server) Serve() error { 34 | errChan := make(chan error) 35 | for i := 0; i < s.Concurrency; i++ { 36 | go s.handleEventReceive(errChan) 37 | } 38 | err := <-errChan 39 | if err != nil { 40 | s.Logger.Info(err) 41 | } 42 | return nil 43 | } 44 | func (s *Server) handleEventReceive(errChan chan error) { 45 | for { 46 | select { 47 | case event := <-eventChan: 48 | filter, ok := Handlers[event.Route] 49 | if ok { 50 | ctx := context.Background() 51 | id := idwork.ID() 52 | request := contracts.Request{ 53 | Id: id, 54 | Data: event.Params, 55 | } 56 | resp, err := filter(ctx, request) 57 | if err != nil { 58 | eventPool.Put(event) 59 | s.Logger.Info("event error:", err) 60 | //errChan <- err // 退出协程了 61 | } else { 62 | s.Logger.Info("event response:", resp) 63 | } 64 | } 65 | eventPool.Put(event) 66 | case <-s.After: 67 | s.Logger.Info("event wait ......") 68 | } 69 | } 70 | } 71 | func (s *Server) Close() { 72 | 73 | } 74 | -------------------------------------------------------------------------------- /demo/src/controller/one_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/contracts" 6 | "github.com/9299381/wego/demo/src/service" 7 | "github.com/9299381/wego/services" 8 | ) 9 | 10 | type OneController struct { 11 | } 12 | 13 | // ServeAPI serves the API for this record store 14 | func (s *OneController) Handle(ctx contracts.Context) (interface{}, error) { 15 | // swagger:route Get /demo/one 分组1 oneController 16 | // Test swagger 17 | // This will ....... 18 | // Responses: 19 | // 200: oneResponse 20 | req := ctx.Request().(*oneRequest) 21 | fmt.Println(req) 22 | fmt.Println(ctx.Get("request")) 23 | 24 | err := services.Pipe(). 25 | Middle(&service.OneService{}). 26 | Middle(&service.TwoService{}). 27 | Line(ctx) 28 | if err != nil { 29 | return nil, err 30 | } 31 | ret := &oneResponse{ 32 | Id: ctx.Get("request.id").(string), 33 | UserName: req.Param1, 34 | Age: req.Param2, 35 | } 36 | return ret, nil 37 | } 38 | 39 | func (s *OneController) GetRules() interface{} { 40 | return &oneRequest{} 41 | } 42 | 43 | func (s *OneController) Mock() interface{} { 44 | return &oneResponse{ 45 | Id: "123123", 46 | UserName: "demo", 47 | Age: 18, 48 | } 49 | } 50 | 51 | // swagger:parameters oneController 52 | type oneRequest struct { 53 | // 参数param1的说明 54 | // 最小1 55 | // Minimum:1 56 | // Required:true 57 | Param1 string `json:"param_1"` 58 | // 最短4 59 | // Required:true 60 | // MinLength:4 61 | Param2 int `json:"param_2"` 62 | Param4 int `json:"param_4"` 63 | } 64 | 65 | // swagger:response oneResponse 66 | type oneResponse struct { 67 | Id string `json:"id"` 68 | // 响应UserName的描述 69 | UserName string `json:"user_name"` 70 | // 整形 71 | Age int `json:"age"` 72 | } 73 | -------------------------------------------------------------------------------- /services/service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/contracts" 6 | ) 7 | 8 | func New(service contracts.IService) *commonService { 9 | var s []contracts.IService 10 | s = append(s, service) 11 | return &commonService{ 12 | services: s, 13 | } 14 | } 15 | 16 | func Pipe() *commonService { 17 | var s []contracts.IService 18 | return &commonService{ 19 | services: s, 20 | } 21 | } 22 | 23 | type commonService struct { 24 | services []contracts.IService 25 | } 26 | 27 | func (s *commonService) Middle(services ...contracts.IService) *commonService { 28 | for _, service := range services { 29 | s.services = append(s.services, service) 30 | } 31 | return s 32 | } 33 | 34 | func (s *commonService) Call(ctx contracts.Context) error { 35 | return s.services[0].Handle(ctx) 36 | } 37 | 38 | func (s *commonService) Line(ctx contracts.Context) error { 39 | for _, service := range s.services { 40 | err := service.Handle(ctx) 41 | if err != nil { 42 | return err 43 | } 44 | } 45 | return nil 46 | } 47 | func (s *commonService) Parallel(ctx contracts.Context) error { 48 | 49 | type st struct { 50 | contracts.Context 51 | err error 52 | } 53 | ch := make([]chan st, len(s.services)) 54 | for k, service := range s.services { 55 | ch[k] = make(chan st) 56 | cc := contracts.Context{ 57 | Context: context.Background(), 58 | Log: ctx.Log, 59 | Keys: ctx.Keys, 60 | } 61 | go func(cc contracts.Context, s contracts.IService, c chan st) { 62 | err := s.Handle(cc) 63 | ret := st{ 64 | Context: cc, 65 | err: err, 66 | } 67 | c <- ret 68 | }(cc, service, ch[k]) 69 | } 70 | m := make(map[string]interface{}) 71 | for _, c := range ch { 72 | res := <-c 73 | if res.err != nil { 74 | return res.err 75 | } 76 | for key, value := range res.Keys { 77 | m[key] = value 78 | } 79 | } 80 | ctx.Keys = m 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /servers/transports/codecs/http_codec.go: -------------------------------------------------------------------------------- 1 | package codecs 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "github.com/9299381/wego/contracts" 7 | "github.com/9299381/wego/tools/idwork" 8 | "net/http" 9 | "strings" 10 | ) 11 | 12 | // HTTP请求数据解码函数 13 | func HttpFormDecodeRequest(_ context.Context, r *http.Request) (interface{}, error) { 14 | //解析url传递的参数,对于POST则解析响应包的主体(request body) 15 | //注意:如果没有调用ParseForm方法,下面无法获取表单的数据 16 | _ = r.ParseForm() 17 | vars := r.Form 18 | requestId, ok := vars["request_id"] 19 | if ok == false { 20 | requestId = make([]string, 1) 21 | requestId[0] = idwork.ID() 22 | } 23 | data := make(map[string]interface{}) 24 | for k, v := range vars { 25 | data[k] = v[0] 26 | } 27 | if strings.Index(r.RemoteAddr, "::") > 0 { 28 | data["client_ip"] = "127.0.0.1" 29 | } else { 30 | data["client_ip"] = r.RemoteAddr 31 | } 32 | if authToken := r.Header.Get("authToken"); authToken != "" { 33 | data["authToken"] = authToken 34 | } 35 | 36 | return contracts.Request{ 37 | Id: requestId[0], 38 | Data: data, 39 | }, nil 40 | } 41 | 42 | func HttpJsonDecodeRequest(_ context.Context, r *http.Request) (interface{}, error) { 43 | //把body json直接转换为request 44 | var request contracts.Request 45 | if err := json.NewDecoder(r.Body).Decode(&request); err != nil { 46 | return nil, err 47 | } 48 | return request, nil 49 | } 50 | 51 | func HttpMuxDecodeRequest(_ context.Context, r *http.Request) (interface{}, error) { 52 | //mux.Vars(r) 53 | //这种方式 适合路由上为 /exam/test/{type}/{value} 模式的解析, 54 | return nil, nil 55 | } 56 | 57 | // HTTP返回数据编码函数 58 | func HttpEncodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { 59 | w.Header().Set("Content-Type", "application/json;charset=utf-8") 60 | w.Header().Set("Access-Control-Allow-Origin", "*") 61 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,authToken") 62 | w.Header().Set("Access-Control-Allow-Credentials", "true") 63 | w.Header().Set("Access-Control-Expose-Headers", "*") 64 | return json.NewEncoder(w).Encode(response) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/9299381/wego 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect 7 | github.com/coocood/freecache v1.1.0 8 | github.com/eclipse/paho.mqtt.golang v1.2.0 9 | github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect 10 | github.com/go-kit/kit v0.9.0 11 | github.com/go-macaron/inject v0.0.0-20200308113650-138e5925c53b 12 | github.com/go-sql-driver/mysql v1.4.1 13 | github.com/golang/protobuf v1.3.1 14 | github.com/gomodule/redigo v2.0.0+incompatible 15 | github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c // indirect 16 | github.com/gorilla/mux v1.7.3 17 | github.com/gorilla/websocket v1.4.1 18 | github.com/hashicorp/consul/api v1.2.0 19 | github.com/hashicorp/go-msgpack v0.5.5 // indirect 20 | github.com/hashicorp/memberlist v0.1.5 // indirect 21 | github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect 22 | github.com/jtolds/gls v4.2.1+incompatible // indirect 23 | github.com/juju/ratelimit v1.0.1 24 | github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect 25 | github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f 26 | github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect 27 | github.com/mitchellh/mapstructure v1.1.2 28 | github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 29 | github.com/robfig/cron/v3 v3.0.0 30 | github.com/sirupsen/logrus v1.4.2 31 | github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect 32 | github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect 33 | github.com/spf13/viper v1.4.0 34 | github.com/tebeka/strftime v0.1.3 // indirect 35 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect 36 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect 37 | golang.org/x/text v0.3.2 // indirect 38 | google.golang.org/grpc v1.23.0 39 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 40 | gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 41 | xorm.io/xorm v1.0.0 42 | 43 | ) 44 | -------------------------------------------------------------------------------- /tools/jwt/token.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "errors" 7 | "github.com/9299381/wego/configs" 8 | "github.com/9299381/wego/constants" 9 | "github.com/9299381/wego/tools/util" 10 | "strconv" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | type Token struct { 16 | Claims *Claims 17 | config *configs.TokenConfig 18 | } 19 | 20 | func New() *Token { 21 | token := &Token{ 22 | Claims: &Claims{}, 23 | } 24 | token.config = configs.LoadTokenConfig() 25 | return token 26 | } 27 | 28 | func (s *Token) SetId(id string) *Token { 29 | s.Claims.Id = id 30 | return s 31 | } 32 | 33 | func (s *Token) SetName(name string) *Token { 34 | s.Claims.Name = name 35 | return s 36 | } 37 | 38 | func (s *Token) SetRole(role string) *Token { 39 | s.Claims.Role = role 40 | return s 41 | } 42 | 43 | func (s *Token) GetToken() string { 44 | s.Claims.Iat = time.Now().Unix() 45 | s.Claims.Exp = s.getExpTime() 46 | jsonClaim, err := json.Marshal(s.Claims) 47 | if err != nil { 48 | panic(err) 49 | } 50 | payload := base64.StdEncoding.EncodeToString(jsonClaim) 51 | sign := s.getSign(s.Claims) 52 | ret := string(payload) + "." + sign 53 | return ret 54 | } 55 | 56 | func (s *Token) VerifyToken(sign string) (*Claims, error) { 57 | m := strings.Split(sign, ".") 58 | if len(m) < 1 { 59 | return nil, errors.New(constants.ErrTokenFmt) 60 | } 61 | jsonClaim, decodeErr := base64.StdEncoding.DecodeString(m[0]) 62 | if decodeErr != nil { 63 | return nil, decodeErr 64 | } 65 | claims := &Claims{} 66 | jsonErr := json.Unmarshal(jsonClaim, claims) 67 | if jsonErr != nil { 68 | return nil, jsonErr 69 | } 70 | 71 | if claims.Exp < time.Now().Unix() { 72 | return nil, errors.New(constants.ErrTokenExp) 73 | } 74 | 75 | if m[1] != s.getSign(claims) { 76 | return nil, errors.New(constants.ErrTokenSign) 77 | } 78 | return claims, nil 79 | } 80 | func (s *Token) getExpTime() int64 { 81 | period := s.config.Exp 82 | return s.Claims.Iat + period 83 | } 84 | func (s *Token) getSign(claims *Claims) string { 85 | key := s.config.Key 86 | keyPlain := claims.Id + strconv.Itoa(int(claims.Iat)) + key 87 | return util.Md5(keyPlain) 88 | 89 | } 90 | -------------------------------------------------------------------------------- /tools/idwork/worker.go: -------------------------------------------------------------------------------- 1 | package idwork 2 | 3 | import ( 4 | "errors" 5 | "github.com/9299381/wego/constants" 6 | "strconv" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | var once sync.Once 12 | var ins *snowflake 13 | 14 | func getID(server int64) string { 15 | n := getIns(server) 16 | return n.nextId() 17 | 18 | } 19 | func getIns(server int64) *snowflake { 20 | once.Do(func() { 21 | var err error 22 | ins, err = newNode(server) 23 | if err != nil { 24 | panic(err) 25 | } 26 | }) 27 | return ins 28 | } 29 | 30 | type snowflake struct { 31 | mu sync.Mutex 32 | lastTime int64 33 | 34 | server int64 35 | serverMax int64 36 | 37 | sequence int64 38 | sequenceMask int64 39 | 40 | timeShift uint8 41 | serverShift uint8 42 | } 43 | 44 | func newNode(server int64) (*snowflake, error) { 45 | var serverBits uint8 = 10 46 | var sequenceBits uint8 = 12 47 | it := snowflake{} 48 | 49 | it.server = server 50 | it.serverMax = -1 ^ (-1 << serverBits) 51 | it.sequenceMask = -1 ^ (-1 << sequenceBits) 52 | 53 | it.serverShift = sequenceBits 54 | it.timeShift = serverBits + sequenceBits 55 | 56 | if it.server < 0 || it.server > it.serverMax { 57 | return nil, errors.New("server number must be between 0 and " + strconv.FormatInt(it.serverMax, 10)) 58 | } 59 | 60 | return &it, nil 61 | } 62 | func (s *snowflake) epochGen() int64 { 63 | start := "2010-01-01 00:00:00" 64 | layout := constants.YmdHis 65 | loc, _ := time.LoadLocation("Local") 66 | theTime, _ := time.ParseInLocation(layout, start, loc) 67 | return theTime.UnixNano() / 1000000 68 | } 69 | 70 | func (s *snowflake) nextId() string { 71 | s.mu.Lock() 72 | epoch := s.epochGen() 73 | timestamp := time.Now().UnixNano() / 1000000 74 | lastTime := s.lastTime 75 | //生成唯一序列 76 | if timestamp == lastTime { 77 | s.sequence = (s.sequence + 1) & s.sequenceMask 78 | if s.sequence == 0 { 79 | for timestamp <= lastTime { 80 | timestamp = time.Now().UnixNano() / 1000000 81 | } 82 | } 83 | } else { 84 | s.sequence = 0 85 | } 86 | s.lastTime = timestamp 87 | r := int64((timestamp-epoch)< 2 | 3 | Swagger UI: OAuth2 Redirect 4 | 5 | 6 | 7 | 69 | -------------------------------------------------------------------------------- /demo/test/reflect_test/reflect_test.go: -------------------------------------------------------------------------------- 1 | package reflect_test 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestReflect(t *testing.T) { 10 | obj := Person{Id: "123", Name: "张三", Age: 50} 11 | if isStruct(reflect.TypeOf(obj)) { 12 | doStruct(obj) 13 | } 14 | if isStructPtr(reflect.TypeOf(&obj)) { 15 | doPointer(&obj) 16 | } 17 | } 18 | 19 | func doStruct(obj interface{}) { 20 | objT := reflect.TypeOf(obj) 21 | objV := reflect.ValueOf(obj) 22 | fmt.Println(objT) 23 | fmt.Println(objV) 24 | // 获取方法字段 25 | // 1. 先获取interface的reflect.Type,然后通过NumField进行遍历 26 | // 2. 再通过reflect.Type的Field获取其Field 27 | // 3. 最后通过Field的Interface()得到对应的value 28 | for i := 0; i < objT.NumField(); i++ { 29 | field := objT.Field(i) 30 | value := objV.Field(i).Interface() 31 | fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value) 32 | } 33 | // 获取方法 34 | // 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历 35 | // 获取方法 36 | for i := 0; i < objT.NumMethod(); i++ { 37 | m := objT.Method(i) 38 | fmt.Printf("%s: %v\n", m.Name, m.Type) 39 | } 40 | m := objV.MethodByName("Hello") 41 | args := []reflect.Value{ 42 | reflect.ValueOf("你好"), 43 | reflect.ValueOf(20), 44 | } 45 | ret := m.Call(args) 46 | fmt.Println(ret) 47 | 48 | } 49 | func doPointer(obj interface{}) { 50 | objT := reflect.TypeOf(obj) 51 | objV := reflect.ValueOf(obj) 52 | fmt.Println(objT) 53 | fmt.Println(objV) 54 | // 获取方法字段 55 | for i := 0; i < objT.Elem().NumField(); i++ { 56 | field := objT.Elem().Field(i) 57 | value := objV.Elem().Field(i).Interface() 58 | fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value) 59 | } 60 | // 获取方法 61 | for i := 0; i < objT.NumMethod(); i++ { 62 | m := objT.Method(i) 63 | fmt.Printf("%s: %v\n", m.Name, m.Type) 64 | } 65 | m1 := objV.MethodByName("HelloPtr") 66 | args1 := []reflect.Value{ 67 | reflect.ValueOf("你好"), 68 | reflect.ValueOf(20), 69 | } 70 | ret1 := m1.Call(args1) 71 | fmt.Println(ret1) 72 | 73 | m2 := objV.MethodByName("Hello") 74 | args2 := []reflect.Value{ 75 | reflect.ValueOf("你好"), 76 | reflect.ValueOf(20), 77 | } 78 | ret2 := m2.Call(args2) 79 | fmt.Println(ret2) 80 | } 81 | func isStruct(t reflect.Type) bool { 82 | return t.Kind() == reflect.Struct 83 | } 84 | 85 | func isStructPtr(t reflect.Type) bool { 86 | return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct 87 | } 88 | 89 | type Person struct { 90 | Id string 91 | Name string 92 | Age int 93 | } 94 | 95 | func (s *Person) HelloPtr(param string, age int) string { 96 | fmt.Println(age + s.Age + 10) 97 | return "hello_ptr:" + s.Name + ":" + param 98 | } 99 | func (s Person) Hello(param string, age int) string { 100 | fmt.Println(age + s.Age) 101 | return "hello:" + s.Name + ":" + param 102 | } 103 | -------------------------------------------------------------------------------- /configs/init.go: -------------------------------------------------------------------------------- 1 | package configs 2 | 3 | import ( 4 | "errors" 5 | "github.com/9299381/wego/args" 6 | "github.com/9299381/wego/constants" 7 | "github.com/spf13/viper" 8 | "strings" 9 | ) 10 | 11 | var cfg *config 12 | 13 | func init() { 14 | m := strings.Split(args.Config, ",") 15 | switch m[0] { 16 | case "consul": 17 | break 18 | default: 19 | cfg = loadFromToml(m[0]) 20 | } 21 | } 22 | func Env(key string, value ...interface{}) interface{} { 23 | mode := args.Mode 24 | modeKey := strings.Join([]string{mode, key}, ".") 25 | commKey := strings.Join([]string{"common", key}, ".") 26 | if cfg.IsSet(modeKey) { 27 | return cfg.Get(modeKey) 28 | } else if cfg.IsSet(commKey) { 29 | return cfg.Get(commKey) 30 | } else { 31 | return value[0] 32 | } 33 | } 34 | 35 | func EnvString(key string, value ...interface{}) string { 36 | mode := args.Mode 37 | modeKey := strings.Join([]string{mode, key}, ".") 38 | commKey := strings.Join([]string{"common", key}, ".") 39 | var ret string 40 | if cfg.IsSet(modeKey) { 41 | ret = cfg.GetString(modeKey) 42 | } else if cfg.IsSet(commKey) { 43 | ret = cfg.GetString(commKey) 44 | } else { 45 | ret = value[0].(string) 46 | } 47 | return ret 48 | } 49 | func EnvInt(key string, value ...interface{}) int { 50 | mode := args.Mode 51 | modeKey := strings.Join([]string{mode, key}, ".") 52 | commKey := strings.Join([]string{"common", key}, ".") 53 | var ret int 54 | if cfg.IsSet(modeKey) { 55 | ret = cfg.GetInt(modeKey) 56 | } else if cfg.IsSet(commKey) { 57 | ret = cfg.GetInt(commKey) 58 | } else { 59 | ret = value[0].(int) 60 | } 61 | return ret 62 | } 63 | func EnvBool(key string, value ...interface{}) bool { 64 | mode := args.Mode 65 | modeKey := strings.Join([]string{mode, key}, ".") 66 | commKey := strings.Join([]string{"common", key}, ".") 67 | var ret bool 68 | if cfg.IsSet(modeKey) { 69 | ret = cfg.GetBool(modeKey) 70 | } else if cfg.IsSet(commKey) { 71 | ret = cfg.GetBool(commKey) 72 | } else { 73 | ret = value[0].(bool) 74 | } 75 | return ret 76 | } 77 | func EnvStringSlice(key string, value ...interface{}) []string { 78 | mode := args.Mode 79 | modeKey := strings.Join([]string{mode, key}, ".") 80 | commKey := strings.Join([]string{"common", key}, ".") 81 | var ret []string 82 | if cfg.IsSet(modeKey) { 83 | ret = cfg.GetStringSlice(modeKey) 84 | } else if cfg.IsSet(commKey) { 85 | ret = cfg.GetStringSlice(commKey) 86 | } else { 87 | ret = value[0].([]string) 88 | } 89 | return ret 90 | } 91 | 92 | type config struct { 93 | *viper.Viper 94 | } 95 | 96 | func loadFromToml(fileName string) *config { 97 | c := &config{} 98 | c.Viper = viper.New() 99 | c.SetConfigName(fileName) 100 | c.AddConfigPath("./") 101 | c.AddConfigPath("../") 102 | c.AddConfigPath("../../") 103 | c.AddConfigPath("./env/") 104 | c.AddConfigPath("../env/") 105 | c.SetConfigType("toml") 106 | if err := c.ReadInConfig(); err != nil { 107 | panic(errors.New(constants.ErrLoadEnv)) 108 | } 109 | return c 110 | } 111 | -------------------------------------------------------------------------------- /wego.go: -------------------------------------------------------------------------------- 1 | package wego 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/args" 6 | "github.com/9299381/wego/container" 7 | "github.com/9299381/wego/contracts" 8 | "github.com/9299381/wego/loggers" 9 | "github.com/go-kit/kit/endpoint" 10 | "github.com/go-kit/kit/sd/consul" 11 | "github.com/spf13/viper" 12 | "os" 13 | "os/signal" 14 | "strings" 15 | "syscall" 16 | ) 17 | 18 | type Application struct { 19 | Status bool 20 | //必须初始化 21 | Service map[string]contracts.IService 22 | Consul map[string]*consul.Registrar 23 | Handlers map[string]endpoint.Endpoint 24 | Routers map[string]contracts.IRouter 25 | tomls map[string]*viper.Viper 26 | } 27 | 28 | var App *Application 29 | 30 | //初始化成全局变量 31 | func init() { 32 | App = &Application{ 33 | Status: true, 34 | Service: make(map[string]contracts.IService), 35 | Consul: make(map[string]*consul.Registrar), 36 | Handlers: make(map[string]endpoint.Endpoint), 37 | Routers: make(map[string]contracts.IRouter), 38 | tomls: make(map[string]*viper.Viper), 39 | } 40 | } 41 | 42 | func Provider(p contracts.IProvider) { 43 | p.Boot() 44 | p.Register() 45 | } 46 | 47 | func Handler(name string, endpoint ...endpoint.Endpoint) endpoint.Endpoint { 48 | if endpoint == nil { 49 | ret, exist := App.Handlers[name] 50 | if exist { 51 | return ret 52 | } 53 | } else { 54 | App.Handlers[name] = endpoint[0] 55 | } 56 | return nil 57 | } 58 | 59 | func Toml(name string, fileName ...string) *viper.Viper { 60 | if fileName == nil { 61 | //这里是get 62 | ret, exist := App.tomls[name] 63 | if exist { 64 | return ret 65 | } 66 | } else { 67 | //这里是注册 68 | c := viper.New() 69 | c.SetConfigName(fileName[0]) 70 | c.AddConfigPath("./toml/") 71 | c.AddConfigPath("../toml/") 72 | c.AddConfigPath("../../toml/") 73 | c.SetConfigType("toml") 74 | if err := c.ReadInConfig(); err != nil { 75 | panic(err) 76 | } 77 | App.tomls[name] = c 78 | } 79 | return nil 80 | } 81 | func Service(name string, service ...contracts.IService) contracts.IService { 82 | if service == nil { 83 | ret, exist := App.Service[name] 84 | if exist { 85 | return ret 86 | } 87 | } else { 88 | App.Service[name] = service[0] 89 | } 90 | return nil 91 | } 92 | 93 | func Router(name string, server contracts.IRouter) { 94 | server.Boot() 95 | server.Load() 96 | server.Register() 97 | App.Routers[name] = server 98 | } 99 | 100 | //启动server 101 | func Start() { 102 | servers := strings.Split(args.Server, ",") 103 | routers := make(map[string]contracts.IRouter) 104 | for _, s := range servers { 105 | if ss, exist := App.Routers[strings.Trim(s, " ")]; exist == true { 106 | routers[s] = ss 107 | } 108 | } 109 | errChans := make(map[string]chan error) 110 | for key, router := range routers { 111 | errChans[key] = make(chan error) 112 | go func(errChan chan error, server contracts.IRouter) { 113 | errChan <- server.Start() 114 | }(errChans[key], router) 115 | go func(errChan chan error) { 116 | c := make(chan os.Signal, 1) 117 | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) 118 | errChan <- fmt.Errorf("%s", <-c) 119 | }(errChans[key]) 120 | } 121 | for _, errChan := range errChans { 122 | loggers.GetLog().Info(<-errChan) 123 | } 124 | //关闭各种路由服务 125 | for _, server := range routers { 126 | server.Close() 127 | } 128 | 129 | } 130 | 131 | func DI() *container.Container { 132 | return container.GetIns() 133 | } 134 | -------------------------------------------------------------------------------- /clients/consul.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "github.com/9299381/wego/args" 8 | "github.com/9299381/wego/cache" 9 | "github.com/9299381/wego/loggers" 10 | "github.com/9299381/wego/tools/idwork" 11 | "github.com/go-kit/kit/sd/consul" 12 | "github.com/hashicorp/consul/api" 13 | "math/rand" 14 | "strconv" 15 | ) 16 | 17 | func NewConsulHttpRegister(service, host, port string) *consul.Registrar { 18 | //注销掉重复的 19 | serviceDeregister(service, host, port) 20 | check := api.AgentServiceCheck{ 21 | HTTP: "http://" + host + ":" + port + "/health", 22 | Interval: "10s", 23 | Timeout: "1s", 24 | Notes: "Consul check service health status.", 25 | } 26 | p, _ := strconv.Atoi(port) 27 | reg := api.AgentServiceRegistration{ 28 | ID: service + "_" + idwork.ID(), 29 | Name: service, 30 | Address: host, 31 | Port: p, 32 | Tags: []string{"http"}, 33 | Check: &check, 34 | } 35 | registy := consul.NewRegistrar(getConsullClient(), ®, loggers.NewKitLog()) 36 | registy.Register() 37 | return registy 38 | 39 | } 40 | func NewConsulGrpcRegister(service, host, port string) *consul.Registrar { 41 | //注销掉重复的 42 | serviceDeregister(service, host, port) 43 | p, _ := strconv.Atoi(port) 44 | check := api.AgentServiceCheck{ 45 | GRPC: fmt.Sprintf("%s:%d/%s", host, p, "health"), 46 | Interval: "10s", 47 | Timeout: "1s", 48 | Notes: "Consul check service health status.", 49 | } 50 | reg := api.AgentServiceRegistration{ 51 | ID: service + "_" + idwork.ID(), 52 | Name: service, 53 | Address: host, 54 | Port: p, 55 | Tags: []string{"grpc"}, 56 | Check: &check, 57 | } 58 | registy := consul.NewRegistrar(getConsullClient(), ®, loggers.NewKitLog()) 59 | registy.Register() 60 | return registy 61 | 62 | } 63 | 64 | func GetConsulService(service string) (entity *api.ServiceEntry, err error) { 65 | //这里考虑可以从缓存中读取,10分钟过期,比如 66 | var entitys []*api.ServiceEntry 67 | c, _ := cache.GetByte("consul_entitys") 68 | if c != nil { 69 | entitys = []*api.ServiceEntry{} 70 | err = json.Unmarshal(c, &entitys) 71 | if err != nil { 72 | panic(err) 73 | return 74 | } 75 | } else { 76 | client := getConsullClient() 77 | entitys, _, err = client.Service(service, "", false, &api.QueryOptions{}) 78 | if err != nil || len(entitys) == 0 { 79 | err = errors.New("9999::没有找到响应的服务") 80 | return 81 | } 82 | _ = cache.Set("consul_entitys", entitys, 60) 83 | } 84 | //随机取一个 85 | entity = entitys[rand.Int()%len(entitys)] 86 | return 87 | 88 | } 89 | 90 | func getConsullClient() consul.Client { 91 | var client consul.Client 92 | { 93 | config := api.DefaultConfig() 94 | config.Address = args.Registy 95 | consulClient, _ := api.NewClient(config) 96 | client = consul.NewClient(consulClient) 97 | } 98 | return client 99 | } 100 | 101 | func serviceDeregister(service, host, port string) { 102 | client := getConsullClient() 103 | entitys, _, err := client.Service(service, "", false, &api.QueryOptions{}) 104 | if err == nil { 105 | for _, entity := range entitys { 106 | str1 := fmt.Sprintf("%s:%d", entity.Service.Address, entity.Service.Port) 107 | str2 := fmt.Sprintf("%s:%s", host, port) 108 | if str1 == str2 { 109 | r := &api.AgentServiceRegistration{ 110 | ID: entity.Service.ID, 111 | Name: service, 112 | } 113 | _ = client.Deregister(r) 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /servers/grpc_comm_server.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego" 6 | "github.com/9299381/wego/configs" 7 | "github.com/9299381/wego/contracts" 8 | "github.com/9299381/wego/loggers" 9 | "github.com/9299381/wego/servers/transports" 10 | "github.com/9299381/wego/servers/transports/protobuf" 11 | "github.com/go-kit/kit/endpoint" 12 | GrpcTransport "github.com/go-kit/kit/transport/grpc" 13 | "google.golang.org/grpc" 14 | "google.golang.org/grpc/health/grpc_health_v1" 15 | "net" 16 | ) 17 | 18 | type GrpcCommServer struct { 19 | *grpc.Server 20 | Logger contracts.ILogger 21 | } 22 | 23 | func NewGrpcCommServer() *GrpcCommServer { 24 | ss := &GrpcCommServer{ 25 | Server: grpc.NewServer(), 26 | } 27 | ss.Logger = loggers.GetLog() 28 | return ss 29 | } 30 | func (s *GrpcCommServer) Route(name string, endpoint endpoint.Endpoint) { 31 | 32 | sd := s.getServiceDesc(name) 33 | service := &grpcService{ 34 | handler: transports.NewGRPC(endpoint), 35 | } 36 | s.RegisterService(&sd, service) 37 | } 38 | 39 | func (s *GrpcCommServer) Load() { 40 | 41 | //注册通用路由 42 | grpc_health_v1.RegisterHealthServer(s.Server, &HealthImpl{}) 43 | } 44 | 45 | func (s *GrpcCommServer) Start() error { 46 | config := configs.LoadGrpcConfig() 47 | address := config.GrpcHost + ":" + config.GrpcPort 48 | s.Logger.Info("Grpc Server Start ", address) 49 | lis, err := net.Listen("tcp", address) 50 | if err != nil { 51 | return err 52 | } 53 | return s.Serve(lis) 54 | } 55 | 56 | //-------------- 57 | 58 | func (s *GrpcCommServer) getServiceDesc(name string) grpc.ServiceDesc { 59 | var serviceDesc = grpc.ServiceDesc{ 60 | ServiceName: "protobuf." + name, 61 | HandlerType: (*protobuf.ServiceServer)(nil), 62 | Methods: []grpc.MethodDesc{ 63 | { 64 | MethodName: "Handle", 65 | Handler: s.serviceHandleHandler, 66 | }, 67 | }, 68 | Streams: []grpc.StreamDesc{}, 69 | Metadata: "message.proto", 70 | } 71 | return serviceDesc 72 | } 73 | 74 | func (s *GrpcCommServer) serviceHandleHandler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 75 | in := new(protobuf.Request) 76 | if err := dec(in); err != nil { 77 | return nil, err 78 | } 79 | //interceptor 拦截器 80 | if interceptor == nil { 81 | return srv.(protobuf.ServiceServer).Handle(ctx, in) 82 | } 83 | info := &grpc.UnaryServerInfo{ 84 | Server: srv, 85 | FullMethod: "/protobuf.Service/Handle", 86 | } 87 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 88 | return srv.(protobuf.ServiceServer).Handle(ctx, req.(*protobuf.Request)) 89 | } 90 | return interceptor(ctx, in, info, handler) 91 | } 92 | 93 | func (s *GrpcCommServer) Close() { 94 | v, ok := wego.App.Consul["grpc"] 95 | if ok { 96 | v.Deregister() 97 | } 98 | } 99 | 100 | type grpcService struct { 101 | handler GrpcTransport.Handler 102 | } 103 | 104 | func (s *grpcService) Handle(ctx context.Context, req *protobuf.Request) (*protobuf.Response, error) { 105 | _, rsp, err := s.handler.ServeGRPC(ctx, req) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return rsp.(*protobuf.Response), err 110 | } 111 | 112 | type HealthImpl struct{} 113 | 114 | // Check 实现健康检查接口,这里直接返回健康状态, 115 | // 这里也可以有更复杂的健康检查策略,比如根据服务器负载来返回 116 | func (s *HealthImpl) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { 117 | return &grpc_health_v1.HealthCheckResponse{ 118 | Status: grpc_health_v1.HealthCheckResponse_SERVING, 119 | }, nil 120 | } 121 | func (s *HealthImpl) Watch(*grpc_health_v1.HealthCheckRequest, grpc_health_v1.Health_WatchServer) error { 122 | 123 | return nil 124 | } 125 | -------------------------------------------------------------------------------- /servers/commons/Server.go: -------------------------------------------------------------------------------- 1 | package commons 2 | 3 | import ( 4 | "context" 5 | "github.com/go-kit/kit/endpoint" 6 | "github.com/go-kit/kit/log" 7 | "github.com/go-kit/kit/transport" 8 | ) 9 | 10 | //通用接口 11 | type Handler interface { 12 | ServeHandle(ctx context.Context, request interface{}) (interface{}, error) 13 | } 14 | 15 | //请求 16 | type DecodeRequestFunc func(context.Context, interface{}) (request interface{}, err error) 17 | type EncodeRequestFunc func(context.Context, interface{}) (request interface{}, err error) 18 | 19 | //响应 20 | type EncodeResponseFunc func(context.Context, interface{}) (response interface{}, err error) 21 | type DecodeResponseFunc func(context.Context, interface{}) (response interface{}, err error) 22 | 23 | type BeforeFunc func(context.Context, interface{}) context.Context 24 | type AfterFunc func(context.Context, interface{}) context.Context 25 | 26 | type FinalizerFunc func(ctx context.Context, err error) 27 | 28 | type Server struct { 29 | e endpoint.Endpoint 30 | dec DecodeRequestFunc 31 | enc EncodeResponseFunc 32 | before []BeforeFunc 33 | after []AfterFunc 34 | finalizer []FinalizerFunc 35 | errorHandler transport.ErrorHandler 36 | } 37 | 38 | type ServerOption func(*Server) 39 | 40 | // ServerBefore functions are executed on the gRPC request object before the 41 | // request is decoded. 42 | func ServerBefore(before ...BeforeFunc) ServerOption { 43 | return func(s *Server) { s.before = append(s.before, before...) } 44 | } 45 | 46 | // ServerAfter functions are executed on the gRPC response writer after the 47 | // endpoint is invoked, but before anything is written to the client. 48 | func ServerAfter(after ...AfterFunc) ServerOption { 49 | return func(s *Server) { s.after = append(s.after, after...) } 50 | } 51 | 52 | // ServerErrorLogger is used to log non-terminal errors. By default, no errors 53 | // are logged. 54 | // Deprecated: Use ServerErrorHandler instead. 55 | func ServerErrorLogger(logger log.Logger) ServerOption { 56 | return func(s *Server) { s.errorHandler = transport.NewLogErrorHandler(logger) } 57 | } 58 | 59 | // ServerErrorHandler is used to handle non-terminal errors. By default, non-terminal errors 60 | // are ignored. 61 | func ServerErrorHandler(errorHandler transport.ErrorHandler) ServerOption { 62 | return func(s *Server) { s.errorHandler = errorHandler } 63 | } 64 | 65 | // ServerFinalizer is executed at the end of every gRPC request. 66 | // By default, no finalizer is registered. 67 | func ServerFinalizer(f ...FinalizerFunc) ServerOption { 68 | return func(s *Server) { s.finalizer = append(s.finalizer, f...) } 69 | } 70 | 71 | func NewServer( 72 | e endpoint.Endpoint, 73 | dec DecodeRequestFunc, 74 | enc EncodeResponseFunc, 75 | options ...ServerOption, 76 | ) *Server { 77 | s := &Server{ 78 | e: e, 79 | dec: dec, 80 | enc: enc, 81 | errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()), 82 | } 83 | for _, option := range options { 84 | option(s) 85 | } 86 | return s 87 | } 88 | 89 | func (s *Server) ServeHandle(ctx context.Context, req interface{}) (resp interface{}, err error) { 90 | 91 | if len(s.finalizer) > 0 { 92 | defer func() { 93 | for _, f := range s.finalizer { 94 | f(ctx, err) 95 | } 96 | }() 97 | } 98 | for _, f := range s.before { 99 | ctx = f(ctx, req) 100 | } 101 | 102 | resp, err = s.dec(ctx, req) 103 | if err != nil { 104 | s.errorHandler.Handle(ctx, err) 105 | return nil, err 106 | } 107 | 108 | resp, err = s.e(ctx, resp) 109 | if err != nil { 110 | s.errorHandler.Handle(ctx, err) 111 | return nil, err 112 | } 113 | 114 | for _, f := range s.after { 115 | ctx = f(ctx, resp) 116 | } 117 | 118 | resp, err = s.enc(ctx, resp) 119 | if err != nil { 120 | s.errorHandler.Handle(ctx, err) 121 | return nil, err 122 | } 123 | return 124 | 125 | } 126 | -------------------------------------------------------------------------------- /servers/gateways/server.go: -------------------------------------------------------------------------------- 1 | package gateways 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "github.com/9299381/wego/clients" 8 | "github.com/9299381/wego/configs" 9 | "github.com/9299381/wego/constants" 10 | "github.com/9299381/wego/contracts" 11 | "github.com/9299381/wego/servers/events" 12 | "github.com/go-kit/kit/endpoint" 13 | "net/http" 14 | "net/http/httputil" 15 | "time" 16 | ) 17 | 18 | type Server struct { 19 | handlers map[string]endpoint.Endpoint 20 | Logger contracts.ILogger 21 | } 22 | 23 | func NewServer() *Server { 24 | ss := &Server{ 25 | handlers: make(map[string]endpoint.Endpoint), 26 | } 27 | return ss 28 | } 29 | 30 | func (s *Server) Register(method, path string, endpoint endpoint.Endpoint) { 31 | key := method + "_" + path 32 | s.handlers[key] = endpoint 33 | } 34 | 35 | func (s *Server) Serve() error { 36 | config := configs.LoadHttpConfig() 37 | address := config.HttpHost + ":" + config.HttpPort 38 | s.Logger.Info("Http Server Start ", address) 39 | handler := s 40 | return http.ListenAndServe(address, handler) 41 | } 42 | 43 | func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 44 | if r.URL.Path == "/favicon.ico" { 45 | return 46 | } 47 | var resp contracts.Response 48 | //通过编解码 进行 路由路由处理 49 | ctx := r.Context() 50 | req, err := decodeRequest(ctx, r) 51 | if err != nil { 52 | resp = contracts.ResponseFailed(err) 53 | _ = encodeResponse(ctx, w, resp) 54 | return 55 | } 56 | key := req.Method + "_" + r.URL.Path 57 | filter, ok := s.handlers[key] 58 | if ok && filter != nil { 59 | // 如果有注册管理,则注册管理处理 60 | //注意filter的endpoint可以只过滤,不进行service处理, 61 | // gateway_endpoint负责返回GATEWAY,h或者error 62 | resp = s.runFilter(filter, ctx, req) 63 | data, exist := resp.Data.(map[string]interface{}) 64 | if exist && data != nil { 65 | req.Data = data 66 | } 67 | } 68 | if !ok || req.Data["GATEWAY"] == "GATEWAY" { 69 | if req.Service == "" { 70 | resp = contracts.ResponseFailed(errors.New("9999:没有响应的服务")) 71 | _ = encodeResponse(ctx, w, resp) 72 | return 73 | } 74 | var tag, host string 75 | defer s.fireEvent(time.Now(), &key, &tag, &host) 76 | 77 | //服务发现 78 | entity, err := clients.GetConsulService(req.Service) 79 | if err != nil { 80 | resp = contracts.ResponseFailed(err) 81 | _ = encodeResponse(ctx, w, resp) 82 | return 83 | } 84 | tag = entity.Service.Tags[0] 85 | host = fmt.Sprintf("%s:%d", entity.Service.Address, entity.Service.Port) 86 | if tag == "http" { 87 | director := func(dr *http.Request) { 88 | dr.URL.Scheme = "http" 89 | dr.URL.Host = host 90 | dr.URL.Path = req.Dest 91 | dr.Method = req.Method 92 | } 93 | gateway := &httputil.ReverseProxy{Director: director} 94 | gateway.ServeHTTP(w, r) 95 | return 96 | 97 | } else if tag == "grpc" && req.Route != "" { 98 | resp = clients.NewGrpcCall(host, req.Route, req.Data) 99 | _ = encodeResponse(ctx, w, resp) 100 | return 101 | } 102 | } 103 | _ = encodeResponse(ctx, w, resp) 104 | } 105 | 106 | func (s *Server) runFilter(filter endpoint.Endpoint, ctx context.Context, req *contracts.GateWayRequest) contracts.Response { 107 | filterResp, err := filter(ctx, contracts.Request{ 108 | Id: req.Id, 109 | Data: req.Data, 110 | }) 111 | if err != nil { 112 | return contracts.ResponseFailed(err) 113 | } else { 114 | return filterResp.(contracts.Response) 115 | } 116 | } 117 | func (s *Server) fireEvent(begin time.Time, key, tag, host *string) { 118 | params := make(map[string]interface{}) 119 | params["url"] = key 120 | params["begin"] = begin.Format(constants.YmdHis) 121 | params["took"] = time.Since(begin) 122 | params["tag"] = *tag 123 | params["host"] = *host 124 | payload := &contracts.Payload{ 125 | Route: configs.EnvString("gateway.event_handler", "GATEWAY_EVENT_HANDLER"), 126 | Params: params, 127 | } 128 | events.Fire(payload) 129 | } 130 | func (s *Server) Close() { 131 | 132 | } 133 | -------------------------------------------------------------------------------- /servers/gateways/codec.go: -------------------------------------------------------------------------------- 1 | package gateways 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "github.com/9299381/wego/contracts" 9 | "github.com/9299381/wego/tools/idwork" 10 | "io" 11 | "io/ioutil" 12 | "mime" 13 | "net/http" 14 | "net/url" 15 | "strings" 16 | ) 17 | 18 | func decodeRequest(_ context.Context, r *http.Request) (req *contracts.GateWayRequest, err error) { 19 | data := make(map[string]interface{}) 20 | var vars url.Values 21 | //r.Body 读取一次就消失了,因此重写了http.request中的parsePostForm 22 | if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" { 23 | vars, err = parsePostForm(r) 24 | if err != nil { 25 | return nil, errors.New(err.Error()) 26 | } 27 | } else { 28 | _ = r.ParseForm() 29 | vars = r.Form 30 | } 31 | for k, v := range vars { 32 | data[k] = v[0] 33 | } 34 | if _, ok := vars["request_id"]; ok == false { 35 | data["request_id"] = idwork.ID() 36 | } 37 | if strings.Index(r.RemoteAddr, "::") > 0 { 38 | data["client_ip"] = "127.0.0.1" 39 | } else { 40 | data["client_ip"] = r.RemoteAddr 41 | } 42 | if authToken := r.Header.Get("authToken"); authToken != "" { 43 | data["authToken"] = authToken 44 | } 45 | req = parseUrl(r) 46 | req.Data = data 47 | req.Id = data["request_id"].(string) 48 | 49 | return 50 | } 51 | 52 | //从http.request 中拷贝修改,目的是body读出,写入 53 | func parsePostForm(r *http.Request) (vs url.Values, err error) { 54 | if r.Body == nil { 55 | err = errors.New("missing form body") 56 | return 57 | } 58 | ct := r.Header.Get("Content-Type") 59 | // RFC 7231, section 3.1.1.5 - empty type 60 | // MAY be treated as application/octet-stream 61 | if ct == "" { 62 | ct = "application/octet-stream" 63 | } 64 | ct, _, err = mime.ParseMediaType(ct) 65 | switch { 66 | case ct == "application/x-www-form-urlencoded": 67 | //备份body 68 | bodyBytes, _ := ioutil.ReadAll(r.Body) 69 | var reader io.Reader = r.Body 70 | maxFormSize := int64(1<<63 - 1) 71 | if _, ok := r.Body.(*maxBytesReader); !ok { 72 | maxFormSize = int64(10 << 20) // 10 MB is a lot of text. 73 | reader = io.LimitReader(r.Body, maxFormSize+1) 74 | } 75 | b, e := ioutil.ReadAll(reader) 76 | if e != nil { 77 | if err == nil { 78 | err = e 79 | } 80 | break 81 | } 82 | if int64(len(b)) > maxFormSize { 83 | err = errors.New("http: POST too large") 84 | return 85 | } 86 | vs, e = url.ParseQuery(string(b)) 87 | if err == nil { 88 | err = e 89 | } 90 | //回写body 91 | r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) 92 | 93 | case ct == "multipart/form-data": 94 | // handled by ParseMultipartForm (which is calling us, or should be) 95 | // TODO(bradfitz): there are too many possible 96 | // orders to call too many functions here. 97 | // Clean this up and write more tests. 98 | // request_test.go contains the start of this, 99 | // in TestParseMultipartFormOrder and others. 100 | } 101 | 102 | return 103 | } 104 | 105 | func parseUrl(r *http.Request) *contracts.GateWayRequest { 106 | var service, route, dest string 107 | pathArray := strings.Split(r.URL.Path, "/") 108 | if len(pathArray) <= 2 { 109 | //这是本地的 110 | //如果是health,则返回 SERVING 111 | service = pathArray[1] 112 | route = "" 113 | dest = r.URL.Path 114 | } else { 115 | service = pathArray[1] 116 | route = strings.Join(pathArray[2:], ".") 117 | dest = "/" + strings.Join(pathArray[2:], "/") 118 | } 119 | return &contracts.GateWayRequest{ 120 | Dest: dest, 121 | Method: r.Method, 122 | Service: service, 123 | Route: route, 124 | } 125 | } 126 | 127 | func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { 128 | w.Header().Set("Content-Type", "application/json;charset=utf-8") 129 | w.Header().Set("Access-Control-Allow-Origin", "*") 130 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,authToken") 131 | w.Header().Set("Access-Control-Allow-Credentials", "true") 132 | w.Header().Set("Access-Control-Expose-Headers", "*") 133 | return json.NewEncoder(w).Encode(response) 134 | } 135 | -------------------------------------------------------------------------------- /servers/queues/server.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "github.com/9299381/wego/contracts" 10 | "github.com/9299381/wego/servers/commons" 11 | "github.com/gomodule/redigo/redis" 12 | "time" 13 | ) 14 | 15 | type Options struct { 16 | Prefix string 17 | Listen []string 18 | Interval time.Duration 19 | Concurrency int 20 | UseNumber bool 21 | } 22 | 23 | type Server struct { 24 | opts Options 25 | handlers map[string]*commons.CommHandler 26 | ctx context.Context 27 | RedisPool *redis.Pool 28 | Logger contracts.ILogger 29 | } 30 | 31 | func NewServer(opts *Options) *Server { 32 | //初始化,logger,redis池 33 | s := &Server{ 34 | opts: *opts, 35 | ctx: context.Background(), 36 | handlers: make(map[string]*commons.CommHandler), 37 | } 38 | return s 39 | } 40 | 41 | func (s *Server) Register(name string, handler *commons.CommHandler) { 42 | s.handlers[name] = handler 43 | 44 | } 45 | 46 | func (s *Server) Serve() error { 47 | errChan := make(chan error) 48 | quit := signals() 49 | jobs := s.poll(quit, errChan) 50 | for id := 0; id < s.opts.Concurrency; id++ { 51 | s.work(id, jobs, errChan) 52 | } 53 | return <-errChan 54 | } 55 | 56 | func (s *Server) work(id int, jobs <-chan *Job, errChan chan error) { 57 | go func() { 58 | for job := range jobs { 59 | if handler, ok := s.handlers[job.Payload.Route]; ok { 60 | ctx := context.Background() 61 | ctx = context.WithValue(ctx, "Queue", job.Queue) 62 | request := job.Payload.Params 63 | response, err := handler.Handle(ctx, request) 64 | if err != nil { 65 | errChan <- err 66 | return 67 | } 68 | msg := fmt.Sprintf( 69 | "Concurrency_Id:%d ,Job Response:%v", 70 | id, 71 | response) 72 | s.Logger.Debug(msg) 73 | } else { 74 | errorLog := fmt.Sprintf( 75 | "No worker for %s in queue %s with args %v", 76 | job.Payload.Route, 77 | job.Queue, 78 | job.Payload.Params) 79 | s.Logger.Error(errorLog) 80 | errChan <- errors.New(errorLog) 81 | return 82 | } 83 | } 84 | }() 85 | } 86 | 87 | func (s *Server) poll(quit <-chan bool, errChan chan error) <-chan *Job { 88 | jobs := make(chan *Job) 89 | go func() { 90 | conn := s.RedisPool.Get() 91 | defer conn.Close() 92 | for { 93 | select { 94 | default: 95 | job, err := s.getJob(conn) 96 | if err != nil { 97 | errorLog := fmt.Sprintf( 98 | "Error on %v getting job from: %v", 99 | s.opts.Listen, 100 | err) 101 | s.Logger.Error(errorLog) 102 | errChan <- errors.New(errorLog) 103 | return 104 | } 105 | if job != nil { 106 | select { 107 | case jobs <- job: 108 | case <-quit: 109 | buf, err := json.Marshal(job.Payload) 110 | if err != nil { 111 | errorLog := fmt.Sprintf( 112 | "Error requeueing %v: %v", 113 | job, err) 114 | s.Logger.Error(errorLog) 115 | errChan <- errors.New(errorLog) 116 | return 117 | } 118 | arg := fmt.Sprintf("%s_queue:%s", s.opts.Prefix, job.Queue) 119 | _ = conn.Send("LPUSH", arg, buf) 120 | _ = conn.Flush() 121 | return 122 | } 123 | } else { 124 | s.Logger.Debugf("Sleeping for %v", s.opts.Interval) 125 | s.Logger.Debugf("Waiting for %v", s.opts.Listen) 126 | timeout := time.After(s.opts.Interval) 127 | select { 128 | case <-quit: 129 | return 130 | case <-timeout: 131 | } 132 | } 133 | } 134 | } 135 | }() 136 | 137 | return jobs 138 | } 139 | 140 | func (s *Server) getJob(conn redis.Conn) (*Job, error) { 141 | for _, queue := range s.opts.Listen { 142 | s.Logger.Debugf("Checking %s", queue) 143 | arg := fmt.Sprintf("%s_queue:%s", s.opts.Prefix, queue) 144 | reply, err := conn.Do("LPOP", arg) 145 | if err != nil { 146 | return nil, err 147 | } 148 | if reply != nil { 149 | s.Logger.Debugf("Found job on %s", queue) 150 | job := &Job{Queue: queue} 151 | decoder := json.NewDecoder(bytes.NewReader(reply.([]byte))) 152 | if s.opts.UseNumber { 153 | decoder.UseNumber() 154 | } 155 | if err := decoder.Decode(&job.Payload); err != nil { 156 | return nil, err 157 | } 158 | return job, nil 159 | } 160 | } 161 | return nil, nil 162 | } 163 | 164 | func (s *Server) Close() { 165 | 166 | } 167 | -------------------------------------------------------------------------------- /demo/logs/log.20191106.log: -------------------------------------------------------------------------------- 1 | {"level":"info","msg":"Http Server Start :8341","time":"2019-11-06 16:59:26"} 2 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403324415934464","time":"2019-11-06 16:59:28"} 3 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403324415934464","time":"2019-11-06 16:59:28"} 4 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403324415934464","time":"2019-11-06 16:59:28"} 5 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403328002064384","time":"2019-11-06 16:59:29"} 6 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403328002064384","time":"2019-11-06 16:59:29"} 7 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403328002064384","time":"2019-11-06 16:59:29"} 8 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403328949977088","time":"2019-11-06 16:59:29"} 9 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403328949977088","time":"2019-11-06 16:59:29"} 10 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403328949977088","time":"2019-11-06 16:59:29"} 11 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403329839169536","time":"2019-11-06 16:59:29"} 12 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403329839169536","time":"2019-11-06 16:59:29"} 13 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403329839169536","time":"2019-11-06 16:59:29"} 14 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403330610921472","time":"2019-11-06 16:59:30"} 15 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403330610921472","time":"2019-11-06 16:59:30"} 16 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403330610921472","time":"2019-11-06 16:59:30"} 17 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403337254699008","time":"2019-11-06 16:59:31"} 18 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403337254699008","time":"2019-11-06 16:59:31"} 19 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403337254699008","time":"2019-11-06 16:59:31"} 20 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303403337959342080","time":"2019-11-06 16:59:31"} 21 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303403337959342080","time":"2019-11-06 16:59:31"} 22 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303403337959342080","time":"2019-11-06 16:59:31"} 23 | {"level":"info","msg":"interrupt","time":"2019-11-06 16:59:37"} 24 | {"level":"info","msg":"Http Server Start :8341","time":"2019-11-06 17:03:33"} 25 | {"level":"info","msg":"runtime error: invalid memory address or nil pointer dereference","time":"2019-11-06 17:03:36"} 26 | {"level":"info","msg":"interrupt","time":"2019-11-06 17:04:32"} 27 | {"level":"info","msg":"Http Server Start :8341","time":"2019-11-06 17:06:56"} 28 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303405210980319232","time":"2019-11-06 17:06:58"} 29 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303405210980319232","time":"2019-11-06 17:06:58"} 30 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303405210980319232","time":"2019-11-06 17:06:58"} 31 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303405213853417472","time":"2019-11-06 17:06:59"} 32 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303405213853417472","time":"2019-11-06 17:06:59"} 33 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303405213853417472","time":"2019-11-06 17:06:59"} 34 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303405223588397056","time":"2019-11-06 17:07:01"} 35 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303405223588397056","time":"2019-11-06 17:07:01"} 36 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303405223588397056","time":"2019-11-06 17:07:01"} 37 | {"level":"info","msg":"interrupt","time":"2019-11-06 17:07:32"} 38 | {"level":"info","msg":"Http Server Start :8341","time":"2019-11-06 17:07:36"} 39 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303405385866018816","time":"2019-11-06 17:07:40"} 40 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303405385866018816","time":"2019-11-06 17:07:40"} 41 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303405385866018816","time":"2019-11-06 17:07:40"} 42 | {"client_ip":"127.0.0.1","level":"info","msg":"one....","request_id":"1303405396527939584","time":"2019-11-06 17:07:42"} 43 | {"client_ip":"127.0.0.1","level":"info","msg":"map[a:b b:b]","request_id":"1303405396527939584","time":"2019-11-06 17:07:42"} 44 | {"client_ip":"127.0.0.1","level":"info","msg":"two......","request_id":"1303405396527939584","time":"2019-11-06 17:07:42"} 45 | {"level":"info","msg":"interrupt","time":"2019-11-06 17:07:49"} 46 | -------------------------------------------------------------------------------- /demo/swaggerui/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "paths": { 4 | "/demo/one": { 5 | "get": { 6 | "description": "Test swagger\nThis will .......", 7 | "tags": [ 8 | "分组1" 9 | ], 10 | "operationId": "oneController", 11 | "parameters": [ 12 | { 13 | "minimum": 1, 14 | "type": "string", 15 | "x-go-name": "Param1", 16 | "description": "参数param1的说明\n最小1", 17 | "name": "param_1", 18 | "in": "query", 19 | "required": true 20 | }, 21 | { 22 | "minLength": 4, 23 | "type": "integer", 24 | "format": "int64", 25 | "x-go-name": "Param2", 26 | "description": "最短4", 27 | "name": "param_2", 28 | "in": "query", 29 | "required": true 30 | }, 31 | { 32 | "type": "integer", 33 | "format": "int64", 34 | "x-go-name": "Param4", 35 | "name": "param_4", 36 | "in": "query" 37 | } 38 | ], 39 | "responses": { 40 | "200": { 41 | "$ref": "#/responses/oneResponse" 42 | } 43 | } 44 | } 45 | }, 46 | "/demo/post": { 47 | "post": { 48 | "description": "Test swagger\nThis will .......", 49 | "tags": [ 50 | "分组2" 51 | ], 52 | "operationId": "postController", 53 | "parameters": [ 54 | { 55 | "type": "string", 56 | "x-go-name": "Id", 57 | "name": "id", 58 | "in": "query" 59 | }, 60 | { 61 | "type": "string", 62 | "x-go-name": "Value", 63 | "name": "value", 64 | "in": "query" 65 | }, 66 | { 67 | "type": "integer", 68 | "format": "int64", 69 | "x-go-name": "Number", 70 | "name": "number", 71 | "in": "query" 72 | } 73 | ], 74 | "responses": { 75 | "200": { 76 | "$ref": "#/responses/postResponse" 77 | } 78 | } 79 | } 80 | }, 81 | "/demo/two": { 82 | "get": { 83 | "description": "Test swagger\nThis will .......", 84 | "tags": [ 85 | "分组1" 86 | ], 87 | "operationId": "twoController", 88 | "parameters": [ 89 | { 90 | "type": "string", 91 | "x-go-name": "Name", 92 | "description": "备注", 93 | "name": "name", 94 | "in": "query" 95 | } 96 | ], 97 | "responses": { 98 | "200": { 99 | "$ref": "#/responses/twoResponse" 100 | } 101 | } 102 | } 103 | }, 104 | "/demo/valid": { 105 | "post": { 106 | "description": "Test swagger\nThis will .......", 107 | "tags": [ 108 | "分组2" 109 | ], 110 | "operationId": "validController", 111 | "responses": { 112 | "200": { 113 | "$ref": "#/responses/postResponse" 114 | } 115 | } 116 | } 117 | } 118 | }, 119 | "definitions": { 120 | "Demo": { 121 | "type": "object", 122 | "properties": { 123 | "id": { 124 | "type": "string", 125 | "x-go-name": "Id" 126 | }, 127 | "name": { 128 | "type": "string", 129 | "x-go-name": "Name" 130 | } 131 | }, 132 | "x-go-package": "github.com/9299381/wego/demo/src/dto" 133 | }, 134 | "postRequest": { 135 | "type": "object", 136 | "properties": { 137 | "id": { 138 | "type": "string", 139 | "x-go-name": "Id" 140 | }, 141 | "number": { 142 | "type": "integer", 143 | "format": "int64", 144 | "x-go-name": "Number" 145 | }, 146 | "value": { 147 | "type": "string", 148 | "x-go-name": "Value" 149 | } 150 | }, 151 | "x-go-package": "github.com/9299381/wego/demo/src/controller" 152 | } 153 | }, 154 | "responses": { 155 | "oneResponse": { 156 | "headers": { 157 | "age": { 158 | "type": "integer", 159 | "format": "int64", 160 | "description": "整形" 161 | }, 162 | "id": { 163 | "type": "string" 164 | }, 165 | "user_name": { 166 | "type": "string", 167 | "description": "响应UserName的描述" 168 | } 169 | } 170 | }, 171 | "postResponse": { 172 | "schema": { 173 | "$ref": "#/definitions/postRequest" 174 | }, 175 | "headers": { 176 | "id": { 177 | "type": "string" 178 | }, 179 | "resp": {} 180 | } 181 | }, 182 | "twoResponse": { 183 | "headers": { 184 | "id": { 185 | "type": "string" 186 | }, 187 | "user_name": { 188 | "type": "string" 189 | } 190 | } 191 | }, 192 | "validResponse": { 193 | "headers": { 194 | "age": { 195 | "type": "integer", 196 | "format": "int64" 197 | }, 198 | "list": { 199 | "type": "array", 200 | "items": { 201 | "$ref": "#/definitions/Demo" 202 | } 203 | } 204 | } 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /contracts/context.go: -------------------------------------------------------------------------------- 1 | package contracts 2 | 3 | import ( 4 | "context" 5 | "github.com/9299381/wego/constants" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | type Context struct { 11 | context.Context 12 | Keys map[string]interface{} 13 | Log ILogger 14 | } 15 | 16 | func (c *Context) reset() { 17 | c.Keys = nil 18 | } 19 | 20 | func (c *Context) Copy() *Context { 21 | var cp = *c 22 | cp.Keys = make(map[string]interface{}) 23 | for k, v := range c.Keys { 24 | cp.Keys[k] = v 25 | } 26 | return &cp 27 | } 28 | 29 | // Set is used to store a new key/value pair exclusively for this contexts. 30 | // It also lazy initializes c.Keys if it was not used previously. 31 | func (c *Context) Set(key string, value interface{}) { 32 | m := strings.Split(key, ".") 33 | if len(m) > 1 { 34 | c.setValue(key, value) 35 | } else { 36 | if c.Keys == nil { 37 | c.Keys = make(map[string]interface{}) 38 | } 39 | c.Keys[key] = value 40 | } 41 | 42 | } 43 | 44 | // Get returns the value for the given key, ie: (value, true). 45 | // If the value does not exists it returns (nil, false) 46 | func (c *Context) GetKey(key string) (value interface{}, exists bool) { 47 | value, exists = c.Keys[key] 48 | return 49 | } 50 | 51 | // GetKey returns the value for the given key if it exists, otherwise it panics. 52 | func (c *Context) Get(key string) interface{} { 53 | m := strings.Split(key, ".") 54 | if len(m) > 1 { 55 | return c.getValue(key) 56 | } 57 | if value, exists := c.GetKey(key); exists { 58 | return value 59 | } 60 | panic("Key \"" + key + "\" does not exist") 61 | } 62 | 63 | // GetString returns the value associated with the key as a string. 64 | func (c *Context) GetString(key string) (s string) { 65 | if val, ok := c.GetKey(key); ok && val != nil { 66 | s, _ = val.(string) 67 | } 68 | return 69 | } 70 | 71 | // GetBool returns the value associated with the key as a boolean. 72 | func (c *Context) GetBool(key string) (b bool) { 73 | if val, ok := c.GetKey(key); ok && val != nil { 74 | b, _ = val.(bool) 75 | } 76 | return 77 | } 78 | 79 | // GetInt returns the value associated with the key as an integer. 80 | func (c *Context) GetInt(key string) (i int) { 81 | if val, ok := c.GetKey(key); ok && val != nil { 82 | i, _ = val.(int) 83 | } 84 | return 85 | } 86 | 87 | // GetInt64 returns the value associated with the key as an integer. 88 | func (c *Context) GetInt64(key string) (i64 int64) { 89 | if val, ok := c.GetKey(key); ok && val != nil { 90 | i64, _ = val.(int64) 91 | } 92 | return 93 | } 94 | 95 | // GetFloat64 returns the value associated with the key as a float64. 96 | func (c *Context) GetFloat64(key string) (f64 float64) { 97 | if val, ok := c.GetKey(key); ok && val != nil { 98 | f64, _ = val.(float64) 99 | } 100 | return 101 | } 102 | 103 | // GetTime returns the value associated with the key as time. 104 | func (c *Context) GetTime(key string) (t time.Time) { 105 | if val, ok := c.GetKey(key); ok && val != nil { 106 | t, _ = val.(time.Time) 107 | } 108 | return 109 | } 110 | 111 | // GetDuration returns the value associated with the key as a duration. 112 | func (c *Context) GetDuration(key string) (d time.Duration) { 113 | if val, ok := c.GetKey(key); ok && val != nil { 114 | d, _ = val.(time.Duration) 115 | } 116 | return 117 | } 118 | 119 | // GetStringSlice returns the value associated with the key as a slice of strings. 120 | func (c *Context) GetStringSlice(key string) (ss []string) { 121 | if val, ok := c.GetKey(key); ok && val != nil { 122 | ss, _ = val.([]string) 123 | } 124 | return 125 | } 126 | 127 | // GetStringMap returns the value associated with the key as a map of interfaces. 128 | func (c *Context) GetStringMap(key string) (sm map[string]interface{}) { 129 | if val, ok := c.GetKey(key); ok && val != nil { 130 | sm, _ = val.(map[string]interface{}) 131 | } 132 | return 133 | } 134 | 135 | // GetStringMapString returns the value associated with the key as a map of strings. 136 | func (c *Context) GetStringMapString(key string) (sms map[string]string) { 137 | if val, ok := c.GetKey(key); ok && val != nil { 138 | sms, _ = val.(map[string]string) 139 | } 140 | return 141 | } 142 | 143 | // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 144 | func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { 145 | if val, ok := c.GetKey(key); ok && val != nil { 146 | smss, _ = val.(map[string][]string) 147 | } 148 | return 149 | } 150 | 151 | func (c *Context) setValue(key string, value interface{}) { 152 | keyMap := strings.Split(key, ".") 153 | if len(keyMap) == 1 { 154 | c.Set(keyMap[0], value) 155 | } else { 156 | pos := c.getPos(keyMap) 157 | if pos > 0 { 158 | c.modifyValue(keyMap, pos, value) 159 | } else { 160 | ret := c.setKeyToMap(keyMap[1:], value) 161 | c.Set(keyMap[0], ret) 162 | } 163 | } 164 | } 165 | 166 | func (c *Context) getValue(key string) (ret interface{}) { 167 | keyMap := strings.Split(key, ".") 168 | ret = c.getKeyFromMap(keyMap, c.Keys) 169 | return 170 | } 171 | 172 | func (c *Context) Request() interface{} { 173 | return c.Get(constants.RequestDto) 174 | } 175 | 176 | //------私有 177 | 178 | func (c *Context) setKeyToMap(keyMap []string, value interface{}) (ret map[string]interface{}) { 179 | //pos为 180 | ret = make(map[string]interface{}) 181 | if len(keyMap) == 1 { 182 | ret[keyMap[0]] = value 183 | } else if len(keyMap) > 1 { 184 | ret[keyMap[0]] = c.setKeyToMap(keyMap[1:], value) 185 | } 186 | return 187 | } 188 | 189 | /** 190 | 获取有值的位置 191 | */ 192 | func (c *Context) getPos(keyMap []string) (pos int) { 193 | l := len(keyMap) 194 | pos = 0 195 | //是否有值,如果有值应该叠加上,从最后开始 196 | for i := 0; i < l; i++ { 197 | newMap := keyMap[:l-i] 198 | old := c.getKeyFromMap(newMap, c.Keys) 199 | if old != nil { 200 | pos = l - i 201 | break 202 | } 203 | } 204 | return 205 | } 206 | 207 | func (c *Context) getKeyFromMap(keyMap []string, valueMap interface{}) (ret interface{}) { 208 | m, ok := valueMap.(map[string]interface{}) 209 | if ok { 210 | if len(keyMap) == 0 { 211 | ret = nil 212 | } else if len(keyMap) == 1 { 213 | ret = m[keyMap[0]] 214 | } else { 215 | ret = c.getKeyFromMap(keyMap[1:], m[keyMap[0]]) 216 | } 217 | } 218 | return 219 | } 220 | func (c *Context) modifyValue(keyMap []string, pos int, value interface{}) { 221 | //在函数调用时,像切片(slice)、字典(map)、 222 | // 接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递 223 | // (即使没有显式的指出指针)。 224 | ret, ok := c.getKeyFromMap(keyMap[:pos], c.Keys).(map[string]interface{}) 225 | if ok { 226 | for v, k := range c.setKeyToMap(keyMap[pos:], value) { 227 | //注意这里的ret为指针,修改其值则c.key中值发生变化 228 | ret[v] = k 229 | } 230 | } else { 231 | if pos > 1 { 232 | c.modifyValue(keyMap, pos-1, value) 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /demo/test/xorm/xorm_test.go: -------------------------------------------------------------------------------- 1 | package xorm 2 | 3 | import ( 4 | "fmt" 5 | "github.com/9299381/wego/clients" 6 | "github.com/9299381/wego/demo/src/model" 7 | "github.com/9299381/wego/tools/idwork" 8 | "testing" 9 | "xorm.io/builder" 10 | ) 11 | 12 | type Detail struct { 13 | Id string 14 | CardNo string 15 | } 16 | type UserDetail struct { 17 | model.CommUser `xorm:"extends"` 18 | Detail `xorm:"extends"` 19 | } 20 | 21 | func TestListJoin(t *testing.T) { 22 | 23 | var users []UserDetail 24 | results := clients.DB(). 25 | Table("comm_user_info"). 26 | Alias("t1"). 27 | Select("t1.id,t1.user_name,t1.create_time,t1.update_time,t2.card_no"). 28 | Join("LEFT", "user_bank as t2", "t1.user_id=t2.user_id"). 29 | Limit(10, 0). 30 | Find(&users) 31 | fmt.Println(results) 32 | fmt.Println(users) 33 | for key, value := range users { 34 | fmt.Println(key) 35 | fmt.Println(value.UserName) 36 | } 37 | } 38 | 39 | func TestOneJoin(t *testing.T) { 40 | user := &UserDetail{} 41 | result, err := clients.DB(). 42 | Table("comm_user_info"). 43 | Alias("t1"). 44 | Select("t1.id,t1.user_name,t1.create_time,t1.update_time,t2.card_no"). 45 | Join("LEFT", "user_bank as t2", "t1.user_id=t2.user_id"). 46 | Where("t1.id = ?", "1189164474851006208"). 47 | And("t1.user_name = ?", "ccc"). 48 | Limit(1). 49 | Get(user) 50 | if err != nil { 51 | panic(err) 52 | } 53 | fmt.Println(result) 54 | fmt.Println(user.CardNo) 55 | } 56 | 57 | func TestOne(t *testing.T) { 58 | user := &model.CommUser{} 59 | result, _ := clients.DB(). 60 | //Table("comm_user_info"). 61 | Select("id,user_name,status,create_time,update_time"). 62 | Where("id =?", "1189164474851006208"). 63 | Limit(1). 64 | Get(user) 65 | fmt.Println(result) 66 | fmt.Println(user) 67 | } 68 | func TestGet(t *testing.T) { 69 | user := &model.CommUser{Id: "1189164474851006208"} 70 | result, _ := clients.DB().Get(user) 71 | fmt.Println(result) 72 | fmt.Println(user) 73 | } 74 | 75 | func TestList(t *testing.T) { 76 | var users []model.CommUser 77 | results := clients.DB(). 78 | Table("comm_user_info"). 79 | Select("id,user_name,status,create_time,update_time"). 80 | OrderBy("id DESC"). 81 | Limit(5, 10). 82 | Find(&users) 83 | fmt.Println(results) 84 | fmt.Println(users) 85 | for key, value := range users { 86 | fmt.Println(key) 87 | fmt.Println(value.UserName) 88 | } 89 | } 90 | 91 | func TestPage(t *testing.T) { 92 | var users []model.CommUser 93 | page := 1 94 | pageSize := 10 //页面大小 95 | results := clients.DB(). 96 | Table("comm_user_info"). 97 | Select("id,user_name,status,create_time,update_time"). 98 | Where("status = ?", "20"). 99 | OrderBy("id DESC"). 100 | Limit(pageSize*(page), (page-1)*pageSize). 101 | Find(&users) 102 | fmt.Println(results) 103 | fmt.Println(users) 104 | for key, value := range users { 105 | fmt.Println(key) 106 | fmt.Println(value.UserName) 107 | } 108 | } 109 | 110 | func TestUpdateOne(t *testing.T) { 111 | user := &model.CommUser{Id: "1306582895206334464"} 112 | //_, _ = clients.DB().Get(user) 113 | //fmt.Println(user) 114 | user.UserName = "ccc" 115 | _, _ = clients.DB().Update(user, &model.CommUser{Id: user.Id}) 116 | fmt.Println(user) 117 | } 118 | 119 | func TestUpdateTwo(t *testing.T) { 120 | user := &model.CommUser{Id: "1306582895206334464"} 121 | //_, _ = clients.DB().Get(user) 122 | //fmt.Println(user) 123 | user.UserName = "ccc" 124 | _, _ = clients.DB(). 125 | ID(user.Id). 126 | Cols("user_name"). 127 | Update(user) 128 | fmt.Println(user) 129 | } 130 | 131 | //insert 132 | func TestInsert(t *testing.T) { 133 | user := &model.CommUser{ 134 | Id: idwork.ID(), 135 | UserName: "go_test", 136 | Status: "30", 137 | LoginName: "aaaaa", 138 | } 139 | _, _ = clients.DB().Insert(user) 140 | 141 | } 142 | 143 | //可以创建表 144 | func TestSync2(t *testing.T) { 145 | err := clients.DB().Sync2(new(model.CommUser)) 146 | if err != nil { 147 | t.Error(err) 148 | } 149 | } 150 | 151 | /// builder sql 方式 152 | 153 | func TestBuilderFetchListJoin(t *testing.T) { 154 | 155 | sql, args, _ := 156 | builder. 157 | Select("t1.id,t1.user_name,t1.create_time,t1.update_time,t2.card_no"). 158 | From("comm_user_info as t1"). 159 | LeftJoin("user_bank as t2", "t1.user_id=t2.user_id"). 160 | Limit(10, 0). 161 | ToSQL() 162 | var users []UserDetail 163 | results := clients.DB().SQL(sql, args...).Find(&users) 164 | fmt.Println(sql) 165 | fmt.Println(args) 166 | fmt.Println(results) 167 | fmt.Println(users) 168 | } 169 | 170 | func TestBuilderFetchOneJoin(t *testing.T) { 171 | sql, args, _ := 172 | builder. 173 | Select("t1.id,t1.user_name,t1.create_time,t1.update_time,t2.card_no"). 174 | From("comm_user_info as t1"). 175 | LeftJoin("user_bank as t2", "t1.user_id=t2.user_id"). 176 | Where(builder.Eq{"t1.id": "1189164474851006208"}). 177 | And(builder.Eq{"t1.user_name": "aaaaaaaaa"}). 178 | ToSQL() 179 | 180 | user := &UserDetail{} 181 | results, _ := clients.DB().SQL(sql, args...).Get(user) 182 | fmt.Println(sql) 183 | fmt.Println(args) 184 | fmt.Println(results) 185 | fmt.Println(user.CardNo) 186 | } 187 | func TestBuilderFetchOne(t *testing.T) { 188 | req := make(map[string]interface{}) 189 | req["id"] = "1306582895206334464" 190 | cond := builder.Eq{} 191 | for k, v := range req { 192 | cond[k] = v 193 | } 194 | sql, args, _ := 195 | builder. 196 | Select("id,user_name,status,create_time,update_time"). 197 | From("comm_user_info"). 198 | Where(cond). 199 | ToSQL() 200 | 201 | user := &model.CommUser{} 202 | has, _ := clients.DB().SQL(sql, args...).Get(user) 203 | fmt.Println(sql) 204 | fmt.Println(args) 205 | fmt.Println(has) 206 | fmt.Println(user) 207 | } 208 | 209 | func TestBuilderFetch(t *testing.T) { 210 | sql, args, _ := 211 | builder. 212 | Select("*"). 213 | From("comm_user_info"). 214 | OrderBy("id DESC"). 215 | Limit(5, 10). 216 | ToSQL() 217 | 218 | var users []model.CommUser 219 | err := clients.DB().SQL(sql, args...).Find(&users) 220 | for _, v := range users { 221 | fmt.Println(v.Id) 222 | } 223 | fmt.Println(users) 224 | fmt.Println(err) 225 | } 226 | func TestBuilderFage(t *testing.T) { 227 | page := 1 228 | pageSize := 10 //页面大小 229 | 230 | sql, args, _ := 231 | builder. 232 | Select("*"). 233 | From("comm_user_info"). 234 | Where(builder.Eq{"status": "20"}). 235 | OrderBy("id DESC"). 236 | Limit(pageSize*(page), (page-1)*pageSize). 237 | ToSQL() 238 | 239 | var users []model.CommUser 240 | err := clients.DB(). 241 | SQL(sql, args...). 242 | Find(&users) 243 | 244 | fmt.Println(users) 245 | fmt.Println(err) 246 | } 247 | 248 | func TestBuilderPageList(t *testing.T) { 249 | page := 1 250 | pageSize := 10 //页面大小 251 | 252 | sql, args, _ := 253 | builder. 254 | Select("*"). 255 | From("comm_user_info"). 256 | Where(builder.Eq{"status": "20"}). 257 | OrderBy("id DESC"). 258 | ToSQL() 259 | var users []model.CommUser 260 | err := clients.DB(). 261 | SQL(sql, args...). 262 | Limit(pageSize*(page), (page-1)*pageSize). 263 | Find(&users) 264 | 265 | fmt.Println(users) 266 | fmt.Println(err) 267 | } 268 | -------------------------------------------------------------------------------- /validations/util.go: -------------------------------------------------------------------------------- 1 | package validations 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | const ( 12 | // ValidTag struct tag 13 | ValidTag = "valid" 14 | 15 | wordsize = 32 << (^uint(0) >> 32 & 1) 16 | ) 17 | 18 | var ( 19 | // key: function name 20 | // value: the number of parameters 21 | funcs = make(Funcs) 22 | 23 | // doesn't belong to validation functions 24 | unFuncs = map[string]bool{ 25 | "Clear": true, 26 | "HasErrors": true, 27 | "ErrorMap": true, 28 | "Error": true, 29 | "apply": true, 30 | "Check": true, 31 | "Valid": true, 32 | "NoMatch": true, 33 | } 34 | // ErrInt64On32 show 32 bit platform not support int64 35 | ErrInt64On32 = fmt.Errorf("not support int64 on 32-bit platform") 36 | ) 37 | 38 | func init() { 39 | v := &Validation{} 40 | t := reflect.TypeOf(v) 41 | for i := 0; i < t.NumMethod(); i++ { 42 | m := t.Method(i) 43 | if !unFuncs[m.Name] { 44 | funcs[m.Name] = m.Func 45 | } 46 | } 47 | } 48 | 49 | // CustomFunc is for custom validate function 50 | type CustomFunc func(v *Validation, obj interface{}, key string) 51 | 52 | // AddCustomFunc Add a custom function to validation 53 | // The name can not be: 54 | // Clear 55 | // HasErrors 56 | // ErrorMap 57 | // Error 58 | // Check 59 | // Valid 60 | // NoMatch 61 | // If the name is same with exists function, it will replace the origin valid function 62 | func AddCustomFunc(name string, f CustomFunc) error { 63 | if unFuncs[name] { 64 | return fmt.Errorf("invalid function name: %s", name) 65 | } 66 | 67 | funcs[name] = reflect.ValueOf(f) 68 | return nil 69 | } 70 | 71 | // ValidFunc Valid function type 72 | type ValidFunc struct { 73 | Name string 74 | Params []interface{} 75 | } 76 | 77 | // Funcs Validate function map 78 | type Funcs map[string]reflect.Value 79 | 80 | // Call validate values with named type string 81 | func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { 82 | defer func() { 83 | if r := recover(); r != nil { 84 | err = fmt.Errorf("%v", r) 85 | } 86 | }() 87 | if _, ok := f[name]; !ok { 88 | err = fmt.Errorf("%s does not exist", name) 89 | return 90 | } 91 | if len(params) != f[name].Type().NumIn() { 92 | err = fmt.Errorf("The number of params is not adapted") 93 | return 94 | } 95 | in := make([]reflect.Value, len(params)) 96 | for k, param := range params { 97 | in[k] = reflect.ValueOf(param) 98 | } 99 | result = f[name].Call(in) 100 | return 101 | } 102 | 103 | func isStruct(t reflect.Type) bool { 104 | return t.Kind() == reflect.Struct 105 | } 106 | 107 | func isStructPtr(t reflect.Type) bool { 108 | return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct 109 | } 110 | 111 | func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { 112 | tag := f.Tag.Get(ValidTag) 113 | if len(tag) == 0 { 114 | return 115 | } 116 | if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil { 117 | return 118 | } 119 | fs := strings.Split(tag, ";") 120 | for _, vfunc := range fs { 121 | var vf ValidFunc 122 | if len(vfunc) == 0 { 123 | continue 124 | } 125 | vf, err = parseFunc(vfunc, f.Name) 126 | if err != nil { 127 | return 128 | } 129 | vfs = append(vfs, vf) 130 | } 131 | return 132 | } 133 | 134 | // Get Match function 135 | // May be get NoMatch function in the future 136 | func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) { 137 | tag = strings.TrimSpace(tag) 138 | index := strings.Index(tag, "Match(/") 139 | if index == -1 { 140 | str = tag 141 | return 142 | } 143 | end := strings.LastIndex(tag, "/)") 144 | if end < index { 145 | err = fmt.Errorf("invalid Match function") 146 | return 147 | } 148 | reg, err := regexp.Compile(tag[index+len("Match(/") : end]) 149 | if err != nil { 150 | return 151 | } 152 | vfs = []ValidFunc{{"Match", []interface{}{reg, key + ".Match"}}} 153 | str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):]) 154 | return 155 | } 156 | 157 | func parseFunc(vfunc, key string) (v ValidFunc, err error) { 158 | defer func() { 159 | if r := recover(); r != nil { 160 | err = fmt.Errorf("%v", r) 161 | } 162 | }() 163 | 164 | vfunc = strings.TrimSpace(vfunc) 165 | start := strings.Index(vfunc, "(") 166 | var num int 167 | 168 | // doesn't need parameter valid function 169 | if start == -1 { 170 | if num, err = numIn(vfunc); err != nil { 171 | return 172 | } 173 | if num != 0 { 174 | err = fmt.Errorf("%s require %d parameters", vfunc, num) 175 | return 176 | } 177 | v = ValidFunc{vfunc, []interface{}{key + "." + vfunc}} 178 | return 179 | } 180 | 181 | end := strings.Index(vfunc, ")") 182 | if end == -1 { 183 | err = fmt.Errorf("invalid valid function") 184 | return 185 | } 186 | 187 | name := strings.TrimSpace(vfunc[:start]) 188 | if num, err = numIn(name); err != nil { 189 | return 190 | } 191 | 192 | params := strings.Split(vfunc[start+1:end], ",") 193 | // the num of param must be equal 194 | if num != len(params) { 195 | err = fmt.Errorf("%s require %d parameters", name, num) 196 | return 197 | } 198 | 199 | tParams, err := trim(name, key+"."+name, params) 200 | if err != nil { 201 | return 202 | } 203 | v = ValidFunc{name, tParams} 204 | return 205 | } 206 | 207 | func numIn(name string) (num int, err error) { 208 | fn, ok := funcs[name] 209 | if !ok { 210 | err = fmt.Errorf("doesn't exsits %s valid function", name) 211 | return 212 | } 213 | // sub *Validation obj and key 214 | num = fn.Type().NumIn() - 3 215 | return 216 | } 217 | 218 | func trim(name, key string, s []string) (ts []interface{}, err error) { 219 | ts = make([]interface{}, len(s), len(s)+1) 220 | fn, ok := funcs[name] 221 | if !ok { 222 | err = fmt.Errorf("doesn't exsits %s valid function", name) 223 | return 224 | } 225 | for i := 0; i < len(s); i++ { 226 | var param interface{} 227 | // skip *Validation and obj params 228 | if param, err = parseParam(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { 229 | return 230 | } 231 | ts[i] = param 232 | } 233 | ts = append(ts, key) 234 | return 235 | } 236 | 237 | // modify the parameters's type to adapt the function input parameters' type 238 | func parseParam(t reflect.Type, s string) (i interface{}, err error) { 239 | switch t.Kind() { 240 | case reflect.Int: 241 | i, err = strconv.Atoi(s) 242 | case reflect.Int64: 243 | if wordsize == 32 { 244 | return nil, ErrInt64On32 245 | } 246 | i, err = strconv.ParseInt(s, 10, 64) 247 | case reflect.Int32: 248 | var v int64 249 | v, err = strconv.ParseInt(s, 10, 32) 250 | if err == nil { 251 | i = int32(v) 252 | } 253 | case reflect.Int16: 254 | var v int64 255 | v, err = strconv.ParseInt(s, 10, 16) 256 | if err == nil { 257 | i = int16(v) 258 | } 259 | case reflect.Int8: 260 | var v int64 261 | v, err = strconv.ParseInt(s, 10, 8) 262 | if err == nil { 263 | i = int8(v) 264 | } 265 | case reflect.String: 266 | i = s 267 | case reflect.Ptr: 268 | if t.Elem().String() != "regexp.Regexp" { 269 | err = fmt.Errorf("not support %s", t.Elem().String()) 270 | return 271 | } 272 | i, err = regexp.Compile(s) 273 | default: 274 | err = fmt.Errorf("not support %s", t.Kind().String()) 275 | } 276 | return 277 | } 278 | 279 | func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} { 280 | return append([]interface{}{v, obj}, params...) 281 | } 282 | --------------------------------------------------------------------------------