Fetch the repository succeeded.
package frame
import (
"fmt"
"io/ioutil"
"log"
"os"
"runtime/debug"
"strings"
"sync"
"time"
"gitee.com/go-mao/mao/libs/try"
"gitee.com/go-mao/mao/libs/utils"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"xorm.io/core"
"xorm.io/xorm"
)
type Server struct {
once sync.Once
taskIndex int64
app AppInterface
web *WebEngine
ormEngine *xorm.Engine
hook *hookDomain
crontab *crontabDomain //
config *configDomain
logger *logDomain
permission *permissionDomain
}
func NewServer(app AppInterface) *Server {
object := new(Server)
object.app = app
object.web = new(WebEngine)
object.web.eg = gin.New()
object.web.server = object
object.hook = &hookDomain{server: object}
object.permission = &permissionDomain{server: object}
object.config = &configDomain{server: object}
object.crontab = &crontabDomain{server: object}
object.logger = &logDomain{server: object}
object.taskIndex = time.Now().Unix()
object.once = sync.Once{}
return object
}
func (this *Server) TaskLine() *Taskline {
return newTaskline(this, nil)
}
// 启动服务
func (this *Server) Run() {
this.once.Do(func() {
try.Do(this.run, func(e try.Exception) {
log.Println("启动失败:", e.ErrCode(), e.ErrMsg())
})
})
}
// 启动app
func (this *Server) run() {
//初始化目录
this.initDir()
//加载核心配置
this.config.loadConfig(this.app.Config())
//初始化日志
this.logger.init()
//
if RunMode(this.config.RunMode) == RUN_MODE_PRODUCT {
gin.SetMode(gin.ReleaseMode)
}
//初始化数据库
this.initDatabase()
//安装数据库
this.installDatabases()
//异常处理初始化
this.web.Use(func(w *Webline) {
try.Do(func() {
w.Header("MAO-ID", fmt.Sprint(w.index))
this.logger.Debugf("[WEB] %s [%d] %s %s", time.Now().Format("2006-01-02 15:04:05"), w.index, w.Request.Method, w.Request.RequestURI)
w.Next()
}, func(e try.Exception) {
defer recover()
msg := e.ErrMsg()
if strings.Index(msg, "[SQL]") > 0 || e.ErrCode() == CODE_SQL {
msg = "数据库错误"
}
if e.ErrCode() != code_nil {
w.JSON(e.ErrCode(), nil, msg)
}
if e.ErrCode() < CODE_WARN {
stack := debug.Stack()
this.logger.Errorf("[WEB] %s [%d] %s %s %d %s \n%s", time.Now().Format("2006-01-02 15:04:05"), w.index, w.Request.Method, w.Request.RequestURI, e.ErrCode(), e.ErrMsg(), string(stack))
}
w.Abort()
})
})
this.web.Use(this.web.middleMaxConnect())
//应用初始化
this.app.Init(this.web)
//初始化模块
this.initModules()
//如果不启动web服务则直接返回,该配置主要用于测试时使用
if _, ok := this.app.(NoWebInterface); ok {
return
}
//异常处理初始化
listen := this.config.Section("server").Key("listen").String()
this.logger.Info("系统已启动,监听地址", listen)
if err := this.web.Engine().Run(listen); err != nil {
try.Throw(CODE_FATAL, "启动失败", err.Error())
}
}
// 初始化目录
func (this *Server) initDir() {
if err := os.MkdirAll(DIR_CONFIG, 0700); err != nil {
try.Throw(CODE_FATAL, "无法创建config目录", err.Error())
return
}
if err := os.MkdirAll(DIR_RUNTIME, 0700); err != nil {
try.Throw(CODE_FATAL, "无法创建runtime目录", err.Error())
return
}
if err := os.MkdirAll(DIR_LOGS, 0700); err != nil {
try.Throw(CODE_FATAL, "无法创建logs目录", err.Error())
return
}
}
// 初始化数据库,并进行安装尝试
func (this *Server) initDatabase() {
var dbType = "mysql"
var username = this.config.Section("mysql").Key("username").String()
var password = this.config.Section("mysql").Key("password").String()
var host = this.config.Section("mysql").Key("host").String()
var database = this.config.Section("mysql").Key("database").String()
var dbSource = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", username, password, host, database)
//初始化引擎
engine, err := xorm.NewEngine(dbType, dbSource)
if err != nil {
try.Throw(CODE_SQL, "数据库初始失败", err.Error())
return
}
engine.SetMaxOpenConns(500)
engine.SetMapper(new(core.SameMapper))
engine.StoreEngine("InnoDB")
engine.Charset("utf8mb4")
engine.SetTZLocation(time.Local)
engine.EnableSessionID(true)
engine.ShowSQL(true)
this.logger.ShowSQL(true)
engine.SetLogger(this.logger)
if err := engine.Ping(); err != nil {
try.Throw(CODE_SQL, "数据库连接失败", err.Error())
return
}
this.ormEngine = engine
this.logger.Info("数据库更新成功!")
}
// 获取所有模块
func (this *Server) GetModules() []ModuleInterface {
return this.app.Modules()
}
// 获取所有组件
func (this *Server) GetComponents() []ComponentInterface {
modules := this.app.Modules()
comps := make([]ComponentInterface, 0)
for _, item := range modules {
comps = append(comps, item.Components()...)
}
return comps
}
// 安装数据库
func (this *Server) installDatabases() {
lockFile := DIR_RUNTIME + "/install.lock"
if utils.FileExists(lockFile) {
return
}
//app安装执行
if err := this.app.Install(); err != nil {
try.Throw(CODE_SQL, "安装失败", err.Error())
return
}
//模块数据库安装
modules := this.app.Modules()
for _, module := range modules {
this.InstallModule(module)
}
//写入安装文件,避免重复安装
data := time.Now().Format("2006-01-02 15:04:05")
if err := ioutil.WriteFile(lockFile, []byte(data), 0600); err != nil {
try.Throw(CODE_FATAL, "数据库安装锁定失败", err.Error())
}
}
// 任务线包装
func (this *Server) wareTaskline(module ModuleInterface) ModuleInterface {
if taskliner, ok := module.(SetSetTaskLiner); ok {
taskliner.SetTaskline(this.TaskLine())
}
return module
}
// 初始化所有模块
func (this *Server) initModules() {
modules := this.app.Modules()
for _, module := range modules {
this.LoadModule(module)
}
}
// 加载模块路由,定时任务等
func (this *Server) LoadModule(module ModuleInterface) {
this.wareTaskline(module)
this.hook.init(module)
this.crontab.init(module)
this.config.init(module)
this.web.Use(func(w *Webline) {
if !module.Enable() {
w.JSON(CODE_ERROR, nil, "该模块未加载!")
w.Abort()
}
})
module.Init(this.web)
}
// 安装模块的数据库
func (this *Server) InstallModule(module ModuleInterface) {
//模块数据库安装
this.wareTaskline(module)
components := module.Components()
for _, component := range components {
models := make([]any, 0)
for _, model := range component.Models() {
models = append(models, model)
}
if err := this.ormEngine.Sync2(models...); err != nil {
try.Throw(CODE_SQL, module.ModuleName()+"模块"+component.CompName()+"组件数据库安装失败", err.Error())
}
}
module.Install()
}
// 删除模块(待开发)
func (this *Server) RemoveModule() {
}
// 默认异常记录
func (this *Server) defaultCatch(e try.Exception) {
this.logger.Error(e.ErrMsg())
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。