commit
cb49025e3c
23 changed files with 1430 additions and 0 deletions
-
16.gitignore
-
257README.md
-
43example/app/wstest.go
-
8example/config.json
-
13example/main.go
-
11example/private.json
-
157osmanthuswine.go
-
122src/core/config.go
-
25src/core/controller.go
-
121src/core/db.go
-
36src/core/redis.go
-
117src/core/request.go
-
115src/core/response.go
-
118src/core/router.go
-
51src/core/websocket.go
-
71src/core/xorm.go
-
30src/helper/db2struct.go
-
19src/helper/log.go
-
10src/helper/md5.go
-
8src/helper/uuid.go
-
11src/helper/uuid_test.go
-
21src/interfaces/websocket.go
-
50src/session/securecookie.go
@ -0,0 +1,16 @@ |
|||||
|
# Binaries for programs and plugins |
||||
|
*.exe |
||||
|
*.exe~ |
||||
|
*.dll |
||||
|
*.so |
||||
|
*.dylib |
||||
|
|
||||
|
# Test binary, build with `go test -c` |
||||
|
*.test |
||||
|
|
||||
|
# Output of the go coverage tool, specifically when used with LiteIDE |
||||
|
*.out |
||||
|
|
||||
|
.idea |
||||
|
dev.bat |
||||
|
test.go |
@ -0,0 +1,257 @@ |
|||||
|
## 内部使用基于go-chi的web框架 |
||||
|
|
||||
|
# 框架引入 |
||||
|
> go get -u github.com/wailovet/osmanthuswine |
||||
|
|
||||
|
### 目录结构 |
||||
|
``` |
||||
|
app |
||||
|
|--index |
||||
|
|--index.go |
||||
|
html |
||||
|
|--静态文件.... |
||||
|
main.go |
||||
|
config.json |
||||
|
``` |
||||
|
|
||||
|
# 开始 |
||||
|
#### 创建以上目录结构 |
||||
|
|
||||
|
|
||||
|
+ /config.json 配置文件 |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"port": "8808", |
||||
|
"host": "0.0.0.0", |
||||
|
"cross_domain": "*", |
||||
|
"post_max_memory": 1024000, |
||||
|
"update_path": "new_exe", |
||||
|
"db": { |
||||
|
"host": "", |
||||
|
"port": "", |
||||
|
"user": "", |
||||
|
"password": "", |
||||
|
"name": "", |
||||
|
"max_open_conn": 500 |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
+ /main.go文件 |
||||
|
|
||||
|
``` |
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"./app/index" |
||||
|
"github.com/wailovet/osmanthuswine" |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
//注册index控制器 |
||||
|
core.GetInstanceRouterManage().Registered(&index.Index{}) |
||||
|
//主程序执行 |
||||
|
osmanthuswine.Run() |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
+ /app/index/index.go文件 |
||||
|
|
||||
|
``` |
||||
|
package index |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
) |
||||
|
|
||||
|
type Index struct { |
||||
|
core.Controller |
||||
|
} |
||||
|
|
||||
|
func (that *Index) Index() { |
||||
|
that.DisplayByData(that.Request.REQUEST) |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
## core.Controller.Request 使用说明 |
||||
|
#### 输入参数 |
||||
|
+ that.Request.GET["参数"] //类型:map[string]string |
||||
|
+ that.Request.POST["参数"] //类型:map[string]string |
||||
|
+ that.Request.REQUEST["参数"] //类型:map[string]string , 为GET以及POST的合并值,当出现值冲突时GET参数会被覆盖 |
||||
|
#### session与cookie获取 |
||||
|
+ that.Request.SESSION["参数"] //类型:map[string]string |
||||
|
+ that.Request.COOKIE["参数"] //类型:map[string]string |
||||
|
#### header信息获取 |
||||
|
+ that.Request.HEADER["参数"] //类型:map[string]string |
||||
|
#### 该取值一般以POST-RAW形式传入原始数据,有可能 |
||||
|
+ that.Request.BODY //类型:string |
||||
|
#### 快速获取上传的文件 |
||||
|
+ that.Request.FILE //类型:*multipart.FileHeader |
||||
|
#### 获取上传的所有文件 |
||||
|
+ that.Request.FILES //类型:map[string][]*multipart.FileHeader |
||||
|
|
||||
|
|
||||
|
|
||||
|
## core.Controller 使用说明 |
||||
|
#### 输出显示 |
||||
|
> 即使输出时不处于函数结尾,也无需return |
||||
|
+ that.DisplayByData(data interface{}) |
||||
|
``` |
||||
|
{ |
||||
|
"code":0, |
||||
|
"data":data, |
||||
|
"msg":"" |
||||
|
} |
||||
|
``` |
||||
|
- - - |
||||
|
+ that.DisplayBySuccess(msg string) |
||||
|
``` |
||||
|
{ |
||||
|
"code":0, |
||||
|
"data":null, |
||||
|
"msg":msg |
||||
|
} |
||||
|
``` |
||||
|
- - - |
||||
|
+ that.DisplayByError(msg string, code int) |
||||
|
``` |
||||
|
{ |
||||
|
"code":code, |
||||
|
"data":null, |
||||
|
"msg":msg |
||||
|
} |
||||
|
``` |
||||
|
- - - |
||||
|
+ that.Display(data interface{}, msg string, code int) |
||||
|
``` |
||||
|
{ |
||||
|
"code":code, |
||||
|
"data":data, |
||||
|
"msg":msg |
||||
|
} |
||||
|
``` |
||||
|
- - - |
||||
|
+ that.DisplayByString(data string) |
||||
|
``` |
||||
|
data //直接输出data以string形式 |
||||
|
``` |
||||
|
- - - |
||||
|
+ that.DisplayByRaw(data []byte) |
||||
|
``` |
||||
|
data //直接输出data以[]byte形式,可用于直接输出二进制文件 |
||||
|
``` |
||||
|
- - - |
||||
|
##### 20190416新增 |
||||
|
+ that.CheckErrDisplayByError(err error,msg...) |
||||
|
``` |
||||
|
err //错误信息,自动判断是否等于nil,如果等于nil该语句会被忽略 |
||||
|
msg //错误文案提示,不填直接输出err.Error() |
||||
|
``` |
||||
|
|
||||
|
#### session操作 |
||||
|
> 目前session实现基于securecookie,以加密形式储存在cookie中,注意不要存放大量数据,以免超过cookie的最大储存值 |
||||
|
+ that.SetSession(name string, value string) //设置session |
||||
|
+ that.DeleteSession(name string) //删除session |
||||
|
+ that.ClearSession() //清空session |
||||
|
|
||||
|
#### cookie操作 |
||||
|
> 尽量以session的形式操作 |
||||
|
+ that.SetCookie(name string, value string) |
||||
|
|
||||
|
|
||||
|
## 数据库操作 |
||||
|
> 目前框架中集成gorm与xorm框架 |
||||
|
+ core.GetXormAuto() //获取xorm实例 |
||||
|
+ core.GetGormAuto() //获取gorm实例 |
||||
|
#### 数据库配置 |
||||
|
``` |
||||
|
实例的数据库配置来自于相同目录下的config.json或者private.json文件 |
||||
|
{ |
||||
|
...其他配置 |
||||
|
"db": { |
||||
|
"host": "", |
||||
|
"port": "", |
||||
|
"user": "", |
||||
|
"password": "", |
||||
|
"name": "", |
||||
|
"prefix": "", |
||||
|
"max_open_conn": 500 |
||||
|
} |
||||
|
} |
||||
|
prefix为表前缀 |
||||
|
max_open_conn为可支持最大连接数(未测试是否可用 |
||||
|
``` |
||||
|
|
||||
|
## 支持WebSocket |
||||
|
> 当传入core.GetInstanceRouterManage().Registered的对象继承自core.WebSocket时,协议升级为websocket,路由地址忽略最后方法名 |
||||
|
|
||||
|
|
||||
|
#### 集成melody库,使用详情https://github.com/olahol/melody |
||||
|
``` |
||||
|
package index |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
"gopkg.in/olahol/melody.v1" |
||||
|
) |
||||
|
|
||||
|
type Index struct { |
||||
|
core.WebSocket |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleConnect(session *melody.Session) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandlePong(session *melody.Session) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleMessage(session *melody.Session, data []byte) { |
||||
|
that.GetMelody().Broadcast(data) |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleMessageBinary(session *melody.Session, data []byte) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleSentMessage(session *melody.Session, data []byte) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleSentMessageBinary(session *melody.Session, data []byte) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleDisconnect(session *melody.Session) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleError(session *melody.Session, err error) { |
||||
|
//implement |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
``` |
||||
|
//javascript |
||||
|
var ws = new WebSocket("ws://127.0.0.1/Api/Index/Index") |
||||
|
``` |
||||
|
> PS:不同url对应不同的melody实例 |
||||
|
|
||||
|
|
||||
|
## 杂项 |
||||
|
> 热更新,仅支持linux |
||||
|
``` |
||||
|
默认情况下,检测同路径下的<文件名_update>,如果该文件与当前文件不一致,则进行热更,已连接的连接无需断连 |
||||
|
可在config.json中配置检测的文件名 |
||||
|
{ |
||||
|
...其他配置 |
||||
|
"update_path": "需要检测的文件路径" |
||||
|
} |
||||
|
备注:需要检测的文件路径最好不要与当前运行的文件路径相同 |
||||
|
``` |
@ -0,0 +1,43 @@ |
|||||
|
package app |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
"gopkg.in/olahol/melody.v1" |
||||
|
) |
||||
|
|
||||
|
type Wstest struct { |
||||
|
core.WebSocket |
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleConnect(session *melody.Session) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandlePong(session *melody.Session) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleMessage(session *melody.Session, data []byte) { |
||||
|
that.GetMelody().Broadcast(data) |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleMessageBinary(session *melody.Session, data []byte) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleSentMessage(session *melody.Session, data []byte) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleSentMessageBinary(session *melody.Session, data []byte) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleDisconnect(session *melody.Session) { |
||||
|
//implement
|
||||
|
} |
||||
|
|
||||
|
func (that *Wstest) HandleError(session *melody.Session, err error) { |
||||
|
//implement
|
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
{ |
||||
|
"port": "20180", |
||||
|
"host": "0.0.0.0", |
||||
|
"cross_domain": "*", |
||||
|
"post_max_memory": 1024000, |
||||
|
"api_router": "/Api/*", |
||||
|
"update_path": "example_update" |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine" |
||||
|
"github.com/wailovet/osmanthuswine/example/app" |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
core.GetInstanceRouterManage().Registered(&app.Wstest{}) |
||||
|
core.GetInstanceRouterManage().Registered(&app.Test{}) |
||||
|
osmanthuswine.Run() |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"db": { |
||||
|
"host": "", |
||||
|
"port": "", |
||||
|
"user": "", |
||||
|
"password": "", |
||||
|
"name": "", |
||||
|
"prefix": "", |
||||
|
"max_open_conn": 500 |
||||
|
} |
||||
|
} |
@ -0,0 +1,157 @@ |
|||||
|
package osmanthuswine |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"github.com/go-chi/chi" |
||||
|
"github.com/go-chi/chi/middleware" |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
"github.com/wailovet/osmanthuswine/src/helper" |
||||
|
"github.com/wailovet/osmanthuswine/src/session" |
||||
|
"github.com/wailovet/overseer" |
||||
|
"github.com/wailovet/overseer/fetcher" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"net" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
"os/exec" |
||||
|
"path/filepath" |
||||
|
"runtime" |
||||
|
"runtime/debug" |
||||
|
"strings" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
var chiRouter *chi.Mux |
||||
|
|
||||
|
func GetChiRouter() *chi.Mux { |
||||
|
if chiRouter == nil { |
||||
|
|
||||
|
chiRouter = chi.NewRouter() |
||||
|
chiRouter.Use(middleware.RequestID) |
||||
|
chiRouter.Use(middleware.RealIP) |
||||
|
chiRouter.Use(middleware.Logger) |
||||
|
chiRouter.Use(middleware.Recoverer) |
||||
|
chiRouter.Use(middleware.Timeout(60 * time.Second)) |
||||
|
} |
||||
|
return chiRouter |
||||
|
} |
||||
|
func Run() { |
||||
|
path, _ := GetCurrentPath() |
||||
|
os.Chdir(path) |
||||
|
log.Println("工作目录:", path) |
||||
|
cc := core.GetInstanceConfig() |
||||
|
|
||||
|
if runtime.GOOS == "windows" || cc.UpdatePath == "" { |
||||
|
listener, err := net.Listen("tcp", cc.Host+":"+cc.Port) |
||||
|
if err != nil { |
||||
|
log.Fatal(err.Error()) |
||||
|
} |
||||
|
RunProg(overseer.State{ |
||||
|
Listener: listener, |
||||
|
}) |
||||
|
} else { |
||||
|
overseer.Run(overseer.Config{ |
||||
|
Program: RunProg, |
||||
|
Address: cc.Host + ":" + cc.Port, |
||||
|
Fetcher: &fetcher.File{ |
||||
|
Path: cc.UpdateDir + cc.UpdatePath, |
||||
|
Interval: time.Second * 10, |
||||
|
}, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
func RunProg(state overseer.State) { |
||||
|
|
||||
|
cc := core.GetInstanceConfig() |
||||
|
helper.GetInstanceLog().Out("开始监听:", cc.Host+":"+cc.Port) |
||||
|
|
||||
|
r := GetChiRouter() |
||||
|
|
||||
|
apiRouter := cc.ApiRouter |
||||
|
|
||||
|
r.HandleFunc(apiRouter, func(writer http.ResponseWriter, request *http.Request) { |
||||
|
|
||||
|
requestData := core.Request{} |
||||
|
|
||||
|
sessionMan := session.New(request, writer) |
||||
|
|
||||
|
requestData.REQUEST = make(map[string]string) |
||||
|
//GET
|
||||
|
requestData.SyncGetData(request) |
||||
|
//POST
|
||||
|
requestData.SyncPostData(request, cc.PostMaxMemory) |
||||
|
//HEADER
|
||||
|
requestData.SyncHeaderData(request) |
||||
|
//COOKIE
|
||||
|
requestData.SyncCookieData(request) |
||||
|
//SESSION
|
||||
|
requestData.SyncSessionData(sessionMan) |
||||
|
|
||||
|
responseHandle := core.Response{OriginResponseWriter: writer, Session: sessionMan} |
||||
|
|
||||
|
defer func() { |
||||
|
errs := recover() |
||||
|
if errs == nil { |
||||
|
return |
||||
|
} |
||||
|
errtxt := fmt.Sprintf("%v", errs) |
||||
|
if errtxt != "" { |
||||
|
responseHandle.DisplayByError(errtxt, 500, strings.Split(string(debug.Stack()), "\n\t")...) |
||||
|
} |
||||
|
}() |
||||
|
|
||||
|
core.GetInstanceRouterManage().RouterSend(request.URL.Path, requestData, responseHandle, cc.CrossDomain) |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
r.HandleFunc("/*", func(writer http.ResponseWriter, request *http.Request) { |
||||
|
path := request.URL.Path |
||||
|
if path == "/" { |
||||
|
path = "/index.html" |
||||
|
} |
||||
|
|
||||
|
helper.GetInstanceLog().Out("静态文件:", "./html"+path) |
||||
|
|
||||
|
f, err := os.Stat("./html" + path) |
||||
|
if err == nil { |
||||
|
if f.IsDir() { |
||||
|
path += "/index.html" |
||||
|
} |
||||
|
data, err := ioutil.ReadFile("./html" + path) |
||||
|
if err == nil { |
||||
|
writer.Write(data) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writer.WriteHeader(404) |
||||
|
writer.Write([]byte(err.Error())) |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
http.Serve(state.Listener, r) |
||||
|
//http.ListenAndServe(cc.Host+":"+cc.Port, r)
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
func GetCurrentPath() (string, error) { |
||||
|
file, err := exec.LookPath(os.Args[0]) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
path, err := filepath.Abs(file) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
i := strings.LastIndex(path, "/") |
||||
|
if i < 0 { |
||||
|
i = strings.LastIndex(path, "\\") |
||||
|
} |
||||
|
if i < 0 { |
||||
|
return "", errors.New(`error: Can't find "/" or "\".`) |
||||
|
} |
||||
|
return string(path[0 : i+1]), nil |
||||
|
} |
@ -0,0 +1,122 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"os" |
||||
|
) |
||||
|
|
||||
|
type Config struct { |
||||
|
Port string `json:"port"` |
||||
|
Host string `json:"host"` |
||||
|
CrossDomain string `json:"cross_domain"` |
||||
|
ApiRouter string `json:"api_router"` |
||||
|
PostMaxMemory int64 `json:"post_max_memory"` |
||||
|
Db struct { |
||||
|
Host string `json:"host"` |
||||
|
Port string `json:"port"` |
||||
|
User string `json:"user"` |
||||
|
Password string `json:"password"` |
||||
|
Name string `json:"name"` |
||||
|
Prefix string `json:"prefix"` |
||||
|
MaxOpenConn int `json:"max_open_conn"` |
||||
|
Params map[string]string `json:"params"` |
||||
|
Debug bool `json:"debug"` |
||||
|
} `json:"db"` |
||||
|
Redis struct { |
||||
|
Addr string `json:"addr"` |
||||
|
Password string `json:"password"` |
||||
|
Db int `json:"db"` |
||||
|
} `json:"redis"` |
||||
|
UpdateDir string `json:"update_dir"` |
||||
|
UpdatePath string `json:"update_path"` |
||||
|
} |
||||
|
|
||||
|
var instanceConfig *Config |
||||
|
var configFile = "./config.json" |
||||
|
var privateConfigFile = "./private.json" |
||||
|
|
||||
|
func SetConfigFile(c string) { |
||||
|
configFile = c |
||||
|
} |
||||
|
|
||||
|
func SetConfig(c *Config) { |
||||
|
instanceConfig = c |
||||
|
} |
||||
|
|
||||
|
func GetInstanceConfig() *Config { |
||||
|
if instanceConfig == nil { |
||||
|
instanceConfig = &Config{ |
||||
|
Host: "localhost", |
||||
|
Port: "8808", |
||||
|
ApiRouter: "/Api/*", |
||||
|
CrossDomain: "*", |
||||
|
PostMaxMemory: 1024 * 1024 * 10, |
||||
|
Db: struct { |
||||
|
Host string `json:"host"` |
||||
|
Port string `json:"port"` |
||||
|
User string `json:"user"` |
||||
|
Password string `json:"password"` |
||||
|
Name string `json:"name"` |
||||
|
Prefix string `json:"prefix"` |
||||
|
MaxOpenConn int `json:"max_open_conn"` |
||||
|
Params map[string]string `json:"params"` |
||||
|
Debug bool `json:"debug"` |
||||
|
}{ |
||||
|
Host: "localhost", |
||||
|
Port: "3306", |
||||
|
User: "root", |
||||
|
Password: "root", |
||||
|
Name: "test", |
||||
|
Prefix: "", |
||||
|
MaxOpenConn: 500, |
||||
|
Params: map[string]string{ |
||||
|
"charset": "utf8mb4", |
||||
|
"parseTime": "true", |
||||
|
}, |
||||
|
Debug: true, |
||||
|
}, |
||||
|
Redis: struct { |
||||
|
Addr string `json:"addr"` |
||||
|
Password string `json:"password"` |
||||
|
Db int `json:"db"` |
||||
|
}{ |
||||
|
Addr: "localhost:6379", |
||||
|
Password: "", |
||||
|
Db: 0, |
||||
|
}, |
||||
|
UpdateDir: "", |
||||
|
UpdatePath: os.Args[0] + "_update", |
||||
|
} |
||||
|
|
||||
|
instanceConfig.ReadConfig(configFile) |
||||
|
instanceConfig.ReadPrivateConfig(privateConfigFile) |
||||
|
} |
||||
|
return instanceConfig |
||||
|
} |
||||
|
|
||||
|
func (c *Config) ReadConfig(file string) { |
||||
|
configText, err := ioutil.ReadFile(file) |
||||
|
if err != nil { |
||||
|
log.Println("配置文件错误,启动失败:", err.Error()) |
||||
|
os.Exit(0) |
||||
|
} |
||||
|
err = json.Unmarshal(configText, c) |
||||
|
if err != nil { |
||||
|
log.Println("配置文件错误,启动失败:", err.Error()) |
||||
|
os.Exit(0) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Config) ReadPrivateConfig(file string) { |
||||
|
configText, err := ioutil.ReadFile(file) |
||||
|
if err != nil { |
||||
|
log.Println("未加载", privateConfigFile, ":", err.Error()) |
||||
|
return |
||||
|
} |
||||
|
err = json.Unmarshal(configText, c) |
||||
|
if err != nil { |
||||
|
log.Println("未加载", privateConfigFile, ":", err.Error()) |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package core |
||||
|
|
||||
|
import "encoding/json" |
||||
|
|
||||
|
type Controller struct { |
||||
|
Response |
||||
|
Request Request |
||||
|
} |
||||
|
|
||||
|
func (c *Controller) ControllerInit(req Request, res Response) { |
||||
|
c.Request = req |
||||
|
c.Session = res.Session |
||||
|
c.OriginResponseWriter = res.OriginResponseWriter |
||||
|
} |
||||
|
|
||||
|
func (c *Controller) RequestToStruct(v interface{}) error { |
||||
|
if c.Request.BODY != "" { |
||||
|
err := json.Unmarshal([]byte(c.Request.BODY), v) |
||||
|
if err == nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
data, _ := json.Marshal(c.Request.REQUEST) |
||||
|
return json.Unmarshal(data, v) |
||||
|
} |
@ -0,0 +1,121 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"github.com/go-sql-driver/mysql" |
||||
|
"github.com/jinzhu/gorm" |
||||
|
"strings" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
var instanceDb *gorm.DB |
||||
|
|
||||
|
func GetDb() (*gorm.DB, error) { |
||||
|
if instanceDb == nil { |
||||
|
config := GetInstanceConfig() |
||||
|
mysqlConfig := mysql.NewConfig() |
||||
|
mysqlConfig.User = config.Db.User |
||||
|
mysqlConfig.DBName = config.Db.Name |
||||
|
mysqlConfig.Passwd = config.Db.Password |
||||
|
mysqlConfig.Params = config.Db.Params |
||||
|
mysqlConfig.Net = "tcp" |
||||
|
mysqlConfig.Addr = config.Db.Host + ":" + config.Db.Port |
||||
|
|
||||
|
db, err := gorm.Open("mysql", mysqlConfig.FormatDSN()) |
||||
|
gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string { |
||||
|
if len(defaultTableName) > len(config.Db.Prefix) && defaultTableName[:len(config.Db.Prefix)] == config.Db.Prefix { |
||||
|
return defaultTableName |
||||
|
} |
||||
|
return config.Db.Prefix + defaultTableName |
||||
|
} |
||||
|
db.DB().SetMaxOpenConns(config.Db.MaxOpenConn) |
||||
|
db.SingularTable(true) |
||||
|
instanceDb = db |
||||
|
return instanceDb, err |
||||
|
} |
||||
|
return instanceDb, nil |
||||
|
} |
||||
|
|
||||
|
func GetGormAuto() *gorm.DB { |
||||
|
return GetDbAuto() |
||||
|
} |
||||
|
|
||||
|
func GetDbAuto() *gorm.DB { |
||||
|
db, err := GetDb() |
||||
|
if err != nil { |
||||
|
panic("数据库访问错误") |
||||
|
} |
||||
|
return db |
||||
|
} |
||||
|
|
||||
|
func DbQuery(query string, args ...interface{}) []map[string]interface{} { |
||||
|
db := GetDbAuto() |
||||
|
rows, _ := db.DB().Query(query, args...) // Note: Ignoring errors for brevity
|
||||
|
defer rows.Close() |
||||
|
cols, _ := rows.Columns() |
||||
|
var data []map[string]interface{} |
||||
|
for rows.Next() { |
||||
|
columns := make([]interface{}, len(cols)) |
||||
|
columnPointers := make([]interface{}, len(cols)) |
||||
|
for i, _ := range columns { |
||||
|
columnPointers[i] = &columns[i] |
||||
|
} |
||||
|
|
||||
|
// Scan the result into the column pointers...
|
||||
|
if err := rows.Scan(columnPointers...); err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
// Create our map, and retrieve the value for each column from the pointers slice,
|
||||
|
// storing it in the map with the name of the column as the key.
|
||||
|
m := make(map[string]interface{}) |
||||
|
for i, colName := range cols { |
||||
|
val := columnPointers[i].(*interface{}) |
||||
|
m[colName] = *val |
||||
|
} |
||||
|
data = append(data, m) |
||||
|
} |
||||
|
return data |
||||
|
} |
||||
|
|
||||
|
var isUpdateComment = make(map[string]bool) |
||||
|
|
||||
|
func GetDbAutoMigrate(values ...interface{}) *gorm.DB { |
||||
|
db := GetDbAuto() |
||||
|
db.AutoMigrate(values...) |
||||
|
|
||||
|
for _, value := range values { |
||||
|
scope := db.NewScope(value) |
||||
|
tableName := scope.TableName() |
||||
|
_, isOk := isUpdateComment[tableName] |
||||
|
if !isOk { |
||||
|
field := scope.Fields() |
||||
|
for e := range field { |
||||
|
comment := field[e].Tag.Get("comment") |
||||
|
|
||||
|
if len(strings.Trim(comment, " ")) > 0 { |
||||
|
fieldType := db.Dialect().DataTypeOf(field[e].StructField) |
||||
|
scope.Raw(fmt.Sprintf("ALTER TABLE `%v` MODIFY COLUMN `%v` %v COMMENT '%v';", tableName, field[e].DBName, fieldType, comment)).Exec() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
isUpdateComment[tableName] = true |
||||
|
} |
||||
|
|
||||
|
return db |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
go func() { |
||||
|
for { |
||||
|
if instanceDb != nil { |
||||
|
err := instanceDb.DB().Ping() |
||||
|
if err != nil { |
||||
|
println(err.Error()) |
||||
|
instanceDb.Close() |
||||
|
instanceDb = nil |
||||
|
} |
||||
|
} |
||||
|
time.Sleep(time.Second) |
||||
|
} |
||||
|
}() |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"github.com/go-redis/redis" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
var instanceRedis *redis.Client |
||||
|
|
||||
|
func GetRedis() *redis.Client { |
||||
|
if instanceRedis == nil { |
||||
|
config := GetInstanceConfig() |
||||
|
instanceRedis = redis.NewClient(&redis.Options{ |
||||
|
Addr: config.Redis.Addr, |
||||
|
Password: config.Redis.Password, // no password set
|
||||
|
DB: config.Redis.Db, // use default DB
|
||||
|
}) |
||||
|
} |
||||
|
return instanceRedis |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
go func() { |
||||
|
for { |
||||
|
if instanceRedis != nil { |
||||
|
err := instanceRedis.Ping().Err() |
||||
|
if err != nil { |
||||
|
println(err.Error()) |
||||
|
instanceRedis.Close() |
||||
|
instanceRedis = nil |
||||
|
} |
||||
|
} |
||||
|
time.Sleep(time.Second) |
||||
|
} |
||||
|
}() |
||||
|
} |
@ -0,0 +1,117 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/session" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"mime/multipart" |
||||
|
"net/http" |
||||
|
"net/url" |
||||
|
) |
||||
|
|
||||
|
type Request struct { |
||||
|
GET map[string]string |
||||
|
POST map[string]string |
||||
|
REQUEST map[string]string |
||||
|
COOKIE map[string]string |
||||
|
SESSION map[string]string |
||||
|
HEADER map[string]string |
||||
|
BODY string |
||||
|
FILES map[string][]*multipart.FileHeader |
||||
|
FILE *multipart.FileHeader |
||||
|
OriginRequest *http.Request |
||||
|
} |
||||
|
|
||||
|
func (r *Request) SyncGetData(request *http.Request) { |
||||
|
if r.OriginRequest == nil { |
||||
|
r.OriginRequest = request |
||||
|
} |
||||
|
get := request.URL.Query() |
||||
|
r.GET = make(map[string]string) |
||||
|
for k := range get { |
||||
|
str := request.URL.Query().Get(k) |
||||
|
tmp, err := url.QueryUnescape(str) |
||||
|
if err != nil { |
||||
|
log.Println(err.Error()) |
||||
|
r.GET[k] = str |
||||
|
r.REQUEST[k] = str |
||||
|
} else { |
||||
|
r.GET[k] = tmp |
||||
|
r.REQUEST[k] = tmp |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *Request) SyncPostData(request *http.Request, mem int64) { |
||||
|
if r.OriginRequest == nil { |
||||
|
r.OriginRequest = request |
||||
|
} |
||||
|
request.ParseForm() |
||||
|
request.ParseMultipartForm(mem) |
||||
|
r.POST = make(map[string]string) |
||||
|
|
||||
|
post := request.PostForm |
||||
|
for k := range post { |
||||
|
str := request.PostFormValue(k) |
||||
|
tmp, err := url.QueryUnescape(str) |
||||
|
if err != nil { |
||||
|
log.Println(err.Error()) |
||||
|
r.POST[k] = str |
||||
|
r.REQUEST[k] = str |
||||
|
} else { |
||||
|
r.POST[k] = tmp |
||||
|
r.REQUEST[k] = tmp |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if request.MultipartForm != nil { |
||||
|
r.FILES = request.MultipartForm.File |
||||
|
if len(r.FILES) > 0 { |
||||
|
for fe := range r.FILES { |
||||
|
for fk := range r.FILES[fe] { |
||||
|
r.FILE = r.FILES[fe][fk] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
mf := request.MultipartForm.Value |
||||
|
for k := range mf { |
||||
|
if len(mf[k]) > 0 { |
||||
|
r.POST[k] = mf[k][0] |
||||
|
r.REQUEST[k] = mf[k][0] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
body, _ := ioutil.ReadAll(request.Body) |
||||
|
r.BODY = string(body) |
||||
|
} |
||||
|
|
||||
|
func (r *Request) SyncHeaderData(request *http.Request) { |
||||
|
if r.OriginRequest == nil { |
||||
|
r.OriginRequest = request |
||||
|
} |
||||
|
r.HEADER = make(map[string]string) |
||||
|
header := request.Header |
||||
|
for k := range header { |
||||
|
if len(header[k]) > 0 { |
||||
|
r.HEADER[k] = header[k][0] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
func (r *Request) SyncCookieData(request *http.Request) { |
||||
|
if r.OriginRequest == nil { |
||||
|
r.OriginRequest = request |
||||
|
} |
||||
|
cookie := request.Cookies() |
||||
|
r.COOKIE = make(map[string]string) |
||||
|
for k := range cookie { |
||||
|
r.COOKIE[cookie[k].Name] = cookie[k].Value |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *Request) SyncSessionData(session *session.Session) { |
||||
|
r.SESSION = session.GetSession() |
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"github.com/wailovet/osmanthuswine/src/session" |
||||
|
"net/http" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
type ResponseData struct { |
||||
|
Code int `json:"code"` |
||||
|
Data interface{} `json:"data"` |
||||
|
Message string `json:"message"` |
||||
|
} |
||||
|
|
||||
|
type Response struct { |
||||
|
Session *session.Session |
||||
|
IsWebSocket bool |
||||
|
OriginResponseWriter http.ResponseWriter |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DisplayByRaw(data []byte) { |
||||
|
if r.IsWebSocket { |
||||
|
panic(nil) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
r.OriginResponseWriter.Header().Add("Content-Type", "application/json; charset=utf-8") |
||||
|
r.OriginResponseWriter.Write(data) |
||||
|
panic(nil) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DisplayByString(data string) { |
||||
|
r.DisplayByRaw([]byte(data)) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) Display(data interface{}, msg string, code int) { |
||||
|
result := ResponseData{code, data, msg} |
||||
|
text, err := json.Marshal(result) |
||||
|
if err != nil { |
||||
|
r.OriginResponseWriter.WriteHeader(500) |
||||
|
r.DisplayByString("服务器异常:" + err.Error()) |
||||
|
} |
||||
|
r.DisplayByRaw(text) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DisplayByError(msg string, code int, data ...string) { |
||||
|
result := ResponseData{code, data, msg} |
||||
|
text, err := json.Marshal(result) |
||||
|
if err != nil { |
||||
|
r.Display(nil, "JSON返回格式解析异常:"+err.Error(), 500) |
||||
|
} |
||||
|
r.DisplayByRaw(text) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) CheckErrDisplayByError(err error, msg ...string) { |
||||
|
if err == nil { |
||||
|
return |
||||
|
} |
||||
|
if len(msg) > 0 { |
||||
|
r.DisplayByError(strings.Join(msg, ","), 504) |
||||
|
} else { |
||||
|
r.DisplayByError(err.Error(), 504) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DisplayBySuccess(msg string) { |
||||
|
result := ResponseData{0, nil, msg} |
||||
|
text, err := json.Marshal(result) |
||||
|
if err != nil { |
||||
|
r.Display(nil, "JSON返回格式解析异常:"+err.Error(), 500) |
||||
|
} |
||||
|
r.DisplayByRaw(text) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DisplayByData(data interface{}) { |
||||
|
result := ResponseData{0, data, ""} |
||||
|
text, err := json.Marshal(result) |
||||
|
if err != nil { |
||||
|
r.Display(nil, "JSON返回格式解析异常:"+err.Error(), 500) |
||||
|
} |
||||
|
r.DisplayByRaw(text) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) SetSession(name string, value string) { |
||||
|
data := r.Session.GetSession() |
||||
|
data[name] = value |
||||
|
r.Session.SetSession(data) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) DeleteSession(name string) { |
||||
|
data := r.Session.GetSession() |
||||
|
delete(data, name) |
||||
|
r.Session.SetSession(data) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) ClearSession() { |
||||
|
data := make(map[string]string) |
||||
|
r.Session.SetSession(data) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) SetCookie(name string, value string) { |
||||
|
cookie := &http.Cookie{ |
||||
|
Name: name, |
||||
|
Value: value, |
||||
|
Path: "/", |
||||
|
Secure: false, |
||||
|
HttpOnly: false, |
||||
|
} |
||||
|
http.SetCookie(r.OriginResponseWriter, cookie) |
||||
|
} |
||||
|
|
||||
|
func (r *Response) SetHeader(name string, value string) { |
||||
|
r.OriginResponseWriter.Header().Set(name, value) |
||||
|
} |
@ -0,0 +1,118 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/interfaces" |
||||
|
"log" |
||||
|
"reflect" |
||||
|
"strings" |
||||
|
"unicode" |
||||
|
) |
||||
|
|
||||
|
type RouterManage struct { |
||||
|
RegisteredData map[string]reflect.Type |
||||
|
} |
||||
|
|
||||
|
var instanceRouterManage *RouterManage |
||||
|
|
||||
|
func GetInstanceRouterManage() *RouterManage { |
||||
|
if instanceRouterManage == nil { |
||||
|
instanceRouterManage = &RouterManage{} // not thread safe
|
||||
|
instanceRouterManage.RegisteredData = make(map[string]reflect.Type) |
||||
|
} |
||||
|
return instanceRouterManage |
||||
|
} |
||||
|
|
||||
|
func (rm *RouterManage) Registered(i interface{}) { |
||||
|
t := reflect.ValueOf(i) |
||||
|
GetInstanceRouterManage().RegisteredData[t.Type().String()] = reflect.Indirect(t).Type() |
||||
|
} |
||||
|
|
||||
|
func (rm *RouterManage) GetModuleName(name string) string { |
||||
|
if name == "" { |
||||
|
return "index" |
||||
|
} |
||||
|
return strings.ToLower(name) |
||||
|
} |
||||
|
func (rm *RouterManage) GetControllerName(name string) string { |
||||
|
if name == "" { |
||||
|
return "Index" |
||||
|
} |
||||
|
for i, v := range name { |
||||
|
return string(unicode.ToUpper(v)) + name[i+1:] |
||||
|
} |
||||
|
return "Index" |
||||
|
} |
||||
|
func (rm *RouterManage) GetFunName(name string) string { |
||||
|
if name == "" { |
||||
|
return "Index" |
||||
|
} |
||||
|
for i, v := range name { |
||||
|
return string(unicode.ToUpper(v)) + name[i+1:] |
||||
|
} |
||||
|
return "Index" |
||||
|
} |
||||
|
|
||||
|
func (rm *RouterManage) RouterSend(urlPath string, request Request, response Response, crossDomain string) { |
||||
|
tmp := strings.Split(urlPath, ".") |
||||
|
if len(tmp) > 1 { |
||||
|
urlPath = strings.Join(tmp[0:len(tmp)-1], ".") |
||||
|
} |
||||
|
|
||||
|
sar := strings.Split(urlPath, "/") |
||||
|
for len(sar) < 5 { |
||||
|
sar = append(sar, "") |
||||
|
} |
||||
|
//过滤非 /Api开头的
|
||||
|
module := rm.GetModuleName(sar[2]) |
||||
|
controller := rm.GetControllerName(sar[3]) |
||||
|
fun := rm.GetFunName(sar[4]) |
||||
|
|
||||
|
ctr := "*" + module + "." + controller |
||||
|
|
||||
|
_, ok := rm.RegisteredData[ctr] |
||||
|
if !ok { |
||||
|
panic("未注册该组件:" + ctr) |
||||
|
} |
||||
|
|
||||
|
vc := reflect.New(rm.RegisteredData[ctr]) |
||||
|
|
||||
|
wsinit := vc.MethodByName("WebSocketInit") |
||||
|
if wsinit.IsValid() { |
||||
|
response.IsWebSocket = true |
||||
|
hand := vc.Interface().(interfaces.WebSocketInterface) |
||||
|
ws := GetWebSocket(ctr+"-"+fun, hand) |
||||
|
hand.SetFunName(fun) |
||||
|
hand.WebSocketInit(ws) |
||||
|
defer func() { |
||||
|
errs := recover() |
||||
|
if errs == nil { |
||||
|
return |
||||
|
} |
||||
|
log.Printf("websocket error:%v", errs) |
||||
|
}() |
||||
|
|
||||
|
_ = ws.HandleRequest(response.OriginResponseWriter, request.OriginRequest) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
f := vc.MethodByName(fun) |
||||
|
if !f.IsValid() { |
||||
|
panic("组件找不到相应function:" + fun) |
||||
|
} |
||||
|
|
||||
|
init := vc.MethodByName("ControllerInit") |
||||
|
if init.IsValid() { |
||||
|
init.Call([]reflect.Value{reflect.ValueOf(request), reflect.ValueOf(response)}) |
||||
|
f.Call(nil) |
||||
|
} else { |
||||
|
//兼容模式
|
||||
|
log.Println("兼容模式") |
||||
|
f.Call([]reflect.Value{reflect.ValueOf(request), reflect.ValueOf(response)}) |
||||
|
} |
||||
|
|
||||
|
response.OriginResponseWriter.Header().Set("Content-Type", "application/json;charset=UTF-8") |
||||
|
if crossDomain != "" { |
||||
|
response.OriginResponseWriter.Header().Set("Access-Control-Allow-Origin", crossDomain) |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"github.com/wailovet/osmanthuswine/src/interfaces" |
||||
|
"gopkg.in/olahol/melody.v1" |
||||
|
"net/http" |
||||
|
"sync" |
||||
|
) |
||||
|
|
||||
|
var instanceMelody sync.Map |
||||
|
|
||||
|
type WebSocket struct { |
||||
|
ws *melody.Melody |
||||
|
FunName string |
||||
|
} |
||||
|
|
||||
|
func (that *WebSocket) SetFunName(funName string) { |
||||
|
that.FunName = funName |
||||
|
} |
||||
|
|
||||
|
func (that *WebSocket) WebSocketInit(wsx *melody.Melody) { |
||||
|
that.ws = wsx |
||||
|
} |
||||
|
func (that *WebSocket) GetMelody() *melody.Melody { |
||||
|
return that.ws |
||||
|
} |
||||
|
|
||||
|
func (that *WebSocket) GetWebSocket() *melody.Melody { |
||||
|
return that.ws |
||||
|
} |
||||
|
|
||||
|
func GetWebSocket(group string, hand interfaces.WebSocketInterface) *melody.Melody { |
||||
|
var m *melody.Melody |
||||
|
tmp, ok := instanceMelody.Load(group) |
||||
|
if !ok { |
||||
|
m = melody.New() |
||||
|
m.Upgrader.CheckOrigin = func(r *http.Request) bool { return true } |
||||
|
m.HandleConnect(hand.HandleConnect) |
||||
|
m.HandleDisconnect(hand.HandleDisconnect) |
||||
|
m.HandlePong(hand.HandlePong) |
||||
|
m.HandleError(hand.HandleError) |
||||
|
m.HandleMessage(hand.HandleMessage) |
||||
|
m.HandleMessageBinary(hand.HandleMessageBinary) |
||||
|
m.HandleSentMessage(hand.HandleSentMessage) |
||||
|
m.HandleSentMessageBinary(hand.HandleSentMessageBinary) |
||||
|
instanceMelody.Store(group, m) |
||||
|
} else { |
||||
|
m = tmp.(*melody.Melody) |
||||
|
} |
||||
|
return m |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"github.com/go-sql-driver/mysql" |
||||
|
"github.com/xormplus/core" |
||||
|
"github.com/xormplus/xorm" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type Xorm struct { |
||||
|
db *xorm.Engine |
||||
|
} |
||||
|
|
||||
|
var instanceXorm *Xorm |
||||
|
|
||||
|
func GetXormAuto() *xorm.Engine { |
||||
|
db, err := GetXorm() |
||||
|
if err != nil { |
||||
|
panic("数据库访问错误") |
||||
|
} |
||||
|
return db.db |
||||
|
} |
||||
|
|
||||
|
func GetXorm() (*Xorm, error) { |
||||
|
if instanceXorm == nil { |
||||
|
config := GetInstanceConfig() |
||||
|
mysqlConfig := mysql.NewConfig() |
||||
|
mysqlConfig.User = config.Db.User |
||||
|
mysqlConfig.DBName = config.Db.Name |
||||
|
mysqlConfig.Passwd = config.Db.Password |
||||
|
mysqlConfig.Params = config.Db.Params |
||||
|
mysqlConfig.Net = "tcp" |
||||
|
mysqlConfig.Addr = config.Db.Host + ":" + config.Db.Port |
||||
|
|
||||
|
engine, err := xorm.NewEngine("mysql", mysqlConfig.FormatDSN()) |
||||
|
if config.Db.Prefix != "" { |
||||
|
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, config.Db.Prefix) |
||||
|
engine.SetTableMapper(tbMapper) |
||||
|
} |
||||
|
|
||||
|
instanceXorm = &Xorm{db: engine} |
||||
|
instanceXorm.db.SetMaxOpenConns(config.Db.MaxOpenConn) |
||||
|
if config.Db.Debug { |
||||
|
instanceXorm.db.ShowSQL(true) |
||||
|
} |
||||
|
return instanceXorm, err |
||||
|
} |
||||
|
return instanceXorm, nil |
||||
|
} |
||||
|
|
||||
|
func (x *Xorm) Ping() error { |
||||
|
session := x.db.NewSession() |
||||
|
defer session.Close() |
||||
|
return session.DB().Ping() |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
go func() { |
||||
|
for { |
||||
|
if instanceXorm != nil { |
||||
|
err := instanceXorm.Ping() |
||||
|
if err != nil { |
||||
|
println(err.Error()) |
||||
|
instanceXorm.db.Close() |
||||
|
instanceXorm = nil |
||||
|
} |
||||
|
} |
||||
|
time.Sleep(time.Second) |
||||
|
} |
||||
|
}() |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package helper |
||||
|
|
||||
|
import ( |
||||
|
"github.com/go-errors/errors" |
||||
|
"github.com/wailovet/db2struct" |
||||
|
"github.com/wailovet/osmanthuswine/src/core" |
||||
|
"strconv" |
||||
|
) |
||||
|
|
||||
|
func GetStructByDb(tableName string, packageName string, structName string) (string, error) { |
||||
|
mariadbUser := core.GetInstanceConfig().Db.User |
||||
|
mariadbPassword := core.GetInstanceConfig().Db.Password |
||||
|
mariadbHost := core.GetInstanceConfig().Db.Host |
||||
|
mariadbPort, _ := strconv.Atoi(core.GetInstanceConfig().Db.Port) |
||||
|
mariadbDatabase := core.GetInstanceConfig().Db.Name |
||||
|
columnDataTypes, err := db2struct.GetColumnsFromMysqlTable(mariadbUser, mariadbPassword, mariadbHost, mariadbPort, mariadbDatabase, tableName) |
||||
|
|
||||
|
if err != nil { |
||||
|
return "", errors.New("Error in selecting column data information from mysql information schema") |
||||
|
} |
||||
|
|
||||
|
// Generate struct string based on columnDataTypes
|
||||
|
struc, err := db2struct.Generate(*columnDataTypes, tableName, structName, packageName, true, true, false) |
||||
|
|
||||
|
if err != nil { |
||||
|
return "", errors.New("Error in creating struct from json: " + err.Error()) |
||||
|
} |
||||
|
return string(struc), nil |
||||
|
|
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package helper |
||||
|
|
||||
|
import "log" |
||||
|
|
||||
|
type Log struct { |
||||
|
} |
||||
|
|
||||
|
var instanceLog *Log |
||||
|
|
||||
|
func GetInstanceLog() *Log { |
||||
|
if instanceLog == nil { |
||||
|
instanceLog = &Log{} // not thread safe
|
||||
|
} |
||||
|
return instanceLog |
||||
|
} |
||||
|
|
||||
|
func (l *Log) Out(args ...interface{}) { |
||||
|
log.Println(args) |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package helper |
||||
|
|
||||
|
import ( |
||||
|
"crypto/md5" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
func Md5(data string) string { |
||||
|
return fmt.Sprintf("%x", md5.Sum([]byte(data))) |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package helper |
||||
|
|
||||
|
import "github.com/satori/go.uuid" |
||||
|
|
||||
|
func CreateUUID() string { |
||||
|
u1 := uuid.Must(uuid.NewV4()) |
||||
|
return u1.String() |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package helper |
||||
|
|
||||
|
import "testing" |
||||
|
|
||||
|
func TestCreateUUID(t *testing.T) { |
||||
|
s := CreateUUID() |
||||
|
println(s) |
||||
|
if len(s) != 36 { |
||||
|
t.Error("UUID长度错误") |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package interfaces |
||||
|
|
||||
|
import ( |
||||
|
"gopkg.in/olahol/melody.v1" |
||||
|
) |
||||
|
|
||||
|
//WebSocketInterface interface
|
||||
|
type WebSocketInterface interface { |
||||
|
SetFunName(funName string) |
||||
|
WebSocketInit(ws *melody.Melody) |
||||
|
GetWebSocket() *melody.Melody |
||||
|
GetMelody() *melody.Melody |
||||
|
HandleConnect(*melody.Session) |
||||
|
HandlePong(*melody.Session) |
||||
|
HandleMessage(*melody.Session, []byte) |
||||
|
HandleMessageBinary(*melody.Session, []byte) |
||||
|
HandleSentMessage(*melody.Session, []byte) |
||||
|
HandleSentMessageBinary(*melody.Session, []byte) |
||||
|
HandleDisconnect(*melody.Session) |
||||
|
HandleError(*melody.Session, error) |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package session |
||||
|
|
||||
|
import ( |
||||
|
"github.com/gorilla/securecookie" |
||||
|
"net/http" |
||||
|
) |
||||
|
|
||||
|
type Session struct { |
||||
|
secureCookie *securecookie.SecureCookie |
||||
|
r *http.Request |
||||
|
w http.ResponseWriter |
||||
|
data map[string]string |
||||
|
} |
||||
|
|
||||
|
func New(r *http.Request, w http.ResponseWriter) *Session { |
||||
|
session := &Session{} // not thread safe
|
||||
|
var hashKey = []byte("osmanthuswine-very-secret") |
||||
|
// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long.
|
||||
|
// Shorter keys may weaken the encryption used.
|
||||
|
var blockKey = []byte("osmanthuswine-lot-secret") |
||||
|
session.secureCookie = securecookie.New(hashKey, blockKey) |
||||
|
session.r = r |
||||
|
session.w = w |
||||
|
|
||||
|
session.data = make(map[string]string) |
||||
|
if cookie, err := session.r.Cookie("osmseccidhas"); err == nil { |
||||
|
session.secureCookie.Decode("osmseccidhas", cookie.Value, &session.data) |
||||
|
} else { |
||||
|
//helper.GetInstanceLog().Out(err.Error())
|
||||
|
} |
||||
|
return session |
||||
|
} |
||||
|
|
||||
|
func (session *Session) GetSession() map[string]string { |
||||
|
return session.data |
||||
|
} |
||||
|
|
||||
|
func (session *Session) SetSession(value map[string]string) { |
||||
|
if encoded, err := session.secureCookie.Encode("osmseccidhas", value); err == nil { |
||||
|
cookie := &http.Cookie{ |
||||
|
Name: "osmseccidhas", |
||||
|
Value: encoded, |
||||
|
Path: "/", |
||||
|
Secure: false, |
||||
|
HttpOnly: false, |
||||
|
} |
||||
|
http.SetCookie(session.w, cookie) |
||||
|
session.data = value |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue