ulern

module
v0.0.0-...-0cb7091 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2021 License: BSD-3-Clause-Clear

README

ulern

介绍

用于开发应用服务的一套基础组件和微框架

软件架构

查阅cto包.

安装教程
  1. go get -u gitee.com/cloudapex/ulern
使用说明-cto
  1. 极简版
import (
	"gitee.com/cloudapex/ulern/cto"
)

func main() {
	cto.Run(nil) 
}
  1. 完整版
import (
	"gitee.com/cloudapex/ulern/cto"
)

func main() {
	cto.Init(nil)
	if err := cto.Work(); err != nil {
		util.Log.Fatal("Start Work error:%q.", err)
	}
	cto.Wait()
}
  1. 服务版
package main

import (
	"flag"
	"fmt"
	"os"

	"gitee.com/cloudapex/ulern/cto"
	"gitee.com/cloudapex/ulern/util"
	"github.com/kardianos/service"
)

const (
	DEF_APP_MAJOR  = 1        // 主版本号
	DEF_APP_MINOR  = 2        // 次版本号
	DEF_APP_REVISE = 11       // 修订版本号
	DEF_APP_NAME   = "server" // 应用名称
	DEF_APP_TITLE  = "权限管理服务" // 应用显示名称
)

var logConf util.LogConf
var ver = fmt.Sprintf("%d.%d.%d", DEF_APP_MAJOR, DEF_APP_MINOR, DEF_APP_REVISE)

func init() {
	flag.IntVar((*int)(&logConf.Level), "logLv", int(util.ELL_Debug), "Main logger level[1:LL_DEBUG]")
	flag.IntVar((*int)(&logConf.OutMode), "logMode", int(util.ELM_Std|util.ELM_File), "Main logger outMode[std|file]")
	flag.StringVar(&logConf.DirName, "logDir", "./logs", "Main log dir name[logs]")
	flag.StringVar(&logConf.FileName, "logFile", "", "Main log file name[same as exe]")
	flag.StringVar(&logConf.FileSuffix, "logSuffix", "", "Main log file suffix[log]")
}

type program struct{}

func (p *program) Init() bool {
	if len(os.Args) > 1 && (os.Args[1] == "-I" || os.Args[1] == "-U" || os.Args[1] == "-S") {
		svcConfig := &service.Config{
			Name:        DEF_APP_NAME,                                                           //服务显示名称
			DisplayName: DEF_APP_TITLE,                                                          //服务名称
			Description: fmt.Sprintf("This is an YuXue %s server of Go service.", DEF_APP_NAME), //服务描述
			Arguments:   []string{"-S", "-logLv=2", "-logMode=2"},
		}

		s, err := service.New(&program{}, svcConfig)
		if err != nil {
			util.Print("err:%v", err)
			return false
		}

		switch os.Args[1] {
		case "-I":
			if err = s.Install(); err != nil {
				util.Print("Service Installation err:%v.", err)
			} else {
				util.Print("Service Installation successful.")
			}
		case "-U":
			if err = s.Uninstall(); err != nil {
				util.Print("Service Installation err:%v.", err)
			} else {
				util.Print("Service uninstallation successful.")
			}
		case "-S":
			if err = s.Run(); err != nil {
				util.Print("Service Run err:%v", err)
			}
		}
		return false
	}
	return true
}
func (p *program) Start(s service.Service) error {
	go p.Work()
	return nil
}
func (p *program) Stop(s service.Service) error {
	util.Quit()
	return nil
}
func (p *program) Work() {
	cto.Init(&logConf)

	cto.Report(util.ELL_Error, nil)

	defer func() { util.Catch("Main", recover(), true) }()

	if err := cto.Work(); err != nil {
		util.Log.Fatal("Start Work error:%q.", err)
	}

	cto.Wait()
}

