diff --git a/application.go b/application.go new file mode 100644 index 0000000..507d43f --- /dev/null +++ b/application.go @@ -0,0 +1,261 @@ +package hotime + +import ( + "bytes" + "database/sql" + "encoding/json" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" +) + +type Application struct { + Router + Error + Port string //端口号 + connectListener func(context Context) bool //所有的访问监听,true按原计划继续使用,false表示有监听器处理 + connectDbFunc func(err ...*Error) *sql.DB + configPath string + Config Map + Db HoTimeDB + CacheIns + sessionLong CacheIns + sessionShort CacheIns +} + +//启动实例 +func (this *Application) Run(router Router) { + this.Router = router + //this.Port = port + this.Port = this.Config.GetString("port") + + if this.connectDbFunc != nil { + this.Db.SetConnect(this.connectDbFunc) + } + + if this.CacheIns == nil { + this.CacheIns = CacheIns(&CacheMemory{Map: Map{}, Time: this.Config.GetInt64("cacheShortTime")}) + } + + //http.HandleFunc("/", this.handler) + run(this) + +} + +//启动实例 +func (this *Application) SetConnectDB(connect func(err ...*Error) *sql.DB) { + this.connectDbFunc = connect +} + +//设置配置文件路径全路径或者相对路径 +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.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) + } + } + //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(context Context) bool) { + this.connectListener = lis +} + +//网络错误 +func (this *Application) session(w http.ResponseWriter, req *http.Request) { + +} + +//访问 +func (this *Application) handler(w http.ResponseWriter, req *http.Request) { + + q := strings.Index(req.RequestURI, "?") + if q == -1 { + q = len(req.RequestURI) + } + o := Substr(req.RequestURI, 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]) + } + } + + //接口服务 + 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 { + + //获取cookie + // 如果cookie存在直接将sessionId赋值为cookie.Value + // 如果cookie不存在就查找传入的参数中是否有token + // 如果token不存在就生成随机的sessionId + // 如果token存在就判断token是否在Session中有保存 + // 如果有取出token并复制给cookie + // 没有保存就生成随机的session + cookie, err := req.Cookie((Config["sessionName"]).(string)) + 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: Config["sessionName"].(string), Value: sessionId, Path: "/"}) + } else { + sessionId = cookie.Value + } + + //访问实例 + 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} + + //访问拦截 + if this.connectListener != nil { + if !this.connectListener(context) { + context.View() + return + } + } + //控制层 + this.Router[s[0]][s[1]][s[2]](&context) + context.View() + return + } + + } + + //url赋值 + path := Config.GetString("tpt") + o + + //判断是否为默认 + if path[len(path)-1] == '/' { + defFile := Config["defFile"].([]string) + for i := 0; i < len(defFile); i++ { + temp := path + defFile[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 := w.Header() + + //类型判断并设置Content-Type + if strings.Contains(path, ".css") { + header.Set("Content-Type", "text/css") + //header.Get(Config["sessionName"].(string)) + } + header.Set("Cache-Control", "public") + //w.Write(data) + http.ServeFile(w, req, path) + +}