README ¶
ulern
- ulern - 介绍 - 软件架构 - 安装教程 - 使用说明-cto - 使用说明-etc - 使用说明-setting - 使用说明-rds - 使用说明-que - 使用说明-mem - 使用说明-htp - 使用说明-rpc - 参与贡献 - 码云特技
介绍
用于开发应用服务的一套基础组件和微框架
软件架构
查阅cto包.
安装教程
- go get -u gitee.com/cloudapex/ulern
使用说明-cto
- 极简版
import (
"gitee.com/cloudapex/ulern/cto"
)
func main() {
cto.Run(nil)
}
- 完整版
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()
}
- 服务版
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
-
Etcd控制器初始化
- 使用默认控制器
// 在 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 定义 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"))
- 使用自定义的控制器
// 使用 cto 进行安装自定义控制器 etc = cto.Install(ctrlName, &CustomEtcd{}).(*CustomEtcd) // 自定义后, etc包里面的接口则无法直接使用
-
Etcd管理类
- 配置类
// 定义自己的配置结构对象 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 }
- 自由类
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)) }
- 分布式锁
locker, err := etc.NewLocker("cust_locker") if err != nil { util.Log.Fatalv(err) } locker.Lock() defer locker.Unlock()
使用说明-setting
-
Setting控制器初始化
- 使用默认控制器
// 在 cto.Work() 之前 安装 Setting 控制器 Stt:=etc.Install("MC_B1_Setting") if err := cto.Work(); err != nil { util.Log.Fatal("Start Work error:%q.", err) }
- 使用扩展的默认控制器
// 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) }
-
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
-
Redis控制器初始化
- 使用默认控制器
// 安装控制器 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 定义 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())
-
rds管理类
- 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) }
- 分布式锁
locker, err := rds.NewMutex("dbname","cust_locker") if err != nil { util.Log.Fatalv(err) } locker.Lock() defer locker.Unlock()
使用说明-que
- Consum控制器初始化
- 使用默认控制器
que.Install("MC_Q1_Consum", &que.ConnConf{LookupHAddr: ":4161"})
- 使用扩展的默认控制器
// 定义 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"})
- 使用自定义的控制器
que包里的全局方法则不能使用
- 消费者使用
// 定义自己的消费对象(当某主题不存在时,会报错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))
}
- 生产者使用
- API版
- que.Publish(addr,topic,message)
- 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) } // 封装自己的发送接口
- API版
使用说明-mem
- 存储器管理
开箱即用(不需要初始化与安装操作).
mem.GetMem("speed") // 会自动创建Mem
mem.AddMem("speed",nil) // 手动创建Mem
- 存储对象
- 直接使用
(mem.Key{"speed","someKey"}).Get/Set/Delete ...
- 封装自有结构
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
-
Htp控制器初始化
- 使用默认控制器
// 在 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 定义 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) }
- 使用自定义的控制器[不建议]
-
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
-
GServer控制器初始化
- 使用默认控制器
// 在 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 定义 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) }
- 使用自定义的控制器[不建议]
-
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()) })
// ...
}
-
GClient控制器初始化
- 使用默认控制器
// 在 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 定义 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) }
- 使用自定义的控制器[不建议]
-
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(...) // 调用远程方法.
}
参与贡献
- Fork 本仓库
- 新建 Feat_xxx 分支
- 提交代码
- 新建 Pull Request
码云特技
- 使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
- 码云官方博客 blog.gitee.com
- 你可以 https://gitee.com/explore 这个地址来了解码云上的优秀开源项目
- GVP 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
- 码云官方提供的使用手册 https://gitee.com/help
- 码云封面人物是一档用来展示码云会员风采的栏目 https://gitee.com/gitee-stars/
Click to show internal directories.
Click to hide internal directories.