func main() {
	if prg := (&program{}); prg.Init() {
		prg.Work()
	}
}
使用说明-etc
  1. Etcd控制器初始化

    1. 使用默认控制器
    // 在 cto.Work() 之前 安装 etc 控制器 (连接默认是阻塞的)
    etc.Install("MC_A1_etc", &clientv3.Config{Endpoints: []string{"127.0.0.1:2179"}})
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用扩展的默认控制器
    // 1 定义
    var theEtcd MyEtcd // 声明你的变量
    
    type MyEtcd struct { // 继承 etc
    	etc.Etcd
    }
    
    func (this *MyEtcd) HandleEtcd() *etc.Etcd { return &this.Etcd }// 必须实现
    
    func (this *MyEtcd) HandleInit() { this.Etcd.HandleInit() } // override
    func (this *MyEtcd) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    etc.InstallExt("MC_A2_etc", &theEtcd, &clientv3.Config{Endpoints: []string{"127.0.0.1:2179"}})
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    util.Println(theEtcd.Get("/someKey"))
    
    1. 使用自定义的控制器
    // 使用 cto 进行安装自定义控制器
    etc = cto.Install(ctrlName, &CustomEtcd{}).(*CustomEtcd)
    // 自定义后, etc包里面的接口则无法直接使用
    
  2. Etcd管理类

    1. 配置类
    // 定义自己的配置结构对象
    var myConf MyConf
    
    func init() {
    	etc.Preload("myconf", &myConf)
    }
    
    type MyConf struct {
    	IntVal    int    `json:"int"`
    	StringVal string `json:"string"`
    }
    
    // 配置名称
    func (this *MyConf) HandleKey() string { return "/someKey" }
    
    // 配置加载
    func (this *MyConf) HandleInit(val []byte) error {
    	return json.Unmarshal(val, this)
    }
    
    // 配置内容
    func (this *MyConf) HandleContent() string {
    	return fmt.Sprintf("%+v", this)
    }
    
    // 配置热加载[自行保证线程安全,当不需要热加载时可以返回 ErrUnwantReload]
    func (this *MyConf) HandleReload(e etc.EWatchEvent, val []byte) error {
    	switch e {
    	case etc.EWatch_Update: // reload
    		util.Debug("HandleReload e=%v val=%s", e, val)
    	case etc.EWatch_Delete: // clear
    	}
    	return nil
    }
    
    1. 自由类
    type CustEtc struct {
    Val int
    }
    
    func (this *CustEtc) Key() etc.Key { return etc.Key{"/cust_key"} }
    
    func (this *CustEtc) SomeFun() {
    	this.Key().Set(fmt.Sprintf("%d", this.Val))
    }
    
    
    1. 分布式锁
    locker, err := etc.NewLocker("cust_locker")
    if err != nil {
    	util.Log.Fatalv(err)
    }
    locker.Lock()
    defer locker.Unlock()
    
使用说明-setting
  1. Setting控制器初始化

    1. 使用默认控制器
    // 在 cto.Work() 之前 安装 Setting 控制器
    Stt:=etc.Install("MC_B1_Setting")
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用扩展的默认控制器
    // 1 定义
    var Stt MySetting // 声明你的变量
    
    type MySetting struct { // 继承 setting
    	setting.Setting 
    }
    
    func (this *MySetting) HandleSetting() *setting.Setting { return &this.Setting }// 必须实现
    
    func (this *MySetting) HandleInit() { this.Setting.HandleInit() } // override
    func (this *MySetting) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    etc.InstallExt("MC_B2_Setting", &Stt)
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
  2. Setting管理类

// 管理结构
type DBSetting struct {
	DBHost string `json:"dbHost"`
	DBPort uint32 `json:"dbPort"`
	DBName string `json:"dbName"`
	DBUser string `json:"dbUser"`
	DBPass string `json:"dbPass"`
}

//------------------------------------------------------------------------------
var DB *dbConf
// 预加载
func init() { DB = cto.Preload("MT_DB", &dbConf{}).(*dbConf) }

type dbConf struct {
	mutx sync.Mutex
	main *mainDB
}
type mainDB struct {
	ShowSQL bool `json:"showSql"`

	MDBs []DBSetting  `json:"mdbs"`
	RDBs []rds.Config `json:"rdbs"`
}

