mirror of
https://github.com/astaxie/beego.git
synced 2025-07-11 20:51:02 +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 |
27
README.md
27
README.md
@ -1,30 +1,35 @@
|
||||
## beego
|
||||
## Beego
|
||||
|
||||
[](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.
|
||||
|
||||
More info [beego.me](http://beego.me)
|
||||
|
||||
## Installation
|
||||
|
||||
go get github.com/astaxie/beego
|
||||
|
||||
## Features
|
||||
|
||||
* RESTful support
|
||||
* MVC architecture
|
||||
* modularity
|
||||
* auto API documents
|
||||
* annotation router
|
||||
* namespace
|
||||
* powerful develop tools
|
||||
* full stack for web & API
|
||||
* Modularity
|
||||
* Auto API documents
|
||||
* Annotation router
|
||||
* Namespace
|
||||
* Powerful develop tools
|
||||
* Full stack for Web & API
|
||||
|
||||
## 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)
|
||||
|
||||
[中文文档](http://beego.me/docs/intro/)
|
||||
## Community
|
||||
|
||||
* [http://beego.me/community](http://beego.me/community)
|
||||
|
||||
## LICENSE
|
||||
|
||||
|
128
admin.go
128
admin.go
@ -142,121 +142,116 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
||||
tmpl.Execute(rw, data)
|
||||
|
||||
case "router":
|
||||
resultList := new([][]string)
|
||||
content := make(map[string]interface{})
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf("header"),
|
||||
var fields = []string{
|
||||
fmt.Sprintf("Router Pattern"),
|
||||
fmt.Sprintf("Methods"),
|
||||
fmt.Sprintf("Controller"),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
content["Fields"] = fields
|
||||
|
||||
methods := []string{}
|
||||
methodsData := make(map[string]interface{})
|
||||
for method, t := range BeeApp.Handlers.routers {
|
||||
var result = []string{
|
||||
fmt.Sprintf("success"),
|
||||
fmt.Sprintf("Method: %s", method),
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf(""),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
|
||||
resultList := new([][]string)
|
||||
|
||||
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"
|
||||
|
||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||
tmpl = template.Must(tmpl.Parse(routerAndFilterTpl))
|
||||
tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
|
||||
tmpl.Execute(rw, data)
|
||||
case "filter":
|
||||
resultList := new([][]string)
|
||||
content := make(map[string]interface{})
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf("header"),
|
||||
var fields = []string{
|
||||
fmt.Sprintf("Router Pattern"),
|
||||
fmt.Sprintf("Filter Function"),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
content["Fields"] = fields
|
||||
|
||||
filterTypes := []string{}
|
||||
filterTypeData := make(map[string]interface{})
|
||||
|
||||
if BeeApp.Handlers.enableFilter {
|
||||
var result = []string{
|
||||
fmt.Sprintf("success"),
|
||||
fmt.Sprintf("Before Router"),
|
||||
fmt.Sprintf(""),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
var filterType string
|
||||
|
||||
if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok {
|
||||
filterType = "Before Router"
|
||||
filterTypes = append(filterTypes, filterType)
|
||||
resultList := new([][]string)
|
||||
for _, f := range bf {
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", f.pattern),
|
||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||
}
|
||||
*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 {
|
||||
filterType = "Before Exec"
|
||||
filterTypes = append(filterTypes, filterType)
|
||||
resultList := new([][]string)
|
||||
for _, f := range bf {
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", f.pattern),
|
||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||
}
|
||||
*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 {
|
||||
filterType = "After Exec"
|
||||
filterTypes = append(filterTypes, filterType)
|
||||
resultList := new([][]string)
|
||||
for _, f := range bf {
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", f.pattern),
|
||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||
}
|
||||
*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 {
|
||||
filterType = "Finish Router"
|
||||
filterTypes = append(filterTypes, filterType)
|
||||
resultList := new([][]string)
|
||||
for _, f := range bf {
|
||||
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", f.pattern),
|
||||
fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
}
|
||||
filterTypeData[filterType] = resultList
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
data["Content"] = resultList
|
||||
content["Data"] = filterTypeData
|
||||
content["Methods"] = filterTypes
|
||||
|
||||
data["Content"] = content
|
||||
data["Title"] = "Filters"
|
||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||
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.routerType == routerTypeBeego {
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", v.pattern),
|
||||
fmt.Sprintf("%s", v.methods),
|
||||
fmt.Sprintf("%s", v.controllerType),
|
||||
@ -289,7 +283,6 @@ func printTree(resultList *[][]string, t *Tree) {
|
||||
*resultList = append(*resultList, result)
|
||||
} else if v.routerType == routerTypeRESTFul {
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", v.pattern),
|
||||
fmt.Sprintf("%s", v.methods),
|
||||
fmt.Sprintf(""),
|
||||
@ -297,7 +290,6 @@ func printTree(resultList *[][]string, t *Tree) {
|
||||
*resultList = append(*resultList, result)
|
||||
} else if v.routerType == routerTypeHandler {
|
||||
var result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", v.pattern),
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf(""),
|
||||
@ -352,13 +344,15 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
|
||||
func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
||||
data := make(map[interface{}]interface{})
|
||||
|
||||
resultList := new([][]string)
|
||||
var result = []string{
|
||||
fmt.Sprintf("header"),
|
||||
var result = []string{}
|
||||
fields := []string{
|
||||
fmt.Sprintf("Name"),
|
||||
fmt.Sprintf("Message"),
|
||||
fmt.Sprintf("Status"),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
resultList := new([][]string)
|
||||
|
||||
content := make(map[string]interface{})
|
||||
|
||||
for name, h := range toolbox.AdminCheckList {
|
||||
if err := h.Check(); err != nil {
|
||||
@ -379,7 +373,9 @@ func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
||||
*resultList = append(*resultList, result)
|
||||
}
|
||||
|
||||
data["Content"] = resultList
|
||||
content["Fields"] = fields
|
||||
content["Data"] = resultList
|
||||
data["Content"] = content
|
||||
data["Title"] = "Health Check"
|
||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||
tmpl = template.Must(tmpl.Parse(healthCheckTpl))
|
||||
@ -410,17 +406,17 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
// List Tasks
|
||||
content := make(map[string]interface{})
|
||||
resultList := new([][]string)
|
||||
var result = []string{
|
||||
fmt.Sprintf("header"),
|
||||
var result = []string{}
|
||||
var fields = []string{
|
||||
fmt.Sprintf("Task Name"),
|
||||
fmt.Sprintf("Task Spec"),
|
||||
fmt.Sprintf("Task Function"),
|
||||
fmt.Sprintf(""),
|
||||
}
|
||||
*resultList = append(*resultList, result)
|
||||
for tname, tk := range toolbox.AdminTaskList {
|
||||
result = []string{
|
||||
fmt.Sprintf(""),
|
||||
fmt.Sprintf("%s", tname),
|
||||
fmt.Sprintf("%s", tk.GetStatus()),
|
||||
fmt.Sprintf("%s", tk.GetPrev().String()),
|
||||
@ -428,7 +424,9 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
|
||||
*resultList = append(*resultList, result)
|
||||
}
|
||||
|
||||
data["Content"] = resultList
|
||||
content["Fields"] = fields
|
||||
content["Data"] = resultList
|
||||
data["Content"] = content
|
||||
data["Title"] = "Tasks"
|
||||
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
|
||||
tmpl = template.Must(tmpl.Parse(tasksTpl))
|
||||
|
174
adminui.go
174
adminui.go
@ -61,31 +61,35 @@ var gcAjaxTpl = `
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var qpsTpl = `
|
||||
{{define "content"}}
|
||||
var qpsTpl = `{{define "content"}}
|
||||
<h1>Requests statistics</h1>
|
||||
<table class="table table-striped table-hover ">
|
||||
{{range $i, $slice := .Content}}
|
||||
<thead>
|
||||
<tr>
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if eq $i 0}}
|
||||
{{range .Content.Fields}}
|
||||
<th>
|
||||
{{else}}
|
||||
<td>
|
||||
{{end}}
|
||||
{{$elem}}
|
||||
{{if eq $i 0}}
|
||||
{{.}}
|
||||
</th>
|
||||
{{else}}
|
||||
{{end}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{range $i, $elem := .Content.Data}}
|
||||
|
||||
<tr>
|
||||
{{range $elem}}
|
||||
<td>
|
||||
{{.}}
|
||||
</td>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
</tr>
|
||||
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
{{end}}
|
||||
`
|
||||
{{end}}`
|
||||
|
||||
var configTpl = `
|
||||
{{define "content"}}
|
||||
@ -98,49 +102,51 @@ var configTpl = `
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var routerAndFilterTpl = `
|
||||
{{define "content"}}
|
||||
var routerAndFilterTpl = `{{define "content"}}
|
||||
|
||||
|
||||
<h1>{{.Title}}</h1>
|
||||
<table class="table table-striped table-hover ">
|
||||
{{range $i, $slice := .Content}}
|
||||
<tr>
|
||||
|
||||
{{ $header := index $slice 0}}
|
||||
{{if eq "header" $header }}
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
{{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 ">
|
||||
<thead>
|
||||
<tr>
|
||||
{{range $.Content.Fields}}
|
||||
<th>
|
||||
{{$elem}}
|
||||
{{.}}
|
||||
</th>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{else if eq "success" $header}}
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
<th class="success">
|
||||
{{$elem}}
|
||||
</th>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{$slice := index $.Content.Data .}}
|
||||
{{range $i, $elem := $slice}}
|
||||
|
||||
<tr>
|
||||
{{range $elem}}
|
||||
<td>
|
||||
{{$elem}}
|
||||
{{.}}
|
||||
</td>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var tasksTpl = `
|
||||
{{define "content"}}
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{end}}`
|
||||
|
||||
var tasksTpl = `{{define "content"}}
|
||||
|
||||
<h1>{{.Title}}</h1>
|
||||
|
||||
@ -161,59 +167,51 @@ bg-warning
|
||||
|
||||
|
||||
<table class="table table-striped table-hover ">
|
||||
{{range $i, $slice := .Content}}
|
||||
<thead>
|
||||
<tr>
|
||||
{{range .Content.Fields}}
|
||||
<th>
|
||||
{{.}}
|
||||
</th>
|
||||
{{end}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{{ $header := index $slice 0}}
|
||||
{{if eq "header" $header }}
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
<th>
|
||||
{{$elem}}
|
||||
</th>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<th>
|
||||
Run Task
|
||||
</th>
|
||||
{{else}}
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
<tbody>
|
||||
{{range $i, $slice := .Content.Data}}
|
||||
<tr>
|
||||
{{range $slice}}
|
||||
<td>
|
||||
{{$elem}}
|
||||
{{.}}
|
||||
</td>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<td>
|
||||
<a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 1}}">Run</a>
|
||||
</td>
|
||||
{{end}}
|
||||
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{end}}
|
||||
`
|
||||
|
||||
{{end}}`
|
||||
|
||||
var healthCheckTpl = `
|
||||
{{define "content"}}
|
||||
|
||||
<h1>{{.Title}}</h1>
|
||||
<table class="table table-striped table-hover ">
|
||||
{{range $i, $slice := .Content}}
|
||||
|
||||
{{ $header := index $slice 0}}
|
||||
{{if eq "header" $header }}
|
||||
<thead>
|
||||
<tr>
|
||||
{{range $j, $elem := $slice}}
|
||||
{{if ne $j 0}}
|
||||
{{range .Content.Fields}}
|
||||
<th>
|
||||
{{$elem}}
|
||||
{{.}}
|
||||
</th>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</tr>
|
||||
{{else}}
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i, $slice := .Content.Data}}
|
||||
{{ $header := index $slice 0}}
|
||||
{{ if eq "success" $header}}
|
||||
<tr class="success">
|
||||
{{else if eq "error" $header}}
|
||||
@ -228,10 +226,13 @@ var healthCheckTpl = `
|
||||
</td>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<td>
|
||||
{{$header}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{end}}`
|
||||
|
||||
@ -251,7 +252,8 @@ Welcome to Beego Admin Dashboard
|
||||
|
||||
</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">
|
||||
ul.nav li.dropdown:hover > ul.dropdown-menu {
|
||||
@ -336,9 +338,17 @@ Healthcheck
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
|
||||
<script src="http://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="//code.jquery.com/jquery-1.11.1.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" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
2
beego.go
2
beego.go
@ -38,7 +38,7 @@ import (
|
||||
)
|
||||
|
||||
// beego web framework version.
|
||||
const VERSION = "1.4.0"
|
||||
const VERSION = "1.4.1"
|
||||
|
||||
type hookfunc func() error //hook function to run
|
||||
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.
|
||||
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.
|
||||
@ -162,7 +162,7 @@ func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
|
||||
|
||||
// Int returns the integer value for a given key.
|
||||
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.
|
||||
@ -177,7 +177,7 @@ func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
|
||||
|
||||
// Int64 returns the int64 value for a given key.
|
||||
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.
|
||||
@ -192,7 +192,7 @@ func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
|
||||
|
||||
// Float returns the float value for a given key.
|
||||
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.
|
||||
@ -207,8 +207,7 @@ func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float6
|
||||
|
||||
// String returns the string value for a given key.
|
||||
func (c *IniConfigContainer) String(key string) string {
|
||||
key = strings.ToLower(key)
|
||||
return c.getdata(strings.ToLower(key))
|
||||
return c.getdata(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
|
||||
func (c *IniConfigContainer) getdata(key string) string {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
if len(key) == 0 {
|
||||
return ""
|
||||
}
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
var (
|
||||
section, k string
|
||||
sectionKey []string = strings.Split(key, "::")
|
||||
sectionKey []string = strings.Split(strings.ToLower(key), "::")
|
||||
)
|
||||
if len(sectionKey) >= 2 {
|
||||
section = sectionKey[0]
|
||||
|
@ -49,7 +49,7 @@ type Context struct {
|
||||
// It sends http response header directly.
|
||||
func (ctx *Context) Redirect(status int, localurl string) {
|
||||
ctx.Output.Header("Location", localurl)
|
||||
ctx.Output.SetStatus(status)
|
||||
ctx.ResponseWriter.WriteHeader(status)
|
||||
}
|
||||
|
||||
// Abort stops this request.
|
||||
|
@ -60,7 +60,7 @@ func (input *BeegoInput) Uri() string {
|
||||
|
||||
// Url returns request url path (without query string, fragment).
|
||||
func (input *BeegoInput) Url() string {
|
||||
return input.Request.URL.String()
|
||||
return input.Request.URL.Path
|
||||
}
|
||||
|
||||
// Site returns base site url as scheme://domain type.
|
||||
|
@ -6,53 +6,71 @@ httplib is an libs help you to curl remote url.
|
||||
## GET
|
||||
you can use Get to crawl data.
|
||||
|
||||
import "httplib"
|
||||
import "github.com/astaxie/beego/httplib"
|
||||
|
||||
str, err := httplib.Get("http://beego.me/").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
// error
|
||||
}
|
||||
fmt.Println(str)
|
||||
|
||||
## POST
|
||||
POST data to remote url
|
||||
|
||||
b:=httplib.Post("http://beego.me/")
|
||||
b.Param("username","astaxie")
|
||||
b.Param("password","123456")
|
||||
str, err := b.String()
|
||||
req := httplib.Post("http://beego.me/")
|
||||
req.Param("username","astaxie")
|
||||
req.Param("password","123456")
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
// error
|
||||
}
|
||||
fmt.Println(str)
|
||||
|
||||
## set timeout
|
||||
you can set timeout in request.default is 60 seconds.
|
||||
## Set timeout
|
||||
|
||||
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)
|
||||
|
||||
set post timeout:
|
||||
|
||||
// POST
|
||||
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
|
||||
|
||||
- first param is connectTimeout.
|
||||
- second param is readWriteTimeout
|
||||
|
||||
## debug
|
||||
if you want to debug the request info, set the debug on
|
||||
## Debug
|
||||
|
||||
If you want to debug the request info, set the debug on
|
||||
|
||||
httplib.Get("http://beego.me/").Debug(true)
|
||||
|
||||
## support HTTPS client
|
||||
if request url is https. You can set the client support TSL:
|
||||
## Set HTTP Basic Auth
|
||||
|
||||
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})
|
||||
|
||||
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 HTTP Version
|
||||
|
||||
some servers need to specify the protocol version of HTTP
|
||||
|
||||
httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1")
|
||||
|
||||
## Set Cookie
|
||||
|
||||
## set cookie
|
||||
some http request need setcookie. So set it like this:
|
||||
|
||||
cookie := &http.Cookie{}
|
||||
@ -60,21 +78,20 @@ some http request need setcookie. So set it like this:
|
||||
cookie.Value = "astaxie"
|
||||
httplib.Get("http://beego.me/").SetCookie(cookie)
|
||||
|
||||
## upload file
|
||||
httplib support mutil file upload, use `b.PostFile()`
|
||||
## Upload file
|
||||
|
||||
b:=httplib.Post("http://beego.me/")
|
||||
b.Param("username","astaxie")
|
||||
b.Param("password","123456")
|
||||
b.PostFile("uploadfile1", "httplib.pdf")
|
||||
b.PostFile("uploadfile2", "httplib.txt")
|
||||
str, err := b.String()
|
||||
httplib support mutil file upload, use `req.PostFile()`
|
||||
|
||||
req := httplib.Post("http://beego.me/")
|
||||
req.Param("username","astaxie")
|
||||
req.PostFile("uploadfile1", "httplib.pdf")
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
// error
|
||||
}
|
||||
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,7 +14,7 @@
|
||||
|
||||
// Usage:
|
||||
//
|
||||
// import "github.com/astaxie/beego/context"
|
||||
// import "github.com/astaxie/beego/httplib"
|
||||
//
|
||||
// b := httplib.Post("http://beego.me/")
|
||||
// b.Param("username","astaxie")
|
||||
@ -53,7 +53,7 @@ var defaultSetting = BeegoHttpSettings{false, "beegoServer", 60 * time.Second, 6
|
||||
var defaultCookieJar http.CookieJar
|
||||
var settingMutex sync.Mutex
|
||||
|
||||
// createDefaultCookieJar creates a global cookiejar to store cookies.
|
||||
// createDefaultCookie creates a global cookiejar to store cookies.
|
||||
func createDefaultCookie() {
|
||||
settingMutex.Lock()
|
||||
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.
|
||||
func Get(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "GET"
|
||||
req.Header = http.Header{}
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||
return newBeegoRequest(url, "GET")
|
||||
}
|
||||
|
||||
// Post returns *BeegoHttpRequest with POST method.
|
||||
func Post(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "POST"
|
||||
req.Header = http.Header{}
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||
return newBeegoRequest(url, "POST")
|
||||
}
|
||||
|
||||
// Put returns *BeegoHttpRequest with PUT method.
|
||||
func Put(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "PUT"
|
||||
req.Header = http.Header{}
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||
return newBeegoRequest(url, "PUT")
|
||||
}
|
||||
|
||||
// Delete returns *BeegoHttpRequest DELETE GET method.
|
||||
// Delete returns *BeegoHttpRequest DELETE method.
|
||||
func Delete(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "DELETE"
|
||||
req.Header = http.Header{}
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||
return newBeegoRequest(url, "DELETE")
|
||||
}
|
||||
|
||||
// Head returns *BeegoHttpRequest with HEAD method.
|
||||
func Head(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "HEAD"
|
||||
req.Header = http.Header{}
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||
return newBeegoRequest(url, "HEAD")
|
||||
}
|
||||
|
||||
// BeegoHttpSettings
|
||||
@ -132,6 +130,8 @@ type BeegoHttpRequest struct {
|
||||
params map[string]string
|
||||
files map[string]string
|
||||
setting BeegoHttpSettings
|
||||
resp *http.Response
|
||||
body []byte
|
||||
}
|
||||
|
||||
// Change request settings
|
||||
@ -140,6 +140,12 @@ func (b *BeegoHttpRequest) Setting(setting BeegoHttpSettings) *BeegoHttpRequest
|
||||
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
|
||||
func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest {
|
||||
b.setting.EnableCookie = enable
|
||||
@ -247,6 +253,9 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest {
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
||||
if b.resp.StatusCode != 0 {
|
||||
return b.resp, nil
|
||||
}
|
||||
var paramBody string
|
||||
if len(b.params) > 0 {
|
||||
var buf bytes.Buffer
|
||||
@ -301,22 +310,11 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
||||
}
|
||||
|
||||
url, err := url.Parse(b.url)
|
||||
if url.Scheme == "" {
|
||||
b.url = "http://" + b.url
|
||||
url, err = url.Parse(b.url)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -361,10 +359,19 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.resp = resp
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@ -382,6 +389,9 @@ func (b *BeegoHttpRequest) String() (string, error) {
|
||||
// Bytes returns the body []byte in response.
|
||||
// it calls Response inner.
|
||||
func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
||||
if b.body != nil {
|
||||
return b.body, nil
|
||||
}
|
||||
resp, err := b.getResponse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -394,6 +404,7 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.body = data
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
@ -15,27 +15,51 @@
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleGet(t *testing.T) {
|
||||
str, err := Get("http://httpbin.org/get").String()
|
||||
func TestResponse(t *testing.T) {
|
||||
req := Get("http://httpbin.org/get")
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
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) {
|
||||
v := "smallfish"
|
||||
req := Post("http://httpbin.org/post")
|
||||
req.Param("username", v)
|
||||
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in post")
|
||||
@ -47,17 +71,35 @@ func TestPostFile(t *testing.T) {
|
||||
req := Post("http://httpbin.org/post")
|
||||
req.Param("username", v)
|
||||
req.PostFile("uploadfile", "httplib_test.go")
|
||||
|
||||
str, err := req.String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
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) {
|
||||
v := "smallfish"
|
||||
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.Log(str)
|
||||
|
||||
str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
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) {
|
||||
v := "beego"
|
||||
str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
|
||||
@ -83,6 +139,7 @@ func TestWithUserAgent(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in user-agent")
|
||||
@ -102,8 +159,47 @@ func TestWithSetting(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(str, v)
|
||||
if n == -1 {
|
||||
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;33"), // Warning yellow
|
||||
NewBrush("1;32"), // Notice green
|
||||
NewBrush("1;34"), // Informational green
|
||||
NewBrush("1;30"), // Debug black
|
||||
NewBrush("1;34"), // Informational blue
|
||||
NewBrush("1;34"), // Debug blue
|
||||
}
|
||||
|
||||
// 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() {
|
||||
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 strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
|
||||
os.Remove(path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
|
16
logs/log.go
16
logs/log.go
@ -193,7 +193,10 @@ func (bl *BeeLogger) startLogger() {
|
||||
select {
|
||||
case bm := <-bl.msg:
|
||||
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.
|
||||
func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[D] "+format, v...)
|
||||
msg := fmt.Sprintf("[M] "+format, v...)
|
||||
bl.writerMsg(LevelEmergency, msg)
|
||||
}
|
||||
|
||||
// Log ALERT level message.
|
||||
func (bl *BeeLogger) Alert(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[D] "+format, v...)
|
||||
msg := fmt.Sprintf("[A] "+format, v...)
|
||||
bl.writerMsg(LevelAlert, msg)
|
||||
}
|
||||
|
||||
@ -231,7 +234,7 @@ func (bl *BeeLogger) Warning(format string, v ...interface{}) {
|
||||
|
||||
// Log NOTICE level message.
|
||||
func (bl *BeeLogger) Notice(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[W] "+format, v...)
|
||||
msg := fmt.Sprintf("[N] "+format, v...)
|
||||
bl.writerMsg(LevelNotice, msg)
|
||||
}
|
||||
|
||||
@ -281,7 +284,10 @@ func (bl *BeeLogger) Close() {
|
||||
if len(bl.msg) > 0 {
|
||||
bm := <-bl.msg
|
||||
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 {
|
||||
break
|
||||
|
67
logs/smtp.go
67
logs/smtp.go
@ -15,8 +15,10 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
@ -32,6 +34,7 @@ type SmtpWriter struct {
|
||||
Password string `json:"password"`
|
||||
Host string `json:"Host"`
|
||||
Subject string `json:"subject"`
|
||||
FromAddress string `json:"fromAddress"`
|
||||
RecipientAddresses []string `json:"sendTos"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
@ -48,6 +51,7 @@ func NewSmtpWriter() LoggerInterface {
|
||||
// "password:"password",
|
||||
// "host":"smtp.gmail.com:465",
|
||||
// "subject":"email title",
|
||||
// "fromAddress":"from@example.com",
|
||||
// "sendTos":["email1","email2"],
|
||||
// "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.
|
||||
// it will send an email with subject and only this message.
|
||||
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,
|
||||
// and send the email all in one step.
|
||||
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)
|
||||
|
||||
err := smtp.SendMail(
|
||||
s.Host,
|
||||
auth,
|
||||
s.Username,
|
||||
s.RecipientAddresses,
|
||||
mailmsg,
|
||||
)
|
||||
err := s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg)
|
||||
|
||||
return err
|
||||
}
|
||||
|
102
orm/db.go
102
orm/db.go
@ -122,6 +122,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
if nb.Valid {
|
||||
value = nb.Bool
|
||||
}
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
value = nil
|
||||
} else {
|
||||
value = field.Elem().Bool()
|
||||
}
|
||||
} else {
|
||||
value = field.Bool()
|
||||
}
|
||||
@ -131,6 +137,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
if ns.Valid {
|
||||
value = ns.String
|
||||
}
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
value = nil
|
||||
} else {
|
||||
value = field.Elem().String()
|
||||
}
|
||||
} else {
|
||||
value = field.String()
|
||||
}
|
||||
@ -140,6 +152,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
if nf.Valid {
|
||||
value = nf.Float64
|
||||
}
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
value = nil
|
||||
} else {
|
||||
value = field.Elem().Float()
|
||||
}
|
||||
} else {
|
||||
vu := field.Interface()
|
||||
if _, ok := vu.(float32); ok {
|
||||
@ -161,13 +179,27 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
default:
|
||||
switch {
|
||||
case fi.fieldType&IsPostiveIntegerField > 0:
|
||||
if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
value = nil
|
||||
} else {
|
||||
value = field.Elem().Uint()
|
||||
}
|
||||
} else {
|
||||
value = field.Uint()
|
||||
}
|
||||
case fi.fieldType&IsIntegerField > 0:
|
||||
if ni, ok := field.Interface().(sql.NullInt64); ok {
|
||||
value = nil
|
||||
if ni.Valid {
|
||||
value = ni.Int64
|
||||
}
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
value = nil
|
||||
} else {
|
||||
value = field.Elem().Int()
|
||||
}
|
||||
} else {
|
||||
value = field.Int()
|
||||
}
|
||||
@ -1177,6 +1209,11 @@ setValue:
|
||||
nb.Valid = true
|
||||
}
|
||||
field.Set(reflect.ValueOf(nb))
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if value != nil {
|
||||
v := value.(bool)
|
||||
field.Set(reflect.ValueOf(&v))
|
||||
}
|
||||
} else {
|
||||
if value == nil {
|
||||
value = false
|
||||
@ -1194,6 +1231,11 @@ setValue:
|
||||
ns.Valid = true
|
||||
}
|
||||
field.Set(reflect.ValueOf(ns))
|
||||
} else if field.Kind() == reflect.Ptr {
|
||||
if value != nil {
|
||||
v := value.(string)
|
||||
field.Set(reflect.ValueOf(&v))
|
||||
}
|
||||
} else {
|
||||
if value == nil {
|
||||
value = ""
|
||||
@ -1208,6 +1250,56 @@ setValue:
|
||||
}
|
||||
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:
|
||||
if fieldType&IsPostiveIntegerField > 0 {
|
||||
if isNative {
|
||||
@ -1244,6 +1336,16 @@ setValue:
|
||||
nf.Valid = true
|
||||
}
|
||||
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 {
|
||||
|
||||
if value == nil {
|
||||
|
@ -155,6 +155,24 @@ type DataNull struct {
|
||||
NullBool sql.NullBool `orm:"null"`
|
||||
NullFloat64 sql.NullFloat64 `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
|
||||
|
@ -111,6 +111,33 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
|
||||
|
||||
// return field type as type constant from reflect.Value
|
||||
func getFieldType(val reflect.Value) (ft int, err error) {
|
||||
switch val.Type() {
|
||||
case reflect.TypeOf(new(int8)):
|
||||
ft = TypeBitField
|
||||
case reflect.TypeOf(new(int16)):
|
||||
ft = TypeSmallIntegerField
|
||||
case reflect.TypeOf(new(int32)),
|
||||
reflect.TypeOf(new(int)):
|
||||
ft = TypeIntegerField
|
||||
case reflect.TypeOf(new(int64)):
|
||||
ft = TypeBigIntegerField
|
||||
case reflect.TypeOf(new(uint8)):
|
||||
ft = TypePositiveBitField
|
||||
case reflect.TypeOf(new(uint16)):
|
||||
ft = TypePositiveSmallIntegerField
|
||||
case reflect.TypeOf(new(uint32)),
|
||||
reflect.TypeOf(new(uint)):
|
||||
ft = TypePositiveIntegerField
|
||||
case reflect.TypeOf(new(uint64)):
|
||||
ft = TypePositiveBigIntegerField
|
||||
case reflect.TypeOf(new(float32)),
|
||||
reflect.TypeOf(new(float64)):
|
||||
ft = TypeFloatField
|
||||
case reflect.TypeOf(new(bool)):
|
||||
ft = TypeBooleanField
|
||||
case reflect.TypeOf(new(string)):
|
||||
ft = TypeCharField
|
||||
default:
|
||||
elm := reflect.Indirect(val)
|
||||
switch elm.Kind() {
|
||||
case reflect.Int8:
|
||||
@ -152,6 +179,7 @@ func getFieldType(val reflect.Value) (ft int, err error) {
|
||||
ft = TypeDateTimeField
|
||||
}
|
||||
}
|
||||
}
|
||||
if ft&IsFieldType == 0 {
|
||||
err = fmt.Errorf("unsupport field type %s, may be miss setting tag", val)
|
||||
}
|
||||
|
@ -287,6 +287,25 @@ func TestNullDataTypes(t *testing.T) {
|
||||
throwFail(t, AssertIs(d.NullInt64.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()
|
||||
throwFail(t, err)
|
||||
|
||||
@ -294,12 +313,49 @@ func TestNullDataTypes(t *testing.T) {
|
||||
err = dORM.Read(&d)
|
||||
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{
|
||||
DateTime: time.Now(),
|
||||
NullString: sql.NullString{String: "test", Valid: true},
|
||||
NullBool: sql.NullBool{Bool: true, Valid: true},
|
||||
NullInt64: sql.NullInt64{Int64: 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)
|
||||
@ -321,6 +377,25 @@ func TestNullDataTypes(t *testing.T) {
|
||||
|
||||
throwFail(t, AssertIs(d.NullFloat64.Valid, true))
|
||||
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) {
|
||||
|
@ -148,7 +148,7 @@ func genRouterCode() {
|
||||
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
|
||||
beego.ControllerComments{
|
||||
"` + strings.TrimSpace(c.Method) + `",
|
||||
"` + c.Router + `",
|
||||
` + "`" + c.Router + "`" + `,
|
||||
` + allmethod + `,
|
||||
` + 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:
|
||||
//
|
||||
// func SecretAuth(username, password string) bool {
|
||||
// return username == "astaxie" && password == "helloBeego"
|
||||
// }
|
||||
|
@ -818,8 +818,8 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
Critical(file, line)
|
||||
stack = stack + fmt.Sprintln(file, line)
|
||||
Critical(fmt.Sprintf("%s:%d", file, line))
|
||||
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
|
||||
}
|
||||
middleware.ShowErr(err, rw, r, stack)
|
||||
}
|
||||
@ -840,7 +840,7 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques
|
||||
if !ok {
|
||||
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
|
||||
func (m *UrlMap) GetMap() [][]string {
|
||||
func (m *UrlMap) GetMap() map[string]interface{} {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
resultLists := make([][]string, 0)
|
||||
|
||||
var result = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"}
|
||||
resultLists = append(resultLists, result)
|
||||
var fields = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"}
|
||||
|
||||
resultLists := make([][]string, 0)
|
||||
content := make(map[string]interface{})
|
||||
content["Fields"] = fields
|
||||
|
||||
for k, v := range m.urlmap {
|
||||
for kk, vv := range v {
|
||||
result := []string{
|
||||
@ -104,7 +107,8 @@ func (m *UrlMap) GetMap() [][]string {
|
||||
resultLists = append(resultLists, result)
|
||||
}
|
||||
}
|
||||
return resultLists
|
||||
content["Data"] = resultLists
|
||||
return content
|
||||
}
|
||||
|
||||
// global statistics data map
|
||||
|
@ -33,6 +33,8 @@ type bounds struct {
|
||||
var (
|
||||
AdminTaskList map[string]Tasker
|
||||
stop chan bool
|
||||
changed chan bool
|
||||
isstart bool
|
||||
seconds = bounds{0, 59, nil}
|
||||
minutes = bounds{0, 59, nil}
|
||||
hours = bounds{0, 23, nil}
|
||||
@ -379,6 +381,7 @@ func dayMatches(s *Schedule, t time.Time) bool {
|
||||
|
||||
// start all tasks
|
||||
func StartTask() {
|
||||
isstart = true
|
||||
go run()
|
||||
}
|
||||
|
||||
@ -411,6 +414,8 @@ func run() {
|
||||
e.SetNext(effective)
|
||||
}
|
||||
continue
|
||||
case <-changed:
|
||||
continue
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
@ -419,12 +424,24 @@ func run() {
|
||||
|
||||
// start all tasks
|
||||
func StopTask() {
|
||||
isstart = false
|
||||
stop <- true
|
||||
}
|
||||
|
||||
// add task with name
|
||||
func AddTask(taskname string, t Tasker) {
|
||||
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
|
||||
@ -578,4 +595,5 @@ func all(r bounds) uint64 {
|
||||
func init() {
|
||||
AdminTaskList = make(map[string]Tasker)
|
||||
stop = make(chan bool)
|
||||
changed = make(chan bool)
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
||||
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{}) {
|
||||
for _, v := range slice1 {
|
||||
if !InSliceIface(v, slice2) {
|
||||
if InSliceIface(v, slice2) {
|
||||
diffslice = append(diffslice, v)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user