mirror of
https://github.com/astaxie/beego.git
synced 2025-07-11 18:11:01 +00:00
Compare commits
58 Commits
Author | SHA1 | Date | |
---|---|---|---|
0692f92890 | |||
41adcf9966 | |||
e6b42a4070 | |||
bc4780091b | |||
d8614e80e7 | |||
c83a2a0925 | |||
50a21d60c1 | |||
5a087b28d2 | |||
9b40271878 | |||
770dc702f0 | |||
e146100a23 | |||
2d94f7797b | |||
61ce608847 | |||
2fe559701c | |||
37fe175c26 | |||
fcc9d8c45f | |||
e51a9d6481 | |||
e9a1daa3ee | |||
44ea260db1 | |||
1d1ad69954 | |||
59773dfabe | |||
ccb61f0416 | |||
14629c214b | |||
a3888cef7f | |||
f6a1a6c9bf | |||
38ee43701d | |||
421b796f1a | |||
771179a3c6 | |||
c07b1d881b | |||
d8f2b05e08 | |||
7b2fe824d5 | |||
02301caac1 | |||
98c2307763 | |||
485c2e865c | |||
b390667374 | |||
f684de2385 | |||
35b4022ee0 | |||
77294a5881 | |||
7b39bd7042 | |||
01e4084587 | |||
bf429a3a20 | |||
f8ff79d77d | |||
e9487d3571 | |||
d7c3727f96 | |||
03eb1fc104 | |||
0a967875da | |||
6ae8bc1a16 | |||
e70537f8b3 | |||
9a583323a8 | |||
ff9c8d94e6 | |||
7f977a0c8c | |||
aaabeff44f | |||
f85ac088c3 | |||
26da23266a | |||
80274684e0 | |||
be005f9774 | |||
c16b7be9ac | |||
de87529387 |
29
README.md
29
README.md
@ -1,32 +1,37 @@
|
|||||||
## beego
|
## Beego
|
||||||
|
|
||||||
[](https://drone.io/github.com/astaxie/beego/latest)
|
[](https://drone.io/github.com/astaxie/beego/latest)
|
||||||
|
[](https://godoc.org/github.com/astaxie/beego)
|
||||||
|
|
||||||
beego is an open-source, high-performance, modularity, full-stack web framework.
|
beego is an open-source, high-performance, modularity, full-stack web framework.
|
||||||
|
|
||||||
More info [beego.me](http://beego.me)
|
More info [beego.me](http://beego.me)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
go get github.com/astaxie/beego
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* RESTful support
|
* RESTful support
|
||||||
* MVC architecture
|
* MVC architecture
|
||||||
* modularity
|
* Modularity
|
||||||
* auto API documents
|
* Auto API documents
|
||||||
* annotation router
|
* Annotation router
|
||||||
* namespace
|
* Namespace
|
||||||
* powerful develop tools
|
* Powerful develop tools
|
||||||
* full stack for web & API
|
* Full stack for Web & API
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
[English](http://beego.me/docs/intro/)
|
* [English](http://beego.me/docs/intro/)
|
||||||
|
* [中文文档](http://beego.me/docs/intro/)
|
||||||
|
|
||||||
[API](http://godoc.org/github.com/astaxie/beego)
|
## Community
|
||||||
|
|
||||||
[中文文档](http://beego.me/docs/intro/)
|
|
||||||
|
|
||||||
|
* [http://beego.me/community](http://beego.me/community)
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
beego is licensed under the Apache Licence, Version 2.0
|
beego is licensed under the Apache Licence, Version 2.0
|
||||||
(http://www.apache.org/licenses/LICENSE-2.0.html).
|
(http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
|
122
admin.go
122
admin.go
@ -142,121 +142,116 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
|||||||
tmpl.Execute(rw, data)
|
tmpl.Execute(rw, data)
|
||||||
|
|
||||||
case "router":
|
case "router":
|
||||||
resultList := new([][]string)
|
content := make(map[string]interface{})
|
||||||
|
|
||||||
var result = []string{
|
var fields = []string{
|
||||||
fmt.Sprintf("header"),
|
|
||||||
fmt.Sprintf("Router Pattern"),
|
fmt.Sprintf("Router Pattern"),
|
||||||
fmt.Sprintf("Methods"),
|
fmt.Sprintf("Methods"),
|
||||||
fmt.Sprintf("Controller"),
|
fmt.Sprintf("Controller"),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
content["Fields"] = fields
|
||||||
|
|
||||||
|
methods := []string{}
|
||||||
|
methodsData := make(map[string]interface{})
|
||||||
for method, t := range BeeApp.Handlers.routers {
|
for method, t := range BeeApp.Handlers.routers {
|
||||||
var result = []string{
|
|
||||||
fmt.Sprintf("success"),
|
resultList := new([][]string)
|
||||||
fmt.Sprintf("Method: %s", method),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
}
|
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
|
|
||||||
printTree(resultList, t)
|
printTree(resultList, t)
|
||||||
|
|
||||||
|
methods = append(methods, method)
|
||||||
|
methodsData[method] = resultList
|
||||||
}
|
}
|
||||||
data["Content"] = resultList
|
|
||||||
|
content["Data"] = methodsData
|
||||||
|
content["Methods"] = methods
|
||||||
|
data["Content"] = content
|
||||||
data["Title"] = "Routers"
|
data["Title"] = "Routers"
|
||||||
|
|
||||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||||
tmpl = template.Must(tmpl.Parse(routerAndFilterTpl))
|
tmpl = template.Must(tmpl.Parse(routerAndFilterTpl))
|
||||||
tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
|
tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
|
||||||
tmpl.Execute(rw, data)
|
tmpl.Execute(rw, data)
|
||||||
case "filter":
|
case "filter":
|
||||||
resultList := new([][]string)
|
content := make(map[string]interface{})
|
||||||
|
|
||||||
var result = []string{
|
var fields = []string{
|
||||||
fmt.Sprintf("header"),
|
|
||||||
fmt.Sprintf("Router Pattern"),
|
fmt.Sprintf("Router Pattern"),
|
||||||
fmt.Sprintf("Filter Function"),
|
fmt.Sprintf("Filter Function"),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
content["Fields"] = fields
|
||||||
|
|
||||||
|
filterTypes := []string{}
|
||||||
|
filterTypeData := make(map[string]interface{})
|
||||||
|
|
||||||
if BeeApp.Handlers.enableFilter {
|
if BeeApp.Handlers.enableFilter {
|
||||||
var result = []string{
|
var filterType string
|
||||||
fmt.Sprintf("success"),
|
|
||||||
fmt.Sprintf("Before Router"),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
}
|
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
|
|
||||||
if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok {
|
if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok {
|
||||||
|
filterType = "Before Router"
|
||||||
|
filterTypes = append(filterTypes, filterType)
|
||||||
|
resultList := new([][]string)
|
||||||
for _, f := range bf {
|
for _, f := range bf {
|
||||||
|
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", f.pattern),
|
fmt.Sprintf("%s", f.pattern),
|
||||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
filterTypeData[filterType] = resultList
|
||||||
}
|
}
|
||||||
result = []string{
|
|
||||||
fmt.Sprintf("success"),
|
|
||||||
fmt.Sprintf("Before Exec"),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
}
|
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
if bf, ok := BeeApp.Handlers.filters[BeforeExec]; ok {
|
if bf, ok := BeeApp.Handlers.filters[BeforeExec]; ok {
|
||||||
|
filterType = "Before Exec"
|
||||||
|
filterTypes = append(filterTypes, filterType)
|
||||||
|
resultList := new([][]string)
|
||||||
for _, f := range bf {
|
for _, f := range bf {
|
||||||
|
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", f.pattern),
|
fmt.Sprintf("%s", f.pattern),
|
||||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
filterTypeData[filterType] = resultList
|
||||||
}
|
}
|
||||||
result = []string{
|
|
||||||
fmt.Sprintf("success"),
|
|
||||||
fmt.Sprintf("AfterExec Exec"),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
}
|
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
|
|
||||||
if bf, ok := BeeApp.Handlers.filters[AfterExec]; ok {
|
if bf, ok := BeeApp.Handlers.filters[AfterExec]; ok {
|
||||||
|
filterType = "After Exec"
|
||||||
|
filterTypes = append(filterTypes, filterType)
|
||||||
|
resultList := new([][]string)
|
||||||
for _, f := range bf {
|
for _, f := range bf {
|
||||||
|
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", f.pattern),
|
fmt.Sprintf("%s", f.pattern),
|
||||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
filterTypeData[filterType] = resultList
|
||||||
}
|
}
|
||||||
result = []string{
|
|
||||||
fmt.Sprintf("success"),
|
|
||||||
fmt.Sprintf("Finish Router"),
|
|
||||||
fmt.Sprintf(""),
|
|
||||||
}
|
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
|
|
||||||
if bf, ok := BeeApp.Handlers.filters[FinishRouter]; ok {
|
if bf, ok := BeeApp.Handlers.filters[FinishRouter]; ok {
|
||||||
|
filterType = "Finish Router"
|
||||||
|
filterTypes = append(filterTypes, filterType)
|
||||||
|
resultList := new([][]string)
|
||||||
for _, f := range bf {
|
for _, f := range bf {
|
||||||
|
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", f.pattern),
|
fmt.Sprintf("%s", f.pattern),
|
||||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
filterTypeData[filterType] = resultList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data["Content"] = resultList
|
|
||||||
|
content["Data"] = filterTypeData
|
||||||
|
content["Methods"] = filterTypes
|
||||||
|
|
||||||
|
data["Content"] = content
|
||||||
data["Title"] = "Filters"
|
data["Title"] = "Filters"
|
||||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||||
tmpl = template.Must(tmpl.Parse(routerAndFilterTpl))
|
tmpl = template.Must(tmpl.Parse(routerAndFilterTpl))
|
||||||
@ -281,7 +276,6 @@ func printTree(resultList *[][]string, t *Tree) {
|
|||||||
if v, ok := l.runObject.(*controllerInfo); ok {
|
if v, ok := l.runObject.(*controllerInfo); ok {
|
||||||
if v.routerType == routerTypeBeego {
|
if v.routerType == routerTypeBeego {
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", v.pattern),
|
fmt.Sprintf("%s", v.pattern),
|
||||||
fmt.Sprintf("%s", v.methods),
|
fmt.Sprintf("%s", v.methods),
|
||||||
fmt.Sprintf("%s", v.controllerType),
|
fmt.Sprintf("%s", v.controllerType),
|
||||||
@ -289,7 +283,6 @@ func printTree(resultList *[][]string, t *Tree) {
|
|||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
} else if v.routerType == routerTypeRESTFul {
|
} else if v.routerType == routerTypeRESTFul {
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", v.pattern),
|
fmt.Sprintf("%s", v.pattern),
|
||||||
fmt.Sprintf("%s", v.methods),
|
fmt.Sprintf("%s", v.methods),
|
||||||
fmt.Sprintf(""),
|
fmt.Sprintf(""),
|
||||||
@ -297,7 +290,6 @@ func printTree(resultList *[][]string, t *Tree) {
|
|||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
} else if v.routerType == routerTypeHandler {
|
} else if v.routerType == routerTypeHandler {
|
||||||
var result = []string{
|
var result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", v.pattern),
|
fmt.Sprintf("%s", v.pattern),
|
||||||
fmt.Sprintf(""),
|
fmt.Sprintf(""),
|
||||||
fmt.Sprintf(""),
|
fmt.Sprintf(""),
|
||||||
@ -352,13 +344,15 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
|
|||||||
func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
||||||
data := make(map[interface{}]interface{})
|
data := make(map[interface{}]interface{})
|
||||||
|
|
||||||
resultList := new([][]string)
|
var result = []string{}
|
||||||
var result = []string{
|
fields := []string{
|
||||||
fmt.Sprintf("header"),
|
|
||||||
fmt.Sprintf("Name"),
|
fmt.Sprintf("Name"),
|
||||||
|
fmt.Sprintf("Message"),
|
||||||
fmt.Sprintf("Status"),
|
fmt.Sprintf("Status"),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
resultList := new([][]string)
|
||||||
|
|
||||||
|
content := make(map[string]interface{})
|
||||||
|
|
||||||
for name, h := range toolbox.AdminCheckList {
|
for name, h := range toolbox.AdminCheckList {
|
||||||
if err := h.Check(); err != nil {
|
if err := h.Check(); err != nil {
|
||||||
@ -379,7 +373,9 @@ func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
|||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
data["Content"] = resultList
|
content["Fields"] = fields
|
||||||
|
content["Data"] = resultList
|
||||||
|
data["Content"] = content
|
||||||
data["Title"] = "Health Check"
|
data["Title"] = "Health Check"
|
||||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||||
tmpl = template.Must(tmpl.Parse(healthCheckTpl))
|
tmpl = template.Must(tmpl.Parse(healthCheckTpl))
|
||||||
@ -410,17 +406,17 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List Tasks
|
// List Tasks
|
||||||
|
content := make(map[string]interface{})
|
||||||
resultList := new([][]string)
|
resultList := new([][]string)
|
||||||
var result = []string{
|
var result = []string{}
|
||||||
fmt.Sprintf("header"),
|
var fields = []string{
|
||||||
fmt.Sprintf("Task Name"),
|
fmt.Sprintf("Task Name"),
|
||||||
fmt.Sprintf("Task Spec"),
|
fmt.Sprintf("Task Spec"),
|
||||||
fmt.Sprintf("Task Function"),
|
fmt.Sprintf("Task Function"),
|
||||||
|
fmt.Sprintf(""),
|
||||||
}
|
}
|
||||||
*resultList = append(*resultList, result)
|
|
||||||
for tname, tk := range toolbox.AdminTaskList {
|
for tname, tk := range toolbox.AdminTaskList {
|
||||||
result = []string{
|
result = []string{
|
||||||
fmt.Sprintf(""),
|
|
||||||
fmt.Sprintf("%s", tname),
|
fmt.Sprintf("%s", tname),
|
||||||
fmt.Sprintf("%s", tk.GetStatus()),
|
fmt.Sprintf("%s", tk.GetStatus()),
|
||||||
fmt.Sprintf("%s", tk.GetPrev().String()),
|
fmt.Sprintf("%s", tk.GetPrev().String()),
|
||||||
@ -428,7 +424,9 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
|
|||||||
*resultList = append(*resultList, result)
|
*resultList = append(*resultList, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
data["Content"] = resultList
|
content["Fields"] = fields
|
||||||
|
content["Data"] = resultList
|
||||||
|
data["Content"] = content
|
||||||
data["Title"] = "Tasks"
|
data["Title"] = "Tasks"
|
||||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||||
tmpl = template.Must(tmpl.Parse(tasksTpl))
|
tmpl = template.Must(tmpl.Parse(tasksTpl))
|
||||||
|
194
adminui.go
194
adminui.go
@ -61,31 +61,35 @@ var gcAjaxTpl = `
|
|||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
var qpsTpl = `
|
var qpsTpl = `{{define "content"}}
|
||||||
{{define "content"}}
|
|
||||||
<h1>Requests statistics</h1>
|
<h1>Requests statistics</h1>
|
||||||
<table class="table table-striped table-hover ">
|
<table class="table table-striped table-hover ">
|
||||||
{{range $i, $slice := .Content}}
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{{range $j, $elem := $slice}}
|
{{range .Content.Fields}}
|
||||||
{{if eq $i 0}}
|
<th>
|
||||||
<th>
|
{{.}}
|
||||||
{{else}}
|
</th>
|
||||||
<td>
|
{{end}}
|
||||||
{{end}}
|
</tr>
|
||||||
{{$elem}}
|
</thead>
|
||||||
{{if eq $i 0}}
|
|
||||||
</th>
|
<tbody>
|
||||||
{{else}}
|
{{range $i, $elem := .Content.Data}}
|
||||||
</td>
|
|
||||||
{{end}}
|
<tr>
|
||||||
{{end}}
|
{{range $elem}}
|
||||||
|
<td>
|
||||||
|
{{.}}
|
||||||
|
</td>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
</table>
|
||||||
{{end}}
|
{{end}}`
|
||||||
`
|
|
||||||
|
|
||||||
var configTpl = `
|
var configTpl = `
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
@ -98,49 +102,51 @@ var configTpl = `
|
|||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
var routerAndFilterTpl = `
|
var routerAndFilterTpl = `{{define "content"}}
|
||||||
{{define "content"}}
|
|
||||||
|
|
||||||
<h1>{{.Title}}</h1>
|
<h1>{{.Title}}</h1>
|
||||||
|
|
||||||
|
{{range .Content.Methods}}
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading lead success"><strong>{{.}}</strong></div>
|
||||||
|
<div class="panel-body">
|
||||||
<table class="table table-striped table-hover ">
|
<table class="table table-striped table-hover ">
|
||||||
{{range $i, $slice := .Content}}
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
{{range $.Content.Fields}}
|
||||||
|
<th>
|
||||||
|
{{.}}
|
||||||
|
</th>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
{{ $header := index $slice 0}}
|
<tbody>
|
||||||
{{if eq "header" $header }}
|
{{$slice := index $.Content.Data .}}
|
||||||
{{range $j, $elem := $slice}}
|
{{range $i, $elem := $slice}}
|
||||||
{{if ne $j 0}}
|
|
||||||
<th>
|
<tr>
|
||||||
{{$elem}}
|
{{range $elem}}
|
||||||
</th>
|
<td>
|
||||||
{{end}}
|
{{.}}
|
||||||
{{end}}
|
</td>
|
||||||
{{else if eq "success" $header}}
|
{{end}}
|
||||||
{{range $j, $elem := $slice}}
|
</tr>
|
||||||
{{if ne $j 0}}
|
|
||||||
<th class="success">
|
{{end}}
|
||||||
{{$elem}}
|
</tbody>
|
||||||
</th>
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
{{range $j, $elem := $slice}}
|
|
||||||
{{if ne $j 0}}
|
|
||||||
<td>
|
|
||||||
{{$elem}}
|
|
||||||
</td>
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
|
||||||
|
|
||||||
var tasksTpl = `
|
|
||||||
{{define "content"}}
|
{{end}}`
|
||||||
|
|
||||||
|
var tasksTpl = `{{define "content"}}
|
||||||
|
|
||||||
<h1>{{.Title}}</h1>
|
<h1>{{.Title}}</h1>
|
||||||
|
|
||||||
@ -161,59 +167,51 @@ bg-warning
|
|||||||
|
|
||||||
|
|
||||||
<table class="table table-striped table-hover ">
|
<table class="table table-striped table-hover ">
|
||||||
{{range $i, $slice := .Content}}
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
{{range .Content.Fields}}
|
||||||
|
<th>
|
||||||
|
{{.}}
|
||||||
|
</th>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
{{ $header := index $slice 0}}
|
<tbody>
|
||||||
{{if eq "header" $header }}
|
{{range $i, $slice := .Content.Data}}
|
||||||
{{range $j, $elem := $slice}}
|
<tr>
|
||||||
{{if ne $j 0}}
|
{{range $slice}}
|
||||||
<th>
|
|
||||||
{{$elem}}
|
|
||||||
</th>
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
<th>
|
|
||||||
Run Task
|
|
||||||
</th>
|
|
||||||
{{else}}
|
|
||||||
{{range $j, $elem := $slice}}
|
|
||||||
{{if ne $j 0}}
|
|
||||||
<td>
|
<td>
|
||||||
{{$elem}}
|
{{.}}
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 1}}">Run</a>
|
<a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 1}}">Run</a>
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{end}}
|
|
||||||
`
|
{{end}}`
|
||||||
|
|
||||||
var healthCheckTpl = `
|
var healthCheckTpl = `
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
|
|
||||||
<h1>{{.Title}}</h1>
|
<h1>{{.Title}}</h1>
|
||||||
<table class="table table-striped table-hover ">
|
<table class="table table-striped table-hover ">
|
||||||
{{range $i, $slice := .Content}}
|
<thead>
|
||||||
|
|
||||||
{{ $header := index $slice 0}}
|
|
||||||
{{if eq "header" $header }}
|
|
||||||
<tr>
|
<tr>
|
||||||
{{range $j, $elem := $slice}}
|
{{range .Content.Fields}}
|
||||||
{{if ne $j 0}}
|
|
||||||
<th>
|
<th>
|
||||||
{{$elem}}
|
{{.}}
|
||||||
</th>
|
</th>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
</tr>
|
</tr>
|
||||||
{{else}}
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $i, $slice := .Content.Data}}
|
||||||
|
{{ $header := index $slice 0}}
|
||||||
{{ if eq "success" $header}}
|
{{ if eq "success" $header}}
|
||||||
<tr class="success">
|
<tr class="success">
|
||||||
{{else if eq "error" $header}}
|
{{else if eq "error" $header}}
|
||||||
@ -228,10 +226,13 @@ var healthCheckTpl = `
|
|||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
<td>
|
||||||
|
{{$header}}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{end}}
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{end}}`
|
{{end}}`
|
||||||
|
|
||||||
@ -251,7 +252,8 @@ Welcome to Beego Admin Dashboard
|
|||||||
|
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
|
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="//cdn.datatables.net/plug-ins/725b2a2115b/integration/bootstrap/3/dataTables.bootstrap.css" rel="stylesheet">
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
ul.nav li.dropdown:hover > ul.dropdown-menu {
|
ul.nav li.dropdown:hover > ul.dropdown-menu {
|
||||||
@ -336,9 +338,17 @@ Healthcheck
|
|||||||
{{template "content" .}}
|
{{template "content" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
|
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
|
||||||
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||||
|
<script src="//cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="//cdn.datatables.net/plug-ins/725b2a2115b/integration/bootstrap/3/dataTables.bootstrap.js
|
||||||
|
"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.table').dataTable();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{{template "scripts" .}}
|
{{template "scripts" .}}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
12
beego.go
12
beego.go
@ -14,13 +14,13 @@
|
|||||||
|
|
||||||
// beego is an open-source, high-performance, modularity, full-stack web framework
|
// beego is an open-source, high-performance, modularity, full-stack web framework
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
// import "github.com/astaxie/beego"
|
// import "github.com/astaxie/beego"
|
||||||
//
|
//
|
||||||
// func main() {
|
// func main() {
|
||||||
// beego.Run()
|
// beego.Run()
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// more infomation: http://beego.me
|
// more infomation: http://beego.me
|
||||||
package beego
|
package beego
|
||||||
@ -38,7 +38,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// beego web framework version.
|
// beego web framework version.
|
||||||
const VERSION = "1.4.0"
|
const VERSION = "1.4.1"
|
||||||
|
|
||||||
type hookfunc func() error //hook function to run
|
type hookfunc func() error //hook function to run
|
||||||
var hooks []hookfunc //hook function slice to store the hookfunc
|
var hooks []hookfunc //hook function slice to store the hookfunc
|
||||||
|
@ -147,7 +147,7 @@ type IniConfigContainer struct {
|
|||||||
|
|
||||||
// Bool returns the boolean value for a given key.
|
// Bool returns the boolean value for a given key.
|
||||||
func (c *IniConfigContainer) Bool(key string) (bool, error) {
|
func (c *IniConfigContainer) Bool(key string) (bool, error) {
|
||||||
return strconv.ParseBool(c.getdata(strings.ToLower(key)))
|
return strconv.ParseBool(c.getdata(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBool returns the boolean value for a given key.
|
// DefaultBool returns the boolean value for a given key.
|
||||||
@ -162,7 +162,7 @@ func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
|
|||||||
|
|
||||||
// Int returns the integer value for a given key.
|
// Int returns the integer value for a given key.
|
||||||
func (c *IniConfigContainer) Int(key string) (int, error) {
|
func (c *IniConfigContainer) Int(key string) (int, error) {
|
||||||
return strconv.Atoi(c.getdata(strings.ToLower(key)))
|
return strconv.Atoi(c.getdata(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultInt returns the integer value for a given key.
|
// DefaultInt returns the integer value for a given key.
|
||||||
@ -177,7 +177,7 @@ func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
|
|||||||
|
|
||||||
// Int64 returns the int64 value for a given key.
|
// Int64 returns the int64 value for a given key.
|
||||||
func (c *IniConfigContainer) Int64(key string) (int64, error) {
|
func (c *IniConfigContainer) Int64(key string) (int64, error) {
|
||||||
return strconv.ParseInt(c.getdata(strings.ToLower(key)), 10, 64)
|
return strconv.ParseInt(c.getdata(key), 10, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultInt64 returns the int64 value for a given key.
|
// DefaultInt64 returns the int64 value for a given key.
|
||||||
@ -192,7 +192,7 @@ func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
|
|||||||
|
|
||||||
// Float returns the float value for a given key.
|
// Float returns the float value for a given key.
|
||||||
func (c *IniConfigContainer) Float(key string) (float64, error) {
|
func (c *IniConfigContainer) Float(key string) (float64, error) {
|
||||||
return strconv.ParseFloat(c.getdata(strings.ToLower(key)), 64)
|
return strconv.ParseFloat(c.getdata(key), 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultFloat returns the float64 value for a given key.
|
// DefaultFloat returns the float64 value for a given key.
|
||||||
@ -207,8 +207,7 @@ func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float6
|
|||||||
|
|
||||||
// String returns the string value for a given key.
|
// String returns the string value for a given key.
|
||||||
func (c *IniConfigContainer) String(key string) string {
|
func (c *IniConfigContainer) String(key string) string {
|
||||||
key = strings.ToLower(key)
|
return c.getdata(key)
|
||||||
return c.getdata(strings.ToLower(key))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultString returns the string value for a given key.
|
// DefaultString returns the string value for a given key.
|
||||||
@ -338,15 +337,15 @@ func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
|
|||||||
|
|
||||||
// section.key or key
|
// section.key or key
|
||||||
func (c *IniConfigContainer) getdata(key string) string {
|
func (c *IniConfigContainer) getdata(key string) string {
|
||||||
c.RLock()
|
|
||||||
defer c.RUnlock()
|
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
section, k string
|
section, k string
|
||||||
sectionKey []string = strings.Split(key, "::")
|
sectionKey []string = strings.Split(strings.ToLower(key), "::")
|
||||||
)
|
)
|
||||||
if len(sectionKey) >= 2 {
|
if len(sectionKey) >= 2 {
|
||||||
section = sectionKey[0]
|
section = sectionKey[0]
|
||||||
|
@ -49,7 +49,7 @@ type Context struct {
|
|||||||
// It sends http response header directly.
|
// It sends http response header directly.
|
||||||
func (ctx *Context) Redirect(status int, localurl string) {
|
func (ctx *Context) Redirect(status int, localurl string) {
|
||||||
ctx.Output.Header("Location", localurl)
|
ctx.Output.Header("Location", localurl)
|
||||||
ctx.Output.SetStatus(status)
|
ctx.ResponseWriter.WriteHeader(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort stops this request.
|
// Abort stops this request.
|
||||||
|
@ -60,7 +60,7 @@ func (input *BeegoInput) Uri() string {
|
|||||||
|
|
||||||
// Url returns request url path (without query string, fragment).
|
// Url returns request url path (without query string, fragment).
|
||||||
func (input *BeegoInput) Url() string {
|
func (input *BeegoInput) Url() string {
|
||||||
return input.Request.URL.String()
|
return input.Request.URL.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Site returns base site url as scheme://domain type.
|
// Site returns base site url as scheme://domain type.
|
||||||
|
@ -6,53 +6,71 @@ httplib is an libs help you to curl remote url.
|
|||||||
## GET
|
## GET
|
||||||
you can use Get to crawl data.
|
you can use Get to crawl data.
|
||||||
|
|
||||||
import "httplib"
|
import "github.com/astaxie/beego/httplib"
|
||||||
|
|
||||||
str, err := httplib.Get("http://beego.me/").String()
|
str, err := httplib.Get("http://beego.me/").String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
// error
|
||||||
}
|
}
|
||||||
fmt.Println(str)
|
fmt.Println(str)
|
||||||
|
|
||||||
## POST
|
## POST
|
||||||
POST data to remote url
|
POST data to remote url
|
||||||
|
|
||||||
b:=httplib.Post("http://beego.me/")
|
req := httplib.Post("http://beego.me/")
|
||||||
b.Param("username","astaxie")
|
req.Param("username","astaxie")
|
||||||
b.Param("password","123456")
|
req.Param("password","123456")
|
||||||
str, err := b.String()
|
str, err := req.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
// error
|
||||||
}
|
}
|
||||||
fmt.Println(str)
|
fmt.Println(str)
|
||||||
|
|
||||||
## set timeout
|
## Set timeout
|
||||||
you can set timeout in request.default is 60 seconds.
|
|
||||||
|
|
||||||
set Get timeout:
|
The default timeout is `60` seconds, function prototype:
|
||||||
|
|
||||||
|
SetTimeout(connectTimeout, readWriteTimeout time.Duration)
|
||||||
|
|
||||||
|
Exmaple:
|
||||||
|
|
||||||
|
// GET
|
||||||
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
|
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
|
||||||
|
|
||||||
set post timeout:
|
// POST
|
||||||
|
|
||||||
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
|
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
|
||||||
|
|
||||||
- first param is connectTimeout.
|
|
||||||
- second param is readWriteTimeout
|
|
||||||
|
|
||||||
## debug
|
## Debug
|
||||||
if you want to debug the request info, set the debug on
|
|
||||||
|
If you want to debug the request info, set the debug on
|
||||||
|
|
||||||
httplib.Get("http://beego.me/").Debug(true)
|
httplib.Get("http://beego.me/").Debug(true)
|
||||||
|
|
||||||
## support HTTPS client
|
## Set HTTP Basic Auth
|
||||||
if request url is https. You can set the client support TSL:
|
|
||||||
|
str, err := Get("http://beego.me/").SetBasicAuth("user", "passwd").String()
|
||||||
|
if err != nil {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
fmt.Println(str)
|
||||||
|
|
||||||
|
## Set HTTPS
|
||||||
|
|
||||||
|
If request url is https, You can set the client support TSL:
|
||||||
|
|
||||||
httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
|
httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
|
||||||
|
|
||||||
more info about the tls.Config please visit http://golang.org/pkg/crypto/tls/#Config
|
More info about the `tls.Config` please visit http://golang.org/pkg/crypto/tls/#Config
|
||||||
|
|
||||||
## set cookie
|
## Set HTTP Version
|
||||||
|
|
||||||
|
some servers need to specify the protocol version of HTTP
|
||||||
|
|
||||||
|
httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1")
|
||||||
|
|
||||||
|
## Set Cookie
|
||||||
|
|
||||||
some http request need setcookie. So set it like this:
|
some http request need setcookie. So set it like this:
|
||||||
|
|
||||||
cookie := &http.Cookie{}
|
cookie := &http.Cookie{}
|
||||||
@ -60,21 +78,20 @@ some http request need setcookie. So set it like this:
|
|||||||
cookie.Value = "astaxie"
|
cookie.Value = "astaxie"
|
||||||
httplib.Get("http://beego.me/").SetCookie(cookie)
|
httplib.Get("http://beego.me/").SetCookie(cookie)
|
||||||
|
|
||||||
## upload file
|
## Upload file
|
||||||
httplib support mutil file upload, use `b.PostFile()`
|
|
||||||
|
|
||||||
b:=httplib.Post("http://beego.me/")
|
httplib support mutil file upload, use `req.PostFile()`
|
||||||
b.Param("username","astaxie")
|
|
||||||
b.Param("password","123456")
|
req := httplib.Post("http://beego.me/")
|
||||||
b.PostFile("uploadfile1", "httplib.pdf")
|
req.Param("username","astaxie")
|
||||||
b.PostFile("uploadfile2", "httplib.txt")
|
req.PostFile("uploadfile1", "httplib.pdf")
|
||||||
str, err := b.String()
|
str, err := req.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
// error
|
||||||
}
|
}
|
||||||
fmt.Println(str)
|
fmt.Println(str)
|
||||||
|
|
||||||
## set HTTP version
|
|
||||||
some servers need to specify the protocol version of HTTP
|
|
||||||
|
|
||||||
httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1")
|
See godoc for further documentation and examples.
|
||||||
|
|
||||||
|
* [godoc.org/github.com/astaxie/beego/httplib](https://godoc.org/github.com/astaxie/beego/httplib)
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// import "github.com/astaxie/beego/context"
|
// import "github.com/astaxie/beego/httplib"
|
||||||
//
|
//
|
||||||
// b:=httplib.Post("http://beego.me/")
|
// b := httplib.Post("http://beego.me/")
|
||||||
// b.Param("username","astaxie")
|
// b.Param("username","astaxie")
|
||||||
// b.Param("password","123456")
|
// b.Param("password","123456")
|
||||||
// b.PostFile("uploadfile1", "httplib.pdf")
|
// b.PostFile("uploadfile1", "httplib.pdf")
|
||||||
@ -53,7 +53,7 @@ var defaultSetting = BeegoHttpSettings{false, "beegoServer", 60 * time.Second, 6
|
|||||||
var defaultCookieJar http.CookieJar
|
var defaultCookieJar http.CookieJar
|
||||||
var settingMutex sync.Mutex
|
var settingMutex sync.Mutex
|
||||||
|
|
||||||
// createDefaultCookieJar creates a global cookiejar to store cookies.
|
// createDefaultCookie creates a global cookiejar to store cookies.
|
||||||
func createDefaultCookie() {
|
func createDefaultCookie() {
|
||||||
settingMutex.Lock()
|
settingMutex.Lock()
|
||||||
defer settingMutex.Unlock()
|
defer settingMutex.Unlock()
|
||||||
@ -73,44 +73,42 @@ func SetDefaultSetting(setting BeegoHttpSettings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return *BeegoHttpRequest with specific method
|
||||||
|
func newBeegoRequest(url, method string) *BeegoHttpRequest {
|
||||||
|
var resp http.Response
|
||||||
|
req := http.Request{
|
||||||
|
Method: method,
|
||||||
|
Header: make(http.Header),
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
ProtoMajor: 1,
|
||||||
|
ProtoMinor: 1,
|
||||||
|
}
|
||||||
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil}
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns *BeegoHttpRequest with GET method.
|
// Get returns *BeegoHttpRequest with GET method.
|
||||||
func Get(url string) *BeegoHttpRequest {
|
func Get(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
return newBeegoRequest(url, "GET")
|
||||||
req.Method = "GET"
|
|
||||||
req.Header = http.Header{}
|
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post returns *BeegoHttpRequest with POST method.
|
// Post returns *BeegoHttpRequest with POST method.
|
||||||
func Post(url string) *BeegoHttpRequest {
|
func Post(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
return newBeegoRequest(url, "POST")
|
||||||
req.Method = "POST"
|
|
||||||
req.Header = http.Header{}
|
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put returns *BeegoHttpRequest with PUT method.
|
// Put returns *BeegoHttpRequest with PUT method.
|
||||||
func Put(url string) *BeegoHttpRequest {
|
func Put(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
return newBeegoRequest(url, "PUT")
|
||||||
req.Method = "PUT"
|
|
||||||
req.Header = http.Header{}
|
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete returns *BeegoHttpRequest DELETE GET method.
|
// Delete returns *BeegoHttpRequest DELETE method.
|
||||||
func Delete(url string) *BeegoHttpRequest {
|
func Delete(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
return newBeegoRequest(url, "DELETE")
|
||||||
req.Method = "DELETE"
|
|
||||||
req.Header = http.Header{}
|
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head returns *BeegoHttpRequest with HEAD method.
|
// Head returns *BeegoHttpRequest with HEAD method.
|
||||||
func Head(url string) *BeegoHttpRequest {
|
func Head(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
return newBeegoRequest(url, "HEAD")
|
||||||
req.Method = "HEAD"
|
|
||||||
req.Header = http.Header{}
|
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeegoHttpSettings
|
// BeegoHttpSettings
|
||||||
@ -132,6 +130,8 @@ type BeegoHttpRequest struct {
|
|||||||
params map[string]string
|
params map[string]string
|
||||||
files map[string]string
|
files map[string]string
|
||||||
setting BeegoHttpSettings
|
setting BeegoHttpSettings
|
||||||
|
resp *http.Response
|
||||||
|
body []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change request settings
|
// Change request settings
|
||||||
@ -140,6 +140,12 @@ func (b *BeegoHttpRequest) Setting(setting BeegoHttpSettings) *BeegoHttpRequest
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
|
||||||
|
func (b *BeegoHttpRequest) SetBasicAuth(username, password string) *BeegoHttpRequest {
|
||||||
|
b.req.SetBasicAuth(username, password)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// SetEnableCookie sets enable/disable cookiejar
|
// SetEnableCookie sets enable/disable cookiejar
|
||||||
func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest {
|
||||||
b.setting.EnableCookie = enable
|
b.setting.EnableCookie = enable
|
||||||
@ -247,6 +253,9 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
||||||
|
if b.resp.StatusCode != 0 {
|
||||||
|
return b.resp, nil
|
||||||
|
}
|
||||||
var paramBody string
|
var paramBody string
|
||||||
if len(b.params) > 0 {
|
if len(b.params) > 0 {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
@ -301,22 +310,11 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
url, err := url.Parse(b.url)
|
url, err := url.Parse(b.url)
|
||||||
if url.Scheme == "" {
|
|
||||||
b.url = "http://" + b.url
|
|
||||||
url, err = url.Parse(b.url)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.req.URL = url
|
b.req.URL = url
|
||||||
if b.setting.ShowDebug {
|
|
||||||
dump, err := httputil.DumpRequest(b.req, true)
|
|
||||||
if err != nil {
|
|
||||||
println(err.Error())
|
|
||||||
}
|
|
||||||
println(string(dump))
|
|
||||||
}
|
|
||||||
|
|
||||||
trans := b.setting.Transport
|
trans := b.setting.Transport
|
||||||
|
|
||||||
@ -361,10 +359,19 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
|||||||
b.req.Header.Set("User-Agent", b.setting.UserAgent)
|
b.req.Header.Set("User-Agent", b.setting.UserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.setting.ShowDebug {
|
||||||
|
dump, err := httputil.DumpRequest(b.req, true)
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
|
println(string(dump))
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := client.Do(b.req)
|
resp, err := client.Do(b.req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
b.resp = resp
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,6 +389,9 @@ func (b *BeegoHttpRequest) String() (string, error) {
|
|||||||
// Bytes returns the body []byte in response.
|
// Bytes returns the body []byte in response.
|
||||||
// it calls Response inner.
|
// it calls Response inner.
|
||||||
func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
||||||
|
if b.body != nil {
|
||||||
|
return b.body, nil
|
||||||
|
}
|
||||||
resp, err := b.getResponse()
|
resp, err := b.getResponse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -394,6 +404,7 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
b.body = data
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,27 +15,51 @@
|
|||||||
package httplib
|
package httplib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimpleGet(t *testing.T) {
|
func TestResponse(t *testing.T) {
|
||||||
str, err := Get("http://httpbin.org/get").String()
|
req := Get("http://httpbin.org/get")
|
||||||
|
resp, err := req.Response()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
req := Get("http://httpbin.org/get")
|
||||||
|
b, err := req.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(b)
|
||||||
|
|
||||||
|
s, err := req.String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(s)
|
||||||
|
|
||||||
|
if string(b) != s {
|
||||||
|
t.Fatal("request data not match")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimplePost(t *testing.T) {
|
func TestSimplePost(t *testing.T) {
|
||||||
v := "smallfish"
|
v := "smallfish"
|
||||||
req := Post("http://httpbin.org/post")
|
req := Post("http://httpbin.org/post")
|
||||||
req.Param("username", v)
|
req.Param("username", v)
|
||||||
|
|
||||||
str, err := req.String()
|
str, err := req.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
n := strings.Index(str, v)
|
n := strings.Index(str, v)
|
||||||
if n == -1 {
|
if n == -1 {
|
||||||
t.Fatal(v + " not found in post")
|
t.Fatal(v + " not found in post")
|
||||||
@ -47,17 +71,35 @@ func TestPostFile(t *testing.T) {
|
|||||||
req := Post("http://httpbin.org/post")
|
req := Post("http://httpbin.org/post")
|
||||||
req.Param("username", v)
|
req.Param("username", v)
|
||||||
req.PostFile("uploadfile", "httplib_test.go")
|
req.PostFile("uploadfile", "httplib_test.go")
|
||||||
|
|
||||||
str, err := req.String()
|
str, err := req.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
n := strings.Index(str, v)
|
n := strings.Index(str, v)
|
||||||
if n == -1 {
|
if n == -1 {
|
||||||
t.Fatal(v + " not found in post")
|
t.Fatal(v + " not found in post")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSimplePut(t *testing.T) {
|
||||||
|
str, err := Put("http://httpbin.org/put").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleDelete(t *testing.T) {
|
||||||
|
str, err := Delete("http://httpbin.org/delete").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(str)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWithCookie(t *testing.T) {
|
func TestWithCookie(t *testing.T) {
|
||||||
v := "smallfish"
|
v := "smallfish"
|
||||||
str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
|
str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
|
||||||
@ -65,17 +107,31 @@ func TestWithCookie(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
|
str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
n := strings.Index(str, v)
|
n := strings.Index(str, v)
|
||||||
if n == -1 {
|
if n == -1 {
|
||||||
t.Fatal(v + " not found in cookie")
|
t.Fatal(v + " not found in cookie")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWithBasicAuth(t *testing.T) {
|
||||||
|
str, err := Get("http://httpbin.org/basic-auth/user/passwd").SetBasicAuth("user", "passwd").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(str)
|
||||||
|
n := strings.Index(str, "authenticated")
|
||||||
|
if n == -1 {
|
||||||
|
t.Fatal("authenticated not found in response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWithUserAgent(t *testing.T) {
|
func TestWithUserAgent(t *testing.T) {
|
||||||
v := "beego"
|
v := "beego"
|
||||||
str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
|
str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
|
||||||
@ -83,6 +139,7 @@ func TestWithUserAgent(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
n := strings.Index(str, v)
|
n := strings.Index(str, v)
|
||||||
if n == -1 {
|
if n == -1 {
|
||||||
t.Fatal(v + " not found in user-agent")
|
t.Fatal(v + " not found in user-agent")
|
||||||
@ -102,8 +159,47 @@ func TestWithSetting(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
|
||||||
n := strings.Index(str, v)
|
n := strings.Index(str, v)
|
||||||
if n == -1 {
|
if n == -1 {
|
||||||
t.Fatal(v + " not found in user-agent")
|
t.Fatal(v + " not found in user-agent")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToJson(t *testing.T) {
|
||||||
|
req := Get("http://httpbin.org/ip")
|
||||||
|
resp, err := req.Response()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(resp)
|
||||||
|
|
||||||
|
// httpbin will return http remote addr
|
||||||
|
type Ip struct {
|
||||||
|
Origin string `json:"origin"`
|
||||||
|
}
|
||||||
|
var ip Ip
|
||||||
|
err = req.ToJson(&ip)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(ip.Origin)
|
||||||
|
|
||||||
|
if n := strings.Count(ip.Origin, "."); n != 3 {
|
||||||
|
t.Fatal("response is not valid ip")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToFile(t *testing.T) {
|
||||||
|
f := "beego_testfile"
|
||||||
|
req := Get("http://httpbin.org/ip")
|
||||||
|
err := req.ToFile(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(f)
|
||||||
|
b, err := ioutil.ReadFile(f)
|
||||||
|
if n := strings.Index(string(b), "origin"); n == -1 {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -38,8 +38,8 @@ var colors = []Brush{
|
|||||||
NewBrush("1;31"), // Error red
|
NewBrush("1;31"), // Error red
|
||||||
NewBrush("1;33"), // Warning yellow
|
NewBrush("1;33"), // Warning yellow
|
||||||
NewBrush("1;32"), // Notice green
|
NewBrush("1;32"), // Notice green
|
||||||
NewBrush("1;34"), // Informational green
|
NewBrush("1;34"), // Informational blue
|
||||||
NewBrush("1;30"), // Debug black
|
NewBrush("1;34"), // Debug blue
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
|
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
|
||||||
|
11
logs/file.go
11
logs/file.go
@ -226,13 +226,20 @@ func (w *FileLogWriter) DoRotate() error {
|
|||||||
|
|
||||||
func (w *FileLogWriter) deleteOldLog() {
|
func (w *FileLogWriter) deleteOldLog() {
|
||||||
dir := filepath.Dir(w.Filename)
|
dir := filepath.Dir(w.Filename)
|
||||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r)
|
||||||
|
fmt.Println(returnErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) {
|
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) {
|
||||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
|
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
|
||||||
os.Remove(path)
|
os.Remove(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
logs/log.go
16
logs/log.go
@ -193,7 +193,10 @@ func (bl *BeeLogger) startLogger() {
|
|||||||
select {
|
select {
|
||||||
case bm := <-bl.msg:
|
case bm := <-bl.msg:
|
||||||
for _, l := range bl.outputs {
|
for _, l := range bl.outputs {
|
||||||
l.WriteMsg(bm.msg, bm.level)
|
err := l.WriteMsg(bm.msg, bm.level)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ERROR, unable to WriteMsg:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,13 +204,13 @@ func (bl *BeeLogger) startLogger() {
|
|||||||
|
|
||||||
// Log EMERGENCY level message.
|
// Log EMERGENCY level message.
|
||||||
func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
|
func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
|
||||||
msg := fmt.Sprintf("[D] "+format, v...)
|
msg := fmt.Sprintf("[M] "+format, v...)
|
||||||
bl.writerMsg(LevelEmergency, msg)
|
bl.writerMsg(LevelEmergency, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log ALERT level message.
|
// Log ALERT level message.
|
||||||
func (bl *BeeLogger) Alert(format string, v ...interface{}) {
|
func (bl *BeeLogger) Alert(format string, v ...interface{}) {
|
||||||
msg := fmt.Sprintf("[D] "+format, v...)
|
msg := fmt.Sprintf("[A] "+format, v...)
|
||||||
bl.writerMsg(LevelAlert, msg)
|
bl.writerMsg(LevelAlert, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +234,7 @@ func (bl *BeeLogger) Warning(format string, v ...interface{}) {
|
|||||||
|
|
||||||
// Log NOTICE level message.
|
// Log NOTICE level message.
|
||||||
func (bl *BeeLogger) Notice(format string, v ...interface{}) {
|
func (bl *BeeLogger) Notice(format string, v ...interface{}) {
|
||||||
msg := fmt.Sprintf("[W] "+format, v...)
|
msg := fmt.Sprintf("[N] "+format, v...)
|
||||||
bl.writerMsg(LevelNotice, msg)
|
bl.writerMsg(LevelNotice, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +284,10 @@ func (bl *BeeLogger) Close() {
|
|||||||
if len(bl.msg) > 0 {
|
if len(bl.msg) > 0 {
|
||||||
bm := <-bl.msg
|
bm := <-bl.msg
|
||||||
for _, l := range bl.outputs {
|
for _, l := range bl.outputs {
|
||||||
l.WriteMsg(bm.msg, bm.level)
|
err := l.WriteMsg(bm.msg, bm.level)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
|
67
logs/smtp.go
67
logs/smtp.go
@ -15,8 +15,10 @@
|
|||||||
package logs
|
package logs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -32,6 +34,7 @@ type SmtpWriter struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Host string `json:"Host"`
|
Host string `json:"Host"`
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
|
FromAddress string `json:"fromAddress"`
|
||||||
RecipientAddresses []string `json:"sendTos"`
|
RecipientAddresses []string `json:"sendTos"`
|
||||||
Level int `json:"level"`
|
Level int `json:"level"`
|
||||||
}
|
}
|
||||||
@ -48,6 +51,7 @@ func NewSmtpWriter() LoggerInterface {
|
|||||||
// "password:"password",
|
// "password:"password",
|
||||||
// "host":"smtp.gmail.com:465",
|
// "host":"smtp.gmail.com:465",
|
||||||
// "subject":"email title",
|
// "subject":"email title",
|
||||||
|
// "fromAddress":"from@example.com",
|
||||||
// "sendTos":["email1","email2"],
|
// "sendTos":["email1","email2"],
|
||||||
// "level":LevelError
|
// "level":LevelError
|
||||||
// }
|
// }
|
||||||
@ -71,6 +75,59 @@ func (s *SmtpWriter) GetSmtpAuth(host string) smtp.Auth {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SmtpWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error {
|
||||||
|
client, err := smtp.Dial(hostAddressWithPort)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, _ := net.SplitHostPort(hostAddressWithPort)
|
||||||
|
tlsConn := &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: host,
|
||||||
|
}
|
||||||
|
if err = client.StartTLS(tlsConn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if auth != nil {
|
||||||
|
if err = client.Auth(auth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = client.Mail(fromAddress); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rec := range recipients {
|
||||||
|
if err = client.Rcpt(rec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := client.Data()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.Write([]byte(msgContent))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.Quit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// write message in smtp writer.
|
// write message in smtp writer.
|
||||||
// it will send an email with subject and only this message.
|
// it will send an email with subject and only this message.
|
||||||
func (s *SmtpWriter) WriteMsg(msg string, level int) error {
|
func (s *SmtpWriter) WriteMsg(msg string, level int) error {
|
||||||
@ -86,16 +143,10 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error {
|
|||||||
// Connect to the server, authenticate, set the sender and recipient,
|
// Connect to the server, authenticate, set the sender and recipient,
|
||||||
// and send the email all in one step.
|
// and send the email all in one step.
|
||||||
content_type := "Content-Type: text/plain" + "; charset=UTF-8"
|
content_type := "Content-Type: text/plain" + "; charset=UTF-8"
|
||||||
mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.Username + "<" + s.Username +
|
mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress +
|
||||||
">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg)
|
">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg)
|
||||||
|
|
||||||
err := smtp.SendMail(
|
err := s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg)
|
||||||
s.Host,
|
|
||||||
auth,
|
|
||||||
s.Username,
|
|
||||||
s.RecipientAddresses,
|
|
||||||
mailmsg,
|
|
||||||
)
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
104
orm/db.go
104
orm/db.go
@ -122,6 +122,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
if nb.Valid {
|
if nb.Valid {
|
||||||
value = nb.Bool
|
value = nb.Bool
|
||||||
}
|
}
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
|
value = field.Elem().Bool()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value = field.Bool()
|
value = field.Bool()
|
||||||
}
|
}
|
||||||
@ -131,6 +137,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
if ns.Valid {
|
if ns.Valid {
|
||||||
value = ns.String
|
value = ns.String
|
||||||
}
|
}
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
|
value = field.Elem().String()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value = field.String()
|
value = field.String()
|
||||||
}
|
}
|
||||||
@ -140,6 +152,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
if nf.Valid {
|
if nf.Valid {
|
||||||
value = nf.Float64
|
value = nf.Float64
|
||||||
}
|
}
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
|
value = field.Elem().Float()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vu := field.Interface()
|
vu := field.Interface()
|
||||||
if _, ok := vu.(float32); ok {
|
if _, ok := vu.(float32); ok {
|
||||||
@ -161,13 +179,27 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
default:
|
default:
|
||||||
switch {
|
switch {
|
||||||
case fi.fieldType&IsPostiveIntegerField > 0:
|
case fi.fieldType&IsPostiveIntegerField > 0:
|
||||||
value = field.Uint()
|
if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
|
value = field.Elem().Uint()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = field.Uint()
|
||||||
|
}
|
||||||
case fi.fieldType&IsIntegerField > 0:
|
case fi.fieldType&IsIntegerField > 0:
|
||||||
if ni, ok := field.Interface().(sql.NullInt64); ok {
|
if ni, ok := field.Interface().(sql.NullInt64); ok {
|
||||||
value = nil
|
value = nil
|
||||||
if ni.Valid {
|
if ni.Valid {
|
||||||
value = ni.Int64
|
value = ni.Int64
|
||||||
}
|
}
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
|
value = field.Elem().Int()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
value = field.Int()
|
value = field.Int()
|
||||||
}
|
}
|
||||||
@ -1177,6 +1209,11 @@ setValue:
|
|||||||
nb.Valid = true
|
nb.Valid = true
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(nb))
|
field.Set(reflect.ValueOf(nb))
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if value != nil {
|
||||||
|
v := value.(bool)
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
value = false
|
value = false
|
||||||
@ -1194,6 +1231,11 @@ setValue:
|
|||||||
ns.Valid = true
|
ns.Valid = true
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(ns))
|
field.Set(reflect.ValueOf(ns))
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if value != nil {
|
||||||
|
v := value.(string)
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
value = ""
|
value = ""
|
||||||
@ -1208,6 +1250,56 @@ setValue:
|
|||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(value))
|
field.Set(reflect.ValueOf(value))
|
||||||
}
|
}
|
||||||
|
case fieldType == TypePositiveBitField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := uint8(value.(uint64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
case fieldType == TypePositiveSmallIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := uint16(value.(uint64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
case fieldType == TypePositiveIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
if field.Type() == reflect.TypeOf(new(uint)) {
|
||||||
|
v := uint(value.(uint64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
} else {
|
||||||
|
v := uint32(value.(uint64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case fieldType == TypePositiveBigIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := value.(uint64)
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
case fieldType == TypeBitField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := int8(value.(int64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
case fieldType == TypeSmallIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := int16(value.(int64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
case fieldType == TypeIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
if field.Type() == reflect.TypeOf(new(int)) {
|
||||||
|
v := int(value.(int64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
} else {
|
||||||
|
v := int32(value.(int64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case fieldType == TypeBigIntegerField && field.Kind() == reflect.Ptr:
|
||||||
|
if value != nil {
|
||||||
|
v := value.(int64)
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
case fieldType&IsIntegerField > 0:
|
case fieldType&IsIntegerField > 0:
|
||||||
if fieldType&IsPostiveIntegerField > 0 {
|
if fieldType&IsPostiveIntegerField > 0 {
|
||||||
if isNative {
|
if isNative {
|
||||||
@ -1244,6 +1336,16 @@ setValue:
|
|||||||
nf.Valid = true
|
nf.Valid = true
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(nf))
|
field.Set(reflect.ValueOf(nf))
|
||||||
|
} else if field.Kind() == reflect.Ptr {
|
||||||
|
if value != nil {
|
||||||
|
if field.Type() == reflect.TypeOf(new(float32)) {
|
||||||
|
v := float32(value.(float64))
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
} else {
|
||||||
|
v := value.(float64)
|
||||||
|
field.Set(reflect.ValueOf(&v))
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
|
@ -155,6 +155,24 @@ type DataNull struct {
|
|||||||
NullBool sql.NullBool `orm:"null"`
|
NullBool sql.NullBool `orm:"null"`
|
||||||
NullFloat64 sql.NullFloat64 `orm:"null"`
|
NullFloat64 sql.NullFloat64 `orm:"null"`
|
||||||
NullInt64 sql.NullInt64 `orm:"null"`
|
NullInt64 sql.NullInt64 `orm:"null"`
|
||||||
|
BooleanPtr *bool `orm:"null"`
|
||||||
|
CharPtr *string `orm:"null;size(50)"`
|
||||||
|
TextPtr *string `orm:"null;type(text)"`
|
||||||
|
BytePtr *byte `orm:"null"`
|
||||||
|
RunePtr *rune `orm:"null"`
|
||||||
|
IntPtr *int `orm:"null"`
|
||||||
|
Int8Ptr *int8 `orm:"null"`
|
||||||
|
Int16Ptr *int16 `orm:"null"`
|
||||||
|
Int32Ptr *int32 `orm:"null"`
|
||||||
|
Int64Ptr *int64 `orm:"null"`
|
||||||
|
UintPtr *uint `orm:"null"`
|
||||||
|
Uint8Ptr *uint8 `orm:"null"`
|
||||||
|
Uint16Ptr *uint16 `orm:"null"`
|
||||||
|
Uint32Ptr *uint32 `orm:"null"`
|
||||||
|
Uint64Ptr *uint64 `orm:"null"`
|
||||||
|
Float32Ptr *float32 `orm:"null"`
|
||||||
|
Float64Ptr *float64 `orm:"null"`
|
||||||
|
DecimalPtr *float64 `orm:"digits(8);decimals(4);null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type String string
|
type String string
|
||||||
|
@ -111,45 +111,73 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
|
|||||||
|
|
||||||
// return field type as type constant from reflect.Value
|
// return field type as type constant from reflect.Value
|
||||||
func getFieldType(val reflect.Value) (ft int, err error) {
|
func getFieldType(val reflect.Value) (ft int, err error) {
|
||||||
elm := reflect.Indirect(val)
|
switch val.Type() {
|
||||||
switch elm.Kind() {
|
case reflect.TypeOf(new(int8)):
|
||||||
case reflect.Int8:
|
|
||||||
ft = TypeBitField
|
ft = TypeBitField
|
||||||
case reflect.Int16:
|
case reflect.TypeOf(new(int16)):
|
||||||
ft = TypeSmallIntegerField
|
ft = TypeSmallIntegerField
|
||||||
case reflect.Int32, reflect.Int:
|
case reflect.TypeOf(new(int32)),
|
||||||
|
reflect.TypeOf(new(int)):
|
||||||
ft = TypeIntegerField
|
ft = TypeIntegerField
|
||||||
case reflect.Int64:
|
case reflect.TypeOf(new(int64)):
|
||||||
ft = TypeBigIntegerField
|
ft = TypeBigIntegerField
|
||||||
case reflect.Uint8:
|
case reflect.TypeOf(new(uint8)):
|
||||||
ft = TypePositiveBitField
|
ft = TypePositiveBitField
|
||||||
case reflect.Uint16:
|
case reflect.TypeOf(new(uint16)):
|
||||||
ft = TypePositiveSmallIntegerField
|
ft = TypePositiveSmallIntegerField
|
||||||
case reflect.Uint32, reflect.Uint:
|
case reflect.TypeOf(new(uint32)),
|
||||||
|
reflect.TypeOf(new(uint)):
|
||||||
ft = TypePositiveIntegerField
|
ft = TypePositiveIntegerField
|
||||||
case reflect.Uint64:
|
case reflect.TypeOf(new(uint64)):
|
||||||
ft = TypePositiveBigIntegerField
|
ft = TypePositiveBigIntegerField
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.TypeOf(new(float32)),
|
||||||
|
reflect.TypeOf(new(float64)):
|
||||||
ft = TypeFloatField
|
ft = TypeFloatField
|
||||||
case reflect.Bool:
|
case reflect.TypeOf(new(bool)):
|
||||||
ft = TypeBooleanField
|
ft = TypeBooleanField
|
||||||
case reflect.String:
|
case reflect.TypeOf(new(string)):
|
||||||
ft = TypeCharField
|
ft = TypeCharField
|
||||||
default:
|
default:
|
||||||
if elm.Interface() == nil {
|
elm := reflect.Indirect(val)
|
||||||
panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val))
|
switch elm.Kind() {
|
||||||
}
|
case reflect.Int8:
|
||||||
switch elm.Interface().(type) {
|
ft = TypeBitField
|
||||||
case sql.NullInt64:
|
case reflect.Int16:
|
||||||
|
ft = TypeSmallIntegerField
|
||||||
|
case reflect.Int32, reflect.Int:
|
||||||
|
ft = TypeIntegerField
|
||||||
|
case reflect.Int64:
|
||||||
ft = TypeBigIntegerField
|
ft = TypeBigIntegerField
|
||||||
case sql.NullFloat64:
|
case reflect.Uint8:
|
||||||
|
ft = TypePositiveBitField
|
||||||
|
case reflect.Uint16:
|
||||||
|
ft = TypePositiveSmallIntegerField
|
||||||
|
case reflect.Uint32, reflect.Uint:
|
||||||
|
ft = TypePositiveIntegerField
|
||||||
|
case reflect.Uint64:
|
||||||
|
ft = TypePositiveBigIntegerField
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
ft = TypeFloatField
|
ft = TypeFloatField
|
||||||
case sql.NullBool:
|
case reflect.Bool:
|
||||||
ft = TypeBooleanField
|
ft = TypeBooleanField
|
||||||
case sql.NullString:
|
case reflect.String:
|
||||||
ft = TypeCharField
|
ft = TypeCharField
|
||||||
case time.Time:
|
default:
|
||||||
ft = TypeDateTimeField
|
if elm.Interface() == nil {
|
||||||
|
panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val))
|
||||||
|
}
|
||||||
|
switch elm.Interface().(type) {
|
||||||
|
case sql.NullInt64:
|
||||||
|
ft = TypeBigIntegerField
|
||||||
|
case sql.NullFloat64:
|
||||||
|
ft = TypeFloatField
|
||||||
|
case sql.NullBool:
|
||||||
|
ft = TypeBooleanField
|
||||||
|
case sql.NullString:
|
||||||
|
ft = TypeCharField
|
||||||
|
case time.Time:
|
||||||
|
ft = TypeDateTimeField
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ft&IsFieldType == 0 {
|
if ft&IsFieldType == 0 {
|
||||||
|
@ -287,6 +287,25 @@ func TestNullDataTypes(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(d.NullInt64.Valid, false))
|
throwFail(t, AssertIs(d.NullInt64.Valid, false))
|
||||||
throwFail(t, AssertIs(d.NullFloat64.Valid, false))
|
throwFail(t, AssertIs(d.NullFloat64.Valid, false))
|
||||||
|
|
||||||
|
throwFail(t, AssertIs(d.BooleanPtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.CharPtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.TextPtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.BytePtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.RunePtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.IntPtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Int8Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Int16Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Int32Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Int64Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.UintPtr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Uint8Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Uint16Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Uint32Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Uint64Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Float32Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.Float64Ptr, nil))
|
||||||
|
throwFail(t, AssertIs(d.DecimalPtr, nil))
|
||||||
|
|
||||||
_, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec()
|
_, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
@ -294,12 +313,49 @@ func TestNullDataTypes(t *testing.T) {
|
|||||||
err = dORM.Read(&d)
|
err = dORM.Read(&d)
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
|
|
||||||
|
booleanPtr := true
|
||||||
|
charPtr := string("test")
|
||||||
|
textPtr := string("test")
|
||||||
|
bytePtr := byte('t')
|
||||||
|
runePtr := rune('t')
|
||||||
|
intPtr := int(42)
|
||||||
|
int8Ptr := int8(42)
|
||||||
|
int16Ptr := int16(42)
|
||||||
|
int32Ptr := int32(42)
|
||||||
|
int64Ptr := int64(42)
|
||||||
|
uintPtr := uint(42)
|
||||||
|
uint8Ptr := uint8(42)
|
||||||
|
uint16Ptr := uint16(42)
|
||||||
|
uint32Ptr := uint32(42)
|
||||||
|
uint64Ptr := uint64(42)
|
||||||
|
float32Ptr := float32(42.0)
|
||||||
|
float64Ptr := float64(42.0)
|
||||||
|
decimalPtr := float64(42.0)
|
||||||
|
|
||||||
d = DataNull{
|
d = DataNull{
|
||||||
DateTime: time.Now(),
|
DateTime: time.Now(),
|
||||||
NullString: sql.NullString{String: "test", Valid: true},
|
NullString: sql.NullString{String: "test", Valid: true},
|
||||||
NullBool: sql.NullBool{Bool: true, Valid: true},
|
NullBool: sql.NullBool{Bool: true, Valid: true},
|
||||||
NullInt64: sql.NullInt64{Int64: 42, Valid: true},
|
NullInt64: sql.NullInt64{Int64: 42, Valid: true},
|
||||||
NullFloat64: sql.NullFloat64{Float64: 42.42, Valid: true},
|
NullFloat64: sql.NullFloat64{Float64: 42.42, Valid: true},
|
||||||
|
BooleanPtr: &booleanPtr,
|
||||||
|
CharPtr: &charPtr,
|
||||||
|
TextPtr: &textPtr,
|
||||||
|
BytePtr: &bytePtr,
|
||||||
|
RunePtr: &runePtr,
|
||||||
|
IntPtr: &intPtr,
|
||||||
|
Int8Ptr: &int8Ptr,
|
||||||
|
Int16Ptr: &int16Ptr,
|
||||||
|
Int32Ptr: &int32Ptr,
|
||||||
|
Int64Ptr: &int64Ptr,
|
||||||
|
UintPtr: &uintPtr,
|
||||||
|
Uint8Ptr: &uint8Ptr,
|
||||||
|
Uint16Ptr: &uint16Ptr,
|
||||||
|
Uint32Ptr: &uint32Ptr,
|
||||||
|
Uint64Ptr: &uint64Ptr,
|
||||||
|
Float32Ptr: &float32Ptr,
|
||||||
|
Float64Ptr: &float64Ptr,
|
||||||
|
DecimalPtr: &decimalPtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err = dORM.Insert(&d)
|
id, err = dORM.Insert(&d)
|
||||||
@ -321,6 +377,25 @@ func TestNullDataTypes(t *testing.T) {
|
|||||||
|
|
||||||
throwFail(t, AssertIs(d.NullFloat64.Valid, true))
|
throwFail(t, AssertIs(d.NullFloat64.Valid, true))
|
||||||
throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42))
|
throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42))
|
||||||
|
|
||||||
|
throwFail(t, AssertIs(*d.BooleanPtr, booleanPtr))
|
||||||
|
throwFail(t, AssertIs(*d.CharPtr, charPtr))
|
||||||
|
throwFail(t, AssertIs(*d.TextPtr, textPtr))
|
||||||
|
throwFail(t, AssertIs(*d.BytePtr, bytePtr))
|
||||||
|
throwFail(t, AssertIs(*d.RunePtr, runePtr))
|
||||||
|
throwFail(t, AssertIs(*d.IntPtr, intPtr))
|
||||||
|
throwFail(t, AssertIs(*d.Int8Ptr, int8Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Int16Ptr, int16Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Int32Ptr, int32Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Int64Ptr, int64Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.UintPtr, uintPtr))
|
||||||
|
throwFail(t, AssertIs(*d.Uint8Ptr, uint8Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Uint16Ptr, uint16Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Uint32Ptr, uint32Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Uint64Ptr, uint64Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Float32Ptr, float32Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.Float64Ptr, float64Ptr))
|
||||||
|
throwFail(t, AssertIs(*d.DecimalPtr, decimalPtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDataCustomTypes(t *testing.T) {
|
func TestDataCustomTypes(t *testing.T) {
|
||||||
|
@ -148,7 +148,7 @@ func genRouterCode() {
|
|||||||
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
|
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
|
||||||
beego.ControllerComments{
|
beego.ControllerComments{
|
||||||
"` + strings.TrimSpace(c.Method) + `",
|
"` + strings.TrimSpace(c.Method) + `",
|
||||||
"` + c.Router + `",
|
` + "`" + c.Router + "`" + `,
|
||||||
` + allmethod + `,
|
` + allmethod + `,
|
||||||
` + params + `})
|
` + params + `})
|
||||||
`
|
`
|
||||||
|
176
plugins/apiauth/apiauth.go
Normal file
176
plugins/apiauth/apiauth.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2014 beego Author. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package apiauth provides handlers to enable apiauth support.
|
||||||
|
//
|
||||||
|
// Simple Usage:
|
||||||
|
// import(
|
||||||
|
// "github.com/astaxie/beego"
|
||||||
|
// "github.com/astaxie/beego/plugins/apiauth"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func main(){
|
||||||
|
// // apiauth every request
|
||||||
|
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APIBaiscAuth("appid","appkey"))
|
||||||
|
// beego.Run()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Advanced Usage:
|
||||||
|
//
|
||||||
|
// func getAppSecret(appid string) string {
|
||||||
|
// // get appsecret by appid
|
||||||
|
// // maybe store in configure, maybe in database
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APIAuthWithFunc(getAppSecret, 360))
|
||||||
|
//
|
||||||
|
// Infomation:
|
||||||
|
//
|
||||||
|
// In the request user should include these params in the query
|
||||||
|
//
|
||||||
|
// 1. appid
|
||||||
|
//
|
||||||
|
// appid is asigned to the application
|
||||||
|
//
|
||||||
|
// 2. signature
|
||||||
|
//
|
||||||
|
// get the signature use apiauth.Signature()
|
||||||
|
//
|
||||||
|
// when you send to server remember use url.QueryEscape()
|
||||||
|
//
|
||||||
|
// 3. timestamp:
|
||||||
|
//
|
||||||
|
// send the request time, the format is yyyy-mm-dd HH:ii:ss
|
||||||
|
//
|
||||||
|
package apiauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/astaxie/beego/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppIdToAppSecret func(string) string
|
||||||
|
|
||||||
|
func APIBaiscAuth(appid, appkey string) beego.FilterFunc {
|
||||||
|
ft := func(aid string) string {
|
||||||
|
if aid == appid {
|
||||||
|
return appkey
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return APIAuthWithFunc(ft, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
func APIAuthWithFunc(f AppIdToAppSecret, timeout int) beego.FilterFunc {
|
||||||
|
return func(ctx *context.Context) {
|
||||||
|
if ctx.Input.Query("appid") == "" {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("miss query param: appid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appsecret := f(ctx.Input.Query("appid"))
|
||||||
|
if appsecret == "" {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("not exist this appid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx.Input.Query("signature") == "" {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("miss query param: signature")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx.Input.Query("timestamp") == "" {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("miss query param: timestamp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := time.Now()
|
||||||
|
if t.Sub(u).Seconds() > float64(timeout) {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("timeout! the request time is long ago, please try again")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx.Input.Query("signature") !=
|
||||||
|
Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.Uri()) {
|
||||||
|
ctx.Output.SetStatus(403)
|
||||||
|
ctx.WriteString("auth failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Signature(appsecret, method string, params url.Values, RequestURI string) (result string) {
|
||||||
|
var query string
|
||||||
|
pa := make(map[string]string)
|
||||||
|
for k, v := range params {
|
||||||
|
pa[k] = v[0]
|
||||||
|
}
|
||||||
|
vs := mapSorter(pa)
|
||||||
|
vs.Sort()
|
||||||
|
for i := 0; i < vs.Len(); i++ {
|
||||||
|
if vs.Keys[i] == "signature" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if vs.Keys[i] != "" && vs.Vals[i] != "" {
|
||||||
|
query = fmt.Sprintf("%v%v%v", query, vs.Keys[i], vs.Vals[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_to_sign := fmt.Sprintf("%v\n%v\n%v\n", method, query, RequestURI)
|
||||||
|
|
||||||
|
sha256 := sha256.New
|
||||||
|
hash := hmac.New(sha256, []byte(appsecret))
|
||||||
|
hash.Write([]byte(string_to_sign))
|
||||||
|
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
type valSorter struct {
|
||||||
|
Keys []string
|
||||||
|
Vals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapSorter(m map[string]string) *valSorter {
|
||||||
|
vs := &valSorter{
|
||||||
|
Keys: make([]string, 0, len(m)),
|
||||||
|
Vals: make([]string, 0, len(m)),
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
vs.Keys = append(vs.Keys, k)
|
||||||
|
vs.Vals = append(vs.Vals, v)
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vs *valSorter) Sort() {
|
||||||
|
sort.Sort(vs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vs *valSorter) Len() int { return len(vs.Keys) }
|
||||||
|
func (vs *valSorter) Less(i, j int) bool { return vs.Keys[i] < vs.Keys[j] }
|
||||||
|
func (vs *valSorter) Swap(i, j int) {
|
||||||
|
vs.Vals[i], vs.Vals[j] = vs.Vals[j], vs.Vals[i]
|
||||||
|
vs.Keys[i], vs.Keys[j] = vs.Keys[j], vs.Keys[i]
|
||||||
|
}
|
@ -27,6 +27,7 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Advanced Usage:
|
// Advanced Usage:
|
||||||
|
//
|
||||||
// func SecretAuth(username, password string) bool {
|
// func SecretAuth(username, password string) bool {
|
||||||
// return username == "astaxie" && password == "helloBeego"
|
// return username == "astaxie" && password == "helloBeego"
|
||||||
// }
|
// }
|
||||||
|
@ -818,8 +818,8 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques
|
|||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
Critical(file, line)
|
Critical(fmt.Sprintf("%s:%d", file, line))
|
||||||
stack = stack + fmt.Sprintln(file, line)
|
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
||||||
}
|
}
|
||||||
middleware.ShowErr(err, rw, r, stack)
|
middleware.ShowErr(err, rw, r, stack)
|
||||||
}
|
}
|
||||||
@ -840,7 +840,7 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques
|
|||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
Critical(file, line)
|
Critical(fmt.Sprintf("%s:%d", file, line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,13 +83,16 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// put url statistics result in io.Writer
|
// put url statistics result in io.Writer
|
||||||
func (m *UrlMap) GetMap() [][]string {
|
func (m *UrlMap) GetMap() map[string]interface{} {
|
||||||
m.lock.RLock()
|
m.lock.RLock()
|
||||||
defer m.lock.RUnlock()
|
defer m.lock.RUnlock()
|
||||||
resultLists := make([][]string, 0)
|
|
||||||
|
|
||||||
var result = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"}
|
var fields = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"}
|
||||||
resultLists = append(resultLists, result)
|
|
||||||
|
resultLists := make([][]string, 0)
|
||||||
|
content := make(map[string]interface{})
|
||||||
|
content["Fields"] = fields
|
||||||
|
|
||||||
for k, v := range m.urlmap {
|
for k, v := range m.urlmap {
|
||||||
for kk, vv := range v {
|
for kk, vv := range v {
|
||||||
result := []string{
|
result := []string{
|
||||||
@ -104,7 +107,8 @@ func (m *UrlMap) GetMap() [][]string {
|
|||||||
resultLists = append(resultLists, result)
|
resultLists = append(resultLists, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resultLists
|
content["Data"] = resultLists
|
||||||
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
// global statistics data map
|
// global statistics data map
|
||||||
|
@ -33,6 +33,8 @@ type bounds struct {
|
|||||||
var (
|
var (
|
||||||
AdminTaskList map[string]Tasker
|
AdminTaskList map[string]Tasker
|
||||||
stop chan bool
|
stop chan bool
|
||||||
|
changed chan bool
|
||||||
|
isstart bool
|
||||||
seconds = bounds{0, 59, nil}
|
seconds = bounds{0, 59, nil}
|
||||||
minutes = bounds{0, 59, nil}
|
minutes = bounds{0, 59, nil}
|
||||||
hours = bounds{0, 23, nil}
|
hours = bounds{0, 23, nil}
|
||||||
@ -379,6 +381,7 @@ func dayMatches(s *Schedule, t time.Time) bool {
|
|||||||
|
|
||||||
// start all tasks
|
// start all tasks
|
||||||
func StartTask() {
|
func StartTask() {
|
||||||
|
isstart = true
|
||||||
go run()
|
go run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +414,8 @@ func run() {
|
|||||||
e.SetNext(effective)
|
e.SetNext(effective)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
case <-changed:
|
||||||
|
continue
|
||||||
case <-stop:
|
case <-stop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -419,12 +424,24 @@ func run() {
|
|||||||
|
|
||||||
// start all tasks
|
// start all tasks
|
||||||
func StopTask() {
|
func StopTask() {
|
||||||
|
isstart = false
|
||||||
stop <- true
|
stop <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
// add task with name
|
// add task with name
|
||||||
func AddTask(taskname string, t Tasker) {
|
func AddTask(taskname string, t Tasker) {
|
||||||
AdminTaskList[taskname] = t
|
AdminTaskList[taskname] = t
|
||||||
|
if isstart {
|
||||||
|
changed <- true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add task with name
|
||||||
|
func DeleteTask(taskname string) {
|
||||||
|
delete(AdminTaskList, taskname)
|
||||||
|
if isstart {
|
||||||
|
changed <- true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort map for tasker
|
// sort map for tasker
|
||||||
@ -578,4 +595,5 @@ func all(r bounds) uint64 {
|
|||||||
func init() {
|
func init() {
|
||||||
AdminTaskList = make(map[string]Tasker)
|
AdminTaskList = make(map[string]Tasker)
|
||||||
stop = make(chan bool)
|
stop = make(chan bool)
|
||||||
|
changed = make(chan bool)
|
||||||
}
|
}
|
||||||
|
@ -106,10 +106,10 @@ func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SliceIntersect returns diff slice of slice1 - slice2.
|
// SliceIntersect returns slice that are present in all the slice1 and slice2.
|
||||||
func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
||||||
for _, v := range slice1 {
|
for _, v := range slice1 {
|
||||||
if !InSliceIface(v, slice2) {
|
if InSliceIface(v, slice2) {
|
||||||
diffslice = append(diffslice, v)
|
diffslice = append(diffslice, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user