func (this *dbConf) HandleInit() error {
	this.main = &mainDB{}
	data, err := ioutil.ReadFile(this.HandlePath())
	if err != nil {
		return err
	}
	return json.Unmarshal(data, this.main)
}
func (this *dbConf) HandlePath() string { return util.ExePathJoin("confs/db.json") }

func (this *dbConf) HandleContent() string {
	b, err := json.MarshalIndent(this.main, "", "\t")
	if err != nil {
		return err.Error()
	}
	return string(b)
}
func (this *dbConf) HandleReload() error {
	data, err := ioutil.ReadFile(this.HandlePath())
	if err != nil {
		return err
	}

	temp := &mainDB{}
	if err := json.Unmarshal(data, temp); err != nil {
		return err
	}
	defer util.UnLock(util.Lock(&this.mutx))
	// update some fields
	return cto.ErrSettingNotNeed
}

//------------------------------------------------------------------------------
//================================开放方法=======================================
//------------------------------------------------------------------------------
func (this *dbConf) Stg() *mainDB {
	defer util.UnLock(util.Lock(&this.mutx))
	return this.main
}
使用说明-rds
  1. Redis控制器初始化

    1. 使用默认控制器
    // 安装控制器
    rds.Install("MC_C1_Rds", &rds.Config{
    	Name: "cache", Addr: "192.168.3.39:6379", DbIdx: 11,
    })
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    // 测试命令接口
    rds.Command("cache", "", "set", "cloud_key", "cloud_value")
    util.Println(rds.Command("cache", "", "get", "cloud_key").String())
    
    1. 使用扩展的默认控制器
    // 1 定义
    var Rds MyRedis // 声明你的变量
    
    type MyRedis struct { // 继承 rds
    	rds.Redis 
    }
    
    func (this *MyRedis) HandleRedis() *rds.Redis { return &this.Redis }// 必须实现
    
    func (this *MyRedis) HandleInit() { this.Redis.HandleInit() } // override
    func (this *MyRedis) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    etc.InstallExt("MC_C2_Rds", &rds.Config{
    	Name: "black", Addr: "192.168.3.39:6379", DbIdx: 10,
    })
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    // 测试命令接口
    rds.Command("cache", "", "set", "cloud_key", "cloud_value")
    util.Println(rds.Command("cache", "", "get", "cloud_key").String())
    
  2. rds管理类

    1. Key类型
    type CustEtc struct {
    	Val int
    }
    
    func (this *CustEtc) Key() etc.Key { return etc.Key{"/cust_key"} }
    
    func (this *CustEtc) SomeFun() {
    	this.Key().Set(fmt.Sprintf("%d", this.Val))
    }
    
    type CustRds struct {
    	UserId int
    }
    
    func (this *CustRds) Key() rds.String {
    	return rds.String{rds.Key{
    		"cache", fmt.Sprintf("user_score_%d", this.UserId), rds.DEF_CODING_JSON}}
    }
    
    func (this *CustRds) SomeFun() {
    	this.Key().Set(100, 10)
    	n, _ := this.Key().Get().Int()
    	util.Println("CustRds Get ", n)
    }
    
    1. 分布式锁
    locker, err := rds.NewMutex("dbname","cust_locker")
    if err != nil {
    	util.Log.Fatalv(err)
    }
    locker.Lock()
    defer locker.Unlock()
    
使用说明-que
  1. Consum控制器初始化
    1. 使用默认控制器
    que.Install("MC_Q1_Consum", &que.ConnConf{LookupHAddr: ":4161"})
    
    1. 使用扩展的默认控制器
    // 定义
    var theConsum MyConsum // 声明你的变量
    
    type MyConsum struct { // 继承 etc
    	que.Consum
    }
    
    func (this *MyConsum) HandleConsum() *que.Consum { return &this.Consum }// 必须实现
    
    func (this *MyConsum) HandleInit() { this.Consum.HandleInit() } // override
    func (this *MyConsum) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    que.InstallExt("MC_Q2_Consum", &que.ConnConf{LookupHAddr: ":4161"})
    
    1. 使用自定义的控制器
    que包里的全局方法则不能使用
    
  2. 消费者使用
