Skip to content
/ tokit Public

采用go-kit模式封装 专注编写业务逻辑

Notifications You must be signed in to change notification settings

caixos/tokit

Repository files navigation

功能

采用go-kit模式封装 专注编写业务逻辑

流程 步骤

    1 编写controller负责, 请求验证,响应,swagger格式,service中间件调用
    2.handler 由 filter(endpoint)和controller组合形成 
    3.provider中注册handler
    4.server的路由中注册各种handler
    5.支持以下server

内置支持Server

    1 http
    2 grpc
    3 websocket
    4 cronjob
    5 timer
    6 command
    7 redis queue
    8 内部event server
    9 gateway server
    10 mqtt订阅server

举例

    //经过jwt认证后的用户id,和name
	fmt.Println(ctx.Get("request.claim.Id"))
	fmt.Println(ctx.Get("request.claim.Name"))
    //cache使用
    v, _ := cache.Get("aaaaa")
	v := make(map[string]interface{})
	v["aaa"] = "bbb"
	v["ccc"] = "ddd"
	_ = cache.Set("aaaaa", v, 60)
	//日志使用
	ctx.Log.Info("one....")
	ctx.Log.Infof(format,arg...)
	//请求参数
	dto := ctx.Request().(*dto.Request)
	//redis使用
    client := clients.Redis() //从pool中获取一个链接
    defer client.Close()      //延时释放链接,本方法执行完毕时释放
    _, _ = client.Do("SET", "go_key", "value")
    //mysql使用
    user := model.CommUser{Id: id}
    has, _ := clients.DB().Get(&user)
    //event使用
	params := make(map[string]interface{})
	payload := &contracts.Payload{
		Route:  "two", ->接收处理的handler
		Params: params,
	}
	events.Fire(payload)
	//redis queue使用 默认db->1
    msg := make(map[string]interface{})
    msg["aaa"] = "bbb"
    err := queues.Fire(
        "demo1",     ->发送的redis 队列
        "queue_test",  ->侦听队列的server需要处理的路由handler
        msg,
    )
    //远程服务调用,// 为现有php模式而封装
    params:=make(map[string]interface{})
    params["test_rpc_post"] = "test_rpc_post"
    resp := clients.
        Micro("consul_demo").    //服务的名称
        Service("demo.post").    //服务的注册的handler
        Params(params).
        Run()
    该方法会从consul中获取注册的服务,并随机选择一个进行请求,支持grpc和http post
    http post 对应的远端路由为 http:/host+port/demo/post

采用组件:

	github.com/cespare/xxhash
	github.com/coocood/freecache  内存cache	
	github.com/fastly/go-utils 
	github.com/go-kit/kit  //核心组件
	github.com/go-logfmt/logfmt   格式化输出
	
	github.com/go-sql-driver/mysql   mysql
	github.com/go-xorm/xorm          mysql orm
	
	github.com/golang/protobuf      grpc pb协议
	github.com/gomodule/redigo      redis
	github.com/gorilla/mux          http router
	github.com/gorilla/websocket    websocket   
	github.com/jehiah/go-strftime 
	github.com/jonboulle/clockwork  
	github.com/juju/ratelimit       限流endpoint
	github.com/lestrrat/go-envload  
	github.com/lestrrat/go-file-rotatelogs   日志分割
	github.com/lestrrat/go-strftime  
	github.com/rifflock/lfshook             日志hook
	github.com/robfig/cron/v3             cronjob
	github.com/sirupsen/logrus       日志组件
	github.com/tebeka/strftime  
	google.golang.org/grpc           grpc服务
	gopkg.in/check.v1  
    github.com/hashicorp/consul v1.6.1 //  consul http grpc 服务注册,发现
    github.com/hashicorp/consul/api v1.2.0

样例

main

    //如果参数配置了registy,则自动进行consul的服务注册 grpc http 都可
	//例如go run main.go -name=test_service  -registy=127.0.0.1:8500 -server=grpc
	tokit.Provider(&providers.ConsulRegistyProvider{})
    
    //这里注册自己的handler
	tokit.Provider(&provider.ExamProvider{})
	
	//下面的server,根据启动args参数决定
	tokit.Router("grpc",&router.GrpcRouter{})
	tokit.Router("http",&router.HttpRouter{})
	tokit.Router("queue",&router.QueueRouter{})
	tokit.Router("command",&router.CommandRouter{})
	tokit.Router("websocket",&router.WebSocketRouter{})
	tokit.Router("timer",&router.TimerRouter{})
	tokit.Router("cron",&router.CronRouter{})
	
	//内置加载事件服务,无需路由,直接调用  handler
    tokit.Router("event", servers.NewEventCommServer())
	
	tokit.Start()

