hotime/application.go

522 lines
13 KiB
Go
Raw Normal View History

2017-08-17 02:14:59 +00:00
package hotime
import (
2021-05-23 23:27:41 +00:00
. "./cache"
. "./common"
. "./db"
. "./log"
2017-08-17 02:14:59 +00:00
"bytes"
"database/sql"
"encoding/json"
2021-05-22 19:35:49 +00:00
"github.com/sirupsen/logrus"
2017-08-17 02:14:59 +00:00
"io/ioutil"
"net/http"
2019-05-19 15:33:01 +00:00
"net/url"
2017-08-17 02:14:59 +00:00
"os"
"path/filepath"
"strconv"
"strings"
)
type Application struct {
2018-11-14 02:31:08 +00:00
MethodRouter
2017-08-17 02:14:59 +00:00
Router
2021-05-23 23:27:41 +00:00
ContextBase
Log *logrus.Logger
WebConnectLog *logrus.Logger
2017-08-17 02:14:59 +00:00
Port string //端口号
2019-11-10 10:00:45 +00:00
TLSPort string //ssl访问端口号
2017-08-22 08:24:55 +00:00
connectListener []func(this *Context) bool //所有的访问监听,true按原计划继续使用false表示有监听器处理
2021-05-23 22:14:58 +00:00
connectDbFunc func(err ...*Error) (master, slave *sql.DB)
2017-08-17 02:14:59 +00:00
configPath string
Config Map
Db HoTimeDB
*http.Server
2017-08-17 02:14:59 +00:00
CacheIns
sessionLong CacheIns
sessionShort CacheIns
2017-10-27 04:28:47 +00:00
http.Handler
}
func (that *Application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
that.handler(w, req)
2017-08-17 02:14:59 +00:00
}
// Run 启动实例
func (that *Application) Run(router Router) {
2020-02-21 13:44:53 +00:00
//如果没有设置配置自动生成配置
if that.configPath == "" || len(that.Config) == 0 {
that.SetConfig()
2020-02-21 13:44:53 +00:00
}
//防止手动设置缓存误伤
if that.CacheIns == nil {
that.SetCache(CacheIns(&CacheMemory{}))
2020-02-21 13:44:53 +00:00
}
//防止手动设置session误伤
//if that.sessionShort == nil && that.sessionLong == nil {
// if that.connectDbFunc == nil {
// that.SetSession(CacheIns(&CacheMemory{}), nil)
2021-05-23 23:27:41 +00:00
// } else {
// that.SetSession(CacheIns(&CacheMemory{}), CacheIns(&CacheDb{Db: &that.Db, Time: that.Config.GetInt64("cacheLongTime")}))
2021-05-23 23:27:41 +00:00
// }
//
//}
2018-04-03 17:54:27 +00:00
that.Router = router
2018-11-14 02:31:08 +00:00
//重新设置MethodRouter//直达路由
that.MethodRouter = MethodRouter{}
2019-05-19 15:33:01 +00:00
modeRouterStrict := true
if that.Config.GetBool("modeRouterStrict") == false {
2019-05-19 15:33:01 +00:00
modeRouterStrict = false
2018-11-15 03:44:50 +00:00
}
2019-05-19 15:33:01 +00:00
if router != nil {
for pk, pv := range router {
if !modeRouterStrict {
pk = strings.ToLower(pk)
2018-11-15 03:44:50 +00:00
}
2019-05-19 15:33:01 +00:00
if pv != nil {
for ck, cv := range pv {
if !modeRouterStrict {
ck = strings.ToLower(ck)
2018-11-15 03:44:50 +00:00
}
2019-05-19 15:33:01 +00:00
if cv != nil {
for mk, mv := range cv {
if !modeRouterStrict {
mk = strings.ToLower(mk)
2018-11-14 02:31:08 +00:00
}
that.MethodRouter["/"+pk+"/"+ck+"/"+mk] = mv
2018-11-14 02:31:08 +00:00
}
2019-05-19 15:33:01 +00:00
}
2018-11-14 02:31:08 +00:00
}
}
}
}
//that.Port = port
that.Port = that.Config.GetString("port")
that.TLSPort = that.Config.GetString("tlsPort")
2017-08-17 02:14:59 +00:00
if that.connectDbFunc != nil && (that.Db.DB == nil || that.Db.DB.Ping() != nil) {
that.Db.SetConnect(that.connectDbFunc)
2017-08-17 02:14:59 +00:00
}
if that.CacheIns == nil {
that.CacheIns = CacheIns(&CacheMemory{Map: Map{}, Time: that.Config.GetInt64("cacheShortTime")})
2017-08-17 02:14:59 +00:00
}
2017-10-13 09:52:34 +00:00
//异常处理
defer func() {
if err := recover(); err != nil {
//that.SetError(errors.New(fmt.Sprint(err)), LOG_FMT)
that.Log.Warn(err)
that.Run(router)
2017-10-13 09:52:34 +00:00
}
}()
that.Server = &http.Server{}
2017-10-27 04:28:47 +00:00
if !IsRun {
IsRun = true
}
2019-05-27 05:46:03 +00:00
ch := make(chan int)
if ObjToCeilInt(that.Port) != 0 {
2019-11-10 10:00:45 +00:00
go func() {
2019-07-01 04:35:04 +00:00
App[that.Port] = that
that.Server.Handler = that
2019-05-27 05:46:03 +00:00
//启动服务
that.Server.Addr = ":" + that.Port
err := that.Server.ListenAndServe()
that.Log.Error(err)
2019-11-10 10:00:45 +00:00
ch <- 1
2019-05-27 05:46:03 +00:00
2019-11-10 10:00:45 +00:00
}()
2020-07-16 17:10:28 +00:00
}
if ObjToCeilInt(that.TLSPort) != 0 {
2019-07-01 04:35:04 +00:00
go func() {
2019-05-27 05:46:03 +00:00
App[that.TLSPort] = that
that.Server.Handler = that
2019-11-10 10:00:45 +00:00
//启动服务
that.Server.Addr = ":" + that.TLSPort
err := that.Server.ListenAndServeTLS(that.Config.GetString("tlsCert"), that.Config.GetString("tlsKey"))
that.Log.Error(err)
2019-11-10 10:00:45 +00:00
ch <- 2
2019-07-01 04:35:04 +00:00
}()
2020-07-16 17:10:28 +00:00
}
if ObjToCeilInt(that.Port) == 0 && ObjToCeilInt(that.TLSPort) == 0 {
that.Log.Error("没有端口启用")
2019-07-01 04:35:04 +00:00
return
}
2019-11-10 10:00:45 +00:00
value := <-ch
2017-08-17 02:14:59 +00:00
that.Log.Error("启动服务失败 : " + ObjToStr(value))
2017-08-17 02:14:59 +00:00
}
// SetConnectDB 启动实例
func (that *Application) SetConnectDB(connect func(err ...*Error) (master, slave *sql.DB)) {
2019-05-27 17:01:13 +00:00
that.connectDbFunc = connect
that.Db.SetConnect(that.connectDbFunc)
2019-05-27 17:01:13 +00:00
2017-08-17 02:14:59 +00:00
}
// SetSession 设置配置文件路径全路径或者相对路径
func (that *Application) SetSession(short CacheIns, Long CacheIns) {
that.sessionLong = Long
that.sessionShort = short
2017-08-17 02:14:59 +00:00
}
// SetDefault 默认配置缓存和session实现
func (that *Application) SetDefault(connect func(err ...*Error) (*sql.DB, *sql.DB)) {
that.SetConfig()
2019-11-10 10:10:26 +00:00
if connect != nil {
that.connectDbFunc = connect
that.Db.SetConnect(that.connectDbFunc)
2017-10-24 01:31:20 +00:00
}
2017-08-17 02:14:59 +00:00
}
// SetCache 设置配置文件路径全路径或者相对路径
func (that *Application) SetCache(cache CacheIns) {
2017-08-17 02:14:59 +00:00
that.CacheIns = cache
2017-08-17 02:14:59 +00:00
}
// SetConfig 设置配置文件路径全路径或者相对路径
func (that *Application) SetConfig(configPath ...string) {
that.Log = GetLog("", true)
2017-08-17 02:14:59 +00:00
if len(configPath) != 0 {
that.configPath = configPath[0]
2017-08-17 02:14:59 +00:00
}
if that.configPath == "" {
that.configPath = "config/config.json"
2017-08-17 02:14:59 +00:00
}
//加载配置文件
btes, err := ioutil.ReadFile(that.configPath)
that.Config = DeepCopyMap(Config).(Map)
2017-08-17 02:14:59 +00:00
if err == nil {
cmap := Map{}
//文件是否损坏
cmap.JsonToMap(string(btes), &that.Error)
2017-08-17 02:14:59 +00:00
for k, v := range cmap {
that.Config[k] = v //程序配置
Config[k] = v //系统配置
2017-08-17 02:14:59 +00:00
}
2019-11-10 10:00:45 +00:00
} else {
that.Log.Error("配置文件不存在,或者配置出错,使用缺省默认配置")
2019-05-27 05:46:03 +00:00
2017-08-17 02:14:59 +00:00
}
2019-09-03 03:55:05 +00:00
2017-08-17 02:14:59 +00:00
//文件如果损坏则不写入配置防止配置文件数据丢失
if that.Error.GetError() == nil {
var configByte bytes.Buffer
2017-08-17 02:14:59 +00:00
err = json.Indent(&configByte, []byte(that.Config.ToJsonString()), "", "\t")
2019-07-01 04:35:04 +00:00
//判断配置文件是否序列有变化有则修改配置,五则不变
//fmt.Println(len(btes))
if len(btes) != 0 && configByte.String() == string(btes) {
2019-07-01 04:35:04 +00:00
return
}
//写入配置说明
var configNoteByte bytes.Buffer
_ = json.Indent(&configNoteByte, []byte(ConfigNote.ToJsonString()), "", "\t")
_ = os.MkdirAll(filepath.Dir(that.configPath), os.ModeDir)
err = ioutil.WriteFile(that.configPath, configByte.Bytes(), os.ModeAppend)
2017-08-17 02:14:59 +00:00
if err != nil {
that.Error.SetError(err)
2017-08-17 02:14:59 +00:00
}
_ = ioutil.WriteFile(filepath.Dir(that.configPath)+"/configNote.json", configNoteByte.Bytes(), os.ModeAppend)
2017-08-17 02:14:59 +00:00
}
that.Log = GetLog(that.Config.GetString("logFile"), true)
if that.Config.GetBool("webConnectLogShow") {
that.WebConnectLog = GetLog(that.Config.GetString("webConnectLogFile"), false)
}
2017-08-17 02:14:59 +00:00
}
// SetConnectListener 连接判断,返回true继续传输至控制层false则停止传输
func (that *Application) SetConnectListener(lis func(this *Context) bool) {
that.connectListener = append(that.connectListener, lis)
2017-08-17 02:14:59 +00:00
}
//网络错误
2018-04-03 17:54:27 +00:00
//func (this *Application) session(w http.ResponseWriter, req *http.Request) {
//
//}
2017-08-17 02:14:59 +00:00
2017-08-22 08:24:55 +00:00
//序列化链接
func (that *Application) urlSer(url string) (string, []string) {
2017-08-22 08:24:55 +00:00
q := strings.Index(url, "?")
2017-08-17 02:14:59 +00:00
if q == -1 {
2017-08-22 08:24:55 +00:00
q = len(url)
2017-08-17 02:14:59 +00:00
}
2017-08-22 08:24:55 +00:00
o := Substr(url, 0, q)
2017-08-17 02:14:59 +00:00
r := strings.SplitN(o, "/", -1)
var s = make([]string, 0)
for i := 0; i < len(r); i++ {
if !strings.EqualFold("", r[i]) {
s = append(s, r[i])
}
}
2017-08-22 08:24:55 +00:00
return o, s
}
//访问
2018-11-15 03:44:50 +00:00
func (that *Application) handler(w http.ResponseWriter, req *http.Request) {
2017-08-22 08:24:55 +00:00
_, s := that.urlSer(req.RequestURI)
2017-08-22 08:24:55 +00:00
//获取cookie
// 如果cookie存在直接将sessionId赋值为cookie.Value
// 如果cookie不存在就查找传入的参数中是否有token
// 如果token不存在就生成随机的sessionId
// 如果token存在就判断token是否在Session中有保存
// 如果有取出token并复制给cookie
// 没有保存就生成随机的session
cookie, err := req.Cookie(that.Config.GetString("sessionName"))
2017-08-22 08:24:55 +00:00
sessionId := Md5(strconv.Itoa(Rand(10)))
token := req.FormValue("token")
//isFirst:=false
if err != nil || (len(token) == 32 && cookie.Value != token) {
if len(token) == 32 {
sessionId = token
}
//else{
// isFirst=true;
//}
http.SetCookie(w, &http.Cookie{Name: that.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
2017-08-22 08:24:55 +00:00
} else {
sessionId = cookie.Value
}
2017-08-17 02:14:59 +00:00
2019-05-19 15:33:01 +00:00
unescapeUrl, err := url.QueryUnescape(req.RequestURI)
if err != nil {
unescapeUrl = req.RequestURI
2018-11-06 14:57:53 +00:00
}
2017-08-22 08:24:55 +00:00
//访问实例
context := Context{SessionIns: SessionIns{SessionId: sessionId,
LongCache: that.sessionLong,
ShortCache: that.sessionShort,
2017-08-22 08:24:55 +00:00
},
CacheIns: that.CacheIns,
Resp: w, Req: req, Application: that, RouterString: s, Config: that.Config, Db: &that.Db, HandlerStr: unescapeUrl}
2017-10-11 09:45:22 +00:00
//header默认设置
header := w.Header()
2017-10-12 02:07:51 +00:00
header.Set("Content-Type", "text/html; charset=utf-8")
2018-11-14 16:10:41 +00:00
//url去掉参数并序列化
context.HandlerStr, context.RouterString = that.urlSer(context.HandlerStr)
2018-11-14 16:10:41 +00:00
//跨域设置
that.crossDomain(&context)
2020-02-20 07:06:39 +00:00
//是否展示日志
if that.WebConnectLog != nil {
that.WebConnectLog.Infoln(Substr(context.Req.RemoteAddr, 0, strings.Index(context.Req.RemoteAddr, ":")) + " " + context.HandlerStr)
2020-02-20 07:06:39 +00:00
}
2017-08-22 08:24:55 +00:00
//访问拦截true继续false暂停
connectListenerLen := len(that.connectListener)
2017-10-11 09:45:22 +00:00
if connectListenerLen != 0 {
2017-08-22 08:24:55 +00:00
for i := 0; i < connectListenerLen; i++ {
if !that.connectListener[i](&context) {
2017-10-12 02:07:51 +00:00
2017-08-22 08:24:55 +00:00
context.View()
return
}
}
}
2018-11-14 16:10:41 +00:00
2017-08-17 02:14:59 +00:00
//接口服务
2018-11-14 02:31:08 +00:00
//if len(s) == 3 {
// //如果满足规则则路由到对应控制器去
// if that.Router[s[0]] != nil && that.Router[s[0]][s[1]] != nil && that.Router[s[0]][s[1]][s[2]] != nil {
2018-11-14 02:31:08 +00:00
// //控制层
// that.Router[s[0]][s[1]][s[2]](&context)
2018-11-14 02:31:08 +00:00
// //header.Set("Content-Type", "text/html; charset=utf-8")
// context.View()
// return
// }
//
//}
2018-11-15 03:44:50 +00:00
//验证接口严格模式
modeRouterStrict := that.Config.GetBool("modeRouterStrict")
2019-05-19 15:33:01 +00:00
tempHandlerStr := context.HandlerStr
if !modeRouterStrict {
tempHandlerStr = strings.ToLower(tempHandlerStr)
2018-11-15 03:44:50 +00:00
}
2017-08-17 02:14:59 +00:00
2018-11-15 03:44:50 +00:00
//执行接口
if that.MethodRouter[tempHandlerStr] != nil {
that.MethodRouter[tempHandlerStr](&context)
2019-05-19 15:33:01 +00:00
context.View()
return
2017-08-17 02:14:59 +00:00
}
//url赋值
path := that.Config.GetString("tpt") + tempHandlerStr
2017-08-17 02:14:59 +00:00
//判断是否为默认
if path[len(path)-1] == '/' {
defFile := that.Config.GetSlice("defFile")
2017-10-27 04:28:47 +00:00
2017-08-17 02:14:59 +00:00
for i := 0; i < len(defFile); i++ {
2017-10-27 04:28:47 +00:00
temp := path + defFile.GetString(i)
2017-08-17 02:14:59 +00:00
_, err := os.Stat(temp)
if err == nil {
path = temp
break
}
}
if path[len(path)-1] == '/' {
w.WriteHeader(404)
return
}
}
if strings.Contains(path, "/.") {
w.WriteHeader(404)
return
}
2017-10-12 02:07:51 +00:00
//设置header
2019-05-19 15:33:01 +00:00
delete(header, "Content-Type")
if that.Config.GetInt("debug") != 1 {
2018-05-29 17:39:37 +00:00
header.Set("Cache-Control", "public")
}
2017-10-12 02:07:51 +00:00
2019-05-19 15:33:01 +00:00
if strings.Index(path, ".m3u8") != -1 {
header.Add("Content-Type", "audio/mpegurl")
}
2017-08-17 02:14:59 +00:00
//w.Write(data)
http.ServeFile(w, req, path)
}
func (that *Application) crossDomain(context *Context) {
//没有跨域设置
2020-02-21 13:44:53 +00:00
if context.Config.GetString("crossDomain") == "" {
return
}
2020-02-21 13:44:53 +00:00
header := context.Resp.Header()
2021-05-22 19:35:49 +00:00
//header.Set("Access-Control-Allow-Origin", "*")
header.Set("Access-Control-Allow-Methods", "*")
header.Set("Access-Control-Allow-Credentials", "true")
header.Set("Access-Control-Expose-Headers", "*")
header.Set("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Access-Token")
2021-05-22 19:35:49 +00:00
if context.Config.GetString("crossDomain") != "auto" {
header.Set("Access-Control-Allow-Origin", that.Config.GetString("crossDomain"))
return
}
2020-02-21 13:44:53 +00:00
origin := context.Req.Header.Get("Origin")
if origin != "" {
header.Set("Access-Control-Allow-Origin", origin)
return
}
2020-02-21 13:44:53 +00:00
refer := context.Req.Header.Get("Referer")
if refer != "" {
tempInt := 0
lastInt := strings.IndexFunc(refer, func(r rune) bool {
if r == '/' && tempInt > 8 {
return true
}
tempInt++
return false
})
if lastInt < 0 {
lastInt = len(refer)
}
refer = Substr(refer, 0, lastInt)
header.Set("Access-Control-Allow-Origin", refer)
}
}
2021-05-23 23:27:41 +00:00
//Init 初始化application
2021-05-23 21:47:56 +00:00
func Init(config string) Application {
appIns := Application{}
//手动模式,
appIns.SetConfig(config)
2021-05-23 22:14:58 +00:00
SetDB(&appIns)
2021-05-23 21:47:56 +00:00
//appIns.SetCache()
return appIns
}
2021-05-23 23:27:41 +00:00
// SetDB 智能数据库设置
2021-05-23 23:27:41 +00:00
func SetDB(appIns *Application) {
db := appIns.Config.GetMap("db")
dbSqlite := db.GetMap("sqlite")
dbMysql := db.GetMap("mysql")
if db != nil && dbSqlite != nil {
SetSqliteDB(appIns, dbSqlite)
}
if db != nil && dbMysql != nil {
SetMysqlDB(appIns, dbMysql)
}
}
func SetMysqlDB(appIns *Application, config Map) {
appIns.SetConnectDB(func(err ...*Error) (master, slave *sql.DB) {
//master数据库配置
query := config.GetString("user") + ":" + config.GetString("password") +
"@tcp(" + config.GetString("host") + ":" + config.GetString("port") + ")/" + config.GetString("name") + "?charset=utf8"
DB, e := sql.Open("mysql", query)
if e != nil && len(err) != 0 {
err[0].SetError(e)
}
master = DB
//slave数据库配置
configSlave := config.GetMap("slave")
if configSlave != nil {
query := configSlave.GetString("user") + ":" + configSlave.GetString("password") +
"@tcp(" + config.GetString("host") + ":" + configSlave.GetString("port") + ")/" + configSlave.GetString("name") + "?charset=utf8"
DB1, e := sql.Open("mysql", query)
if e != nil && len(err) != 0 {
err[0].SetError(e)
}
slave = DB1
}
return master, slave
//return DB
})
appIns.Db.Type = "mysql"
}
func SetSqliteDB(appIns *Application, config Map) {
appIns.SetConnectDB(func(err ...*Error) (master, slave *sql.DB) {
db, e := sql.Open("sqlite3", config.GetString("path"))
if e != nil && len(err) != 0 {
err[0].SetError(e)
}
master = db
return master, slave
})
appIns.Db.Type = "sqlite"
}