// 定义自己的消费对象(当某主题不存在时,会报错err 忽视即可)
func init() {
	que.PreStart("MyConsumer", &MyConsumer{}) // 预创建自己的对象
}

type MyConsumer struct {
	IntVal    int    `json:"int"`
	StringVal string `json:"string"`
}

func (this *MyConsumer) HandleParam() que.CParam { // 指定参数
	return que.CParam{"que_topic_server#ephemeral", "que_server_channel", 2, 10}
}

func (this *MyConsumer) HandleMessage(msg *que.Msg) error { // 处理消息
	buf, _ := json.Marshal(msg)
	util.Print("%q", buf)
	return nil
}

// 安装控制器
que.Install("MC_Q1_Consum", &que.ConnConf{LookupHAddr: ":4161"})
if err := cto.Work(); err != nil {
	util.Log.Fatal("Start Work error:%q.", err)
}
for i := 0; i < 10; i++ {
	time.Sleep(1 * time.Second)
	que.Publish(":4150", "que_topic_server#ephemeral", fmt.Sprintf("hello cloud %d", i))
}
  1. 生产者使用
    1. API版
      • que.Publish(addr,topic,message)
    2. OOP版
    // 定义自己的结构
    type Prod struct {
    	Message interface{} // 定义自己的消息
    }
    
    func (this *Prod) To() que.To { // 填充属性
    	return que.To{"addr", "topic"}
    }
    func (this *Prod) Publish() { this.To().Publish(this.Message) } // 封装自己的发送接口
    
    
使用说明-mem
  1. 存储器管理

开箱即用(不需要初始化与安装操作).

mem.GetMem("speed") // 会自动创建Mem
mem.AddMem("speed",nil) // 手动创建Mem
  1. 存储对象
    1. 直接使用
    (mem.Key{"speed","someKey"}).Get/Set/Delete ... 
    
    1. 封装自有结构
    type MemObj struct {
    	*Obj
    }
    func (this *MemObj) Key() mem.Key {return mem.Key{"speed","someKey"}}
    func (this *MemObj) SomeFun(){
    	this.Obj = this.Key().Get().(*Obj) // 自行转换
    }
    
使用说明-htp
  1. Htp控制器初始化

    1. 使用默认控制器
    // 在 cto.Work() 之前 安装 Htp 控制器
    htp.Install("MC_S1_Server", &htp.Config{RunMode: "debug", ListenAddr: ":1234"})
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用扩展的默认控制器
    // 1 定义
    var Htp MyHtp // 声明你的变量
    
    type MyHtp struct { // 继承 htp
    	htp.Htp 
    }
    
    func (this *MyHtp) HandleHtp() *htp.Htp { return &this.Htp }// 必须实现
    
    func (this *MyHtp) HandleInit() { this.Htp.HandleInit() } // override
    func (this *MyHtp) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    htp.InstallExt("MC_S2_Server", &Htp, &htp.Config{RunMode: "debug", ListenAddr: ":1234"})
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用自定义的控制器[不建议]
  2. API对象使用



func init() {
	htp.Preregist("assist", &Assist{})
}

type Assist struct {
}

func (a Assist) HandleInit(r *gin.Engine) {
	r.GET("hello", func(c *gin.Context) { c.String(200, "apex") })
	r.GET("list", func(c *gin.Context) { htp.Service(c, &List{}) })
}
// curl http://127.0.0.1:1234/hello => apex


type List struct {
	Param int64 `form:"param" json:"param" binding:"required"`  // 必传
	Page  int64 `form:"page" json:"page" binding:"omitempty"`   // 页码
	Pnum  int64 `form:"pnum" json:"pnum" binding:"omitempty"`   // 单页数量
	Total int64 `form:"total" json:"total" binding:"omitempty"` // 总数
	Order int64 `form:"order" json:"order" binding:"omitempty"` // 排序字段(默认空,则程序用默认字段)
	Orule int64 `form:"orule" json:"orule" binding:"omitempty"` // 1:倒叙; 2:升序;
}

