diff --git a/base/cache/cache.go b/base/cache/cache.go new file mode 100644 index 00000000..c87635e2 --- /dev/null +++ b/base/cache/cache.go @@ -0,0 +1,25 @@ +package cache + +type Cache interface { + // 添加缓存,如果缓存则返回错误 + Add(k string, v interface{}) error + + // 如果不存在则添加缓存值,否则直接返回 + AddIfAbsent(k string, v interface{}) + + // 如果存在则直接返回,否则调用getValue回调函数获取值并添加该缓存值 + // @return 缓存值 + ComputeIfAbsent(k string, getValueFunc func(string) (interface{}, error)) (interface{}, error) + + // 获取缓存值,参数1为值,参数2->是否存在该缓存 + Get(k string) (interface{}, bool) + + // 缓存数量 + Count() int + + // 删除缓存 + Delete(k string) + + // 清空所有缓存 + Clear() +} diff --git a/base/cache/timed_cache.go b/base/cache/timed_cache.go new file mode 100644 index 00000000..7f50c7ea --- /dev/null +++ b/base/cache/timed_cache.go @@ -0,0 +1,426 @@ +package cache + +import ( + "encoding/gob" + "fmt" + "io" + "os" + "sync" + "time" +) + +type Item struct { + Value interface{} // 对象 + Expiration int64 // 缓存有效时间 + UseCount int64 // 使用次数 + AccessTime int64 // 访问时间 +} + +// 是否过期 +func (item Item) Expired() bool { + if item.Expiration == 0 { + return false + } + return time.Now().UnixNano() > item.AccessTime+item.Expiration +} + +// 是否过期 +// @return 值 and 是否过期 +func (item *Item) GetValue(updateAccessTime bool) (interface{}, bool) { + isExpired := item.Expired() + // 更新最后访问时间,用于增加值的有效期 + if !isExpired && updateAccessTime { + item.AccessTime = time.Now().UnixNano() + } + item.UseCount = item.UseCount + 1 + return item.Value, isExpired +} + +const ( + // 无过期时间 + NoExpiration time.Duration = -1 + // 默认过期时间 + DefaultExpiration time.Duration = 0 + // 默认清理缓存时间差 + DefaultCleanupInterval = 10 +) + +type TimedCache struct { + *timedcache +} + +type timedcache struct { + defaultExpiration time.Duration + updateAccessTime bool // 是否更新最后访问时间 + items map[string]*Item + mu sync.RWMutex + onEvicted func(string, interface{}) // 移除时回调函数 + janitor *janitor +} + +// Add an item to the cache only if an item doesn't already exist for the given +// key, or if the existing item has expired. Returns an error otherwise. +func (c *timedcache) Add(k string, x interface{}, d time.Duration) error { + c.mu.Lock() + defer c.mu.Unlock() + _, found := c.get(k) + if found { + return fmt.Errorf("Item %s already exists", k) + } + c.set(k, x, d) + return nil +} + +func (c *timedcache) AddIfAbsent(k string, x interface{}) { + c.mu.Lock() + defer c.mu.Unlock() + _, found := c.get(k) + if found { + return + } + c.set(k, x, c.defaultExpiration) +} + +func (c *timedcache) ComputeIfAbsent(k string, getValueFunc func(string) (interface{}, error)) (interface{}, error) { + c.mu.Lock() + defer c.mu.Unlock() + value, found := c.get(k) + if found { + return value, nil + } + value, err := getValueFunc(k) + if err != nil { + return nil, err + } + + c.set(k, value, c.defaultExpiration) + return value, nil +} + +func (c *timedcache) set(k string, x interface{}, d time.Duration) { + var e int64 + if d == DefaultExpiration { + d = c.defaultExpiration + } + if d > 0 { + e = d.Nanoseconds() + } + c.items[k] = &Item{ + Value: x, + Expiration: e, + AccessTime: time.Now().UnixNano(), + } +} + +// Get an item from the cache. Returns the item or nil, and a bool indicating +// whether the key was found. +func (c *timedcache) Get(k string) (interface{}, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + return c.get(k) +} + +func (c *timedcache) get(k string) (interface{}, bool) { + item, found := c.items[k] + if !found { + return nil, false + } + + value, expired := item.GetValue(c.updateAccessTime) + if expired { + // c.Delete(k) + return nil, false + } + return value, true +} + +// Increment an item of type int, int8, int16, int32, int64, uintptr, uint, +// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the +// item's value is not an integer, if it was not found, or if it is not +// possible to increment it by n. To retrieve the incremented value, use one +// of the specialized methods, e.g. IncrementInt64. +func (c *timedcache) Increment(k string, n int64) error { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return fmt.Errorf("Item %s not found", k) + } + switch v.Value.(type) { + case int: + v.Value = v.Value.(int) + int(n) + case int8: + v.Value = v.Value.(int8) + int8(n) + case int16: + v.Value = v.Value.(int16) + int16(n) + case int32: + v.Value = v.Value.(int32) + int32(n) + case int64: + v.Value = v.Value.(int64) + n + case uint: + v.Value = v.Value.(uint) + uint(n) + case uintptr: + v.Value = v.Value.(uintptr) + uintptr(n) + case uint8: + v.Value = v.Value.(uint8) + uint8(n) + case uint16: + v.Value = v.Value.(uint16) + uint16(n) + case uint32: + v.Value = v.Value.(uint32) + uint32(n) + case uint64: + v.Value = v.Value.(uint64) + uint64(n) + case float32: + v.Value = v.Value.(float32) + float32(n) + case float64: + v.Value = v.Value.(float64) + float64(n) + default: + c.mu.Unlock() + return fmt.Errorf("The value for %s is not an integer", k) + } + c.items[k] = v + c.mu.Unlock() + return nil +} + +// Returns the number of items in the cache. This may include items that have +// expired, but have not yet been cleaned up. +func (c *timedcache) Count() int { + c.mu.RLock() + n := len(c.items) + c.mu.RUnlock() + return n +} + +// Copies all unexpired items in the cache into a new map and returns it. +func (c *timedcache) Items() map[string]*Item { + c.mu.RLock() + defer c.mu.RUnlock() + m := make(map[string]*Item, len(c.items)) + now := time.Now().UnixNano() + for k, v := range c.items { + // "Inlining" of Expired + if v.Expiration > 0 { + if now > (v.Expiration + v.AccessTime) { + continue + } + } + m[k] = v + } + return m +} + +// 删除指定key的数据 +func (c *timedcache) Delete(k string) { + c.mu.Lock() + v, evicted := c.delete(k) + c.mu.Unlock() + if evicted { + c.onEvicted(k, v) + } +} + +func (c *timedcache) delete(k string) (interface{}, bool) { + // 如果有移除回调函数,则返回值及是否有删除回调函数用于进行回调处理 + if c.onEvicted != nil { + if v, found := c.items[k]; found { + delete(c.items, k) + return v.Value, true + } + } + delete(c.items, k) + return nil, false +} + +type keyAndValue struct { + key string + value interface{} +} + +// Delete all expired items from the cache. +func (c *timedcache) DeleteExpired() { + var evictedItems []keyAndValue + now := time.Now().UnixNano() + c.mu.Lock() + for k, v := range c.items { + // "Inlining" of expired + if v.Expiration > 0 && now > (v.Expiration+v.AccessTime) { + ov, evicted := c.delete(k) + if evicted { + evictedItems = append(evictedItems, keyAndValue{k, ov}) + } + } + } + c.mu.Unlock() + for _, v := range evictedItems { + c.onEvicted(v.key, v.value) + } +} + +// 清空所有缓存 +func (c *timedcache) Clear() { + c.mu.Lock() + c.items = map[string]*Item{} + c.mu.Unlock() +} + +// Write the cache's items (using Gob) to an io.Writer. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *timedcache) Save(w io.Writer) (err error) { + enc := gob.NewEncoder(w) + defer func() { + if x := recover(); x != nil { + err = fmt.Errorf("Error registering item types with Gob library") + } + }() + c.mu.RLock() + defer c.mu.RUnlock() + for _, v := range c.items { + gob.Register(v.Value) + } + err = enc.Encode(&c.items) + return +} + +// Save the cache's items to the given filename, creating the file if it +// doesn't exist, and overwriting it if it does. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *timedcache) SaveFile(fname string) error { + fp, err := os.Create(fname) + if err != nil { + return err + } + err = c.Save(fp) + if err != nil { + fp.Close() + return err + } + return fp.Close() +} + +// Add (Gob-serialized) cache items from an io.Reader, excluding any items with +// keys that already exist (and haven't expired) in the current cache. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *timedcache) Load(r io.Reader) error { + dec := gob.NewDecoder(r) + items := map[string]*Item{} + err := dec.Decode(&items) + if err == nil { + c.mu.Lock() + defer c.mu.Unlock() + for k, v := range items { + ov, found := c.items[k] + if !found || ov.Expired() { + c.items[k] = v + } + } + } + return err +} + +// Load and add cache items from the given filename, excluding any items with +// keys that already exist in the current cache. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *timedcache) LoadFile(fname string) error { + fp, err := os.Open(fname) + if err != nil { + return err + } + err = c.Load(fp) + if err != nil { + fp.Close() + return err + } + return fp.Close() +} + +type janitor struct { + Interval time.Duration + stop chan bool +} + +func (j *janitor) Run(c *timedcache) { + ticker := time.NewTicker(j.Interval) + for { + select { + case <-ticker.C: + c.DeleteExpired() + case <-j.stop: + ticker.Stop() + return + } + } +} + +func stopJanitor(c *TimedCache) { + c.janitor.stop <- true +} + +func runJanitor(c *timedcache, ci time.Duration) { + j := &janitor{ + Interval: ci, + stop: make(chan bool), + } + c.janitor = j + go j.Run(c) +} + +func newCache(de time.Duration, m map[string]*Item) *timedcache { + if de == 0 { + de = -1 + } + c := &timedcache{ + defaultExpiration: de, + items: m, + } + return c +} + +func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]*Item) *TimedCache { + c := newCache(de, m) + // This trick ensures that the janitor goroutine (which--granted it + // was enabled--is running DeleteExpired on c forever) does not keep + // the returned C object from being garbage collected. When it is + // garbage collected, the finalizer stops the janitor goroutine, after + // which c can be collected. + C := &TimedCache{c} + if ci > 0 { + runJanitor(c, ci) + // runtime.SetFinalizer(C, stopJanitor) + } + return C +} + +// Return a new cache with a given default expiration duration and cleanup +// interval. If the expiration duration is less than one (or NoExpiration), +// the items in the cache never expire (by default), and must be deleted +// manually. If the cleanup interval is less than one, expired items are not +// deleted from the cache before calling c.DeleteExpired(). +func NewTimedCache(defaultExpiration, cleanupInterval time.Duration) *TimedCache { + items := make(map[string]*Item) + return newCacheWithJanitor(defaultExpiration, cleanupInterval, items) +} + +// 调用删除函数时,会回调该剔除函数 +func (c *timedcache) OnEvicted(f func(string, interface{})) *timedcache { + c.mu.Lock() + c.onEvicted = f + c.mu.Unlock() + return c +} + +// 是否更新最后访问时间,是则会更新最后访问时间 +// 即只要在指定缓存时间内都没有访问该缓存,则会失效,反之失效开始时间点为最后访问时间 +func (c *timedcache) WithUpdateAccessTime(update bool) *timedcache { + c.mu.Lock() + c.updateAccessTime = update + c.mu.Unlock() + return c +} diff --git a/base/ctx/log_handler.go b/base/ctx/log_handler.go index bd796adb..7335a284 100644 --- a/base/ctx/log_handler.go +++ b/base/ctx/log_handler.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "mayfly-go/base/biz" - "mayfly-go/base/mlog" + "mayfly-go/base/logger" "mayfly-go/base/utils" "reflect" "runtime/debug" @@ -13,7 +13,7 @@ import ( ) func init() { - log.SetFormatter(new(mlog.LogFormatter)) + log.SetFormatter(new(logger.LogFormatter)) log.SetReportCaller(true) } diff --git a/base/ginx/ginx.go b/base/ginx/ginx.go index aed68662..98e6e3af 100644 --- a/base/ginx/ginx.go +++ b/base/ginx/ginx.go @@ -1,8 +1,9 @@ package ginx import ( + "fmt" "mayfly-go/base/biz" - "mayfly-go/base/mlog" + "mayfly-go/base/global" "mayfly-go/base/model" "net/http" "strconv" @@ -40,6 +41,13 @@ func QueryInt(g *gin.Context, qm string, defaultInt int) int { return qvi } +// 获取路径参数 +func PathParamInt(g *gin.Context, pm string) int { + value, _ := strconv.Atoi(g.Param(pm)) + biz.IsTrue(value != 0, fmt.Sprintf("%s不存在", pm)) + return value +} + // 文件下载 func Download(g *gin.Context, data []byte, filename string) { g.Header("Content-Type", "application/octet-stream") @@ -60,15 +68,15 @@ func ErrorRes(g *gin.Context, err interface{}) { break case error: g.JSON(http.StatusOK, model.ServerError()) - mlog.Log.Error(t) + global.Log.Error(t) // panic(err) break case string: g.JSON(http.StatusOK, model.ServerError()) - mlog.Log.Error(t) + global.Log.Error(t) // panic(err) break default: - mlog.Log.Error(t) + global.Log.Error(t) } } diff --git a/base/global/global.go b/base/global/global.go index cd4c3121..ee6bd001 100644 --- a/base/global/global.go +++ b/base/global/global.go @@ -2,13 +2,13 @@ package global import ( "mayfly-go/base/config" - "mayfly-go/base/mlog" + "mayfly-go/base/logger" "gorm.io/gorm" ) // 日志 -var Log = mlog.Log +var Log = logger.Log // config.yml配置文件映射对象 var Config = config.Conf diff --git a/base/mlog/mlog.go b/base/logger/logger.go similarity index 77% rename from base/mlog/mlog.go rename to base/logger/logger.go index 79ae5802..a123c1b7 100644 --- a/base/mlog/mlog.go +++ b/base/logger/logger.go @@ -1,8 +1,7 @@ -package mlog +package logger import ( "fmt" - "path/filepath" "strings" "time" @@ -17,22 +16,25 @@ func init() { // customFormatter.FullTimestamp = true Log.SetFormatter(new(LogFormatter)) Log.SetReportCaller(true) + Log.SetLevel(logrus.DebugLevel) } type LogFormatter struct{} func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) { timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000") - level := entry.Level logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String())) // 如果存在调用信息,且为error级别以上记录文件及行号 if caller := entry.Caller; caller != nil { var fp string - if level <= logrus.ErrorLevel { - fp = caller.File + // 全路径切割,只获取项目相关路径, + // 即/Users/hml/Desktop/project/go/mayfly-go/server/test.go只获取/server/test.go + ps := strings.Split(caller.File, "mayfly-go/") + if len(ps) >= 2 { + fp = ps[1] } else { - fp = filepath.Base(caller.File) + fp = ps[0] } logMsg = logMsg + fmt.Sprintf(" [%s:%d]", fp, caller.Line) } diff --git a/base/model/model.go b/base/model/model.go index 66491d9c..3e410729 100644 --- a/base/model/model.go +++ b/base/model/model.go @@ -1,11 +1,14 @@ package model import ( + "fmt" "mayfly-go/base/global" "strconv" "strings" "time" + + "gorm.io/gorm" ) type Model struct { @@ -40,6 +43,25 @@ func (m *Model) SetBaseInfo(account *LoginAccount) { m.ModifierId = id } +func Tx(funcs ...func(db *gorm.DB) error) (err error) { + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + err = fmt.Errorf("%v", err) + } + }() + for _, f := range funcs { + err = f(tx) + if err != nil { + tx.Rollback() + return + } + } + err = tx.Commit().Error + return +} + // 根据id获取实体对象。model需为指针类型(需要将查询出来的值赋值给model) // // 若error不为nil则为不存在该记录 @@ -47,6 +69,33 @@ func GetById(model interface{}, id uint64, cols ...string) error { return global.Db.Select(cols).Where("id = ?", id).First(model).Error } +// 根据id列表查询 +func GetByIdIn(model interface{}, list interface{}, ids []uint64, orderBy ...string) { + var idsStr string + for i, v := range ids { + idStr := strconv.Itoa(int(v)) + if i == 0 { + idsStr += idStr + } else { + idsStr += ("," + idStr) + } + } + var orderByStr string + if orderBy == nil { + orderByStr = "id desc" + } else { + orderByStr = strings.Join(orderBy, ",") + } + global.Db.Model(model).Where("id in (?)", idsStr).Order(orderByStr).Find(list) +} + +// 根据id列表查询 +func CountBy(model interface{}) int64 { + var count int64 + global.Db.Model(model).Where(model).Count(&count) + return count +} + // 根据id更新model,更新字段为model中不为空的值,即int类型不为0,ptr类型不为nil这类字段值 func UpdateById(model interface{}) error { return global.Db.Model(model).Updates(model).Error @@ -57,6 +106,11 @@ func DeleteById(model interface{}, id uint64) error { return global.Db.Delete(model, "id = ?", id).Error } +// 根据条件删除 +func DeleteByCondition(model interface{}) error { + return global.Db.Where(model).Delete(model).Error +} + // 插入model func Insert(model interface{}) error { return global.Db.Create(model).Error @@ -64,11 +118,24 @@ func Insert(model interface{}) error { // 获取满足model中不为空的字段值条件的所有数据. // -// @param list为数组类型 如 var users []*User,可指定为非model结构体,即只包含需要返回的字段结构体 +// @param list为数组类型 如 var users *[]User,可指定为非model结构体,即只包含需要返回的字段结构体 func ListBy(model interface{}, list interface{}, cols ...string) { global.Db.Model(model).Select(cols).Where(model).Find(list) } +// 获取满足model中不为空的字段值条件的所有数据. +// +// @param list为数组类型 如 var users *[]User,可指定为非model结构体 +func ListByOrder(model interface{}, list interface{}, order ...string) { + var orderByStr string + if order == nil { + orderByStr = "id desc" + } else { + orderByStr = strings.Join(order, ",") + } + global.Db.Model(model).Where(model).Order(orderByStr).Find(list) +} + // 获取满足model中不为空的字段值条件的单个对象。model需为指针类型(需要将查询出来的值赋值给model) // // 若 error不为nil,则为不存在该记录 @@ -126,3 +193,7 @@ func GetListBySql(sql string, params ...interface{}) []map[string]interface{} { global.Db.Raw(sql, params).Scan(&maps) return maps } + +func GetListBySql2Model(sql string, toEntity interface{}, params ...interface{}) { + global.Db.Raw(sql, params).Find(toEntity) +} diff --git a/base/utils/array_utils.go b/base/utils/array_utils.go new file mode 100644 index 00000000..b3c8e976 --- /dev/null +++ b/base/utils/array_utils.go @@ -0,0 +1,33 @@ +package utils + +// 数组比较 +// 依次返回,新增值,删除值,以及不变值 +func ArrayCompare(newArr []interface{}, oldArr []interface{}, compareFun func(interface{}, interface{}) bool) ([]interface{}, []interface{}, []interface{}) { + var unmodifierValue []interface{} + ni, oi := 0, 0 + for { + if ni >= len(newArr) { + break + } + nv := newArr[ni] + for { + if oi >= len(oldArr) { + oi = 0 + break + } + ov := oldArr[oi] + if compareFun(nv, ov) { + unmodifierValue = append(unmodifierValue, nv) + // 新数组移除该位置值 + newArr = append(newArr[:ni], newArr[ni+1:]...) + oldArr = append(oldArr[:oi], oldArr[oi+1:]...) + ni = ni - 1 + oi = oi - 1 + } + oi = oi + 1 + } + ni = ni + 1 + } + + return newArr, oldArr, unmodifierValue +} diff --git a/base/utils/array_utils_test.go b/base/utils/array_utils_test.go new file mode 100644 index 00000000..8d64d8c5 --- /dev/null +++ b/base/utils/array_utils_test.go @@ -0,0 +1,17 @@ +package utils + +import ( + "fmt" + "testing" +) + +func TestArrayCompare(t *testing.T) { + newArr := []interface{}{1, 2, 3, 5} + oldArr := []interface{}{3, 6} + add, del, unmodifier := ArrayCompare(newArr, oldArr, func(i1, i2 interface{}) bool { + return i1.(int) == i2.(int) + }) + fmt.Println(add...) + fmt.Println(del...) + fmt.Println(unmodifier...) +} diff --git a/base/utils/json_utils.go b/base/utils/json_utils.go new file mode 100644 index 00000000..c158de9c --- /dev/null +++ b/base/utils/json_utils.go @@ -0,0 +1,14 @@ +package utils + +import ( + "encoding/json" +) + +func Json2Map(jsonStr string) map[string]interface{} { + var res map[string]interface{} + if jsonStr == "" { + return res + } + _ = json.Unmarshal([]byte(jsonStr), &res) + return res +} diff --git a/base/utils/tree_utils.go b/base/utils/tree_utils.go new file mode 100644 index 00000000..54df3e23 --- /dev/null +++ b/base/utils/tree_utils.go @@ -0,0 +1,74 @@ +package utils + +// ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口 +type INode interface { + // GetId获取id + GetId() int + // GetPid 获取父id + GetPid() int + // IsRoot 判断当前节点是否是顶层根节点 + IsRoot() bool + + SetChildren(childern interface{}) +} + +type INodes []INode + +func (nodes INodes) Len() int { + return len(nodes) +} +func (nodes INodes) Swap(i, j int) { + nodes[i], nodes[j] = nodes[j], nodes[i] +} +func (nodes INodes) Less(i, j int) bool { + return nodes[i].GetId() < nodes[j].GetId() +} + +// GenerateTree 自定义的结构体实现 INode 接口后调用此方法生成树结构 +// nodes 需要生成树的节点 +// selectedNode 生成树后选中的节点 +// menuTrees 生成成功后的树结构对象 +func GenerateTree(nodes []INode) (trees []INode) { + trees = []INode{} + // 定义顶层根和子节点 + var roots, childs []INode + for _, v := range nodes { + if v.IsRoot() { + // 判断顶层根节点 + roots = append(roots, v) + } + childs = append(childs, v) + } + + for _, v := range roots { + // 递归 + setChildren(v, childs) + trees = append(trees, v) + } + return +} + +// recursiveTree 递归生成树结构 +// tree 递归的树对象 +// nodes 递归的节点 +// selectedNodes 选中的节点 +func setChildren(parent INode, nodes []INode) { + children := []INode{} + for _, v := range nodes { + if v.IsRoot() { + // 如果当前节点是顶层根节点就跳过 + continue + } + if parent.GetId() == v.GetPid() { + children = append(children, v) + } + } + if len(children) == 0 { + return + } + + parent.SetChildren(children) + for _, c := range children { + setChildren(c, nodes) + } +} diff --git a/devops/__debug_bin b/devops/__debug_bin deleted file mode 100755 index ae733d84..00000000 Binary files a/devops/__debug_bin and /dev/null differ diff --git a/devops/apis/account.go b/devops/apis/account.go deleted file mode 100644 index 6a8d9bbc..00000000 --- a/devops/apis/account.go +++ /dev/null @@ -1,33 +0,0 @@ -package apis - -import ( - "mayfly-go/base/biz" - "mayfly-go/base/ctx" - "mayfly-go/base/ginx" - "mayfly-go/devops/apis/form" - "mayfly-go/devops/application" - "mayfly-go/devops/domain/entity" -) - -type Account struct { - AccountApp application.IAccount -} - -// @router /accounts/login [post] -func (a *Account) Login(rc *ctx.ReqCtx) { - loginForm := &form.LoginForm{} - ginx.BindJsonAndValid(rc.GinCtx, loginForm) - rc.ReqParam = loginForm.Username - - account := &entity.Account{Username: loginForm.Username, Password: loginForm.Password} - biz.ErrIsNil(a.AccountApp.GetAccount(account, "Id", "Username", "Password"), "用户名或密码错误") - rc.ResData = map[string]interface{}{ - "token": ctx.CreateToken(account.Id, account.Username), - "username": account.Username, - } -} - -// @router /accounts [get] -func (a *Account) Accounts(rc *ctx.ReqCtx) { - // rc.ResData = models.ListAccount(ginx.GetPageParam(rc.GinCtx)) -} diff --git a/devops/application/account_app.go b/devops/application/account_app.go deleted file mode 100644 index 9c00ede8..00000000 --- a/devops/application/account_app.go +++ /dev/null @@ -1,22 +0,0 @@ -package application - -import ( - "mayfly-go/devops/domain/entity" - "mayfly-go/devops/domain/repository" - "mayfly-go/devops/infrastructure/persistence" -) - -type IAccount interface { - GetAccount(condition *entity.Account, cols ...string) error -} - -type accountApp struct { - accountRepo repository.Account -} - -var Account IAccount = &accountApp{accountRepo: persistence.AccountDao} - -// 根据条件获取账号信息 -func (a *accountApp) GetAccount(condition *entity.Account, cols ...string) error { - return a.accountRepo.GetAccount(condition, cols...) -} diff --git a/devops/devops b/devops/devops deleted file mode 100755 index 0949172a..00000000 Binary files a/devops/devops and /dev/null differ diff --git a/devops/domain/entity/account.go b/devops/domain/entity/account.go deleted file mode 100644 index c934b56f..00000000 --- a/devops/domain/entity/account.go +++ /dev/null @@ -1,13 +0,0 @@ -package entity - -import ( - "mayfly-go/base/model" -) - -type Account struct { - model.Model - - Username string `json:"username"` - Password string `json:"-"` - Status int8 `json:"status"` -} diff --git a/devops/domain/repository/account.go b/devops/domain/repository/account.go deleted file mode 100644 index dc8f3965..00000000 --- a/devops/domain/repository/account.go +++ /dev/null @@ -1,8 +0,0 @@ -package repository - -import "mayfly-go/devops/domain/entity" - -type Account interface { - // 根据条件获取账号信息 - GetAccount(condition *entity.Account, cols ...string) error -} diff --git a/devops/infrastructure/persistence/account_repo.go b/devops/infrastructure/persistence/account_repo.go deleted file mode 100644 index 971e8376..00000000 --- a/devops/infrastructure/persistence/account_repo.go +++ /dev/null @@ -1,15 +0,0 @@ -package persistence - -import ( - "mayfly-go/base/model" - "mayfly-go/devops/domain/entity" - "mayfly-go/devops/domain/repository" -) - -type accountRepo struct{} - -var AccountDao repository.Account = &accountRepo{} - -func (a *accountRepo) GetAccount(condition *entity.Account, cols ...string) error { - return model.GetBy(condition, cols...) -} diff --git a/devops/infrastructure/scheudler/mytask.go b/devops/infrastructure/scheudler/mytask.go deleted file mode 100644 index 3234ce2c..00000000 --- a/devops/infrastructure/scheudler/mytask.go +++ /dev/null @@ -1,35 +0,0 @@ -package scheduler - -import ( - "mayfly-go/base/mlog" - "mayfly-go/base/model" - "mayfly-go/base/utils" - "mayfly-go/devops/machine" - "mayfly-go/devops/models" -) - -func init() { - SaveMachineMonitor() -} - -func SaveMachineMonitor() { - AddFun("@every 60s", func() { - for _, m := range models.GetNeedMonitorMachine() { - m := m - go func() { - cli, err := machine.GetCli(uint64(utils.GetInt4Map(m, "id"))) - if err != nil { - mlog.Log.Error("获取客户端失败:", err.Error()) - return - } - mm := cli.GetMonitorInfo() - if mm != nil { - err := model.Insert(mm) - if err != nil { - mlog.Log.Error("保存机器监控信息失败: ", err.Error()) - } - } - }() - } - }) -} diff --git a/devops/lastupdate.tmp b/devops/lastupdate.tmp deleted file mode 100755 index 55235d7c..00000000 --- a/devops/lastupdate.tmp +++ /dev/null @@ -1 +0,0 @@ -{"/Users/hml/Desktop/project/go/mayfly-go/devops/controllers":1616491109228810023} \ No newline at end of file diff --git a/devops/routers/account.go b/devops/routers/account.go deleted file mode 100644 index c7111561..00000000 --- a/devops/routers/account.go +++ /dev/null @@ -1,26 +0,0 @@ -package routers - -import ( - "mayfly-go/base/ctx" - "mayfly-go/devops/apis" - "mayfly-go/devops/application" - - "github.com/gin-gonic/gin" -) - -func InitAccountRouter(router *gin.RouterGroup) { - account := router.Group("accounts") - a := &apis.Account{AccountApp: application.Account} - { - // 用户登录 - account.POST("login", func(g *gin.Context) { - rc := ctx.NewReqCtxWithGin(g).WithNeedToken(false).WithLog(ctx.NewLogInfo("用户登录")) - rc.Handle(a.Login) - }) - // 获取所有用户列表 - account.GET("", func(c *gin.Context) { - rc := ctx.NewReqCtxWithGin(c).WithLog(ctx.NewLogInfo("获取账号列表")) - rc.Handle(a.Accounts) - }) - } -} diff --git a/devops/static/favicon.ico b/devops/static/favicon.ico deleted file mode 100644 index df36fcfb..00000000 Binary files a/devops/static/favicon.ico and /dev/null differ diff --git a/devops/static/index.html b/devops/static/index.html deleted file mode 100644 index f69340af..00000000 --- a/devops/static/index.html +++ /dev/null @@ -1 +0,0 @@ -
=r)return 0;if(128!=(192&(_=e[l++]))){l--,h=!0;break}this.interim[f++]=_,u<<=6,u|=63&_}h||(2===d?u<128?l--:t[a++]=u:3===d?u<2048||u>=55296&&u<=57343||65279===u||(t[a++]=u):u<65536||u>1114111||(t[a++]=u)),this.interim.fill(0)}for(var v=r-4,g=l;gn)return NaN;return parseInt(o,i)}return+l};if(o(g,!y(" 0o1")||!y("0b1")||y("+0x1"))){for(var C,w=function(e){var t=arguments.length<1?0:e,r=this;return r instanceof w&&(S?u((function(){b.valueOf.call(r)})):c(r)!=g)?l(new y(m(t)),r,w):m(t)},E=i?_(y):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,fromString,range".split(","),L=0;E.length>L;L++)a(y,C=E[L])&&!a(w,C)&&p(w,C,d(y,C));w.prototype=b,b.constructor=w,s(n,g,w)}},"649a":function(e,t,r){"use strict";var i=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"xterm",style:{height:e.height},attrs:{id:"xterm"}})},n=[],o=(r("24a8"),r("16ca"),r("1dee"),r("09ae")),s=r("fef5"),a={name:"Xterm",props:{machineId:Number,cmd:String,height:String},watch:{machineId:function(e){""!==e&&this.initSocket()}},mounted:function(){this.initSocket()},beforeDestroy:function(){this.socket.close(),this.term&&this.term.dispose()},methods:{initXterm:function(){var e=this,t=new o["Terminal"]({fontSize:14,cursorBlink:!0,disableStdin:!1,theme:{foreground:"#000000",background:"#c7edcc",cursor:"help",lineHeight:16}}),r=new s["FitAddon"];t.loadAddon(r),t.open(document.getElementById("xterm")),r.fit(),t.focus(),this.term=t,t.onData((function(t){e.sendCmd(t)})),this.send({type:"resize",Cols:parseInt(t.cols),Rows:parseInt(t.rows)}),this.cmd&&this.sendCmd(this.cmd+" \r")},initSocket:function(){this.socket=new WebSocket("ws://localhost:8888/api/machines/".concat(this.machineId,"/terminal?token=").concat(sessionStorage.getItem("token"))),this.socket.onopen=this.open,this.socket.onerror=this.error,this.socket.onmessage=this.getMessage,this.socket.onsend=this.send},open:function(){console.log("socket连接成功"),this.initXterm()},error:function(){console.log("连接错误"),this.reconnect()},close:function(){this.socket.close(),console.log("socket关闭")},getMessage:function(e){this.term.write(e["data"])},send:function(e){this.socket.send(JSON.stringify(e))},sendCmd:function(e){this.send({type:"cmd",msg:e})},closeAll:function(){this.close(),this.term&&(this.term.dispose(),this.term=null)}}},c=a,l=r("5d22"),h=Object(l["a"])(c,i,n,!1,null,null,null);t["a"]=h.exports},"6a8c":function(e,t){e.exports="\t\n\v\f\r \u2028\u2029\ufeff"},f8d5:function(e,t,r){var i=r("4023"),n=r("6a8c"),o="["+n+"]",s=RegExp("^"+o+o+"*"),a=RegExp(o+o+"*$"),c=function(e){return function(t){var r=String(i(t));return 1&e&&(r=r.replace(s,"")),2&e&&(r=r.replace(a,"")),r}};e.exports={start:c(1),end:c(2),trim:c(3)}},fef5:function(e,t,r){!function(t,r){e.exports=r()}(window,(function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var i=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core,t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),i=Math.max(0,parseInt(t.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),o=r-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),s=i-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(s/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(o/e._renderService.dimensions.actualCellHeight))}}},e}();t.FitAddon=i}])}))}}]);
\ No newline at end of file
diff --git a/devops/static/static/js/chunk-41567cb6.a2584647.js b/devops/static/static/js/chunk-41567cb6.a2584647.js
deleted file mode 100644
index 27d7d837..00000000
--- a/devops/static/static/js/chunk-41567cb6.a2584647.js
+++ /dev/null
@@ -1 +0,0 @@
-(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-41567cb6"],{"4c88":function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"file-manage"},[n("ssh-terminal",{ref:"terminal",attrs:{machineId:e.machineId,height:e.height+"px"}})],1)},c=[],i=n("303e"),r=n("acf6"),o=n("e378"),s=n("a8e5"),h=n("21c9"),u=n("e4a1"),p=n("649a"),l=function(e){Object(o["a"])(n,e);var t=Object(s["a"])(n);function n(){var e;return Object(i["a"])(this,n),e=t.apply(this,arguments),e.machineId="",e.height=700,e}return Object(r["a"])(n,[{key:"created",value:function(){this.height=window.innerHeight,this.machineId=this.$route.params.id}}]),n}(u["c"]);l=Object(h["a"])([Object(u["a"])({name:"ServiceManage",components:{SshTerminal:p["a"]}})],l);var f=l,d=f,m=n("5d22"),b=Object(m["a"])(d,a,c,!1,null,null,null);t["default"]=b.exports},"83d4":function(e,t,n){var a=n("97f5"),c=n("721d");e.exports=function(e,t,n){var i,r;return c&&"function"==typeof(i=t.constructor)&&i!==n&&a(r=i.prototype)&&r!==n.prototype&&c(e,r),e}}}]);
\ No newline at end of file
diff --git a/devops/static/static/js/chunk-4852ffd2.0b916b88.js b/devops/static/static/js/chunk-4852ffd2.0b916b88.js
deleted file mode 100644
index 40084d28..00000000
--- a/devops/static/static/js/chunk-4852ffd2.0b916b88.js
+++ /dev/null
@@ -1 +0,0 @@
-(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4852ffd2"],{"0034":function(e,t,n){var r=n("6136"),i=n("0102");function a(e,t){var n=i(e,t);return r(n)?n:void 0}e.exports=a},"0102":function(e,t){function n(e,t){return null==e?void 0:e[t]}e.exports=n},"0190":function(e,t,n){var r=n("0a96"),i=n("54bf"),a=n("f868"),o=n("943c"),s=n("4de3"),l=n("94ea"),c=Object.prototype,u=c.hasOwnProperty;function d(e,t){var n=a(e),c=!n&&i(e),d=!n&&!c&&o(e),p=!n&&!c&&!d&&l(e),E=n||c||d||p,f=E?r(e.length,String):[],m=f.length;for(var h in e)!t&&!u.call(e,h)||E&&("length"==h||d&&("offset"==h||"parent"==h)||p&&("buffer"==h||"byteLength"==h||"byteOffset"==h)||s(h,m))||f.push(h);return f}e.exports=d},"026b":function(e,t){var n="\\ud800-\\udfff",r="\\u0300-\\u036f",i="\\ufe20-\\ufe2f",a="\\u20d0-\\u20ff",o=r+i+a,s="\\ufe0e\\ufe0f",l="\\u200d",c=RegExp("["+l+n+o+s+"]");function u(e){return c.test(e)}e.exports=u},"0578":function(e,t,n){var r=n("0034"),i=n("82c6"),a=r(i,"Set");e.exports=a},"05a2":function(e,t,n){var r=n("dc9b"),i=n("f868"),a=n("d92c"),o="[object String]";function s(e){return"string"==typeof e||!i(e)&&a(e)&&r(e)==o}e.exports=s},"071d":function(e,t){var n=Function.prototype,r=n.toString;function i(e){if(null!=e){try{return r.call(e)}catch(t){}try{return e+""}catch(t){}}return""}e.exports=i},"07cc":function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t){r(this,e),this.params=t,this.index=0}return e.prototype.get=function(e){var t=e.key,n=e.value;return this.params?t?this.params[t]:this.params[this.index++]:n},e}();t["default"]=i,e.exports=t["default"]},"08ab":function(e,t,n){var r=n("5eff"),i=n("9d34"),a=n("635e"),o=n("ff8d"),s=n("700f"),l=n("346e");function c(e,t,n){if(e=s(e),e&&(n||void 0===t))return e.slice(0,l(e)+1);if(!e||!(t=r(t)))return e;var c=o(e),u=a(c,o(t))+1;return i(c,0,u).join("")}e.exports=c},"0a96":function(e,t){function n(e,t){var n=-1,r=Array(e);while(++n