ExamProvider

	tokit.Handler("one", filters.Limit(&controller.OneController{}))
	tokit.Handler("two", filters.New(&controller.TwoController{}))

OneController 请求,响应,swagger,调用service中间件chain


type OneController struct {
}

//swagger:route GET .....
func (it *OneController) Handle(ctx contract.Context) (interface{}, error) {
    
	chain := services.Chain(
		&service.OneService{},
		&service.TwoService{},
	)
	_ = chain.Handle(ctx)

	ret := &FirstResp{
		Id:       idwork.ID(),
		UserName: ctx.Get("k.a").(string),
	}
	return ret, nil
}

// swagger:parameters .....
type FirstRequest struct {
	Param1 string `json:"param_1"`
	Param2 int    `json:"param_2"`
}

// swagger:response .....
type FirstResp struct {
	Id       string `json:"id"`
	UserName string `json:"user_name"`
}

HttpRouter

	it.Get("/exam/one", tokit.Handler("one"))
	it.Get("/exam/two", tokit.Handler("two"))
	it.Post("/exam/auth", tokit.Handler("auth"))

CronRouter

	it.Route("*/5 * * * * *", tokit.Handler("one"))
	it.Route("*/2 * * * * *", tokit.Handler("two"))

GrpcRouter

	it.Route("Two", tokit.Handler("two"))

RedisService

func (it *RedisService)Handle(ctx contract.Context) error  {
	client := clients.Redis() //从pool中获取一个链接
	defer client.Close()   //延时释放链接,本方法执行完毕时释放
	_, _ = client.Do("SET", "go_key", "value")
	res,_ :=redis.String(client.Do("GET","go_key"))
	exists, _ := redis.Bool(client.Do("EXISTS", "foo"))
	if exists {
		ctx.Log.Info("foo 存在")
	}else{
		_, _ = client.Do("SET", "foo", "value")
		ctx.Log.Info("foo 不存在")

	}
	ctx.Log.Info("redis-go_key 的值:", res)
	return nil
}

SqlService

func (it *SqlService)Handle(ctx contract.Context) error  {
	repo := &repository2.UserRepo{Context: ctx}
	user := repo.FetchId("1189164474851006208")
	ctx.Set("user",user)
	return nil
}

struct validations 由 beego的validations 修改而来 github.com/astaxie/beego/validation

	req := ctx.Get("request")
	st := &dto.TestDto{}
	err := convert.Map2Struct(req, st)
	if err != nil {
		return err
	}
	err = validations.Valid(st)

type TestDto struct {
	Name string `json:"name" valid:"Required;MinSize(1);MaxSize(5)"`
	Age  int    `json:"age" valid:"Required"`
	//Name   string `json:"name" valid:"Required;Match(/^tokit.*/)"` // Name 不能为空并且以 tokit 开头
	////有问题
	//Age    string    `json:"age" valid:"Range(1, 140)"` // 1 <= Age <= 140,超出此范围即为不合法
	//Email  string `json:"email" valid:"Email; MaxSize(100)"` // Email 字段需要符合邮箱格式,并且最大长度不能大于 100 个字符
	//Mobile string `json:"mobile" valid:"Mobile"` // Mobile 必须为正确的手机号
	//IP     string `json:"ip" valid:"IP"` // IP 必须为一个正确的 IPv4 地址
	Desc string `json:"desc" valid:"Required;Custom(CheckDesc)"` //自定义处理
}

//自定义方法
func (it *TestDto) CheckDesc(v *validations.Validation) {
	if strings.Index(it.Desc, "desc") != -1 {
		_ = v.SetError("Desc", "名称里不能含有 desc")
	}
}

//全部通过后最后执行
func (it *TestDto) Finish(v *validations.Validation) {
	if strings.Index(it.Name, "admin") != -1 {
		// 通过 SetError 设置 Name 的错误信息,HasErrors 将会返回 true
		_ = v.SetError("Name", "名称里不能含有 admin")
	}
}


snowflake id生成器

    idwork.ID()

command

    main -cmd="注册的路由" -args="json参数"

request过程

    request
    server
        decode
        route(handler)
            endpoint.....
                controller
                    service ......(并行,串行运行)
        encode
    response

url

    https://goswagger.io