func (this *List) Handle(c *gin.Context, ctx context.Context) htp.Response {
	// user := mod.CurrUser(c)

	if this.Param != 5 {
		return htp.RespModelErr("", errors.New("this.Param != 5"))
	}
	return htp.RespOK("", &struct {
		Total int64       `json:"total"`
		List  interface{} `json:"list"`
	}{10, []int{1, 2, 3, 4, 5}})
}
使用说明-rpc
  1. GServer控制器初始化

    1. 使用默认控制器
    // 在 cto.Work() 之前 安装 GServer 控制器
    GSer=rpc.Install("MC_G1_Server", &rpc.ConfigSer{RunMode: "debug", ListenAddr: ":1234"})
    GSer.SetTokenInfoer((*TokenInfo)(nil)) // 把自己的类型设置进去(可选).
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用扩展控制器
    // 1 定义
    var GSer MyServer // 声明你的变量
    
    type GSer struct { // 继承 GServer
    	rpc.GServer 
    }
    
    func (this *GSer) HandleSer() *rpc.GServer { return &this.GServer }// 必须实现
    
    func (this *GSer) HandleInit() { this.GServer.HandleInit() } // override
    func (this *GSer) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    rpc.InstallExt("MC_G2_Server", &GSer, &rpc.ConfigSer{RunMode: "debug", ListenAddr: ":1234"})
    GSer.SetTokenInfoer((*TokenInfo)(nil)) // 把自己的类型设置进去(可选).
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用自定义的控制器[不建议]
  2. GServer注册service

func init(){
	// 把自己的服务注册进去
	GSer.Register(func(gs *grpc.Server){ gpb.RegisterLoginServer(gs, login.GServer()) })
	GSer.Register(func(gs *grpc.Server){ gpb.RegisterxxxxxServer(gs, xxxxx.GServer()) })
	// ...
}
  1. GClient控制器初始化

    1. 使用默认控制器
    // 在 cto.Work() 之前 安装 GClient 控制器
    rpc.RegisterResolver("your_scheme")// 使用etcd做服务发现
    rpc.Install("MC_G1_Client", &rpc.ConfigCli{RunMode: "debug", ListenAddr: ":1234"})
    
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用扩展控制器
    // 1 定义
    var GCli MyClient // 声明你的变量
    
    type GCli struct { // 继承 GClient
    	rpc.GClient 
    }
    
    func (this *GCli) HandleSer() *rpc.GClient { return &this.GClient }// 必须实现
    func (this *GCli) HandleInit() { this.GClient.HandleInit() } // override
    func (this *GCli) CustomFunc() {}                         // 扩展你的功能
    
    // 2 使用
    rpc.InstallExt("MC_G2_Client", &GCli, &rpc.ConfigCli{RunMode: "debug", ListenAddr: ":1234"})
    if err := cto.Work(); err != nil {
    	util.Log.Fatal("Start Work error:%q.", err)
    }
    
    1. 使用自定义的控制器[不建议]
  2. GClient注册Client

func init(){
	// 把自己的客户端结构注册进去
	GCli.Register("connName",func(cc *grpc.ClientConn){ Hello.cli = gpb.NewHelloClient(cc) })
	GCli.Register("connName",func(cc *grpc.ClientConn){ Xxxxx.cli = gpb.NewXxxxxClient(cc) })
	// ...
	Hello.cli.SomeFunc(...) // 调用远程方法.
}
参与贡献
  1. Fork 本仓库
  2. 新建 Feat_xxx 分支
  3. 提交代码
  4. 新建 Pull Request
码云特技
  1. 使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
  2. 码云官方博客 blog.gitee.com
  3. 你可以 https://gitee.com/explore 这个地址来了解码云上的优秀开源项目
  4. GVP 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
  5. 码云官方提供的使用手册 https://gitee.com/help
  6. 码云封面人物是一档用来展示码云会员风采的栏目 https://gitee.com/gitee-stars/

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL