From aaf75782906771a26d0178cdca12331d356a8775 Mon Sep 17 00:00:00 2001 From: zicla Date: Sun, 28 Apr 2019 01:25:31 +0800 Subject: [PATCH] Finish the Abstract of Config. --- code/core/config.go | 27 +++ code/core/context.go | 6 +- code/core/global.go | 3 + code/rest/base_model.go | 4 +- code/rest/bean.go | 3 +- code/rest/context.go | 220 ------------------ code/rest/dashboard_model.go | 4 +- code/rest/download_token_model.go | 4 +- code/rest/footprint_model.go | 4 +- code/rest/footprint_service.go | 4 +- code/rest/image_cache_model.go | 4 +- code/rest/install_controller.go | 36 +-- code/rest/matter_dao.go | 3 +- code/rest/matter_model.go | 9 +- code/rest/preference_model.go | 4 +- code/rest/session_model.go | 4 +- code/rest/upload_token_model.go | 4 +- code/rest/user_controller.go | 7 +- code/rest/user_model.go | 4 +- code/rest/user_service.go | 5 +- .../config.go => support/tank_config.go} | 81 +++++-- code/support/tank_context.go | 219 +++++++++++++++++ .../router.go => support/tank_router.go} | 31 +-- main.go | 20 +- 24 files changed, 371 insertions(+), 339 deletions(-) create mode 100644 code/core/config.go delete mode 100644 code/rest/context.go rename code/{config/config.go => support/tank_config.go} (70%) rename code/{rest/router.go => support/tank_router.go} (88%) diff --git a/code/core/config.go b/code/core/config.go new file mode 100644 index 0000000..bbbe8b8 --- /dev/null +++ b/code/core/config.go @@ -0,0 +1,27 @@ +package core + +const ( + //用户身份的cookie字段名 + COOKIE_AUTH_KEY = "_ak" + + //数据库表前缀 tank200表示当前应用版本是tank:2.0.x版,数据库结构发生变化必然是中型升级 + TABLE_PREFIX = "tank20_" + + //当前版本 + VERSION = "2.0.0" +) + +type Config interface { + + //是否已经安装 + IsInstalled() bool + //启动端口 + GetServerPort() int + //获取mysql链接 + GetMysqlUrl() string + + //文件存放路径 + GetMatterPath() string + //完成安装过程,主要是要将配置写入到文件中 + FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string) +} diff --git a/code/core/context.go b/code/core/context.go index 53745b6..dd4cf80 100644 --- a/code/core/context.go +++ b/code/core/context.go @@ -7,6 +7,9 @@ import ( ) type Context interface { + //具备响应http请求的能力 + http.Handler + //获取数据库链接 GetDB() *gorm.DB @@ -19,9 +22,6 @@ type Context interface { //获取全局的ControllerMap GetControllerMap() map[string]IController - //响应http的能力 - ServeHTTP(writer http.ResponseWriter, request *http.Request) - //系统安装成功 InstallOk() diff --git a/code/core/global.go b/code/core/global.go index 1a1854d..1310a17 100644 --- a/code/core/global.go +++ b/code/core/global.go @@ -6,5 +6,8 @@ package core //全局唯一的日志对象(在main函数中初始化) var LOGGER Logger +//全局唯一配置 +var CONFIG Config + //全局唯一的上下文(在main函数中初始化) var CONTEXT Context diff --git a/code/rest/base_model.go b/code/rest/base_model.go index 1ec405a..3c5543d 100644 --- a/code/rest/base_model.go +++ b/code/rest/base_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "math" "reflect" "time" @@ -40,7 +40,7 @@ func (this *Base) Map() map[string]interface{} { } func (this *Base) TableName() string { - return config.TABLE_PREFIX + "base" + return core.TABLE_PREFIX + "base" } //分页类 diff --git a/code/rest/bean.go b/code/rest/bean.go index 1a197f4..3e3c253 100644 --- a/code/rest/bean.go +++ b/code/rest/bean.go @@ -1,7 +1,6 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" @@ -35,7 +34,7 @@ func (this *Bean) findUser(writer http.ResponseWriter, request *http.Request) *U //验证用户是否已经登录。 //登录身份有效期以数据库中记录的为准 - sessionId := util.GetSessionUuidFromRequest(request, config.COOKIE_AUTH_KEY) + sessionId := util.GetSessionUuidFromRequest(request, core.COOKIE_AUTH_KEY) if sessionId == "" { return nil } diff --git a/code/rest/context.go b/code/rest/context.go deleted file mode 100644 index 0a36219..0000000 --- a/code/rest/context.go +++ /dev/null @@ -1,220 +0,0 @@ -package rest - -import ( - "fmt" - "github.com/eyebluecn/tank/code/config" - "github.com/eyebluecn/tank/code/core" - "github.com/eyebluecn/tank/code/tool/cache" - "github.com/jinzhu/gorm" - "net/http" - "reflect" -) - -//上下文,管理数据库连接,管理所有路由请求,管理所有的单例component. -type Context struct { - //数据库连接 - db *gorm.DB - //session缓存 - SessionCache *cache.Table - //各类的Bean Map。这里面是包含ControllerMap中所有元素 - BeanMap map[string]core.IBean - //只包含了Controller的map - ControllerMap map[string]core.IController - //处理所有路由请求 - Router *Router -} - -//初始化上下文 -func (this *Context) Init() { - - //创建一个用于存储session的缓存。 - this.SessionCache = cache.NewTable() - - //初始化Map - this.BeanMap = make(map[string]core.IBean) - this.ControllerMap = make(map[string]core.IController) - - //注册各类Beans.在这个方法里面顺便把Controller装入ControllerMap中去。 - this.registerBeans() - - //初始化每个bean. - this.initBeans() - - //初始化Router. 这个方法要在Bean注册好了之后才能。 - this.Router = NewRouter() - - //如果数据库信息配置好了,就直接打开数据库连接 同时执行Bean的ConfigPost方法 - this.InstallOk() - -} - -//获取数据库对象 -func (this *Context) GetDB() *gorm.DB { - return this.db -} - -func (this *Context) GetSessionCache() *cache.Table { - return this.SessionCache -} - -func (this *Context) GetControllerMap() map[string]core.IController { - return this.ControllerMap -} - -func (this *Context) Cleanup() { - for _, bean := range this.BeanMap { - bean.Cleanup() - } -} - -//响应http的能力 -func (this *Context) ServeHTTP(writer http.ResponseWriter, request *http.Request) { - this.Router.ServeHTTP(writer, request) -} - -func (this *Context) OpenDb() { - - var err error = nil - this.db, err = gorm.Open("mysql", config.CONFIG.MysqlUrl) - - if err != nil { - core.LOGGER.Panic("failed to connect mysql database") - } - - //是否打开sql日志(在调试阶段可以打开,以方便查看执行的SQL) - this.db.LogMode(false) -} - -func (this *Context) CloseDb() { - - if this.db != nil { - err := this.db.Close() - if err != nil { - core.LOGGER.Error("关闭数据库连接出错 %s", err.Error()) - } - } -} - -//注册一个Bean -func (this *Context) registerBean(bean core.IBean) { - - typeOf := reflect.TypeOf(bean) - typeName := typeOf.String() - - if element, ok := bean.(core.IBean); ok { - - err := fmt.Sprintf("【%s】已经被注册了,跳过。", typeName) - if _, ok := this.BeanMap[typeName]; ok { - core.LOGGER.Error(fmt.Sprintf(err)) - } else { - this.BeanMap[typeName] = element - - //看看是不是controller类型,如果是,那么单独放在ControllerMap中。 - if controller, ok1 := bean.(core.IController); ok1 { - this.ControllerMap[typeName] = controller - } - - } - - } else { - core.LOGGER.Panic("注册的【%s】不是Bean类型。", typeName) - } - -} - -//注册各个Beans -func (this *Context) registerBeans() { - - //alien - this.registerBean(new(AlienController)) - this.registerBean(new(AlienService)) - - //dashboard - this.registerBean(new(DashboardController)) - this.registerBean(new(DashboardDao)) - this.registerBean(new(DashboardService)) - - //downloadToken - this.registerBean(new(DownloadTokenDao)) - - //imageCache - this.registerBean(new(ImageCacheController)) - this.registerBean(new(ImageCacheDao)) - this.registerBean(new(ImageCacheService)) - - //install - this.registerBean(new(InstallController)) - - //matter - this.registerBean(new(MatterController)) - this.registerBean(new(MatterDao)) - this.registerBean(new(MatterService)) - - //preference - this.registerBean(new(PreferenceController)) - this.registerBean(new(PreferenceDao)) - this.registerBean(new(PreferenceService)) - - //footprint - this.registerBean(new(FootprintController)) - this.registerBean(new(FootprintDao)) - this.registerBean(new(FootprintService)) - - //session - this.registerBean(new(SessionDao)) - this.registerBean(new(SessionService)) - - //uploadToken - this.registerBean(new(UploadTokenDao)) - - //user - this.registerBean(new(UserController)) - this.registerBean(new(UserDao)) - this.registerBean(new(UserService)) - - //webdav - this.registerBean(new(DavController)) - this.registerBean(new(DavService)) - -} - -//从Map中获取某个Bean. -func (this *Context) GetBean(bean core.IBean) core.IBean { - - typeOf := reflect.TypeOf(bean) - typeName := typeOf.String() - - if val, ok := this.BeanMap[typeName]; ok { - return val - } else { - core.LOGGER.Panic("【%s】没有注册。", typeName) - return nil - } -} - -//初始化每个Bean -func (this *Context) initBeans() { - - for key, bean := range this.BeanMap { - core.LOGGER.Info("init %s", key) - bean.Init() - } -} - -//系统如果安装好了就调用这个方法。 -func (this *Context) InstallOk() { - - if config.CONFIG.Installed { - this.OpenDb() - - for _, bean := range this.BeanMap { - bean.Bootstrap() - } - } - -} - -//销毁的方法 -func (this *Context) Destroy() { - this.CloseDb() -} diff --git a/code/rest/dashboard_model.go b/code/rest/dashboard_model.go index 0288445..0803299 100644 --- a/code/rest/dashboard_model.go +++ b/code/rest/dashboard_model.go @@ -1,6 +1,6 @@ package rest -import "github.com/eyebluecn/tank/code/config" +import "github.com/eyebluecn/tank/code/core" /** * 系统的所有访问记录均记录在此 @@ -21,7 +21,7 @@ type Dashboard struct { // set File's table name to be `profiles` func (this *Dashboard) TableName() string { - return config.TABLE_PREFIX + "dashboard" + return core.TABLE_PREFIX + "dashboard" } /** diff --git a/code/rest/download_token_model.go b/code/rest/download_token_model.go index dd43e1c..ece6c0f 100644 --- a/code/rest/download_token_model.go +++ b/code/rest/download_token_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "time" ) @@ -14,5 +14,5 @@ type DownloadToken struct { } func (this *DownloadToken) TableName() string { - return config.TABLE_PREFIX + "download_token" + return core.TABLE_PREFIX + "download_token" } diff --git a/code/rest/footprint_model.go b/code/rest/footprint_model.go index 345c46c..ec177c3 100644 --- a/code/rest/footprint_model.go +++ b/code/rest/footprint_model.go @@ -1,6 +1,6 @@ package rest -import "github.com/eyebluecn/tank/code/config" +import "github.com/eyebluecn/tank/code/core" /** * 系统的所有访问记录均记录在此 @@ -18,5 +18,5 @@ type Footprint struct { // set File's table name to be `profiles` func (this *Footprint) TableName() string { - return config.TABLE_PREFIX + "footprint" + return core.TABLE_PREFIX + "footprint" } diff --git a/code/rest/footprint_service.go b/code/rest/footprint_service.go index a758d5f..9c6785e 100644 --- a/code/rest/footprint_service.go +++ b/code/rest/footprint_service.go @@ -2,7 +2,7 @@ package rest import ( "encoding/json" - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/util" "github.com/robfig/cron" @@ -76,7 +76,7 @@ func (this *FootprintService) Trace(writer http.ResponseWriter, request *http.Re } //有可能DB尚且没有配置 直接打印出内容,并且退出 - if config.CONFIG.Installed { + if core.CONFIG.IsInstalled() { user := this.findUser(writer, request) userUuid := "" if user != nil { diff --git a/code/rest/image_cache_model.go b/code/rest/image_cache_model.go index 7afb1a5..0eceaed 100644 --- a/code/rest/image_cache_model.go +++ b/code/rest/image_cache_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" ) /** @@ -23,7 +23,7 @@ type ImageCache struct { // set File's table name to be `profiles` func (this *ImageCache) TableName() string { - return config.TABLE_PREFIX + "image_cache" + return core.TABLE_PREFIX + "image_cache" } // 获取该ImageCache的绝对路径。path代表的是相对路径。 diff --git a/code/rest/install_controller.go b/code/rest/install_controller.go index 77b42ef..c012a32 100644 --- a/code/rest/install_controller.go +++ b/code/rest/install_controller.go @@ -2,18 +2,16 @@ package rest import ( "fmt" - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" "github.com/jinzhu/gorm" - "github.com/json-iterator/go" "github.com/nu7hatch/gouuid" "go/build" "io/ioutil" "net/http" - "os" "regexp" "strconv" "time" @@ -427,38 +425,8 @@ func (this *InstallController) Finish(writer http.ResponseWriter, request *http. panic(result.BadRequest(`请至少配置一名管理员`)) } - var configItem = &config.ConfigItem{ - //默认监听端口号 - ServerPort: config.CONFIG.ServerPort, - //上传的文件路径,要求不以/结尾。如果没有指定,默认在根目录下的matter文件夹中。eg: /var/www/matter - MatterPath: config.CONFIG.MatterPath, - //mysql相关配置。 - //数据库端口 - MysqlPort: mysqlPort, - //数据库Host - MysqlHost: mysqlHost, - //数据库名字 - MysqlSchema: mysqlSchema, - //用户名 - MysqlUsername: mysqlUsername, - //密码 - MysqlPassword: mysqlPassword, - } - - //用json的方式输出返回值。为了让格式更好看。 - jsonStr, _ := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(configItem, "", " ") - - //写入到配置文件中(不能使用os.O_APPEND 否则会追加) - filePath := util.GetConfPath() + "/tank.json" - f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0777) - this.PanicError(err) - _, err = f.Write(jsonStr) - this.PanicError(err) - err = f.Close() - this.PanicError(err) - //通知配置文件安装完毕。 - config.CONFIG.InstallOk() + core.CONFIG.FinishInstall(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword) //通知全局上下文,说系统安装好了 core.CONTEXT.InstallOk() diff --git a/code/rest/matter_dao.go b/code/rest/matter_dao.go index 33ebe80..40ec5aa 100644 --- a/code/rest/matter_dao.go +++ b/code/rest/matter_dao.go @@ -1,7 +1,6 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" "github.com/eyebluecn/tank/code/tool/result" @@ -367,7 +366,7 @@ func (this *MatterDao) Cleanup() { db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Matter{}) this.PanicError(db.Error) - err := os.RemoveAll(config.CONFIG.MatterPath) + err := os.RemoveAll(core.CONFIG.GetMatterPath()) this.PanicError(err) } diff --git a/code/rest/matter_model.go b/code/rest/matter_model.go index 34365ff..3c525f9 100644 --- a/code/rest/matter_model.go +++ b/code/rest/matter_model.go @@ -2,7 +2,8 @@ package rest import ( "fmt" - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/util" ) @@ -37,7 +38,7 @@ type Matter struct { // set File's table name to be `profiles` func (Matter) TableName() string { - return config.TABLE_PREFIX + "matter" + return core.TABLE_PREFIX + "matter" } // 获取该Matter的绝对路径。path代表的是相对路径。 @@ -67,7 +68,7 @@ func NewRootMatter(user *User) *Matter { //获取到用户文件的根目录。 func GetUserFileRootDir(username string) (rootDirPath string) { - rootDirPath = fmt.Sprintf("%s/%s/%s", config.CONFIG.MatterPath, username, MATTER_ROOT) + rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.GetMatterPath(), username, MATTER_ROOT) return rootDirPath } @@ -75,7 +76,7 @@ func GetUserFileRootDir(username string) (rootDirPath string) { //获取到用户缓存的根目录。 func GetUserCacheRootDir(username string) (rootDirPath string) { - rootDirPath = fmt.Sprintf("%s/%s/%s", config.CONFIG.MatterPath, username, MATTER_CACHE) + rootDirPath = fmt.Sprintf("%s/%s/%s", core.CONFIG.GetMatterPath(), username, MATTER_CACHE) return rootDirPath } diff --git a/code/rest/preference_model.go b/code/rest/preference_model.go index 55443f0..55c2468 100644 --- a/code/rest/preference_model.go +++ b/code/rest/preference_model.go @@ -1,6 +1,6 @@ package rest -import "github.com/eyebluecn/tank/code/config" +import "github.com/eyebluecn/tank/code/core" type Preference struct { Base @@ -14,5 +14,5 @@ type Preference struct { // set File's table name to be `profiles` func (this *Preference) TableName() string { - return config.TABLE_PREFIX + "preference" + return core.TABLE_PREFIX + "preference" } diff --git a/code/rest/session_model.go b/code/rest/session_model.go index b5ce7fe..079924f 100644 --- a/code/rest/session_model.go +++ b/code/rest/session_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "time" ) @@ -14,5 +14,5 @@ type Session struct { // set User's table name to be `profiles` func (this *Session) TableName() string { - return config.TABLE_PREFIX + "session" + return core.TABLE_PREFIX + "session" } diff --git a/code/rest/upload_token_model.go b/code/rest/upload_token_model.go index 1bdccd9..0062cdf 100644 --- a/code/rest/upload_token_model.go +++ b/code/rest/upload_token_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "time" ) @@ -18,5 +18,5 @@ type UploadToken struct { } func (this *UploadToken) TableName() string { - return config.TABLE_PREFIX + "upload_token" + return core.TABLE_PREFIX + "upload_token" } diff --git a/code/rest/user_controller.go b/code/rest/user_controller.go index 602c2dd..e87340f 100644 --- a/code/rest/user_controller.go +++ b/code/rest/user_controller.go @@ -1,7 +1,6 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" "github.com/eyebluecn/tank/code/tool/result" @@ -83,7 +82,7 @@ func (this *UserController) Login(writer http.ResponseWriter, request *http.Requ //设置用户的cookie. cookie := http.Cookie{ - Name: config.COOKIE_AUTH_KEY, + Name: core.COOKIE_AUTH_KEY, Path: "/", Value: session.Uuid, Expires: expiration} @@ -218,7 +217,7 @@ func (this *UserController) Detail(writer http.ResponseWriter, request *http.Req func (this *UserController) Logout(writer http.ResponseWriter, request *http.Request) *result.WebResult { //session置为过期 - sessionCookie, err := request.Cookie(config.COOKIE_AUTH_KEY) + sessionCookie, err := request.Cookie(core.COOKIE_AUTH_KEY) if err != nil { return this.Success("已经退出登录了!") } @@ -241,7 +240,7 @@ func (this *UserController) Logout(writer http.ResponseWriter, request *http.Req expiration := time.Now() expiration = expiration.AddDate(-1, 0, 0) cookie := http.Cookie{ - Name: config.COOKIE_AUTH_KEY, + Name: core.COOKIE_AUTH_KEY, Path: "/", Value: sessionId, Expires: expiration} diff --git a/code/rest/user_model.go b/code/rest/user_model.go index 3c72d79..e0b14d6 100644 --- a/code/rest/user_model.go +++ b/code/rest/user_model.go @@ -1,7 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" "time" ) @@ -45,7 +45,7 @@ type User struct { // set User's table name to be `profiles` func (this *User) TableName() string { - return config.TABLE_PREFIX + "user" + return core.TABLE_PREFIX + "user" } //通过一个字符串获取性别 diff --git a/code/rest/user_service.go b/code/rest/user_service.go index 3c8e3c0..e8dc4e6 100644 --- a/code/rest/user_service.go +++ b/code/rest/user_service.go @@ -1,7 +1,6 @@ package rest import ( - "github.com/eyebluecn/tank/code/config" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/cache" "github.com/eyebluecn/tank/code/tool/result" @@ -72,12 +71,12 @@ func (this *UserService) MatterUnlock(userUuid string) { //装载session信息,如果session没有了根据cookie去装填用户信息。 //在所有的路由最初会调用这个方法 -func (this *UserService) preHandle(writer http.ResponseWriter, request *http.Request) { +func (this *UserService) PreHandle(writer http.ResponseWriter, request *http.Request) { //登录身份有效期以数据库中记录的为准 //验证用户是否已经登录。 - sessionCookie, err := request.Cookie(config.COOKIE_AUTH_KEY) + sessionCookie, err := request.Cookie(core.COOKIE_AUTH_KEY) if err != nil { return } diff --git a/code/config/config.go b/code/support/tank_config.go similarity index 70% rename from code/config/config.go rename to code/support/tank_config.go index 6fe3dd4..3e7d5f6 100644 --- a/code/config/config.go +++ b/code/support/tank_config.go @@ -1,35 +1,24 @@ -package config +package support import ( "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/util" "github.com/json-iterator/go" "io/ioutil" + "os" "time" "unsafe" ) -const ( - //用户身份的cookie字段名 - COOKIE_AUTH_KEY = "_ak" - - //数据库表前缀 tank200表示当前应用版本是tank:2.0.x版,数据库结构发生变化必然是中型升级 - TABLE_PREFIX = "tank20_" - - //当前版本 - VERSION = "2.0.0" -) - /* 如果你需要在本地127.0.0.1创建默认的数据库和账号,使用以下语句。 create database tank; grant all privileges on tank.* to tank identified by 'tank123'; flush privileges; */ -var CONFIG = &Config{} //依赖外部定义的变量。 -type Config struct { +type TankConfig struct { //默认监听端口号 ServerPort int //网站是否已经完成安装 @@ -67,9 +56,6 @@ func (this *ConfigItem) validate() bool { if this.ServerPort == 0 { core.LOGGER.Error("ServerPort 未配置") return false - } else { - //只要配置文件中有配置端口,就使用。 - CONFIG.ServerPort = this.ServerPort } if this.MysqlUsername == "" { @@ -102,7 +88,7 @@ func (this *ConfigItem) validate() bool { } //验证配置文件是否完好 -func (this *Config) Init() { +func (this *TankConfig) Init() { //JSON初始化 jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { @@ -129,7 +115,7 @@ func (this *Config) Init() { } //系统如果安装好了就调用这个方法。 -func (this *Config) ReadFromConfigFile() { +func (this *TankConfig) ReadFromConfigFile() { //读取配置文件 filePath := util.GetConfPath() + "/tank.json" @@ -161,7 +147,7 @@ func (this *Config) ReadFromConfigFile() { } else { this.MatterPath = this.Item.MatterPath } - util.MakeDirAll(CONFIG.MatterPath) + util.MakeDirAll(this.MatterPath) //使用配置项中的端口 if this.Item.ServerPort != 0 { @@ -176,8 +162,59 @@ func (this *Config) ReadFromConfigFile() { } } -//系统如果安装好了就调用这个方法。 -func (this *Config) InstallOk() { +//是否已经安装 +func (this *TankConfig) IsInstalled() bool { + return this.Installed +} + +//启动端口 +func (this *TankConfig) GetServerPort() int { + return this.ServerPort +} + +//获取mysql链接 +func (this *TankConfig) GetMysqlUrl() string { + return this.MysqlUrl +} + +//文件存放路径 +func (this *TankConfig) GetMatterPath() string { + return this.MatterPath +} + +//完成安装过程,主要是要将配置写入到文件中 +func (this *TankConfig) FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string) { + + var configItem = &ConfigItem{ + //默认监听端口号 + ServerPort: core.CONFIG.GetServerPort(), + //上传的文件路径,要求不以/结尾。如果没有指定,默认在根目录下的matter文件夹中。eg: /var/www/matter + MatterPath: core.CONFIG.GetMatterPath(), + //mysql相关配置。 + //数据库端口 + MysqlPort: mysqlPort, + //数据库Host + MysqlHost: mysqlHost, + //数据库名字 + MysqlSchema: mysqlSchema, + //用户名 + MysqlUsername: mysqlUsername, + //密码 + MysqlPassword: mysqlPassword, + } + + //用json的方式输出返回值。为了让格式更好看。 + jsonStr, _ := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(configItem, "", " ") + + //写入到配置文件中(不能使用os.O_APPEND 否则会追加) + filePath := util.GetConfPath() + "/tank.json" + f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0777) + util.PanicError(err) + _, err = f.Write(jsonStr) + util.PanicError(err) + err = f.Close() + util.PanicError(err) this.ReadFromConfigFile() + } diff --git a/code/support/tank_context.go b/code/support/tank_context.go index 17d5ef2..2a44193 100644 --- a/code/support/tank_context.go +++ b/code/support/tank_context.go @@ -1 +1,220 @@ package support + +import ( + "fmt" + + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/rest" + "github.com/eyebluecn/tank/code/tool/cache" + "github.com/jinzhu/gorm" + "net/http" + "reflect" +) + +//上下文,管理数据库连接,管理所有路由请求,管理所有的单例component. +type TankContext struct { + //数据库连接 + db *gorm.DB + //session缓存 + SessionCache *cache.Table + //各类的Bean Map。这里面是包含ControllerMap中所有元素 + BeanMap map[string]core.IBean + //只包含了Controller的map + ControllerMap map[string]core.IController + //处理所有路由请求 + Router *TankRouter +} + +//初始化上下文 +func (this *TankContext) Init() { + + //创建一个用于存储session的缓存。 + this.SessionCache = cache.NewTable() + + //初始化Map + this.BeanMap = make(map[string]core.IBean) + this.ControllerMap = make(map[string]core.IController) + + //注册各类Beans.在这个方法里面顺便把Controller装入ControllerMap中去。 + this.registerBeans() + + //初始化每个bean. + this.initBeans() + + //初始化Router. 这个方法要在Bean注册好了之后才能。 + this.Router = NewRouter() + + //如果数据库信息配置好了,就直接打开数据库连接 同时执行Bean的ConfigPost方法 + this.InstallOk() + +} + +//获取数据库对象 +func (this *TankContext) GetDB() *gorm.DB { + return this.db +} + +func (this *TankContext) GetSessionCache() *cache.Table { + return this.SessionCache +} + +func (this *TankContext) GetControllerMap() map[string]core.IController { + return this.ControllerMap +} + +func (this *TankContext) Cleanup() { + for _, bean := range this.BeanMap { + bean.Cleanup() + } +} + +//响应http的能力 +func (this *TankContext) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + this.Router.ServeHTTP(writer, request) +} + +func (this *TankContext) OpenDb() { + + var err error = nil + this.db, err = gorm.Open("mysql", core.CONFIG.GetMysqlUrl()) + + if err != nil { + core.LOGGER.Panic("failed to connect mysql database") + } + + //是否打开sql日志(在调试阶段可以打开,以方便查看执行的SQL) + this.db.LogMode(false) +} + +func (this *TankContext) CloseDb() { + + if this.db != nil { + err := this.db.Close() + if err != nil { + core.LOGGER.Error("关闭数据库连接出错 %s", err.Error()) + } + } +} + +//注册一个Bean +func (this *TankContext) registerBean(bean core.IBean) { + + typeOf := reflect.TypeOf(bean) + typeName := typeOf.String() + + if element, ok := bean.(core.IBean); ok { + + err := fmt.Sprintf("【%s】已经被注册了,跳过。", typeName) + if _, ok := this.BeanMap[typeName]; ok { + core.LOGGER.Error(fmt.Sprintf(err)) + } else { + this.BeanMap[typeName] = element + + //看看是不是controller类型,如果是,那么单独放在ControllerMap中。 + if controller, ok1 := bean.(core.IController); ok1 { + this.ControllerMap[typeName] = controller + } + + } + + } else { + core.LOGGER.Panic("注册的【%s】不是Bean类型。", typeName) + } + +} + +//注册各个Beans +func (this *TankContext) registerBeans() { + + //alien + this.registerBean(new(rest.AlienController)) + this.registerBean(new(rest.AlienService)) + + //dashboard + this.registerBean(new(rest.DashboardController)) + this.registerBean(new(rest.DashboardDao)) + this.registerBean(new(rest.DashboardService)) + + //downloadToken + this.registerBean(new(rest.DownloadTokenDao)) + + //imageCache + this.registerBean(new(rest.ImageCacheController)) + this.registerBean(new(rest.ImageCacheDao)) + this.registerBean(new(rest.ImageCacheService)) + + //install + this.registerBean(new(rest.InstallController)) + + //matter + this.registerBean(new(rest.MatterController)) + this.registerBean(new(rest.MatterDao)) + this.registerBean(new(rest.MatterService)) + + //preference + this.registerBean(new(rest.PreferenceController)) + this.registerBean(new(rest.PreferenceDao)) + this.registerBean(new(rest.PreferenceService)) + + //footprint + this.registerBean(new(rest.FootprintController)) + this.registerBean(new(rest.FootprintDao)) + this.registerBean(new(rest.FootprintService)) + + //session + this.registerBean(new(rest.SessionDao)) + this.registerBean(new(rest.SessionService)) + + //uploadToken + this.registerBean(new(rest.UploadTokenDao)) + + //user + this.registerBean(new(rest.UserController)) + this.registerBean(new(rest.UserDao)) + this.registerBean(new(rest.UserService)) + + //webdav + this.registerBean(new(rest.DavController)) + this.registerBean(new(rest.DavService)) + +} + +//从Map中获取某个Bean. +func (this *TankContext) GetBean(bean core.IBean) core.IBean { + + typeOf := reflect.TypeOf(bean) + typeName := typeOf.String() + + if val, ok := this.BeanMap[typeName]; ok { + return val + } else { + core.LOGGER.Panic("【%s】没有注册。", typeName) + return nil + } +} + +//初始化每个Bean +func (this *TankContext) initBeans() { + + for _, bean := range this.BeanMap { + bean.Init() + } +} + +//系统如果安装好了就调用这个方法。 +func (this *TankContext) InstallOk() { + + if core.CONFIG.IsInstalled() { + this.OpenDb() + + for _, bean := range this.BeanMap { + bean.Bootstrap() + } + } + +} + +//销毁的方法 +func (this *TankContext) Destroy() { + this.CloseDb() +} diff --git a/code/rest/router.go b/code/support/tank_router.go similarity index 88% rename from code/rest/router.go rename to code/support/tank_router.go index 66c3dae..fb6c7e6 100644 --- a/code/rest/router.go +++ b/code/support/tank_router.go @@ -1,9 +1,10 @@ -package rest +package support import ( "fmt" - "github.com/eyebluecn/tank/code/config" + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/rest" "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" "github.com/json-iterator/go" @@ -15,36 +16,36 @@ import ( ) //用于处理所有前来的请求 -type Router struct { - installController *InstallController - footprintService *FootprintService - userService *UserService +type TankRouter struct { + installController *rest.InstallController + footprintService *rest.FootprintService + userService *rest.UserService routeMap map[string]func(writer http.ResponseWriter, request *http.Request) installRouteMap map[string]func(writer http.ResponseWriter, request *http.Request) } //构造方法 -func NewRouter() *Router { - router := &Router{ +func NewRouter() *TankRouter { + router := &TankRouter{ routeMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)), installRouteMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)), } //installController. b := core.CONTEXT.GetBean(router.installController) - if b, ok := b.(*InstallController); ok { + if b, ok := b.(*rest.InstallController); ok { router.installController = b } //装载userService. b = core.CONTEXT.GetBean(router.userService) - if b, ok := b.(*UserService); ok { + if b, ok := b.(*rest.UserService); ok { router.userService = b } //装载footprintService b = core.CONTEXT.GetBean(router.footprintService) - if b, ok := b.(*FootprintService); ok { + if b, ok := b.(*rest.FootprintService); ok { router.footprintService = b } @@ -69,7 +70,7 @@ func NewRouter() *Router { } //全局的异常捕获 -func (this *Router) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request, startTime time.Time) { +func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request, startTime time.Time) { if err := recover(); err != nil { core.LOGGER.Error("错误: %v", err) @@ -115,7 +116,7 @@ func (this *Router) GlobalPanicHandler(writer http.ResponseWriter, request *http } //让Router具有处理请求的功能。 -func (this *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) { +func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) { startTime := time.Now() @@ -131,11 +132,11 @@ func (this *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) writer.Header().Set("Cache-Control", "no-cache") writer.Header().Set("Expires", "0") - if config.CONFIG.Installed { + if core.CONFIG.IsInstalled() { //已安装的模式 //统一处理用户的身份信息。 - this.userService.preHandle(writer, request) + this.userService.PreHandle(writer, request) if handler, ok := this.routeMap[path]; ok { handler(writer, request) diff --git a/main.go b/main.go index 96593d4..27011fa 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,7 @@ package main import ( "fmt" - "github.com/eyebluecn/tank/code/config" "github.com/eyebluecn/tank/code/core" - "github.com/eyebluecn/tank/code/rest" "github.com/eyebluecn/tank/code/support" _ "github.com/go-sql-driver/mysql" "log" @@ -13,26 +11,28 @@ import ( func main() { - //日志第一优先级保障 + //第一步。日志 tankLogger := &support.TankLogger{} core.LOGGER = tankLogger tankLogger.Init() defer tankLogger.Destroy() - //装载配置文件,这个决定了是否需要执行安装过程 - config.CONFIG.Init() + //第二步。配置 + tankConfig := &support.TankConfig{} + core.CONFIG = tankConfig + tankConfig.Init() - //全局运行的上下文 - tankContext := &rest.Context{} + //第三步。全局运行的上下文 + tankContext := &support.TankContext{} core.CONTEXT = tankContext tankContext.Init() defer tankContext.Destroy() + //第四步。启动http服务 http.Handle("/", core.CONTEXT) + core.LOGGER.Info("App started at http://localhost:%v", core.CONFIG.GetServerPort()) - core.LOGGER.Info("App started at http://localhost:%v", config.CONFIG.ServerPort) - - dotPort := fmt.Sprintf(":%v", config.CONFIG.ServerPort) + dotPort := fmt.Sprintf(":%v", core.CONFIG.GetServerPort()) err1 := http.ListenAndServe(dotPort, nil) if err1 != nil { log.Fatal("ListenAndServe: ", err1)