hotime/application.go
2018-11-06 14:57:53 +00:00

318 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package hotime
import (
"bytes"
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"net/url"
)
type Application struct {
Router
contextBase
Port string //端口号
connectListener []func(this *Context) bool //所有的访问监听,true按原计划继续使用false表示有监听器处理
connectDbFunc func(err ...*Error) *sql.DB
configPath string
Config Map
Db HoTimeDB
Server *http.Server
CacheIns
sessionLong CacheIns
sessionShort CacheIns
http.Handler
}
func (this *Application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
this.handler(w, req)
}
//启动实例
func (this *Application) Run(router Router) {
this.Router = router
//this.Port = port
this.Port = this.Config.GetString("port")
if this.connectDbFunc != nil && (this.Db.DB==nil||this.Db.DB.Ping() != nil) {
this.Db.SetConnect(this.connectDbFunc)
}
if this.CacheIns == nil {
this.CacheIns = CacheIns(&CacheMemory{Map: Map{}, Time: this.Config.GetInt64("cacheShortTime")})
}
//异常处理
defer func() {
if err := recover(); err != nil {
//e.SetError(errors.New(ObjToStr(err)), LOG_FMT)
fmt.Println(err)
this.Run(router)
}
}()
this.Server = &http.Server{}
if !IsRun {
IsRun = true
}
App[this.Port] = this
this.Server.Handler = this
//启动服务
this.Server.Addr = ":" + this.Port
this.Server.ListenAndServe()
}
//启动实例
func (this *Application) SetConnectDB(connect func(err ...*Error) *sql.DB) {
this.connectDbFunc = connect
this.Db.SetConnect(this.connectDbFunc)
}
//设置配置文件路径全路径或者相对路径
func (this *Application) SetSession(short CacheIns, Long CacheIns) {
this.sessionLong = Long
this.sessionShort = short
}
//默认配置缓存和session实现
func (this *Application) SetDefault(connect func(err ...*Error) *sql.DB) {
this.SetConfig()
this.connectDbFunc = connect
if this.connectDbFunc != nil {
this.Db.SetConnect(this.connectDbFunc)
}
//防止手动设置缓存误伤
if this.CacheIns == nil {
this.SetCache(CacheIns(&CacheMemory{}))
}
//防止手动设置session误伤
if this.sessionShort == nil && this.sessionLong == nil {
if this.connectDbFunc == nil {
this.SetSession(CacheIns(&CacheMemory{}), nil)
} else {
this.SetSession(CacheIns(&CacheMemory{}), CacheIns(&CacheDb{Db: &this.Db, Time: this.Config.GetInt64("cacheLongTime")}))
}
}
}
//设置配置文件路径全路径或者相对路径
func (this *Application) SetCache(cache CacheIns) {
this.CacheIns = cache
}
//设置配置文件路径全路径或者相对路径
func (this *Application) SetConfig(configPath ...string) {
if len(configPath) != 0 {
this.configPath = configPath[0]
}
if this.configPath == "" {
this.configPath = "config/config.json"
}
//加载配置文件
btes, err := ioutil.ReadFile(this.configPath)
this.Config = DeepCopyMap(Config).(Map)
if err == nil {
cmap := Map{}
//文件是否损坏
cmap.JsonToMap(string(btes), &this.Error)
for k, v := range cmap {
this.Config.Put(k, v)//程序配置
Config.Put(k,v)//系统配置
}
}
//else {
// //文件不存在则写入文件,存在不做处理
// var out bytes.Buffer
// err = json.Indent(&out, []byte(this.Config.ToJsonString()), "", "\t")
// os.MkdirAll(filepath.Dir(this.configPath), os.ModeDir)
// os.Create(this.configPath)
// err = ioutil.WriteFile(this.configPath, out.Bytes(), os.ModeApplicationend)
// if err != nil {
// this.Error.SetError(err)
// }
//}
//文件如果损坏则不写入配置防止配置文件数据丢失
if this.Error.GetError() == nil {
var out bytes.Buffer
err = json.Indent(&out, []byte(this.Config.ToJsonString()), "", "\t")
err = ioutil.WriteFile(this.configPath, out.Bytes(), os.ModeAppend)
if err != nil {
os.MkdirAll(filepath.Dir(this.configPath), os.ModeDir)
os.Create(this.configPath)
err = ioutil.WriteFile(this.configPath, out.Bytes(), os.ModeAppend)
if err != nil {
this.Error.SetError(err)
}
}
} else {
this.Error.SetError(nil)
}
}
//连接判断,返回true继续传输至控制层false则停止传输
func (this *Application) SetConnectListener(lis func(this *Context) bool) {
this.connectListener = append(this.connectListener, lis)
}
//网络错误
//func (this *Application) session(w http.ResponseWriter, req *http.Request) {
//
//}
//序列化链接
func (this *Application) urlSer(url string) (string, []string) {
q := strings.Index(url, "?")
if q == -1 {
q = len(url)
}
o := Substr(url, 0, q)
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])
}
}
return o, s
}
//访问
func (this *Application) handler(w http.ResponseWriter, req *http.Request) {
o, s := this.urlSer(req.RequestURI)
//获取cookie
// 如果cookie存在直接将sessionId赋值为cookie.Value
// 如果cookie不存在就查找传入的参数中是否有token
// 如果token不存在就生成随机的sessionId
// 如果token存在就判断token是否在Session中有保存
// 如果有取出token并复制给cookie
// 没有保存就生成随机的session
cookie, err := req.Cookie(this.Config.GetString("sessionName"))
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: this.Config.GetString("sessionName"), Value: sessionId, Path: "/"})
} else {
sessionId = cookie.Value
}
unescapeUrl,err:=url.QueryUnescape(req.RequestURI)
if err!=nil{
unescapeUrl=req.RequestURI
}
//访问实例
context := Context{SessionIns: SessionIns{SessionId: sessionId,
LongCache: this.sessionLong,
ShortCache: this.sessionShort,
},
CacheIns: this.CacheIns,
Resp: w, Req: req, Application: this, RouterString: s, Config: this.Config, Db: &this.Db, HandlerStr: unescapeUrl}
//header默认设置
header := w.Header()
header.Set("Content-Type", "text/html; charset=utf-8")
//访问拦截true继续false暂停
connectListenerLen := len(this.connectListener)
if connectListenerLen != 0 {
for i := 0; i < connectListenerLen; i++ {
if !this.connectListener[i](&context) {
context.View()
return
}
}
}
o, s = this.urlSer(context.HandlerStr)
context.RouterString = s
//接口服务
if len(s) == 3 {
//如果满足规则则路由到对应控制器去
if this.Router[s[0]] != nil && this.Router[s[0]][s[1]] != nil && this.Router[s[0]][s[1]][s[2]] != nil {
//控制层
this.Router[s[0]][s[1]][s[2]](&context)
//header.Set("Content-Type", "text/html; charset=utf-8")
context.View()
return
}
}
//url赋值
path := this.Config.GetString("tpt") + o
//判断是否为默认
if path[len(path)-1] == '/' {
defFile := this.Config.GetSlice("defFile")
for i := 0; i < len(defFile); i++ {
temp := path + defFile.GetString(i)
_, 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
}
//设置header
mimeStr := Substr(path, strings.LastIndex(path, "."), len(path))
//类型判断并设置Content-Type
if value, ok := mimeMaps[mimeStr]; ok {
header.Set("Content-Type", value)
}
if this.Config.GetInt("debug")!=1{
header.Set("Cache-Control", "public")
}
//w.Write(data)
http.ServeFile(w, req, path)
}