mirror of
https://github.com/xxjwxc/public.git
synced 2025-09-26 20:01:19 +08:00
rebase
This commit is contained in:
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# public
|
||||
golang 工具包。
|
||||
|
||||
- 里面包含很多公共函数
|
||||
|
||||
包括:
|
||||
|
||||
`文件功能`,`leveldb`,`restful风格消息包头定义`,`cache缓存`,`绘图函数`,`elastic`,`echarts`,`http`,`日志`,`nsq抽取`,`线程安全队列`,`签名`,`gorm封装`,`时间函数`,`国际化i18n`,`gocui 界面类`,`驼峰命名转换工具`,`大驼峰到网络标准json串自动转换`,`剪切板`,`微信`,`ast`,`swagger 文档支持`,`mindoc/markdown 文档支持`
|
||||
......
|
48
dev/dev.go
Normal file
48
dev/dev.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _isDev = true
|
||||
var service = "service"
|
||||
var fileHost = "file"
|
||||
|
||||
//是否开发模式
|
||||
func OnSetDev(isDev bool) {
|
||||
_isDev = isDev
|
||||
}
|
||||
|
||||
//OnIsDev ... 是否是开发版本
|
||||
func OnIsDev() bool {
|
||||
return _isDev
|
||||
}
|
||||
|
||||
//判断是否在测试环境下使用
|
||||
func IsRunTesting() bool {
|
||||
if len(os.Args) > 1 {
|
||||
return strings.HasPrefix(os.Args[1], "-test")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//设置服务名
|
||||
func SetService(s string) {
|
||||
service = s
|
||||
}
|
||||
|
||||
//获取服务名
|
||||
func GetService() string {
|
||||
return service
|
||||
}
|
||||
|
||||
//设置服务名
|
||||
func SetFileHost(s string) {
|
||||
fileHost = s
|
||||
}
|
||||
|
||||
//获取文件host
|
||||
func GetFileHost() string {
|
||||
return fileHost
|
||||
}
|
283
errors/errors.go
Normal file
283
errors/errors.go
Normal file
@@ -0,0 +1,283 @@
|
||||
// from https://github.com/pkg/errors
|
||||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d", f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", w.Cause())
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
36
errors/errors_test.go
Normal file
36
errors/errors_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func test1() error {
|
||||
return test2()
|
||||
}
|
||||
|
||||
func test2() error {
|
||||
return Wrapf(New("something go wrong"), "自定义消息")
|
||||
}
|
||||
|
||||
func TestErr(t *testing.T) {
|
||||
err := test1()
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
err = Cause(err) //获取原始对象
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
|
||||
func test11() error {
|
||||
return test21()
|
||||
}
|
||||
|
||||
func test21() error {
|
||||
return New("something go wrong")
|
||||
}
|
||||
|
||||
func TestErr1(t *testing.T) {
|
||||
err := test11()
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
err = Cause(err) //获取原始对象
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
}
|
147
errors/stack.go
Normal file
147
errors/stack.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
pc := f.pc()
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
io.WriteString(s, "unknown")
|
||||
} else {
|
||||
file, _ := fn.FileLine(pc)
|
||||
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||
}
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
fmt.Fprintf(s, "%d", f.line())
|
||||
case 'n':
|
||||
name := runtime.FuncForPC(f.pc()).Name()
|
||||
io.WriteString(s, funcname(name))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
fmt.Fprintf(s, "\n%+v", f)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
fmt.Fprintf(s, "%v", []Frame(st))
|
||||
}
|
||||
case 's':
|
||||
fmt.Fprintf(s, "%s", []Frame(st))
|
||||
}
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
28
fractional/fal_test.go
Normal file
28
fractional/fal_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package fractional
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_fal(t *testing.T) {
|
||||
tmp := Model(7, 12)
|
||||
tmp1 := Model(1, 12)
|
||||
fmt.Println(tmp.Add(tmp1))
|
||||
|
||||
tmp = Model(1, 4)
|
||||
tmp1 = Model(1, 3)
|
||||
fmt.Println(tmp.Sub(tmp1))
|
||||
|
||||
tmp = Model(3, 4)
|
||||
tmp1 = Model(2, 3)
|
||||
fmt.Println(tmp.Mul(tmp1))
|
||||
|
||||
tmp = Model(3, 4)
|
||||
tmp1 = Model(2, 3)
|
||||
fmt.Println(tmp.Div(tmp1))
|
||||
|
||||
tmp = Model(1, 3)
|
||||
fmt.Println(tmp.Verdict())
|
||||
|
||||
}
|
93
fractional/fractional.go
Normal file
93
fractional/fractional.go
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Package fractional 分数运算相关
|
||||
*/
|
||||
package fractional
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/xxjwxc/public/mymath"
|
||||
)
|
||||
|
||||
//FAL 分数
|
||||
type FAL struct {
|
||||
Nume int64 //numerator 分子
|
||||
Deno int64 //denominator 分母 (一定不为0)
|
||||
}
|
||||
|
||||
//Model Create a score (molecular, denominator) with a denominator default of 1 创建一个分数(分子,分母),分母默认为1:
|
||||
func Model(nd ...int64) *FAL {
|
||||
var f FAL
|
||||
if len(nd) == 1 {
|
||||
f.Nume = nd[0]
|
||||
f.Deno = 1
|
||||
} else if len(nd) == 2 {
|
||||
f.Nume = nd[0]
|
||||
f.Deno = nd[1]
|
||||
}
|
||||
|
||||
if f.Deno == 0 { //分母为0
|
||||
panic(fmt.Sprintf("fractional init error. if denominator can't zero."))
|
||||
}
|
||||
|
||||
return &f
|
||||
}
|
||||
|
||||
//阔张
|
||||
func (s *FAL) broad(lcm int64) {
|
||||
s.Nume = s.Nume * (lcm / s.Deno)
|
||||
s.Deno = lcm
|
||||
}
|
||||
|
||||
//压缩 整理
|
||||
func (s *FAL) offset() {
|
||||
lcm := mymath.Gcd(s.Nume, s.Deno)
|
||||
|
||||
s.Nume /= lcm
|
||||
s.Deno /= lcm
|
||||
}
|
||||
|
||||
//Add 分数加法
|
||||
func (s *FAL) Add(f *FAL) *FAL {
|
||||
//获取最小公倍数
|
||||
lcm := mymath.Lcm(f.Deno, s.Deno)
|
||||
s.broad(lcm)
|
||||
f.broad(lcm)
|
||||
|
||||
s.Nume += f.Nume
|
||||
s.offset()
|
||||
return s
|
||||
}
|
||||
|
||||
//Sub 分数减法
|
||||
func (s *FAL) Sub(f *FAL) *FAL {
|
||||
//获取最小公倍数
|
||||
lcm := mymath.Lcm(s.Deno, f.Deno)
|
||||
s.broad(lcm)
|
||||
f.broad(lcm)
|
||||
|
||||
s.Nume -= f.Nume
|
||||
s.offset()
|
||||
return s
|
||||
}
|
||||
|
||||
//Mul 乘法
|
||||
func (s *FAL) Mul(f *FAL) *FAL {
|
||||
s.Deno *= f.Deno
|
||||
s.Nume *= f.Nume
|
||||
s.offset()
|
||||
return s
|
||||
}
|
||||
|
||||
//Div 乘法
|
||||
func (s *FAL) Div(f *FAL) *FAL {
|
||||
tmp := Model(f.Deno, f.Nume)
|
||||
s.Mul(tmp)
|
||||
s.offset()
|
||||
return s
|
||||
}
|
||||
|
||||
//Verdict 计算结果
|
||||
func (s *FAL) Verdict() float64 {
|
||||
return float64(s.Nume) / float64(s.Deno)
|
||||
}
|
32
go.mod
Normal file
32
go.mod
Normal file
@@ -0,0 +1,32 @@
|
||||
module github.com/xxjwxc/public
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/ant0ine/go-json-rest v3.3.2+incompatible
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/btcsuite/winsvc v1.0.0 // indirect
|
||||
github.com/ezbuy/tgen v0.0.0-20180109020500-95ef13895032 // indirect
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/gookit/color v1.1.7
|
||||
github.com/jander/golog v0.0.0-20150917071935-954a5be801fc
|
||||
github.com/jinzhu/gorm v1.9.11
|
||||
github.com/jroimartin/gocui v0.4.0
|
||||
github.com/kardianos/service v1.0.1-0.20191017145738-4df36c9fc1c6
|
||||
github.com/mailru/easyjson v0.7.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.8 // indirect
|
||||
github.com/muesli/cache2go v0.0.0-20191019095710-4098a3aa8c94
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.3
|
||||
github.com/nsf/termbox-go v0.0.0-20191229070316-58d4fcbce2a7 // indirect
|
||||
github.com/olivere/elastic v6.2.26+incompatible
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/silenceper/wechat v1.2.3
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
golang.org/x/net v0.0.0-20191125084936-ffdde1057850
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/eapache/queue.v1 v1.1.0
|
||||
gopkg.in/go-with/wxpay.v1 v1.3.0
|
||||
)
|
297
go.sum
Normal file
297
go.sum
Normal file
@@ -0,0 +1,297 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/ant0ine/go-json-rest v3.3.2+incompatible h1:nBixrkLFiDNAW0hauKDLc8yJI6XfrQumWvytE1Hk14E=
|
||||
github.com/ant0ine/go-json-rest v3.3.2+incompatible/go.mod h1:q6aCt0GfU6LhpBsnZ/2U+mwe+0XB5WStbmwyoPfc+sk=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/astaxie/beego v1.7.1/go.mod h1:0R4++1tUqERR0WYFWdfkcrsyoVBCG4DgpDGokT3yb+U=
|
||||
github.com/atotto/clipboard v0.1.2 h1:YZCtFu5Ie8qX2VmVTBnrqLSiU9XOWwqNRmdT3gIQzbY=
|
||||
github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a h1:k5TuEkqEYCRs8+66WdOkswWOj+L/YbP5ruainvn94wg=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
|
||||
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
|
||||
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/ezbuy/tgen v0.0.0-20180109020500-95ef13895032 h1:diFmlmmibvulzbAoXmREHdqOsH9jIYkQLG6DZ6W2F7g=
|
||||
github.com/ezbuy/tgen v0.0.0-20180109020500-95ef13895032/go.mod h1:OeW1N0acAlRaGTlOG8jRZZUKEtyiGa0qvD+lWNWb9vs=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-gonic/gin v1.1.4/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v2.0.1-0.20180627144507-2cd21d9966bf+incompatible h1:QJ4V3LjaRe/6NKoaaj2QzQZcezt5gNXdPv0axxS4VNA=
|
||||
github.com/gomodule/redigo v2.0.1-0.20180627144507-2cd21d9966bf+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gookit/color v1.1.7 h1:WR5I/mhSHzemW2DzG54hTsUb7OzaREvkcmUG4/WST4Q=
|
||||
github.com/gookit/color v1.1.7/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jander/golog v0.0.0-20150917071935-954a5be801fc h1:l+v2jwOsGum32nR8cN1MxAtvUWQCIcQGm4WHwizaAbA=
|
||||
github.com/jander/golog v0.0.0-20150917071935-954a5be801fc/go.mod h1:uWhWXOR4dpfk9J8fegnMY7sP2GFXxe3PFI9Ps+TRXJs=
|
||||
github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE=
|
||||
github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jroimartin/gocui v0.4.0 h1:52jnalstgmc25FmtGcWqa0tcbMEWS6RpFLsOIO+I+E8=
|
||||
github.com/jroimartin/gocui v0.4.0/go.mod h1:7i7bbj99OgFHzo7kB2zPb8pXLqMBSQegY7azfqXMkyY=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
|
||||
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
|
||||
github.com/kardianos/service v1.0.1-0.20191017145738-4df36c9fc1c6 h1:yXmAejtSQYYDbY5Zv4BQDV4irr8r88UjcWufn4PtF5I=
|
||||
github.com/kardianos/service v1.0.1-0.20191017145738-4df36c9fc1c6/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739/go.mod h1:zUx1mhth20V3VKgL5jbd1BSQcW4Fy6Qs4PZvQwRFwzM=
|
||||
github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/muesli/cache2go v0.0.0-20191019095710-4098a3aa8c94 h1:aJflkQlskelDMdsFUYWffZXg0xtmYtjQJGwzRx3byDw=
|
||||
github.com/muesli/cache2go v0.0.0-20191019095710-4098a3aa8c94/go.mod h1:414R+qZrt4f9S2TO/s6YVQMNAXR2KdwqQ7pW+O4oYzU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.3 h1:ks/JkQiOEhhuF6jpNvx+Wih1NIiXzUnZeZVnJuI8R8M=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.3/go.mod h1:oDab7q8XCYMRlcrBnaY/7B1eOectbvj6B1UPBT+p5jo=
|
||||
github.com/nsf/termbox-go v0.0.0-20191229070316-58d4fcbce2a7 h1:OkWEy7aQeQTbgdrcGi9bifx+Y6bMM7ae7y42hDFaBvA=
|
||||
github.com/nsf/termbox-go v0.0.0-20191229070316-58d4fcbce2a7/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olivere/elastic v6.2.26+incompatible h1:3PjUHKyt8xKwbFQpRC5cgtEY7Qz6ejopBkukhI7UWvE=
|
||||
github.com/olivere/elastic v6.2.26+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/samuel/go-thrift v0.0.0-20190219015601-e8b6b52668fe h1:gD4vkYmuoWVgdV6UwI3tPo9MtMfVoIRY+Xn9919SJBg=
|
||||
github.com/samuel/go-thrift v0.0.0-20190219015601-e8b6b52668fe/go.mod h1:Vrkh1pnjV9Bl8c3P9zH0/D4NlOHWP5d4/hF4YTULaec=
|
||||
github.com/silenceper/wechat v1.2.3 h1:9ZrCdg6MkJTuZQ6PzxlzktktQLUzRd4VZag8zlUfag0=
|
||||
github.com/silenceper/wechat v1.2.3/go.mod h1:sEqmYpYrwwMCXUSzTaxcA78+fd0p+srrj8qRkOnpbLQ=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=
|
||||
github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 h1:rlLehGeYg6jfoyz/eDqDU1iRXLKfR42nnNh57ytKEWo=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20191125084936-ffdde1057850/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 h1:ZJUmhYTp8GbGC0ViZRc2U+MIYQ8xx9MscsdXnclfIhw=
|
||||
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc=
|
||||
gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.1/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-with/wxpay.v1 v1.3.0 h1:RXVQck9qNIGkajbTMCvlRPHeewyAIItzOybTTykVdV0=
|
||||
gopkg.in/go-with/wxpay.v1 v1.3.0/go.mod h1:12lWy92n19pAUSSE3BrOiEZbWRkl+9tneOd/aU/LU6g=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
@@ -4,13 +4,12 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"data/config"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"public/tools"
|
||||
|
||||
"github.com/bitly/go-simplejson"
|
||||
"github.com/xxjwxc/public/dev"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
const ( //消息id定义
|
||||
@@ -106,6 +105,7 @@ const ( //消息id定义
|
||||
ExistedError = 1084 //已存在
|
||||
NotBindError = 1085 //未绑定
|
||||
BindError = 1086 //绑定失败
|
||||
CalError = 1087 //计算错误
|
||||
)
|
||||
|
||||
//消息翻译
|
||||
@@ -202,9 +202,10 @@ var MessageMap = map[int]string{
|
||||
ExistedError: "已存在",
|
||||
NotBindError: "未绑定",
|
||||
BindError: "绑定失败",
|
||||
CalError: "计算错误",
|
||||
}
|
||||
|
||||
//
|
||||
//MessageBody 消息头
|
||||
type MessageBody struct {
|
||||
State bool `json:"state"`
|
||||
Code int `json:"code,omitempty"`
|
||||
@@ -212,7 +213,7 @@ type MessageBody struct {
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
//获取错误消息 参数(int,string)
|
||||
//GetErrorMsg 获取错误消息 参数(int,string)
|
||||
func GetErrorMsg(errorCode ...interface{}) (msg MessageBody) {
|
||||
if len(errorCode) == 0 {
|
||||
log.Println("未知")
|
||||
@@ -228,10 +229,11 @@ func GetErrorMsg(errorCode ...interface{}) (msg MessageBody) {
|
||||
msg.Error = MessageMap[msg.Code]
|
||||
case string:
|
||||
msg.Error = string(v)
|
||||
fmt.Println(v)
|
||||
case error:
|
||||
msg.Error = v.Error()
|
||||
case interface{}:
|
||||
{
|
||||
if config.OnIsDev() {
|
||||
if dev.OnIsDev() {
|
||||
msg.Error = onCheckParam(v)
|
||||
}
|
||||
}
|
||||
@@ -261,12 +263,12 @@ func onCheckParam(op interface{}) string {
|
||||
}
|
||||
|
||||
//成功消息
|
||||
func GetSuccessMsg(errorCode ...int) (msg MessageBody) {
|
||||
func GetSuccessMsg(code ...int) (msg MessageBody) {
|
||||
msg.State = true
|
||||
if len(errorCode) == 0 {
|
||||
if len(code) == 0 {
|
||||
msg.Code = NormalMessageId
|
||||
} else {
|
||||
msg.Code = errorCode[0]
|
||||
msg.Code = code[0]
|
||||
}
|
||||
|
||||
msg.Error = MessageMap[msg.Code]
|
||||
|
166
myast/common.go
Normal file
166
myast/common.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package myast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/errors"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
// GetModuleInfo find and get module info , return module [ name ,path ]
|
||||
// 通过model信息获取[model name] [和 根目录绝对地址]
|
||||
func GetModuleInfo(n int) (string, string, bool) {
|
||||
index := n
|
||||
// This is used to support third-party package encapsulation
|
||||
// 这样做用于支持第三方包封装,(主要找到main调用者)
|
||||
for true { // find main file
|
||||
_, filename, _, ok := runtime.Caller(index)
|
||||
if ok {
|
||||
if strings.HasSuffix(filename, "runtime/asm_amd64.s") {
|
||||
index = index - 2
|
||||
break
|
||||
}
|
||||
index++
|
||||
} else {
|
||||
panic(errors.New("package parsing failed:can not find main files"))
|
||||
}
|
||||
}
|
||||
|
||||
_, filename, _, _ := runtime.Caller(index)
|
||||
filename = strings.Replace(filename, "\\", "/", -1) // offset
|
||||
for true {
|
||||
n := strings.LastIndex(filename, "/")
|
||||
if n > 0 {
|
||||
filename = filename[0:n]
|
||||
if tools.CheckFileIsExist(filename + "/go.mod") {
|
||||
list := tools.ReadFile(filename + "/go.mod")
|
||||
if len(list) > 0 {
|
||||
line := strings.TrimSpace(list[0])
|
||||
if len(line) > 0 && strings.HasPrefix(line, "module") { // find it
|
||||
return strings.TrimSpace(strings.TrimPrefix(line, "module")), filename, true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
// panic(errors.New("package parsing failed:can not find module file[go.mod] , golang version must up 1.11"))
|
||||
}
|
||||
}
|
||||
|
||||
// never reach
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
// EvalSymlinks Return to relative path . 通过module 游标返回包相对路径
|
||||
func EvalSymlinks(modPkg, modFile, objPkg string) string {
|
||||
if strings.EqualFold(objPkg, "main") { // if main return default path
|
||||
return modFile
|
||||
}
|
||||
|
||||
if strings.HasPrefix(objPkg, modPkg) {
|
||||
return modFile + strings.Replace(objPkg[len(modPkg):], ".", "/", -1)
|
||||
}
|
||||
|
||||
// get the error space
|
||||
panic(errors.Errorf("can not eval pkg:[%v] must include [%v]", objPkg, modPkg))
|
||||
}
|
||||
|
||||
// Re
|
||||
// GetAstPkgs Parsing source file ast structure (with main restriction).解析源文件ast结构(带 main 限制)
|
||||
func GetAstPkgs(objPkg, objFile string) (*ast.Package, bool) {
|
||||
fileSet := token.NewFileSet()
|
||||
astPkgs, err := parser.ParseDir(fileSet, objFile, func(info os.FileInfo) bool {
|
||||
name := info.Name()
|
||||
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
|
||||
}, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// check the package is same.判断 package 是否一致
|
||||
for _, pkg := range astPkgs {
|
||||
if objPkg == pkg.Name || strings.HasSuffix(objPkg, "/"+pkg.Name) { // find it
|
||||
return pkg, true
|
||||
}
|
||||
}
|
||||
|
||||
// not find . maybe is main pakge and find main package
|
||||
if objPkg == "main" {
|
||||
dirs := tools.GetPathDirs(objFile) // get all of dir
|
||||
for _, dir := range dirs {
|
||||
if !strings.HasPrefix(dir, ".") {
|
||||
pkg, b := GetAstPkgs(objPkg, objFile+"/"+dir)
|
||||
if b {
|
||||
return pkg, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ast.Print(fileSet, astPkgs)
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetObjFunMp find all exported func of sturct objName
|
||||
// GetObjFunMp 类中的所有导出函数
|
||||
func GetObjFunMp(astPkg *ast.Package, objName string) map[string]*ast.FuncDecl {
|
||||
funMp := make(map[string]*ast.FuncDecl)
|
||||
// find all exported func of sturct objName
|
||||
for _, fl := range astPkg.Files {
|
||||
for _, d := range fl.Decls {
|
||||
switch specDecl := d.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if specDecl.Recv != nil {
|
||||
if exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr); ok { // Check that the type is correct first beforing throwing to parser
|
||||
if strings.Compare(fmt.Sprint(exp.X), objName) == 0 { // is the same struct
|
||||
funMp[specDecl.Name.String()] = specDecl // catch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return funMp
|
||||
}
|
||||
|
||||
// AnalysisImport 分析整合import相关信息
|
||||
func AnalysisImport(astPkgs *ast.Package) map[string]string {
|
||||
imports := make(map[string]string)
|
||||
for _, f := range astPkgs.Files {
|
||||
for _, p := range f.Imports {
|
||||
k := ""
|
||||
if p.Name != nil {
|
||||
k = p.Name.Name
|
||||
}
|
||||
v := strings.Trim(p.Path.Value, `"`)
|
||||
if len(k) == 0 {
|
||||
n := strings.LastIndex(v, "/")
|
||||
if n > 0 {
|
||||
k = v[n+1:]
|
||||
} else {
|
||||
k = v
|
||||
}
|
||||
}
|
||||
imports[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return imports
|
||||
}
|
||||
|
||||
// GetImportPkg 分析得出 pkg
|
||||
func GetImportPkg(i string) string {
|
||||
n := strings.LastIndex(i, "/")
|
||||
if n > 0 {
|
||||
return i[n+1:]
|
||||
}
|
||||
return i
|
||||
}
|
139
myast/myast.go
Normal file
139
myast/myast.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package myast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/mydoc"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
type structAnalys struct {
|
||||
ModPkg, ModFile string
|
||||
}
|
||||
|
||||
// NewStructAnalys 新建一个导出结构体类
|
||||
func NewStructAnalys(modPkg, modFile string) *structAnalys {
|
||||
result := &structAnalys{ModPkg: modPkg, ModFile: modFile}
|
||||
return result
|
||||
}
|
||||
|
||||
// ParserStruct 解析结构体定义及相关信息
|
||||
func (a *structAnalys) ParserStruct(astPkg *ast.Package, structName string) (info *mydoc.StructInfo) {
|
||||
if astPkg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ast.Print(token.NewFileSet(), astPkg)
|
||||
|
||||
for _, fl := range astPkg.Files {
|
||||
for _, d := range fl.Decls {
|
||||
switch specDecl := d.(type) {
|
||||
case *ast.GenDecl:
|
||||
for _, subitem := range specDecl.Specs {
|
||||
switch specDecl.Tok {
|
||||
case token.TYPE:
|
||||
spec := subitem.(*ast.TypeSpec)
|
||||
switch st := spec.Type.(type) {
|
||||
case *ast.StructType:
|
||||
if spec.Name.Name == structName { // find it
|
||||
info = new(mydoc.StructInfo)
|
||||
info.Pkg = astPkg.Name
|
||||
for _, v := range specDecl.Doc.List { // 结构体注释
|
||||
t := strings.TrimSpace(strings.TrimPrefix(v.Text, "//"))
|
||||
if strings.HasPrefix(t, structName) { // find note
|
||||
t = strings.TrimSpace(strings.TrimPrefix(t, structName))
|
||||
info.Note += t
|
||||
}
|
||||
}
|
||||
info.Name = structName
|
||||
info.Items = a.structFieldInfo(astPkg, st)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *structAnalys) structFieldInfo(astPkg *ast.Package, sinfo *ast.StructType) (items []mydoc.ElementInfo) {
|
||||
if sinfo == nil || sinfo.Fields == nil {
|
||||
return
|
||||
}
|
||||
|
||||
importMP := AnalysisImport(astPkg)
|
||||
|
||||
var info mydoc.ElementInfo
|
||||
for _, field := range sinfo.Fields.List {
|
||||
info = mydoc.ElementInfo{}
|
||||
for _, fnames := range field.Names {
|
||||
info.Name += fnames.Name
|
||||
}
|
||||
if field.Tag != nil {
|
||||
info.Tag = strings.Trim(field.Tag.Value, "`")
|
||||
}
|
||||
if field.Comment != nil {
|
||||
info.Note = strings.TrimSpace(field.Comment.Text())
|
||||
}
|
||||
if field.Doc != nil {
|
||||
info.Note += strings.TrimSpace(field.Doc.List[0].Text)
|
||||
}
|
||||
|
||||
switch exp := field.Type.(type) {
|
||||
case *ast.SelectorExpr: // 非本文件包
|
||||
a.dealSelectorExpr(exp, &info, importMP)
|
||||
case *ast.ArrayType:
|
||||
info.IsArray = true
|
||||
switch x := exp.Elt.(type) {
|
||||
case *ast.SelectorExpr: // 非本文件包
|
||||
a.dealSelectorExpr(x, &info, importMP)
|
||||
case *ast.Ident:
|
||||
a.dealIdent(astPkg, x, &info)
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
switch x := exp.X.(type) {
|
||||
case *ast.SelectorExpr: // 非本文件包
|
||||
a.dealSelectorExpr(x, &info, importMP)
|
||||
case *ast.Ident:
|
||||
a.dealIdent(astPkg, x, &info)
|
||||
}
|
||||
case *ast.Ident: // 本文件
|
||||
a.dealIdent(astPkg, exp, &info)
|
||||
}
|
||||
|
||||
if len(info.Type) == 0 {
|
||||
panic(fmt.Sprintf("can not deal the type : %v", field.Type))
|
||||
}
|
||||
|
||||
items = append(items, info)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (a *structAnalys) dealSelectorExpr(exp *ast.SelectorExpr, info *mydoc.ElementInfo, importMP map[string]string) { // 非本文件包
|
||||
info.Type = exp.Sel.Name
|
||||
if !tools.IsInternalType(info.Type) { // 非基础类型(time)
|
||||
if x, ok := exp.X.(*ast.Ident); ok {
|
||||
if v, ok := importMP[x.Name]; ok {
|
||||
objFile := EvalSymlinks(a.ModPkg, a.ModFile, v)
|
||||
objPkg := GetImportPkg(v)
|
||||
astFile, _b := GetAstPkgs(objPkg, objFile)
|
||||
if _b {
|
||||
info.TypeRef = a.ParserStruct(astFile, info.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *structAnalys) dealIdent(astPkg *ast.Package, exp *ast.Ident, info *mydoc.ElementInfo) { // 本文件
|
||||
info.Type = exp.Name
|
||||
if !tools.IsInternalType(info.Type) { // 非基础类型
|
||||
info.TypeRef = a.ParserStruct(astPkg, info.Type)
|
||||
}
|
||||
}
|
21
mybigcamel/def.go
Normal file
21
mybigcamel/def.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package mybigcamel
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Copied from golint
|
||||
var commonInitialisms = []string{"ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS"}
|
||||
var commonInitialismsReplacer *strings.Replacer
|
||||
var uncommonInitialismsReplacer *strings.Replacer
|
||||
|
||||
func init() {
|
||||
var commonInitialismsForReplacer []string
|
||||
var uncommonInitialismsForReplacer []string
|
||||
for _, initialism := range commonInitialisms {
|
||||
commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
|
||||
uncommonInitialismsForReplacer = append(uncommonInitialismsForReplacer, strings.Title(strings.ToLower(initialism)), initialism)
|
||||
}
|
||||
commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
|
||||
uncommonInitialismsReplacer = strings.NewReplacer(uncommonInitialismsForReplacer...)
|
||||
}
|
91
mybigcamel/mybigcamel.go
Normal file
91
mybigcamel/mybigcamel.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package mybigcamel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
大驼峰命名规则转换
|
||||
基本满足大驼峰命名法则 首字母大写 “_” 忽略后大写
|
||||
device_id 对应 DeviceID create_time 对应 CreateTime location 对应 Location
|
||||
*/
|
||||
|
||||
/*
|
||||
转换为大驼峰命名法则
|
||||
首字母大写,“_” 忽略后大写
|
||||
*/
|
||||
func Marshal(name string) string {
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
temp := strings.Split(name, "_")
|
||||
var s string
|
||||
for _, v := range temp {
|
||||
vv := []rune(v)
|
||||
if len(vv) > 0 {
|
||||
if bool(vv[0] >= 'a' && vv[0] <= 'z') { //首字母大写
|
||||
vv[0] -= 32
|
||||
}
|
||||
s += string(vv)
|
||||
}
|
||||
}
|
||||
|
||||
s = uncommonInitialismsReplacer.Replace(s)
|
||||
//smap.Set(name, s)
|
||||
return s
|
||||
}
|
||||
|
||||
/*
|
||||
回退网络模式
|
||||
*/
|
||||
func UnMarshal(name string) string {
|
||||
const (
|
||||
lower = false
|
||||
upper = true
|
||||
)
|
||||
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
value = commonInitialismsReplacer.Replace(name)
|
||||
buf = bytes.NewBufferString("")
|
||||
lastCase, currCase, nextCase, nextNumber bool
|
||||
)
|
||||
|
||||
for i, v := range value[:len(value)-1] {
|
||||
nextCase = bool(value[i+1] >= 'A' && value[i+1] <= 'Z')
|
||||
nextNumber = bool(value[i+1] >= '0' && value[i+1] <= '9')
|
||||
|
||||
if i > 0 {
|
||||
if currCase == upper {
|
||||
if lastCase == upper && (nextCase == upper || nextNumber == upper) {
|
||||
buf.WriteRune(v)
|
||||
} else {
|
||||
if value[i-1] != '_' && value[i+1] != '_' {
|
||||
buf.WriteRune('_')
|
||||
}
|
||||
buf.WriteRune(v)
|
||||
}
|
||||
} else {
|
||||
buf.WriteRune(v)
|
||||
if i == len(value)-2 && (nextCase == upper && nextNumber == lower) {
|
||||
buf.WriteRune('_')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currCase = upper
|
||||
buf.WriteRune(v)
|
||||
}
|
||||
lastCase = currCase
|
||||
currCase = nextCase
|
||||
}
|
||||
|
||||
buf.WriteByte(value[len(value)-1])
|
||||
|
||||
s := strings.ToLower(buf.String())
|
||||
return s
|
||||
}
|
19
mybigcamel/mybigcamel_test.go
Normal file
19
mybigcamel/mybigcamel_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package mybigcamel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_cache(t *testing.T) {
|
||||
SS := "OauthIDAPI"
|
||||
|
||||
tmp0 := UnMarshal(SS)
|
||||
fmt.Println(tmp0)
|
||||
tmp1 := Marshal(tmp0)
|
||||
fmt.Println(tmp1)
|
||||
|
||||
if SS != tmp1 {
|
||||
fmt.Println("false.")
|
||||
}
|
||||
}
|
@@ -11,10 +11,10 @@ package mycatch
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
func Dmp() {
|
||||
@@ -29,17 +29,15 @@ func Dmp() {
|
||||
}
|
||||
|
||||
func OnPrintErr(errstring string) {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
path = filepath.Dir(path)
|
||||
path := tools.GetModelPath() + "/err"
|
||||
if !tools.CheckFileIsExist(path) {
|
||||
os.MkdirAll(path, os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
now := time.Now() //获取当前时间
|
||||
pid := os.Getpid() //获取进程ID
|
||||
|
||||
os.MkdirAll(path+"/err", os.ModePerm) //生成多级目录
|
||||
|
||||
time_str := now.Format("2006-01-02") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/err/panic_%s-%x.log", path, time_str, pid) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||
now := time.Now() //获取当前时间
|
||||
pid := os.Getpid() //获取进程ID
|
||||
time_str := now.Format("2006-01-02") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/panic_%s-%x.log", path, time_str, pid) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||
fmt.Println("panic to file ", fname)
|
||||
|
||||
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
|
22
myclipboard/myclipboard.go
Normal file
22
myclipboard/myclipboard.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package myclipboard
|
||||
|
||||
import (
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
// Get 读取剪切板中的内容到字符串
|
||||
func Get() string {
|
||||
// 读取剪切板中的内容到字符串
|
||||
content, err := clipboard.ReadAll()
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return ""
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// Set 复制内容到剪切板
|
||||
func Set(cb string) {
|
||||
clipboard.WriteAll(cb)
|
||||
}
|
142
mycui/button.go
Normal file
142
mycui/button.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Button button struct
|
||||
type Button struct {
|
||||
*gocui.Gui
|
||||
label string
|
||||
name string
|
||||
handlers Handlers
|
||||
ctype ComponentType
|
||||
*Position
|
||||
*Attributes
|
||||
}
|
||||
|
||||
// NewButton new button
|
||||
func NewButton(gui *gocui.Gui, label, name string, x, y, width int) *Button {
|
||||
if len(label) >= width {
|
||||
width = len([]rune(name)) + 1
|
||||
}
|
||||
|
||||
b := &Button{
|
||||
Gui: gui,
|
||||
label: label,
|
||||
name: name,
|
||||
Position: &Position{
|
||||
x,
|
||||
y,
|
||||
x + width + 2,
|
||||
y + 2,
|
||||
},
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorWhite | gocui.AttrBold,
|
||||
textBgColor: gocui.ColorBlue,
|
||||
hilightColor: gocui.ColorBlue | gocui.AttrBold,
|
||||
hilightBgColor: gocui.ColorGreen,
|
||||
},
|
||||
handlers: make(Handlers),
|
||||
ctype: TypeButton,
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// AddHandler add handler
|
||||
func (b *Button) AddHandler(key Key, handler Handler) *Button {
|
||||
b.handlers[key] = handler
|
||||
return b
|
||||
}
|
||||
|
||||
// SetTextColor add button fg and bg color
|
||||
func (b *Button) SetTextColor(fgColor, bgColor gocui.Attribute) *Button {
|
||||
b.textColor = fgColor
|
||||
b.textBgColor = bgColor
|
||||
return b
|
||||
}
|
||||
|
||||
// SetHilightColor add button fg and bg color
|
||||
func (b *Button) SetHilightColor(fgColor, bgColor gocui.Attribute) *Button {
|
||||
b.hilightColor = fgColor
|
||||
b.hilightBgColor = bgColor
|
||||
return b
|
||||
}
|
||||
|
||||
// GetLabel get button label
|
||||
func (b *Button) GetLabel() string {
|
||||
return b.label
|
||||
}
|
||||
|
||||
// GetPosition get button position
|
||||
func (b *Button) GetPosition() *Position {
|
||||
return b.Position
|
||||
}
|
||||
|
||||
// Focus focus to button
|
||||
func (b *Button) Focus() {
|
||||
b.Gui.Cursor = false
|
||||
v, _ := b.Gui.SetCurrentView(b.label)
|
||||
v.Highlight = true
|
||||
}
|
||||
|
||||
// UnFocus un focus
|
||||
func (b *Button) UnFocus() {
|
||||
v, _ := b.Gui.View(b.label)
|
||||
v.Highlight = false
|
||||
}
|
||||
|
||||
// GetType get component type
|
||||
func (b *Button) GetType() ComponentType {
|
||||
return b.ctype
|
||||
}
|
||||
|
||||
// Draw draw button
|
||||
func (b *Button) Draw() {
|
||||
if v, err := b.Gui.SetView(b.label, b.X, b.Y, b.W, b.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Title = b.name
|
||||
v.Frame = false
|
||||
|
||||
v.FgColor = b.textColor
|
||||
v.BgColor = b.textBgColor
|
||||
|
||||
v.SelFgColor = b.hilightColor
|
||||
v.SelBgColor = b.hilightBgColor
|
||||
|
||||
fmt.Fprint(v, fmt.Sprintf(" %s ", b.name))
|
||||
}
|
||||
|
||||
if b.handlers != nil {
|
||||
for key, handler := range b.handlers {
|
||||
if err := b.Gui.SetKeybinding(b.label, key, gocui.ModNone, handler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Close close button
|
||||
func (b *Button) Close() {
|
||||
if err := b.DeleteView(b.label); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if b.handlers != nil {
|
||||
b.DeleteKeybindings(b.label)
|
||||
}
|
||||
}
|
||||
|
||||
// AddHandlerOnly ...
|
||||
func (b *Button) AddHandlerOnly(key Key, handler Handler) {
|
||||
b.handlers[key] = handler
|
||||
}
|
186
mycui/checkbox.go
Normal file
186
mycui/checkbox.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// CheckBox struct
|
||||
type CheckBox struct {
|
||||
*gocui.Gui
|
||||
label string
|
||||
isChecked bool
|
||||
box *box
|
||||
ctype ComponentType
|
||||
*Position
|
||||
*Attributes
|
||||
handlers Handlers
|
||||
}
|
||||
|
||||
type box struct {
|
||||
name string
|
||||
*Position
|
||||
*Attributes
|
||||
}
|
||||
|
||||
// NewCheckBox new checkbox
|
||||
func NewCheckBox(gui *gocui.Gui, label string, x, y, labelWidth int) *CheckBox {
|
||||
if len(label) > labelWidth {
|
||||
labelWidth = len(label)
|
||||
}
|
||||
p := &Position{
|
||||
X: x,
|
||||
Y: y,
|
||||
W: x + labelWidth + 1,
|
||||
H: y + 2,
|
||||
}
|
||||
|
||||
c := &CheckBox{
|
||||
Gui: gui,
|
||||
label: label,
|
||||
isChecked: false,
|
||||
Position: p,
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorYellow | gocui.AttrBold,
|
||||
textBgColor: gocui.ColorDefault,
|
||||
},
|
||||
box: &box{
|
||||
name: label + "box",
|
||||
Position: &Position{
|
||||
X: p.W,
|
||||
Y: p.Y,
|
||||
W: p.W + 2,
|
||||
H: p.H,
|
||||
},
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorBlack,
|
||||
textBgColor: gocui.ColorCyan,
|
||||
},
|
||||
},
|
||||
handlers: make(Handlers),
|
||||
ctype: TypeCheckBox,
|
||||
}
|
||||
|
||||
c.handlers[gocui.KeyEnter] = c.Check
|
||||
c.handlers[gocui.KeySpace] = c.Check
|
||||
return c
|
||||
}
|
||||
|
||||
// GetLabel get checkbox label
|
||||
func (c *CheckBox) GetLabel() string {
|
||||
return c.label
|
||||
}
|
||||
|
||||
// GetPosition get checkbox position
|
||||
func (c *CheckBox) GetPosition() *Position {
|
||||
return c.box.Position
|
||||
}
|
||||
|
||||
// Check check true or false
|
||||
func (c *CheckBox) Check(g *gocui.Gui, v *gocui.View) error {
|
||||
if v.Buffer() != "" {
|
||||
v.Clear()
|
||||
c.isChecked = false
|
||||
} else {
|
||||
fmt.Fprint(v, "X")
|
||||
c.isChecked = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddHandler add handler
|
||||
func (c *CheckBox) AddHandler(key Key, handler Handler) *CheckBox {
|
||||
c.handlers[key] = handler
|
||||
return c
|
||||
}
|
||||
|
||||
// AddAttribute add text and bg color
|
||||
func (c *CheckBox) AddAttribute(textColor, textBgColor gocui.Attribute) *CheckBox {
|
||||
c.Attributes = &Attributes{
|
||||
textColor: textColor,
|
||||
textBgColor: textBgColor,
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// IsChecked return check state
|
||||
func (c *CheckBox) IsChecked() bool {
|
||||
return c.isChecked
|
||||
}
|
||||
|
||||
// Focus focus to checkbox
|
||||
func (c *CheckBox) Focus() {
|
||||
c.Gui.Cursor = true
|
||||
c.Gui.SetCurrentView(c.box.name)
|
||||
}
|
||||
|
||||
// UnFocus unfocus
|
||||
func (c *CheckBox) UnFocus() {
|
||||
c.Gui.Cursor = false
|
||||
}
|
||||
|
||||
// GetType get component type
|
||||
func (c *CheckBox) GetType() ComponentType {
|
||||
return c.ctype
|
||||
}
|
||||
|
||||
// Draw draw label and checkbox
|
||||
func (c *CheckBox) Draw() {
|
||||
// draw label
|
||||
if v, err := c.Gui.SetView(c.label, c.X, c.Y, c.W, c.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = false
|
||||
v.FgColor = c.textColor
|
||||
v.BgColor = c.textBgColor
|
||||
fmt.Fprint(v, c.label)
|
||||
}
|
||||
|
||||
// draw checkbox
|
||||
b := c.box
|
||||
if v, err := c.Gui.SetView(b.name, b.X, b.Y, b.W, b.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = false
|
||||
v.FgColor = b.textColor
|
||||
v.BgColor = b.textBgColor
|
||||
|
||||
c.Gui.SetCurrentView(v.Name())
|
||||
|
||||
for key, handler := range c.handlers {
|
||||
if err := c.Gui.SetKeybinding(v.Name(), key, gocui.ModNone, handler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close close checkbox
|
||||
func (c *CheckBox) Close() {
|
||||
views := []string{
|
||||
c.label,
|
||||
c.box.name,
|
||||
}
|
||||
|
||||
for _, v := range views {
|
||||
if err := c.DeleteView(v); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.DeleteKeybindings(c.box.name)
|
||||
}
|
||||
|
||||
// AddHandlerOnly add handler not retrun
|
||||
func (c *CheckBox) AddHandlerOnly(key Key, handler Handler) {
|
||||
c.AddHandler(key, handler)
|
||||
}
|
386
mycui/form.go
Normal file
386
mycui/form.go
Normal file
@@ -0,0 +1,386 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Form form struct
|
||||
type Form struct {
|
||||
*gocui.Gui
|
||||
activeItem int
|
||||
activeRadio int
|
||||
id string
|
||||
name string
|
||||
inputs []*InputField
|
||||
checkBoxs []*CheckBox
|
||||
buttons []*Button
|
||||
selects []*Select
|
||||
//radios []*Radio
|
||||
components []Component
|
||||
closeFuncs []func() error
|
||||
*Position
|
||||
}
|
||||
|
||||
// FormData form data struct
|
||||
type FormData struct {
|
||||
inputs map[string]string
|
||||
checkBoxs map[string]bool
|
||||
selects map[string]string
|
||||
radio map[string]string
|
||||
}
|
||||
|
||||
// NewForm new form
|
||||
func NewForm(gui *gocui.Gui, id, name string, x, y, w, h int) *Form {
|
||||
f := &Form{
|
||||
Gui: gui,
|
||||
activeItem: 0,
|
||||
id: id,
|
||||
name: name,
|
||||
Position: &Position{
|
||||
X: x,
|
||||
Y: y,
|
||||
W: x + w,
|
||||
H: y + h,
|
||||
},
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// AddInputField add input field to form
|
||||
func (f *Form) AddInputField(label, name string, labelWidth, fieldWidth int) *InputField {
|
||||
var y int
|
||||
|
||||
p := f.getLastViewPosition()
|
||||
if p != nil {
|
||||
y = p.H
|
||||
} else {
|
||||
y = f.Y + 1
|
||||
}
|
||||
|
||||
input := NewInputField(
|
||||
f.Gui,
|
||||
label,
|
||||
name,
|
||||
f.X+1,
|
||||
y,
|
||||
labelWidth,
|
||||
fieldWidth,
|
||||
)
|
||||
|
||||
f.inputs = append(f.inputs, input)
|
||||
f.components = append(f.components, input)
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
// AddButton add button to form
|
||||
func (f *Form) AddButton(id, label string, handler Handler) *Button {
|
||||
var x int
|
||||
var y int
|
||||
|
||||
p := f.getLastViewPosition()
|
||||
if p != nil {
|
||||
if f.isButtonLastView() {
|
||||
x = p.W
|
||||
y = p.Y - 1
|
||||
} else {
|
||||
x = f.X
|
||||
y = p.H
|
||||
}
|
||||
} else {
|
||||
x = f.X
|
||||
y = f.Y
|
||||
}
|
||||
|
||||
button := NewButton(
|
||||
f.Gui,
|
||||
id,
|
||||
label,
|
||||
x+1,
|
||||
y+1,
|
||||
len([]rune(label))+1,
|
||||
)
|
||||
|
||||
button.AddHandler(gocui.KeyEnter, handler)
|
||||
|
||||
f.buttons = append(f.buttons, button)
|
||||
f.components = append(f.components, button)
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
// AddCheckBox add checkbox
|
||||
func (f *Form) AddCheckBox(label string, width int) *CheckBox {
|
||||
var y int
|
||||
|
||||
p := f.getLastViewPosition()
|
||||
if p != nil {
|
||||
y = p.H
|
||||
} else {
|
||||
y = f.Y
|
||||
}
|
||||
|
||||
checkbox := NewCheckBox(
|
||||
f.Gui,
|
||||
label,
|
||||
f.X+1,
|
||||
y,
|
||||
width,
|
||||
)
|
||||
|
||||
f.checkBoxs = append(f.checkBoxs, checkbox)
|
||||
f.components = append(f.components, checkbox)
|
||||
|
||||
return checkbox
|
||||
}
|
||||
|
||||
// AddSelect add select
|
||||
func (f *Form) AddSelect(label, name string, labelWidth, listWidth int) *Select {
|
||||
var y int
|
||||
|
||||
p := f.getLastViewPosition()
|
||||
if p != nil {
|
||||
y = p.H
|
||||
} else {
|
||||
y = f.Y
|
||||
}
|
||||
|
||||
Select := NewSelect(
|
||||
f.Gui,
|
||||
label,
|
||||
name,
|
||||
f.X+1,
|
||||
y,
|
||||
labelWidth,
|
||||
listWidth,
|
||||
)
|
||||
|
||||
f.selects = append(f.selects, Select)
|
||||
f.components = append(f.components, Select)
|
||||
|
||||
return Select
|
||||
}
|
||||
|
||||
// AddCloseFunc add close function
|
||||
func (f *Form) AddCloseFunc(function func() error) {
|
||||
f.closeFuncs = append(f.closeFuncs, function)
|
||||
}
|
||||
|
||||
// GetFieldTexts form data
|
||||
func (f *Form) GetFieldTexts() map[string]string {
|
||||
data := make(map[string]string)
|
||||
|
||||
if len(f.inputs) == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
for _, item := range f.inputs {
|
||||
data[item.GetLabel()] = item.GetFieldText()
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// GetFieldText get form data with field name
|
||||
func (f *Form) GetFieldText(target string) string {
|
||||
return f.GetFieldTexts()[target]
|
||||
}
|
||||
|
||||
// GetCheckBoxStates get checkbox states
|
||||
func (f *Form) GetCheckBoxStates() map[string]bool {
|
||||
state := make(map[string]bool)
|
||||
|
||||
if len(f.checkBoxs) == 0 {
|
||||
return state
|
||||
}
|
||||
|
||||
for _, box := range f.checkBoxs {
|
||||
state[box.GetLabel()] = box.IsChecked()
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
// GetCheckBoxState get checkbox states
|
||||
func (f *Form) GetCheckBoxState(target string) bool {
|
||||
return f.GetCheckBoxStates()[target]
|
||||
}
|
||||
|
||||
// GetSelectedOpts get selected options
|
||||
func (f *Form) GetSelectedOpts() map[string]string {
|
||||
opts := make(map[string]string)
|
||||
|
||||
if len(f.selects) == 0 {
|
||||
return opts
|
||||
}
|
||||
|
||||
for _, Select := range f.selects {
|
||||
opts[Select.GetLabel()] = Select.GetSelected()
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// GetSelectedOpt get selected options
|
||||
func (f *Form) GetSelectedOpt(target string) string {
|
||||
return f.GetSelectedOpts()[target]
|
||||
}
|
||||
|
||||
// GetSelectedRadio get selected radio
|
||||
func (f *Form) GetSelectedRadio(target string) string {
|
||||
return f.GetSelectedOpts()[target]
|
||||
}
|
||||
|
||||
// GetFormData get form data
|
||||
func (f *Form) GetFormData() *FormData {
|
||||
fd := &FormData{
|
||||
inputs: f.GetFieldTexts(),
|
||||
checkBoxs: f.GetCheckBoxStates(),
|
||||
selects: f.GetSelectedOpts(),
|
||||
}
|
||||
|
||||
return fd
|
||||
}
|
||||
|
||||
// GetInputs get inputs
|
||||
func (f *Form) GetInputs() []*InputField {
|
||||
return f.inputs
|
||||
}
|
||||
|
||||
// GetCheckBoxs get checkboxs
|
||||
func (f *Form) GetCheckBoxs() []*CheckBox {
|
||||
return f.checkBoxs
|
||||
}
|
||||
|
||||
// GetButtons get buttons
|
||||
func (f *Form) GetButtons() []*Button {
|
||||
return f.buttons
|
||||
}
|
||||
|
||||
// GetSelects get selects
|
||||
func (f *Form) GetSelects() []*Select {
|
||||
return f.selects
|
||||
}
|
||||
|
||||
// GetItems get items
|
||||
func (f *Form) GetItems() []Component {
|
||||
return f.components
|
||||
}
|
||||
|
||||
// SetCurrentItem set current item index
|
||||
func (f *Form) SetCurrentItem(index int) *Form {
|
||||
f.activeItem = index
|
||||
f.components[index].Focus()
|
||||
return f
|
||||
}
|
||||
|
||||
// GetCurrentItem get current item index
|
||||
func (f *Form) GetCurrentItem() int {
|
||||
return f.activeItem
|
||||
}
|
||||
|
||||
// Validate validate form items
|
||||
func (f *Form) Validate() bool {
|
||||
isValid := true
|
||||
for _, item := range f.inputs {
|
||||
if !item.Validate() {
|
||||
isValid = false
|
||||
}
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
// NextItem to next item
|
||||
func (f *Form) NextItem(g *gocui.Gui, v *gocui.View) error {
|
||||
f.components[f.activeItem].UnFocus()
|
||||
f.activeItem = (f.activeItem + 1) % len(f.components)
|
||||
f.components[f.activeItem].Focus()
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreItem to pre item
|
||||
func (f *Form) PreItem(g *gocui.Gui, v *gocui.View) error {
|
||||
f.components[f.activeItem].UnFocus()
|
||||
|
||||
if f.activeItem-1 < 0 {
|
||||
f.activeItem = len(f.components) - 1
|
||||
} else {
|
||||
f.activeItem = (f.activeItem - 1) % len(f.components)
|
||||
}
|
||||
|
||||
f.components[f.activeItem].Focus()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Draw form
|
||||
func (f *Form) Draw() {
|
||||
if v, err := f.Gui.SetView(f.id, f.X, f.Y, f.W+1, f.H+1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Title = f.name
|
||||
}
|
||||
|
||||
for _, cp := range f.components {
|
||||
p := cp.GetPosition()
|
||||
if p.W > f.W {
|
||||
f.W = p.W
|
||||
}
|
||||
if p.H > f.H {
|
||||
f.H = p.H
|
||||
}
|
||||
cp.AddHandlerOnly(gocui.KeyTab, f.NextItem)
|
||||
cp.AddHandlerOnly(gocui.KeyArrowDown, f.NextItem)
|
||||
cp.AddHandlerOnly(gocui.KeyArrowUp, f.PreItem)
|
||||
cp.Draw()
|
||||
}
|
||||
|
||||
f.SetView(f.id, f.X, f.Y, f.W+1, f.H+1)
|
||||
|
||||
if len(f.components) != 0 {
|
||||
f.components[0].Focus()
|
||||
}
|
||||
}
|
||||
|
||||
// Close close form
|
||||
func (f *Form) Close(g *gocui.Gui, v *gocui.View) error {
|
||||
if err := f.Gui.DeleteView(f.id); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range f.components {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
if len(f.closeFuncs) != 0 {
|
||||
for _, f := range f.closeFuncs {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Form) getLastViewPosition() *Position {
|
||||
cpl := len(f.components)
|
||||
if cpl == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.components[cpl-1].GetPosition()
|
||||
}
|
||||
|
||||
func (f *Form) isButtonLastView() bool {
|
||||
cpl := len(f.components)
|
||||
if cpl == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return f.components[cpl-1].GetType() == TypeButton
|
||||
}
|
376
mycui/inputField.go
Normal file
376
mycui/inputField.go
Normal file
@@ -0,0 +1,376 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Margin struct
|
||||
type Margin struct {
|
||||
top int
|
||||
left int
|
||||
}
|
||||
|
||||
// InputField struct
|
||||
type InputField struct {
|
||||
*gocui.Gui
|
||||
label *Label
|
||||
field *Field
|
||||
}
|
||||
|
||||
// Label struct
|
||||
type Label struct {
|
||||
text string
|
||||
name string
|
||||
width int
|
||||
drawFrame bool
|
||||
*Position
|
||||
*Attributes
|
||||
margin *Margin
|
||||
}
|
||||
|
||||
// Field struct
|
||||
type Field struct {
|
||||
text string
|
||||
width int
|
||||
drawFrame bool
|
||||
handlers Handlers
|
||||
margin *Margin
|
||||
mask bool
|
||||
editable bool
|
||||
ctype ComponentType
|
||||
*Position
|
||||
*Attributes
|
||||
*Validator
|
||||
}
|
||||
|
||||
var labelPrefix = "label"
|
||||
|
||||
// NewInputField new input label and field
|
||||
func NewInputField(gui *gocui.Gui, labelText, name string, x, y, labelWidth, fieldWidth int) *InputField {
|
||||
gui.Cursor = true
|
||||
|
||||
// label psition
|
||||
lp := &Position{
|
||||
x,
|
||||
y,
|
||||
x + labelWidth + 1,
|
||||
y + 2,
|
||||
}
|
||||
|
||||
// field position
|
||||
fp := &Position{
|
||||
lp.W,
|
||||
lp.Y,
|
||||
lp.W + fieldWidth,
|
||||
lp.H,
|
||||
}
|
||||
|
||||
// new label
|
||||
label := &Label{
|
||||
text: labelText,
|
||||
name: name,
|
||||
width: labelWidth,
|
||||
Position: lp,
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorYellow,
|
||||
textBgColor: gocui.ColorDefault,
|
||||
},
|
||||
drawFrame: false,
|
||||
margin: &Margin{
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
}
|
||||
|
||||
// new field
|
||||
field := &Field{
|
||||
width: fieldWidth,
|
||||
Position: fp,
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorBlack,
|
||||
textBgColor: gocui.ColorCyan,
|
||||
},
|
||||
handlers: make(Handlers),
|
||||
drawFrame: false,
|
||||
margin: &Margin{
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
Validator: NewValidator(gui, label.text+"validator", fp.X, fp.Y+1, fp.W, fp.H+1),
|
||||
editable: true,
|
||||
ctype: TypeInputField,
|
||||
}
|
||||
|
||||
// new input field
|
||||
i := &InputField{
|
||||
Gui: gui,
|
||||
label: label,
|
||||
field: field,
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// AddFieldAttribute add field colors
|
||||
func (i *InputField) AddFieldAttribute(textColor, textBgColor, fgColor, bgColor gocui.Attribute) *InputField {
|
||||
i.field.Attributes = &Attributes{
|
||||
textColor: textColor,
|
||||
textBgColor: textBgColor,
|
||||
hilightColor: fgColor,
|
||||
hilightBgColor: bgColor,
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// AddLabelAttribute add label colors
|
||||
func (i *InputField) AddLabelAttribute(textColor, textBgColor gocui.Attribute) *InputField {
|
||||
i.label.Attributes = &Attributes{
|
||||
textColor: textColor,
|
||||
textBgColor: textBgColor,
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// AddHandler add keybinding
|
||||
func (i *InputField) AddHandler(key Key, handler Handler) *InputField {
|
||||
i.field.handlers[key] = handler
|
||||
return i
|
||||
}
|
||||
|
||||
// AddMarginTop add margin top
|
||||
func (i *InputField) AddMarginTop(top int) *InputField {
|
||||
i.label.margin.top += top
|
||||
i.field.margin.top += top
|
||||
return i
|
||||
}
|
||||
|
||||
// AddMarginLeft add margin left
|
||||
func (i *InputField) AddMarginLeft(left int) *InputField {
|
||||
i.label.margin.left += left
|
||||
i.field.margin.left += left
|
||||
return i
|
||||
}
|
||||
|
||||
// AddValidate add input validator
|
||||
func (i *InputField) AddValidate(errMsg string, validate func(value string) bool) *InputField {
|
||||
i.field.AddValidate(errMsg, validate)
|
||||
return i
|
||||
}
|
||||
|
||||
// SetLabelBorder draw label border
|
||||
func (i *InputField) SetLabelBorder() *InputField {
|
||||
i.label.drawFrame = true
|
||||
return i
|
||||
}
|
||||
|
||||
// SetFieldBorder draw field border
|
||||
func (i *InputField) SetFieldBorder() *InputField {
|
||||
i.field.drawFrame = true
|
||||
return i
|
||||
}
|
||||
|
||||
// SetMask set input field to mask '*'
|
||||
func (i *InputField) SetMask() *InputField {
|
||||
i.field.mask = true
|
||||
return i
|
||||
}
|
||||
|
||||
// SetMaskKeybinding set or unset input field to mask '*' with key
|
||||
func (i *InputField) SetMaskKeybinding(key Key) *InputField {
|
||||
if err := i.Gui.SetKeybinding(i.label.text, key, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
|
||||
v.Mask ^= '*'
|
||||
return nil
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// SetText set text
|
||||
func (i *InputField) SetText(text string) *InputField {
|
||||
i.field.text = text
|
||||
return i
|
||||
}
|
||||
|
||||
// SetCursor set input field cursor
|
||||
func (i *InputField) SetCursor(b bool) *InputField {
|
||||
i.Gui.Cursor = b
|
||||
return i
|
||||
}
|
||||
|
||||
// SetEditable if editmode is true can input
|
||||
func (i *InputField) SetEditable(b bool) *InputField {
|
||||
i.field.editable = b
|
||||
return i
|
||||
}
|
||||
|
||||
// Focus focus to input field
|
||||
func (i *InputField) Focus() {
|
||||
i.Gui.Cursor = true
|
||||
i.Gui.SetCurrentView(i.label.text)
|
||||
}
|
||||
|
||||
// UnFocus un focus
|
||||
func (i *InputField) UnFocus() {
|
||||
i.Gui.Cursor = false
|
||||
}
|
||||
|
||||
// Edit input field editor
|
||||
func (i *InputField) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
|
||||
switch {
|
||||
case ch != 0 && mod == 0:
|
||||
v.EditWrite(ch)
|
||||
case key == gocui.KeySpace:
|
||||
v.EditWrite(' ')
|
||||
case key == gocui.KeyBackspace || key == gocui.KeyBackspace2:
|
||||
v.EditDelete(true)
|
||||
case key == gocui.KeyArrowLeft:
|
||||
v.MoveCursor(-1, 0, false)
|
||||
case key == gocui.KeyArrowRight:
|
||||
v.MoveCursor(+1, 0, false)
|
||||
}
|
||||
|
||||
// get field text
|
||||
i.field.text = i.cutNewline(v.Buffer())
|
||||
|
||||
// validate
|
||||
i.field.Validate(i.GetFieldText())
|
||||
}
|
||||
|
||||
// GetFieldText get input field text
|
||||
func (i *InputField) GetFieldText() string {
|
||||
return i.field.text
|
||||
}
|
||||
|
||||
// GetLabel get label text
|
||||
func (i *InputField) GetLabel() string {
|
||||
return i.label.text
|
||||
}
|
||||
|
||||
// GetPosition get input field position
|
||||
func (i *InputField) GetPosition() *Position {
|
||||
return i.field.Position
|
||||
}
|
||||
|
||||
// Validate validate field
|
||||
func (i *InputField) Validate() bool {
|
||||
i.field.Validate(i.GetFieldText())
|
||||
return i.field.IsValid()
|
||||
}
|
||||
|
||||
// IsValid valid field data will be return true
|
||||
func (i *InputField) IsValid() bool {
|
||||
return i.field.Validator.IsValid()
|
||||
}
|
||||
|
||||
// GetType get component type
|
||||
func (i *InputField) GetType() ComponentType {
|
||||
return i.field.ctype
|
||||
}
|
||||
|
||||
// Draw draw label and field
|
||||
func (i *InputField) Draw() {
|
||||
// draw label
|
||||
x, y, w, h := i.addMargin(i.label)
|
||||
if v, err := i.Gui.SetView(labelPrefix+i.label.text, x, y, w, h); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = i.label.drawFrame
|
||||
|
||||
v.FgColor = i.label.textColor | gocui.AttrBold
|
||||
v.BgColor = i.label.textBgColor
|
||||
|
||||
fmt.Fprint(v, i.label.name)
|
||||
}
|
||||
|
||||
// draw input
|
||||
x, y, w, h = i.addMargin(i.field)
|
||||
if v, err := i.Gui.SetView(i.label.text, x, y, w, h); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = i.field.drawFrame
|
||||
|
||||
v.FgColor = i.field.textColor
|
||||
v.BgColor = i.field.textBgColor
|
||||
|
||||
v.Editable = i.field.editable
|
||||
v.Editor = i
|
||||
|
||||
if i.field.mask {
|
||||
v.Mask = '*'
|
||||
}
|
||||
|
||||
if i.field.text != "" {
|
||||
fmt.Fprint(v, i.field.text)
|
||||
}
|
||||
|
||||
// focus input field
|
||||
i.Focus()
|
||||
}
|
||||
|
||||
// set keybindings
|
||||
if i.field.handlers != nil {
|
||||
for key, handler := range i.field.handlers {
|
||||
if err := i.Gui.SetKeybinding(i.label.text, key, gocui.ModNone, handler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close close input field
|
||||
func (i *InputField) Close() {
|
||||
views := []string{
|
||||
i.label.text,
|
||||
labelPrefix + i.label.text,
|
||||
}
|
||||
|
||||
for _, v := range views {
|
||||
if err := i.DeleteView(v); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if i.field.handlers != nil {
|
||||
i.DeleteKeybindings(i.label.text)
|
||||
}
|
||||
|
||||
if i.field.Validator != nil {
|
||||
i.field.Validator.CloseValidateMsg()
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InputField) addMargin(view interface{}) (int, int, int, int) {
|
||||
switch v := view.(type) {
|
||||
case *Field:
|
||||
p := v.Position
|
||||
m := v.margin
|
||||
return p.X + m.left, p.Y + m.top, p.W + m.left, p.H + m.top
|
||||
case *Label:
|
||||
p := v.Position
|
||||
m := v.margin
|
||||
return p.X + m.left, p.Y + m.top, p.W + m.left, p.H + m.top
|
||||
default:
|
||||
panic("Unkown type")
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InputField) cutNewline(text string) string {
|
||||
return strings.Replace(text, "\n", "", -1)
|
||||
}
|
||||
|
||||
// AddHandlerOnly add handler not return
|
||||
func (i *InputField) AddHandlerOnly(key Key, handler Handler) {
|
||||
i.AddHandler(key, handler)
|
||||
}
|
200
mycui/modal.go
Normal file
200
mycui/modal.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Modal struct
|
||||
type Modal struct {
|
||||
*gocui.Gui
|
||||
name string
|
||||
textArea *textArea
|
||||
activeButton int
|
||||
buttons []*Button
|
||||
*Attributes
|
||||
*Position
|
||||
}
|
||||
|
||||
type textArea struct {
|
||||
*gocui.Gui
|
||||
name string
|
||||
text string
|
||||
*Attributes
|
||||
*Position
|
||||
}
|
||||
|
||||
// NewModal new modal
|
||||
func NewModal(gui *gocui.Gui, x, y, w int) *Modal {
|
||||
p := &Position{
|
||||
X: x,
|
||||
Y: y,
|
||||
W: w,
|
||||
H: y + 3,
|
||||
}
|
||||
|
||||
return &Modal{
|
||||
Gui: gui,
|
||||
name: "modal",
|
||||
activeButton: 0,
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorWhite,
|
||||
textBgColor: gocui.ColorBlue,
|
||||
},
|
||||
Position: p,
|
||||
textArea: &textArea{
|
||||
Gui: gui,
|
||||
name: "textArea",
|
||||
Attributes: &Attributes{
|
||||
textColor: gocui.ColorWhite,
|
||||
textBgColor: gocui.ColorBlue,
|
||||
},
|
||||
Position: &Position{
|
||||
X: p.X + 1,
|
||||
Y: p.Y + 1,
|
||||
W: p.W - 1,
|
||||
H: p.H - 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetText set text
|
||||
func (m *Modal) SetText(text string) *Modal {
|
||||
m.textArea.text = text
|
||||
h := int(roundUp(float64(len(text)/(m.W-m.X)), 0))
|
||||
|
||||
newLineCount := strings.Count(text, "\n")
|
||||
if newLineCount > h {
|
||||
h = newLineCount
|
||||
}
|
||||
|
||||
m.textArea.H += h
|
||||
m.H += h
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// SetTextColor set text color
|
||||
func (m *Modal) SetTextColor(textColor gocui.Attribute) *Modal {
|
||||
m.textArea.textColor = textColor
|
||||
return m
|
||||
}
|
||||
|
||||
// SetBgColor set bg color
|
||||
func (m *Modal) SetBgColor(textColor gocui.Attribute) *Modal {
|
||||
m.textArea.textBgColor = textColor
|
||||
return m
|
||||
}
|
||||
|
||||
// AddButton add button
|
||||
func (m *Modal) AddButton(id, label string, key Key, handler Handler) *Button {
|
||||
var x, y, w int
|
||||
if len(m.buttons) == 0 {
|
||||
w = m.W - 5
|
||||
x = w - len(label)
|
||||
y = m.H - 1
|
||||
m.H += 2
|
||||
} else {
|
||||
p := m.buttons[len(m.buttons)-1].GetPosition()
|
||||
w = p.W - 10
|
||||
x = w - len(label)
|
||||
y = p.Y
|
||||
}
|
||||
|
||||
button := NewButton(m.Gui, id, label, x, y, len(label)).
|
||||
AddHandler(gocui.KeyTab, m.nextButton).
|
||||
AddHandler(key, handler).
|
||||
SetTextColor(gocui.ColorWhite, gocui.ColorBlack).
|
||||
SetHilightColor(gocui.ColorBlack, gocui.ColorWhite)
|
||||
|
||||
m.buttons = append(m.buttons, button)
|
||||
return button
|
||||
}
|
||||
|
||||
// GetPosition get modal position
|
||||
func (m *Modal) GetPosition() *Position {
|
||||
return m.Position
|
||||
}
|
||||
|
||||
// Draw draw modal
|
||||
func (m *Modal) Draw() {
|
||||
// modal
|
||||
if v, err := m.Gui.SetView(m.name, m.X, m.Y, m.W, m.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = false
|
||||
v.FgColor = m.textColor
|
||||
v.BgColor = m.textBgColor
|
||||
}
|
||||
|
||||
// text area
|
||||
area := m.textArea
|
||||
if area.text != "" {
|
||||
if v, err := area.Gui.SetView(area.name, area.X, area.Y, area.W, area.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Wrap = true
|
||||
v.Frame = false
|
||||
|
||||
v.FgColor = area.textColor
|
||||
v.BgColor = area.textBgColor
|
||||
|
||||
fmt.Fprint(v, area.text)
|
||||
}
|
||||
}
|
||||
|
||||
// button
|
||||
for _, b := range m.buttons {
|
||||
b.Draw()
|
||||
}
|
||||
|
||||
if len(m.buttons) != 0 {
|
||||
m.activeButton = len(m.buttons) - 1
|
||||
m.buttons[m.activeButton].Focus()
|
||||
}
|
||||
}
|
||||
|
||||
// Close close modal
|
||||
func (m *Modal) Close() {
|
||||
if err := m.DeleteView(m.name); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.DeleteView(m.textArea.name); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range m.buttons {
|
||||
b.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// nextButton focus netxt button
|
||||
func (m *Modal) nextButton(g *gocui.Gui, v *gocui.View) error {
|
||||
m.buttons[m.activeButton].UnFocus()
|
||||
m.activeButton = (m.activeButton + 1) % len(m.buttons)
|
||||
m.buttons[m.activeButton].Focus()
|
||||
return nil
|
||||
}
|
||||
|
||||
func roundUp(num, places float64) float64 {
|
||||
shift := math.Pow(10, places)
|
||||
return roundUpInt(num*shift) / shift
|
||||
}
|
||||
|
||||
func roundUpInt(num float64) float64 {
|
||||
t := math.Trunc(num)
|
||||
return t + math.Copysign(1, num)
|
||||
}
|
242
mycui/select.go
Normal file
242
mycui/select.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Select struct
|
||||
type Select struct {
|
||||
*InputField
|
||||
options []string
|
||||
currentOpt int
|
||||
isExpanded bool
|
||||
ctype ComponentType
|
||||
listColor *Attributes
|
||||
listHandlers Handlers
|
||||
}
|
||||
|
||||
// NewSelect new select
|
||||
func NewSelect(gui *gocui.Gui, label, name string, x, y, labelWidth, fieldWidth int) *Select {
|
||||
|
||||
s := &Select{
|
||||
InputField: NewInputField(gui, label, name, x, y, labelWidth, fieldWidth),
|
||||
listHandlers: make(Handlers),
|
||||
ctype: TypeSelect,
|
||||
}
|
||||
|
||||
s.AddHandler(gocui.KeyEnter, s.expandOpt)
|
||||
s.AddAttribute(gocui.ColorBlack, gocui.ColorWhite, gocui.ColorBlack, gocui.ColorGreen).
|
||||
AddListHandler('j', s.nextOpt).
|
||||
AddListHandler('k', s.preOpt).
|
||||
AddListHandler(gocui.KeyArrowDown, s.nextOpt).
|
||||
AddListHandler(gocui.KeyArrowUp, s.preOpt).
|
||||
AddListHandler(gocui.KeyEnter, s.selectOpt).
|
||||
SetEditable(false)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// AddOptions add select options
|
||||
func (s *Select) AddOptions(opts ...string) *Select {
|
||||
for _, opt := range opts {
|
||||
s.options = append(s.options, opt)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// AddOption add select option
|
||||
func (s *Select) AddOption(opt string) *Select {
|
||||
s.options = append(s.options, opt)
|
||||
return s
|
||||
}
|
||||
|
||||
// AddAttribute add select attribute
|
||||
func (s *Select) AddAttribute(textColor, textBgColor, fgColor, bgColor gocui.Attribute) *Select {
|
||||
s.listColor = &Attributes{
|
||||
textColor: textColor,
|
||||
textBgColor: textBgColor,
|
||||
hilightColor: fgColor,
|
||||
hilightBgColor: bgColor,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// AddListHandler add list handler
|
||||
func (s *Select) AddListHandler(key Key, handler Handler) *Select {
|
||||
s.listHandlers[key] = handler
|
||||
return s
|
||||
}
|
||||
|
||||
// GetSelected get selected option
|
||||
func (s *Select) GetSelected() string {
|
||||
return s.options[s.currentOpt]
|
||||
}
|
||||
|
||||
// SetSelected set the default selected
|
||||
func (s *Select) SetSelected(str string) {
|
||||
for i := 0; i < len(s.options); i++ {
|
||||
if strings.EqualFold(s.options[i], str) {
|
||||
s.currentOpt = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Focus set focus to select
|
||||
func (s *Select) Focus() {
|
||||
s.Gui.Cursor = true
|
||||
s.Gui.SetCurrentView(s.GetLabel())
|
||||
}
|
||||
|
||||
// UnFocus un focus
|
||||
func (s *Select) UnFocus() {
|
||||
s.Gui.Cursor = false
|
||||
}
|
||||
|
||||
// GetType get component type
|
||||
func (s *Select) GetType() ComponentType {
|
||||
return s.ctype
|
||||
}
|
||||
|
||||
// Close close select
|
||||
func (s *Select) Close() {
|
||||
s.InputField.Close()
|
||||
if s.isExpanded {
|
||||
for _, opt := range s.options {
|
||||
s.DeleteView(opt)
|
||||
s.DeleteKeybindings(opt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw draw select
|
||||
func (s *Select) Draw() {
|
||||
if len(s.options) > 0 {
|
||||
s.InputField.SetText(s.options[s.currentOpt])
|
||||
}
|
||||
s.InputField.Draw()
|
||||
}
|
||||
|
||||
func (s *Select) nextOpt(g *gocui.Gui, v *gocui.View) error {
|
||||
maxOpt := len(s.options)
|
||||
if maxOpt == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
v.Highlight = false
|
||||
|
||||
next := s.currentOpt + 1
|
||||
if next >= maxOpt {
|
||||
next = s.currentOpt
|
||||
}
|
||||
|
||||
s.currentOpt = next
|
||||
v, _ = g.SetCurrentView(s.options[next])
|
||||
|
||||
v.Highlight = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Select) preOpt(g *gocui.Gui, v *gocui.View) error {
|
||||
maxOpt := len(s.options)
|
||||
if maxOpt == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
v.Highlight = false
|
||||
|
||||
next := s.currentOpt - 1
|
||||
if next < 0 {
|
||||
next = 0
|
||||
}
|
||||
|
||||
s.currentOpt = next
|
||||
v, _ = g.SetCurrentView(s.options[next])
|
||||
|
||||
v.Highlight = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Select) selectOpt(g *gocui.Gui, v *gocui.View) error {
|
||||
if !s.isExpanded {
|
||||
s.expandOpt(g, v)
|
||||
} else {
|
||||
s.closeOpt(g, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Select) expandOpt(g *gocui.Gui, vi *gocui.View) error {
|
||||
if s.hasOpts() {
|
||||
s.isExpanded = true
|
||||
g.Cursor = false
|
||||
|
||||
x := s.field.X
|
||||
w := s.field.W
|
||||
|
||||
y := s.field.Y
|
||||
h := y + 2
|
||||
|
||||
for _, opt := range s.options {
|
||||
y++
|
||||
h++
|
||||
if v, err := g.SetView(opt, x, y, w, h); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v.Frame = false
|
||||
v.SelFgColor = s.listColor.textColor
|
||||
v.SelBgColor = s.listColor.textBgColor
|
||||
v.FgColor = s.listColor.hilightColor
|
||||
v.BgColor = s.listColor.hilightBgColor
|
||||
|
||||
for key, handler := range s.listHandlers {
|
||||
if err := g.SetKeybinding(v.Name(), key, gocui.ModNone, handler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(v, opt)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
v, _ := g.SetCurrentView(s.options[s.currentOpt])
|
||||
v.Highlight = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Select) closeOpt(g *gocui.Gui, v *gocui.View) error {
|
||||
s.isExpanded = false
|
||||
g.Cursor = true
|
||||
|
||||
for _, opt := range s.options {
|
||||
g.DeleteView(opt)
|
||||
g.DeleteKeybindings(opt)
|
||||
}
|
||||
|
||||
v, _ = g.SetCurrentView(s.GetLabel())
|
||||
|
||||
v.Clear()
|
||||
|
||||
fmt.Fprint(v, s.GetSelected())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Select) hasOpts() bool {
|
||||
if len(s.options) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
BIN
mycui/test.zip
Normal file
BIN
mycui/test.zip
Normal file
Binary file not shown.
56
mycui/type.go
Normal file
56
mycui/type.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package mycui
|
||||
|
||||
import "github.com/jroimartin/gocui"
|
||||
|
||||
// Key define kye type
|
||||
type Key interface{}
|
||||
|
||||
// Handler define handler type
|
||||
type Handler func(g *gocui.Gui, v *gocui.View) error
|
||||
|
||||
// Handlers handlers
|
||||
type Handlers map[Key]Handler
|
||||
|
||||
// Component form component interface
|
||||
type Component interface {
|
||||
GetLabel() string
|
||||
GetPosition() *Position
|
||||
GetType() ComponentType
|
||||
Focus()
|
||||
UnFocus()
|
||||
Draw()
|
||||
Close()
|
||||
AddHandlerOnly(Key, Handler)
|
||||
}
|
||||
|
||||
// Attributes text and hilight color
|
||||
type Attributes struct {
|
||||
textColor gocui.Attribute
|
||||
textBgColor gocui.Attribute
|
||||
hilightColor gocui.Attribute
|
||||
hilightBgColor gocui.Attribute
|
||||
}
|
||||
|
||||
// Position component position
|
||||
type Position struct {
|
||||
X, Y int
|
||||
W, H int
|
||||
}
|
||||
|
||||
// ComponentType component type
|
||||
type ComponentType int
|
||||
|
||||
const (
|
||||
// TypeInputField type is input component
|
||||
TypeInputField ComponentType = iota
|
||||
// TypeSelect type is select component
|
||||
TypeSelect
|
||||
// TypeButton type is button component
|
||||
TypeButton
|
||||
// TypeCheckBox type is checkbox component
|
||||
TypeCheckBox
|
||||
// TypeRadio type is radio component
|
||||
TypeRadio
|
||||
// TypeTable type is table component
|
||||
TypeTable
|
||||
)
|
90
mycui/validator.go
Normal file
90
mycui/validator.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package mycui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
// Validate validate struct
|
||||
type Validate struct {
|
||||
ErrMsg string
|
||||
Do func(value string) bool
|
||||
}
|
||||
|
||||
// Validator validate struct
|
||||
type Validator struct {
|
||||
*gocui.Gui
|
||||
name string
|
||||
errMsg string
|
||||
isValid bool
|
||||
validates []Validate
|
||||
*Position
|
||||
}
|
||||
|
||||
// NewValidator new validator
|
||||
func NewValidator(gui *gocui.Gui, name string, x, y, w, h int) *Validator {
|
||||
return &Validator{
|
||||
Gui: gui,
|
||||
name: name,
|
||||
isValid: true,
|
||||
Position: &Position{
|
||||
X: x,
|
||||
Y: y,
|
||||
W: w,
|
||||
H: h,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddValidate add validate
|
||||
func (v *Validator) AddValidate(errMsg string, validate func(value string) bool) {
|
||||
v.validates = append(v.validates, Validate{
|
||||
ErrMsg: errMsg,
|
||||
Do: validate,
|
||||
})
|
||||
|
||||
if v.X+len(errMsg) > v.W {
|
||||
v.W += len(errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// DispValidateMsg display validate error message
|
||||
func (v *Validator) DispValidateMsg() {
|
||||
if vi, err := v.SetView(v.name, v.X, v.Y, v.W, v.H); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
vi.Frame = false
|
||||
vi.BgColor = gocui.ColorDefault
|
||||
vi.FgColor = gocui.ColorRed
|
||||
|
||||
fmt.Fprint(vi, v.errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// CloseValidateMsg close validate error message
|
||||
func (v *Validator) CloseValidateMsg() {
|
||||
v.DeleteView(v.name)
|
||||
}
|
||||
|
||||
// IsValid if valid return true
|
||||
func (v *Validator) IsValid() bool {
|
||||
return v.isValid
|
||||
}
|
||||
|
||||
// Validate validate value
|
||||
func (v *Validator) Validate(value string) {
|
||||
for _, validate := range v.validates {
|
||||
if !validate.Do(value) {
|
||||
v.errMsg = validate.ErrMsg
|
||||
v.isValid = false
|
||||
v.DispValidateMsg()
|
||||
break
|
||||
} else {
|
||||
v.isValid = true
|
||||
v.CloseValidateMsg()
|
||||
}
|
||||
}
|
||||
}
|
172
mydoc/common.go
Normal file
172
mydoc/common.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package mydoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/mydoc/mymarkdown"
|
||||
"github.com/xxjwxc/public/mydoc/myswagger"
|
||||
)
|
||||
|
||||
func (m *model) analysisStructInfo(info *StructInfo) {
|
||||
if info != nil {
|
||||
for i := 0; i < len(info.Items); i++ {
|
||||
tag := reflect.StructTag(strings.Trim(info.Items[i].Tag, "`"))
|
||||
|
||||
// json
|
||||
tagStr := tag.Get("json")
|
||||
if tagStr == "-" || tagStr == "" {
|
||||
tagStr = tag.Get("url")
|
||||
}
|
||||
tagStrs := strings.Split(tagStr, ",")
|
||||
if len(tagStrs[0]) > 0 {
|
||||
info.Items[i].Name = tagStrs[0]
|
||||
}
|
||||
// -------- end
|
||||
|
||||
// required
|
||||
tagStr = tag.Get("binding")
|
||||
tagStrs = strings.Split(tagStr, ",")
|
||||
for _, v := range tagStrs {
|
||||
if strings.EqualFold(v, "required") {
|
||||
info.Items[i].Requierd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// ---------------end
|
||||
|
||||
// default
|
||||
info.Items[i].Default = tag.Get("default")
|
||||
// ---------------end
|
||||
|
||||
if info.Items[i].TypeRef != nil {
|
||||
m.analysisStructInfo(info.Items[i].TypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (m *model) setDefinition(doc *myswagger.DocSwagger, tmp *StructInfo) string {
|
||||
if tmp != nil {
|
||||
var def myswagger.Definition
|
||||
def.Type = "object"
|
||||
def.Properties = make(map[string]myswagger.Propertie)
|
||||
for _, v2 := range tmp.Items {
|
||||
if v2.TypeRef != nil {
|
||||
def.Properties[v2.Name] = myswagger.Propertie{
|
||||
Ref: m.setDefinition(doc, v2.TypeRef),
|
||||
}
|
||||
} else {
|
||||
def.Properties[v2.Name] = myswagger.Propertie{
|
||||
Type: myswagger.GetKvType(v2.Type, v2.IsArray, true),
|
||||
Format: myswagger.GetKvType(v2.Type, v2.IsArray, false),
|
||||
Description: v2.Note,
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.AddDefinitions(tmp.Name, def)
|
||||
return "#/definitions/" + tmp.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func buildRelativePath(prepath, routerPath string) string {
|
||||
if strings.HasSuffix(prepath, "/") {
|
||||
if strings.HasPrefix(routerPath, "/") {
|
||||
return prepath + strings.TrimPrefix(routerPath, "/")
|
||||
}
|
||||
return prepath + routerPath
|
||||
}
|
||||
|
||||
if strings.HasPrefix(routerPath, "/") {
|
||||
return prepath + routerPath
|
||||
}
|
||||
|
||||
return prepath + "/" + routerPath
|
||||
}
|
||||
|
||||
func conType(pkg *StructInfo, tp string, isArray bool) string {
|
||||
re := tp
|
||||
if pkg != nil {
|
||||
re = "`" + pkg.Pkg + "." + tp + "`"
|
||||
}
|
||||
if isArray {
|
||||
re = "[]" + re
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
func (m *model) buildSubStructMD(doc *mymarkdown.DocMarkdown, tmp *StructInfo) (jsonMp map[string]interface{}) {
|
||||
jsonMp = make(map[string]interface{})
|
||||
if tmp != nil {
|
||||
var info mymarkdown.TmpTable
|
||||
info.SC = "`"
|
||||
info.Pkg = tmp.Pkg
|
||||
info.Name = tmp.Name
|
||||
info.Note = tmp.Note
|
||||
for _, v := range tmp.Items {
|
||||
if v.TypeRef != nil {
|
||||
mp := m.buildSubStructMD(doc, v.TypeRef)
|
||||
jsonMp[v.Name] = doc.GetTypeList(mp, v.IsArray)
|
||||
} else {
|
||||
jsonMp[v.Name] = doc.GetValueType(v.Type, v.Default, v.IsArray)
|
||||
}
|
||||
|
||||
info.Item = append(info.Item, mymarkdown.TmpElement{
|
||||
Name: v.Name,
|
||||
Requierd: doc.GetBoolStr(v.Requierd),
|
||||
Type: conType(v.TypeRef, v.Type, v.IsArray),
|
||||
Note: v.Note,
|
||||
})
|
||||
}
|
||||
|
||||
tmpl, err := template.New("struct_mod").
|
||||
Parse(doc.GetTableInfo())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
tmpl.Execute(&buf, info)
|
||||
doc.AddBaseStruct(tmp.Pkg, tmp.Name, buf.String())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *model) buildDefinitionMD(doc *mymarkdown.DocMarkdown, tmp *StructInfo) (rest string, jsonMp map[string]interface{}) {
|
||||
jsonMp = make(map[string]interface{})
|
||||
if tmp != nil {
|
||||
var info mymarkdown.TmpTable
|
||||
info.SC = "`"
|
||||
info.Name = tmp.Name
|
||||
info.Note = tmp.Note
|
||||
for _, v := range tmp.Items {
|
||||
if v.TypeRef != nil {
|
||||
mp := m.buildSubStructMD(doc, v.TypeRef)
|
||||
jsonMp[v.Name] = doc.GetTypeList(mp, v.IsArray)
|
||||
} else {
|
||||
jsonMp[v.Name] = doc.GetValueType(v.Type, v.Default, v.IsArray)
|
||||
}
|
||||
|
||||
info.Item = append(info.Item, mymarkdown.TmpElement{
|
||||
Name: v.Name,
|
||||
Requierd: doc.GetBoolStr(v.Requierd),
|
||||
Type: conType(v.TypeRef, v.Type, v.IsArray),
|
||||
Note: v.Note,
|
||||
})
|
||||
}
|
||||
|
||||
tmpl, err := template.New("struct_mod").
|
||||
Parse(doc.GetTableInfo())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
tmpl.Execute(&buf, info)
|
||||
rest = buf.String()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
30
mydoc/def.go
Normal file
30
mydoc/def.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package mydoc
|
||||
|
||||
// ElementInfo 结构信息
|
||||
type ElementInfo struct {
|
||||
Name string // 参数名
|
||||
// URL string // web 访问参数
|
||||
Tag string // 标签
|
||||
Type string // 类型
|
||||
TypeRef *StructInfo // 类型定义
|
||||
IsArray bool // 是否是数组
|
||||
Requierd bool // 是否必须
|
||||
Note string // 注释
|
||||
Default string // 默认值
|
||||
}
|
||||
|
||||
// StructInfo struct define
|
||||
type StructInfo struct {
|
||||
Items []ElementInfo // 结构体元素
|
||||
Note string // 注释
|
||||
Name string //结构体名字
|
||||
Pkg string // 包名
|
||||
}
|
||||
|
||||
// DocModel model
|
||||
type DocModel struct {
|
||||
RouterPath string
|
||||
Methods []string
|
||||
Note string
|
||||
Req, Resp *StructInfo
|
||||
}
|
106
mydoc/mydoc.go
Normal file
106
mydoc/mydoc.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package mydoc
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
|
||||
"github.com/xxjwxc/public/mydoc/mymarkdown"
|
||||
"github.com/xxjwxc/public/mydoc/myswagger"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
Group string // group 标记
|
||||
MP map[string]map[string]DocModel
|
||||
}
|
||||
|
||||
// NewDoc 新建一个doc模板
|
||||
func NewDoc(group string) *model {
|
||||
doc := &model{Group: group}
|
||||
doc.MP = make(map[string]map[string]DocModel)
|
||||
return doc
|
||||
}
|
||||
|
||||
// 添加一个
|
||||
func (m *model) AddOne(group string, routerPath string, methods []string, note string, req, resp *StructInfo) {
|
||||
if m.MP[group] == nil {
|
||||
m.MP[group] = make(map[string]DocModel)
|
||||
}
|
||||
|
||||
m.analysisStructInfo(req)
|
||||
m.analysisStructInfo(resp)
|
||||
m.MP[group][routerPath] = DocModel{
|
||||
RouterPath: routerPath,
|
||||
Methods: methods,
|
||||
Note: note,
|
||||
Req: req,
|
||||
Resp: resp,
|
||||
}
|
||||
}
|
||||
|
||||
// GenSwagger 生成swagger文档
|
||||
func (m *model) GenSwagger(outPath string) {
|
||||
doc := myswagger.NewDoc()
|
||||
reqRef, _ := "", ""
|
||||
|
||||
// define
|
||||
for _, v := range m.MP {
|
||||
for _, v1 := range v {
|
||||
reqRef = m.setDefinition(doc, v1.Req)
|
||||
//respRef = m.setDefinition(doc, v1.Resp)
|
||||
}
|
||||
}
|
||||
// ------------------end
|
||||
|
||||
for k, v := range m.MP {
|
||||
tag := myswagger.Tag{Name: k}
|
||||
doc.AddTag(tag)
|
||||
for _, v1 := range v {
|
||||
var p myswagger.Param
|
||||
p.Tags = []string{k}
|
||||
p.Summary = v1.Note
|
||||
p.Description = v1.Note
|
||||
// p.OperationID = "addPet"
|
||||
p.Parameters = []myswagger.Element{myswagger.Element{
|
||||
In: "body", // body, header, formData, query, path
|
||||
Name: "body", // body, header, formData, query, path
|
||||
Description: v1.Note,
|
||||
Required: true,
|
||||
Schema: myswagger.Schema{
|
||||
Ref: reqRef,
|
||||
},
|
||||
}}
|
||||
doc.AddPatch(buildRelativePath(m.Group, v1.RouterPath), p, v1.Methods...)
|
||||
}
|
||||
}
|
||||
|
||||
jsonsrc := doc.GetAPIString()
|
||||
|
||||
tools.WriteFile(outPath+"swagger.json", []string{jsonsrc}, true)
|
||||
}
|
||||
|
||||
// GenMd 生成 markdown 文档
|
||||
func (m *model) GenMarkdown(outPath string) {
|
||||
for k, v := range m.MP {
|
||||
doc := mymarkdown.NewDoc()
|
||||
var tmp mymarkdown.TmpInterface
|
||||
tmp.Class = k
|
||||
tmp.Note = "Waiting to write..."
|
||||
for _, v1 := range v {
|
||||
reqTable, reqMp := m.buildDefinitionMD(doc, v1.Req)
|
||||
resTable, respMpon := m.buildDefinitionMD(doc, v1.Resp)
|
||||
var sub mymarkdown.TmpSub
|
||||
sub.ReqTab = reqTable
|
||||
sub.ReqJSON = template.HTML(tools.GetJSONStr(reqMp, true))
|
||||
|
||||
sub.RespTab = resTable
|
||||
sub.RespJSON = template.HTML(tools.GetJSONStr(respMpon, true))
|
||||
|
||||
sub.Methods = v1.Methods
|
||||
sub.Note = v1.Note
|
||||
sub.RouterPath = buildRelativePath(m.Group, v1.RouterPath)
|
||||
tmp.Item = append(tmp.Item, sub)
|
||||
}
|
||||
jsonsrc := doc.GenMarkdown(tmp)
|
||||
tools.WriteFile(outPath+k+".md", []string{jsonsrc}, true)
|
||||
}
|
||||
}
|
197
mydoc/mymarkdown/def.go
Normal file
197
mydoc/mymarkdown/def.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package mymarkdown
|
||||
|
||||
import "html/template"
|
||||
|
||||
var headMod = []string{
|
||||
`
|
||||
#### Brief description:
|
||||
|
||||
- [%s]
|
||||
- [Waiting to write...]
|
||||
`,
|
||||
`
|
||||
#### 简要描述:
|
||||
|
||||
- [%s]
|
||||
- [等待写入]
|
||||
`,
|
||||
}
|
||||
|
||||
var bTrue = []string{"`YES`", "`是`"}
|
||||
var bFalse = []string{"NO", "否"}
|
||||
|
||||
var tableMod = []string{
|
||||
`{{$obj := .}}
|
||||
- {{$obj.SC}} {{$obj.Name}} {{$obj.SC}} : {{$obj.Note}}
|
||||
|
||||
|Parameter| Requierd | Type | Description|
|
||||
|:---- |:---|:----- |----- |{{range $oem := $obj.Item}}
|
||||
|{{$obj.SC}}{{$oem.Name}}{{$obj.SC}} | {{$oem.Requierd}}|{{$oem.Type}}|{{$oem.Note}} |{{end}}
|
||||
`,
|
||||
`{{$obj := .}}
|
||||
- {{$obj.SC}} {{$obj.Name}} {{$obj.SC}} : {{$obj.Note}}
|
||||
|
||||
|参数名|是否必须|类型|说明|
|
||||
|:---- |:---|:----- |----- |{{range $oem := $obj.Item}}
|
||||
|{{$obj.SC}}{{$oem.Name}}{{$obj.SC}} | {{$oem.Requierd}}|{{$oem.Type}}|{{$oem.Note}} |{{end}}
|
||||
`,
|
||||
}
|
||||
|
||||
var bodyMod = []string{
|
||||
`
|
||||
{{$obj := .}}
|
||||
## [Viewing tools](https://www.iminho.me/)
|
||||
|
||||
## Overview:
|
||||
- [{{$obj.Class}}]
|
||||
- [{{$obj.Note}}]
|
||||
{{range $oem := $obj.Item}}
|
||||
--------------------
|
||||
|
||||
#### Brief description:
|
||||
|
||||
- [{{$oem.Note}}]
|
||||
|
||||
#### Request URL:
|
||||
|
||||
- {{$oem.RouterPath}}
|
||||
|
||||
#### Methods:
|
||||
{{range $me := $oem.Methods}}
|
||||
- {{$me}}{{end}}
|
||||
|
||||
#### Parameters:
|
||||
{{$oem.ReqTab}}
|
||||
|
||||
#### Request example:
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
{{$oem.ReqJSON}}
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
|
||||
#### Return parameter description:
|
||||
$oem.RespTab
|
||||
|
||||
#### Return example:
|
||||
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
{{$oem.RespJSON}}
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
|
||||
#### Remarks:
|
||||
|
||||
- {{$oem.Note}}
|
||||
{{end}}
|
||||
|
||||
--------------------
|
||||
--------------------
|
||||
|
||||
#### Custom type:
|
||||
{{range $k,$v := $obj.BMP}}
|
||||
#### {{$obj.SC}} {{$k}} {{$obj.SC}}
|
||||
{{range $v1 := $v}}
|
||||
{{$v1.Context}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
`,
|
||||
`
|
||||
{{$obj := .}}
|
||||
## [推荐查看工具](https://www.iminho.me/)
|
||||
|
||||
## 总览:
|
||||
- [{{$obj.Class}}]
|
||||
- [{{$obj.Note}}]
|
||||
{{range $oem := $obj.Item}}
|
||||
--------------------
|
||||
|
||||
#### 简要描述:
|
||||
|
||||
- [{{$oem.Note}}]
|
||||
|
||||
#### 请求URL:
|
||||
|
||||
- {{$oem.RouterPath}}
|
||||
|
||||
#### 请求方式:
|
||||
{{range $me := $oem.Methods}}
|
||||
- {{$me}}{{end}}
|
||||
|
||||
#### 请求参数:
|
||||
{{$oem.ReqTab}}
|
||||
|
||||
#### 请求示例:
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
{{$oem.ReqJSON}}
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
|
||||
#### 返回参数说明:
|
||||
$oem.RespTab
|
||||
|
||||
#### 返回示例:
|
||||
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
{{$oem.RespJSON}}
|
||||
{{$obj.SC}}{{$obj.SC}}{{$obj.SC}}
|
||||
|
||||
#### 备注:
|
||||
|
||||
- {{$oem.Note}}
|
||||
{{end}}
|
||||
|
||||
--------------------
|
||||
--------------------
|
||||
|
||||
#### 自定义类型:
|
||||
{{range $k,$v := $obj.BMP}}
|
||||
#### {{$obj.SC}} {{$k}} {{$obj.SC}}
|
||||
{{range $v1 := $v}}
|
||||
{{$v1.Context}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
`,
|
||||
}
|
||||
|
||||
// TmpElement 元素
|
||||
type TmpElement struct {
|
||||
Name string
|
||||
Requierd string
|
||||
Type string
|
||||
Note string
|
||||
}
|
||||
|
||||
// TmpTable 模板
|
||||
type TmpTable struct {
|
||||
SC string
|
||||
Pkg string
|
||||
Name string
|
||||
Note string
|
||||
Item []TmpElement
|
||||
}
|
||||
|
||||
// TmpSub 模板
|
||||
type TmpSub struct {
|
||||
ReqTab string // 请求参数列表
|
||||
ReqJSON template.HTML // 请求示例
|
||||
|
||||
RespTab string // 返回参数列表
|
||||
RespJSON template.HTML // 返回示例
|
||||
|
||||
Methods []string // 请求方式
|
||||
|
||||
Note string // 注释
|
||||
RouterPath string // 请求url
|
||||
}
|
||||
|
||||
// TmpInterface 模板
|
||||
type TmpInterface struct {
|
||||
SC string
|
||||
Class string
|
||||
Note string
|
||||
Item []TmpSub
|
||||
BMP map[string][]BaseStruct
|
||||
}
|
||||
|
||||
// BaseStruct 模板
|
||||
type BaseStruct struct { // 基础类型
|
||||
Class string
|
||||
Context string
|
||||
}
|
59
mydoc/mymarkdown/demo.md
Normal file
59
mydoc/mymarkdown/demo.md
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
#### 简要描述:
|
||||
|
||||
- 用户登录接口
|
||||
|
||||
#### 请求URL:
|
||||
|
||||
- http://xx.com/api/login
|
||||
|
||||
#### 请求方式:
|
||||
|
||||
- GET
|
||||
- POST
|
||||
|
||||
|
||||
#### 请求参数:
|
||||
|
||||
|参数名|是否必须|类型|说明|
|
||||
|:---- |:---|:----- |----- |
|
||||
|username |是 |string |用户名 |
|
||||
|password |是 |string | 密码 |
|
||||
|
||||
#### 返回示例:
|
||||
|
||||
**正确时返回:**
|
||||
|
||||
```
|
||||
{
|
||||
"errcode": 0,
|
||||
"data": {
|
||||
"uid": "1",
|
||||
"account": "admin",
|
||||
"nickname": "Minho",
|
||||
"group_level": 0 ,
|
||||
"create_time": "1436864169",
|
||||
"last_login_time": "0",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误时返回:**
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"errcode": 500,
|
||||
"errmsg": "invalid appid"
|
||||
}
|
||||
```
|
||||
|
||||
#### 返回参数说明:
|
||||
|
||||
|参数名|类型|说明|
|
||||
|:----- |:-----|----- |
|
||||
|group_level |int |用户组id,1:超级管理员;2:普通用户 |
|
||||
|
||||
#### 备注:
|
||||
|
||||
- 更多返回错误代码请看首页的错误代码描述
|
149
mydoc/mymarkdown/mymarkdown.go
Normal file
149
mydoc/mymarkdown/mymarkdown.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package mymarkdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
// DocMarkdown
|
||||
type DocMarkdown struct {
|
||||
n int
|
||||
baseStructMP map[string][]BaseStruct
|
||||
}
|
||||
|
||||
// NewDoc 新建一个markdown文件
|
||||
func NewDoc() *DocMarkdown {
|
||||
doc := &DocMarkdown{}
|
||||
if tools.GetLocalSystemLang(true) == "zh" { // en
|
||||
doc.n = 1
|
||||
}
|
||||
doc.baseStructMP = make(map[string][]BaseStruct)
|
||||
return doc
|
||||
}
|
||||
|
||||
// AddBaseStruct 添加一个基础类型
|
||||
func (m *DocMarkdown) AddBaseStruct(pkg, class, context string) {
|
||||
for _, v := range m.baseStructMP[pkg] {
|
||||
if v.Class == class {
|
||||
return
|
||||
}
|
||||
}
|
||||
m.baseStructMP[pkg] = append(m.baseStructMP[pkg], BaseStruct{
|
||||
Class: class,
|
||||
Context: context,
|
||||
})
|
||||
}
|
||||
|
||||
// GetBoolStr 获取bool类型字符串
|
||||
func (m *DocMarkdown) GetBoolStr(b bool) string {
|
||||
if b {
|
||||
return bTrue[m.n]
|
||||
}
|
||||
|
||||
return bFalse[m.n]
|
||||
}
|
||||
|
||||
// GetTableInfo 获取table表格
|
||||
func (m *DocMarkdown) GetTableInfo() string {
|
||||
return tableMod[m.n]
|
||||
}
|
||||
|
||||
// GetBodyInfo 获取table表格
|
||||
func (m *DocMarkdown) GetBodyInfo() string {
|
||||
return bodyMod[m.n]
|
||||
}
|
||||
|
||||
// GetTypeList 转换typelist
|
||||
func (m *DocMarkdown) GetTypeList(k interface{}, isArray bool) interface{} {
|
||||
if isArray {
|
||||
return []interface{}{k}
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// GetValueType 根据类型获取内容
|
||||
func (m *DocMarkdown) GetValueType(k, v string, isArray bool) interface{} {
|
||||
array := strings.Split(v, ",")
|
||||
k = strings.ToLower(k)
|
||||
switch k {
|
||||
case "string":
|
||||
if isArray {
|
||||
var list []string
|
||||
for _, v := range array {
|
||||
list = append(list, v)
|
||||
}
|
||||
return list
|
||||
}
|
||||
return v
|
||||
case "bool":
|
||||
if isArray {
|
||||
var list []bool
|
||||
for _, v := range array {
|
||||
list = append(list, (v == "true" || v == "1"))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
return (v == "true" || v == "1")
|
||||
case "int", "uint", "byte", "rune", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "uintptr":
|
||||
if isArray {
|
||||
var list []int
|
||||
for _, v := range array {
|
||||
i, _ := strconv.Atoi(v)
|
||||
list = append(list, i)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
i, _ := strconv.Atoi(v)
|
||||
return i
|
||||
case "float32", "float64":
|
||||
if isArray {
|
||||
var list []float64
|
||||
for _, v := range array {
|
||||
f, _ := strconv.ParseFloat(v, 64)
|
||||
list = append(list, f)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
f, _ := strconv.ParseFloat(v, 64)
|
||||
return f
|
||||
case "map":
|
||||
return v
|
||||
case "Time":
|
||||
if isArray {
|
||||
var list []tools.Time
|
||||
for _, v := range array {
|
||||
var t tools.Time
|
||||
t.Time = time.Unix(tools.StringTimetoUnix(v), 0)
|
||||
list = append(list, t)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
var t tools.Time
|
||||
t.Time = time.Unix(tools.StringTimetoUnix(v), 0)
|
||||
return t
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// GenMarkdown 生成markdown
|
||||
func (m *DocMarkdown) GenMarkdown(info TmpInterface) string {
|
||||
info.SC = "`"
|
||||
info.BMP = m.baseStructMP
|
||||
tmpl, err := template.New("struct_markdown").Parse(m.GetBodyInfo())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
tmpl.Execute(&buf, info)
|
||||
return buf.String()
|
||||
}
|
96
mydoc/myswagger/def.go
Normal file
96
mydoc/myswagger/def.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package myswagger
|
||||
|
||||
// Head Swagger 版本
|
||||
type Head struct {
|
||||
Swagger string `json:"swagger"`
|
||||
}
|
||||
|
||||
// Info 指定 API 的 info-title
|
||||
type Info struct {
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// ExternalDocs tags of group
|
||||
type ExternalDocs struct {
|
||||
Description string `json:"description,omitempty"` // 描述
|
||||
URL string `json:"url,omitempty"` // url addr
|
||||
}
|
||||
|
||||
// Tag group of tags
|
||||
type Tag struct {
|
||||
Name string `json:"name"` // tags name
|
||||
Description string `json:"description"` // 描述
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty"` // doc group of tags
|
||||
}
|
||||
|
||||
// Schema 引用
|
||||
type Schema struct {
|
||||
Ref string `json:"$ref"` // 主体模式和响应主体模式中引用
|
||||
}
|
||||
|
||||
// Element 元素定义
|
||||
type Element struct {
|
||||
In string `json:"in"` // 入参
|
||||
Name string `json:"name"` // 参数名字
|
||||
Description string `json:"description"` // 描述
|
||||
Required bool `json:"required"` // 是否必须
|
||||
Type string `json:"type,omitempty"` // 类型
|
||||
Schema Schema `json:"schema"` // 引用
|
||||
}
|
||||
|
||||
// Param API 路径 paths 和操作在 API 规范的全局部分定义
|
||||
type Param struct {
|
||||
Tags []string `json:"tags"` // 分组标记
|
||||
Summary string `json:"summary"` // 摘要
|
||||
Description string `json:"description"` // 描述
|
||||
OperationID string `json:"operationId,omitempty"` // 操作id
|
||||
Consumes []string `json:"consumes"` // Parameter content type
|
||||
Produces []string `json:"produces"` // Response content type
|
||||
Parameters []Element `json:"parameters"` // 请求参数
|
||||
Responses map[string]map[string]string `json:"responses"` // 返回参数
|
||||
Security interface{} `json:"security,omitempty"` // 认证信息
|
||||
}
|
||||
|
||||
// SecurityDefinitions 安全验证
|
||||
type SecurityDefinitions struct {
|
||||
PetstoreAuth interface{} `json:"petstore_auth,omitempty"` // 安全验证定义
|
||||
AIPKey interface{} `json:"api_key,omitempty"` // api key
|
||||
}
|
||||
|
||||
// Propertie 属性
|
||||
type Propertie struct {
|
||||
Type string `json:"type,omitempty"` // 类型
|
||||
Format string `json:"format"` // format 类型
|
||||
Description string `json:"description"` // 描述
|
||||
Enum interface{} `json:"enum,omitempty"` // enum
|
||||
Ref string `json:"$ref,omitempty"` // 主体模式和响应主体模式中引用
|
||||
}
|
||||
|
||||
// XML xml
|
||||
type XML struct {
|
||||
Name string `json:"name"`
|
||||
Wrapped bool `json:"wrapped"`
|
||||
}
|
||||
|
||||
// Definition 通用结构体定义
|
||||
type Definition struct {
|
||||
Type string `json:"type"` // 类型 object
|
||||
Properties map[string]Propertie `json:"properties"` // 属性列表
|
||||
XML XML `json:"xml"`
|
||||
}
|
||||
|
||||
// APIBody swagger api body info
|
||||
type APIBody struct {
|
||||
Head
|
||||
Info Info `json:"info"`
|
||||
Host string `json:"host"` // http host
|
||||
BasePath string `json:"basePath"` // 根级别
|
||||
Tags []Tag `json:"tags"`
|
||||
Schemes []string `json:"schemes"` // http/https
|
||||
Patchs map[string]map[string]Param `json:"paths"` // API 路径
|
||||
SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"` // 安全验证
|
||||
Definitions map[string]Definition `json:"definitions"` // 通用结构体定义
|
||||
ExternalDocs ExternalDocs `json:"externalDocs"` // 外部链接
|
||||
}
|
82
mydoc/myswagger/model_set.go
Normal file
82
mydoc/myswagger/model_set.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package myswagger
|
||||
|
||||
import "strings"
|
||||
|
||||
var version string = "2.0"
|
||||
var host string = "localhost"
|
||||
var basePath string = "/v1"
|
||||
var schemes []string = []string{"http", "https"}
|
||||
var reqCtxType []string = []string{"application/json", "application/xml"}
|
||||
var respCtxType []string = []string{"application/json", "application/xml"}
|
||||
var info Info = Info{
|
||||
Description: "swagger default desc",
|
||||
Version: "1.0.0",
|
||||
Title: "Swagger Petstore",
|
||||
}
|
||||
var externalDocs ExternalDocs = ExternalDocs{
|
||||
Description: "Find out more about Swagger",
|
||||
URL: "https://github.com/xxjwxc/public",
|
||||
}
|
||||
|
||||
// SetVersion 设置版本号
|
||||
func SetVersion(v string) {
|
||||
version = v
|
||||
}
|
||||
|
||||
// SetHost 设置host
|
||||
func SetHost(h string) {
|
||||
h = strings.TrimPrefix(h, "http://")
|
||||
h = strings.TrimPrefix(h, "https://")
|
||||
host = h
|
||||
}
|
||||
|
||||
// SetBasePath set basePath
|
||||
func SetBasePath(b string) {
|
||||
if !strings.HasPrefix(b, "/") {
|
||||
b = "/" + b
|
||||
}
|
||||
basePath = b
|
||||
}
|
||||
|
||||
// SetSchemes 设置 http头
|
||||
func SetSchemes(isHTTP, isHTTPS bool) {
|
||||
schemes = []string{}
|
||||
if isHTTP {
|
||||
schemes = append(schemes, "http")
|
||||
}
|
||||
if isHTTPS {
|
||||
schemes = append(schemes, "https")
|
||||
}
|
||||
}
|
||||
|
||||
// SetReqCtxType 设置请求数据传输方式
|
||||
func SetReqCtxType(isJSON, isXML bool) {
|
||||
reqCtxType = []string{}
|
||||
if isJSON {
|
||||
reqCtxType = append(schemes, "application/json")
|
||||
}
|
||||
if isXML {
|
||||
reqCtxType = append(schemes, "application/xml")
|
||||
}
|
||||
}
|
||||
|
||||
// SetRespCtxType 设置响应(返回)求数据传输方式
|
||||
func SetRespCtxType(isJSON, isXML bool) {
|
||||
respCtxType = []string{}
|
||||
if isJSON {
|
||||
respCtxType = append(schemes, "application/json")
|
||||
}
|
||||
if isXML {
|
||||
respCtxType = append(schemes, "application/xml")
|
||||
}
|
||||
}
|
||||
|
||||
// SetInfo 设置信息
|
||||
func SetInfo(i Info) {
|
||||
info = i
|
||||
}
|
||||
|
||||
// SetExternalDocs 设置外部doc链接
|
||||
func SetExternalDocs(e ExternalDocs) {
|
||||
externalDocs = e
|
||||
}
|
132
mydoc/myswagger/myswagger.go
Normal file
132
mydoc/myswagger/myswagger.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package myswagger
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
// DocSwagger ...
|
||||
type DocSwagger struct {
|
||||
client *APIBody
|
||||
}
|
||||
|
||||
// NewDoc 新建一个swagger doc
|
||||
func NewDoc() *DocSwagger {
|
||||
doc := &DocSwagger{}
|
||||
doc.client = &APIBody{
|
||||
Head: Head{Swagger: version},
|
||||
Info: info,
|
||||
Host: host,
|
||||
BasePath: basePath,
|
||||
// Tags
|
||||
Schemes: schemes,
|
||||
// Patchs
|
||||
// SecurityDefinitions
|
||||
// Definitions
|
||||
ExternalDocs: externalDocs,
|
||||
}
|
||||
doc.client.Patchs = make(map[string]map[string]Param)
|
||||
return doc
|
||||
}
|
||||
|
||||
// AddTag add tag (排他)
|
||||
func (doc *DocSwagger) AddTag(tag Tag) {
|
||||
for _, v := range doc.client.Tags {
|
||||
if v.Name == tag.Name { // find it
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
doc.client.Tags = append(doc.client.Tags, tag)
|
||||
}
|
||||
|
||||
// AddDefinitions 添加 通用结构体定义
|
||||
func (doc *DocSwagger) AddDefinitions(key string, def Definition) {
|
||||
// for k := range doc.client.Definitions {
|
||||
// if k == key { // find it
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
if doc.client.Definitions == nil {
|
||||
doc.client.Definitions = make(map[string]Definition)
|
||||
}
|
||||
|
||||
doc.client.Definitions[key] = def
|
||||
}
|
||||
|
||||
// AddPatch ... API 路径 paths 和操作在 API 规范的全局部分定义
|
||||
func (doc *DocSwagger) AddPatch(url string, p Param, metheds ...string) {
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
url = "/" + url
|
||||
}
|
||||
|
||||
if doc.client.Patchs[url] == nil {
|
||||
doc.client.Patchs[url] = make(map[string]Param)
|
||||
}
|
||||
if len(p.Consumes) == 0 {
|
||||
p.Consumes = reqCtxType
|
||||
}
|
||||
if len(p.Produces) == 0 {
|
||||
p.Produces = respCtxType
|
||||
}
|
||||
if p.Responses == nil {
|
||||
p.Responses = map[string]map[string]string{
|
||||
"400": {"description": "v"},
|
||||
"404": {"description": "not found"},
|
||||
"405": {"description": "Validation exception"},
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range metheds {
|
||||
doc.client.Patchs[url][strings.ToLower(v)] = p
|
||||
}
|
||||
}
|
||||
|
||||
// GetAPIString 获取返回数据
|
||||
func (doc *DocSwagger) GetAPIString() string {
|
||||
return tools.GetJSONStr(doc.client, true)
|
||||
}
|
||||
|
||||
var kvType = map[string]string{ // array, boolean, integer, number, object, string
|
||||
"int": "integer",
|
||||
"uint": "integer",
|
||||
"byte": "integer",
|
||||
"rune": "integer",
|
||||
"int8": "integer",
|
||||
"int16": "integer",
|
||||
"int32": "integer",
|
||||
"int64": "integer",
|
||||
"uint8": "integer",
|
||||
"uint16": "integer",
|
||||
"uint32": "integer",
|
||||
"uint64": "integer",
|
||||
"uintptr": "integer",
|
||||
"float32": "integer",
|
||||
"float64": "integer",
|
||||
"bool": "boolean",
|
||||
"map": "object",
|
||||
"Time": "string"}
|
||||
|
||||
var kvFormat = map[string]string{}
|
||||
|
||||
// GetKvType 获取类型转换
|
||||
func GetKvType(k string, isArray, isType bool) string {
|
||||
if isArray {
|
||||
if isType {
|
||||
return "object"
|
||||
}
|
||||
return "array"
|
||||
}
|
||||
|
||||
if isType {
|
||||
if _, ok := kvType[k]; ok {
|
||||
return kvType[k]
|
||||
}
|
||||
return k
|
||||
}
|
||||
if _, ok := kvFormat[k]; ok {
|
||||
return kvFormat[k]
|
||||
}
|
||||
return k
|
||||
}
|
59
mydoc/myswagger/myswagger_test.go
Normal file
59
mydoc/myswagger/myswagger_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package myswagger
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
func TestDomain(t *testing.T) {
|
||||
SetHost("http://localhost:8080")
|
||||
SetBasePath("/v1")
|
||||
doc := NewDoc()
|
||||
var tag Tag
|
||||
tag.Name = "pet"
|
||||
tag.Description = "Everything about your Pets"
|
||||
tag.ExternalDocs = &ExternalDocs{
|
||||
Description: "Find out more",
|
||||
URL: "https://github.com/xxjwxc/public",
|
||||
}
|
||||
doc.AddTag(tag)
|
||||
|
||||
var def Definition
|
||||
def.Type = "object"
|
||||
def.Properties = make(map[string]Propertie)
|
||||
def.Properties["id"] = Propertie{
|
||||
Type: "integer",
|
||||
Format: "int64",
|
||||
Description: "des text",
|
||||
}
|
||||
def.Properties["status"] = Propertie{
|
||||
Type: "string",
|
||||
Format: "string",
|
||||
Description: "Order Status",
|
||||
Enum: []string{"placed", "approved", "delivered"},
|
||||
}
|
||||
|
||||
doc.AddDefinitions("Pet", def)
|
||||
|
||||
var p Param
|
||||
p.Tags = []string{"pet"}
|
||||
p.Summary = "Add a new pet to the store"
|
||||
p.Description = "描述"
|
||||
// p.OperationID = "addPet"
|
||||
p.Parameters = []Element{Element{
|
||||
In: "body", // body, header, formData, query, path
|
||||
Name: "body", // body, header, formData, query, path
|
||||
Description: "Pet object that needs to be added to the store",
|
||||
Required: true,
|
||||
Schema: Schema{
|
||||
Ref: "#/definitions/Pet",
|
||||
},
|
||||
}}
|
||||
doc.AddPatch("/pet", p, "post", "get")
|
||||
|
||||
jsonsrc := doc.GetAPIString()
|
||||
|
||||
tools.WriteFile("/Users/xxj/Downloads/out.json", []string{jsonsrc}, true)
|
||||
|
||||
}
|
@@ -3,9 +3,10 @@ package myelastic
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/xxjwxc/public/errors"
|
||||
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -149,10 +150,8 @@ func (es *MyElastic) SortQueryReturnHits(index_name string, from, size int, buil
|
||||
|
||||
// log.Println("wwwwww", es_result.Aggregations)
|
||||
if es_result.Hits.TotalHits > 0 {
|
||||
|
||||
return true, es_result.Hits.Hits
|
||||
} else {
|
||||
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
@@ -314,7 +313,7 @@ func scanMapElement(fieldv reflect.Value, field reflect.StructField, objMap map[
|
||||
bb := field.Tag
|
||||
sqlTag := bb.Get("json")
|
||||
|
||||
if bb.Get("json") == "-" || sqlTag == "-" || reflect.ValueOf(bb).String() == "-" {
|
||||
if sqlTag == "-" || reflect.ValueOf(bb).String() == "-" {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,9 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"public/tools"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
//上传单个文件
|
||||
|
@@ -2,7 +2,6 @@ package myhttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"data/config"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -10,15 +9,16 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"public/mylog"
|
||||
"public/tools"
|
||||
|
||||
"github.com/xxjwxc/public/dev"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
/*
|
||||
多文件上传
|
||||
dir:空则使用文件后缀做dir
|
||||
*/
|
||||
//UploadMoreFile 多文件上传,dir:空则使用文件后缀做dir
|
||||
func UploadMoreFile(r *http.Request, dir string) (result bool, optionDirs []string) {
|
||||
//接受post请求
|
||||
if r.Method == "POST" {
|
||||
@@ -39,15 +39,14 @@ func UploadMoreFile(r *http.Request, dir string) (result bool, optionDirs []stri
|
||||
_dir = ext
|
||||
}
|
||||
|
||||
abs_dir := tools.GetModelPath() + config.File_host + "/" + _dir + "/"
|
||||
file_name := getFileName(ext)
|
||||
if !tools.CheckFileIsExist(abs_dir) {
|
||||
tools.BuildDir(abs_dir)
|
||||
//err := os.MkdirAll(tools.GetModelPath()+config.File_host+"/"+_dir+"/", os.ModePerm) //生成多级目录
|
||||
absDir := tools.GetCurrentDirectory() + "/" + dev.GetFileHost() + "/" + _dir + "/"
|
||||
fileName := getFileName(ext)
|
||||
if !tools.CheckFileIsExist(absDir) {
|
||||
tools.BuildDir(absDir)
|
||||
}
|
||||
|
||||
//存在则覆盖
|
||||
f, err := os.OpenFile(abs_dir+file_name,
|
||||
f, err := os.OpenFile(absDir+fileName,
|
||||
os.O_WRONLY|os.O_CREATE, 0666)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
@@ -57,7 +56,7 @@ func UploadMoreFile(r *http.Request, dir string) (result bool, optionDirs []stri
|
||||
}
|
||||
|
||||
io.Copy(f, file)
|
||||
optionDirs = append(optionDirs, config.Url_host+config.File_host+"/"+_dir+"/"+file_name)
|
||||
optionDirs = append(optionDirs, "/"+dev.GetService()+"/"+dev.GetFileHost()+"/"+_dir+"/"+fileName)
|
||||
result = true
|
||||
}
|
||||
}
|
||||
@@ -81,9 +80,9 @@ func getFileType(exp string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
//模拟客戶端文件上传
|
||||
//PostFile 模拟客戶端文件上传
|
||||
//fieldname注意与服务器端保持一致
|
||||
func PostFile(filename, fieldname string, targetUrl string) (e error, result string) {
|
||||
func PostFile(filename, fieldname, targetURL string) (result string, e error) {
|
||||
bodyBuf := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||
|
||||
@@ -114,19 +113,19 @@ func PostFile(filename, fieldname string, targetUrl string) (e error, result str
|
||||
contentType := bodyWriter.FormDataContentType()
|
||||
bodyWriter.Close()
|
||||
|
||||
resp, err := http.Post(targetUrl, contentType, bodyBuf)
|
||||
resp, err := http.Post(targetURL, contentType, bodyBuf)
|
||||
if err != nil {
|
||||
e = err
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
resp_body, err := ioutil.ReadAll(resp.Body)
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
e = err
|
||||
return
|
||||
}
|
||||
fmt.Println(resp.Status)
|
||||
fmt.Println(string(resp_body))
|
||||
result = string(resp_body)
|
||||
fmt.Println(string(respBody))
|
||||
result = string(respBody)
|
||||
return
|
||||
}
|
||||
|
@@ -5,14 +5,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"public/mylog"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
//发送修改密码
|
||||
func OnPostJson(url, jsonstr string) []byte {
|
||||
//OnPostJSON 发送修改密码
|
||||
func OnPostJSON(url, jsonstr string) []byte {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
body := bytes.NewBuffer([]byte(jsonstr))
|
||||
resp, err := http.Post(url, "application/json;charset=utf-8", body)
|
||||
@@ -22,14 +22,15 @@ func OnPostJson(url, jsonstr string) []byte {
|
||||
defer resp.Body.Close()
|
||||
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||
if err1 != nil {
|
||||
mylog.Error(err1)
|
||||
return []byte("")
|
||||
}
|
||||
|
||||
return body1
|
||||
}
|
||||
|
||||
//发送get 请求
|
||||
func OnGetJson(url, params string) string {
|
||||
//OnGetJSON 发送get 请求
|
||||
func OnGetJSON(url, params string) string {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
var urls = url
|
||||
if len(params) > 0 {
|
||||
@@ -42,13 +43,14 @@ func OnGetJson(url, params string) string {
|
||||
defer resp.Body.Close()
|
||||
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||
if err1 != nil {
|
||||
mylog.Error(err1)
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(body1)
|
||||
}
|
||||
|
||||
//发送get 请求 返回对象
|
||||
//SendGet 发送get 请求 返回对象
|
||||
func SendGet(url, params string, obj interface{}) bool {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
var urls = url
|
||||
@@ -66,12 +68,17 @@ func SendGet(url, params string, obj interface{}) bool {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
log.Println((string(body)))
|
||||
//log.Println((string(body)))
|
||||
err = json.Unmarshal([]byte(body), &obj)
|
||||
return err == nil
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//发送GET请求
|
||||
//SendGetEx 发送GET请求
|
||||
func SendGetEx(url string, reponse interface{}) bool {
|
||||
resp, e := http.Get(url)
|
||||
if e != nil {
|
||||
@@ -84,12 +91,17 @@ func SendGetEx(url string, reponse interface{}) bool {
|
||||
mylog.Error(e)
|
||||
return false
|
||||
}
|
||||
mylog.Debug(string(body))
|
||||
//mylog.Debug(string(body))
|
||||
err = json.Unmarshal(body, &reponse)
|
||||
return err == nil
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//form 方式发送post请求
|
||||
//OnPostForm form 方式发送post请求
|
||||
func OnPostForm(url string, data url.Values) (body []byte) {
|
||||
resp, err := http.PostForm(url, data)
|
||||
if err != nil {
|
||||
@@ -104,7 +116,7 @@ func OnPostForm(url string, data url.Values) (body []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//SendPost 发送POST请求
|
||||
func SendPost(requestBody interface{}, responseBody interface{}, url string) bool {
|
||||
postData, err := json.Marshal(requestBody)
|
||||
client := &http.Client{}
|
||||
@@ -125,15 +137,20 @@ func SendPost(requestBody interface{}, responseBody interface{}, url string) boo
|
||||
return false
|
||||
}
|
||||
// result := string(body)
|
||||
mylog.Debug(string(body))
|
||||
//mylog.Debug(string(body))
|
||||
|
||||
err = json.Unmarshal(body, &responseBody)
|
||||
return err == nil
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//像指定client 发送json 包
|
||||
//WriteJSON 像指定client 发送json 包
|
||||
//msg message.MessageBody
|
||||
func WriteJson(w http.ResponseWriter, msg interface{}) {
|
||||
func WriteJSON(w http.ResponseWriter, msg interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
js, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
|
10
myi18n/def.go
Normal file
10
myi18n/def.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package myi18n
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
/*
|
||||
Internationalization 国际化
|
||||
*/
|
||||
|
||||
var tr *i18n.Localizer
|
||||
var i18nBundle *i18n.Bundle
|
52
myi18n/myi18n.go
Normal file
52
myi18n/myi18n.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package myi18n
|
||||
|
||||
import (
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ReSet()
|
||||
}
|
||||
|
||||
// SetLocalLG 设置本地语言包 (空 将获取系统值)
|
||||
func SetLocalLG(lg string) {
|
||||
if len(lg) == 0 {
|
||||
lg = tools.GetLocalSystemLang(true)
|
||||
}
|
||||
// return the new localizer that can be used to translate text
|
||||
tr = i18n.NewLocalizer(i18nBundle, lg)
|
||||
}
|
||||
|
||||
// AddMessages 添加语言
|
||||
func AddMessages(tag language.Tag, messages ...*i18n.Message) error {
|
||||
return i18nBundle.AddMessages(tag, messages...)
|
||||
}
|
||||
|
||||
// AddKV 添加语言
|
||||
func AddKV(tag language.Tag, k, v string) error {
|
||||
return i18nBundle.AddMessages(tag, &i18n.Message{
|
||||
ID: k,
|
||||
Other: v,
|
||||
})
|
||||
}
|
||||
|
||||
// ReSet 重置
|
||||
func ReSet() {
|
||||
i18nBundle = i18n.NewBundle(language.English)
|
||||
SetLocalLG("") // default
|
||||
}
|
||||
|
||||
// Get 获取值
|
||||
func Get(Key string) string {
|
||||
if tr != nil {
|
||||
return tr.MustLocalize(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: Key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return Key
|
||||
}
|
@@ -1,24 +1,39 @@
|
||||
package myleveldb
|
||||
|
||||
import (
|
||||
"public/mylog"
|
||||
"public/tools"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
)
|
||||
|
||||
var lock sync.Mutex
|
||||
var locks = map[string]*sync.Mutex{}
|
||||
|
||||
type Param struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func OnInitDB(dataSourceName string) MyLevelDB {
|
||||
if _, ok := locks[dataSourceName]; !ok {
|
||||
lock.Lock()
|
||||
if _, ok := locks[dataSourceName]; !ok {
|
||||
locks[dataSourceName] = &sync.Mutex{}
|
||||
}
|
||||
lock.Unlock()
|
||||
}
|
||||
|
||||
locks[dataSourceName].Lock()
|
||||
var L MyLevelDB
|
||||
L.dataSourceName = dataSourceName
|
||||
L.DB, L.E = leveldb.OpenFile(dataSourceName, nil)
|
||||
if L.E != nil {
|
||||
locks[dataSourceName].Unlock()
|
||||
mylog.Error(L.E)
|
||||
}
|
||||
// L.op = &opt.ReadOptions{
|
||||
@@ -29,8 +44,9 @@ func OnInitDB(dataSourceName string) MyLevelDB {
|
||||
}
|
||||
|
||||
type MyLevelDB struct {
|
||||
DB *leveldb.DB
|
||||
E error
|
||||
DB *leveldb.DB
|
||||
E error
|
||||
dataSourceName string
|
||||
//op *opt.ReadOptions
|
||||
Value interface{}
|
||||
}
|
||||
@@ -39,6 +55,7 @@ func (L *MyLevelDB) OnDestoryDB() {
|
||||
if L.DB != nil {
|
||||
L.DB.Close()
|
||||
L.DB = nil
|
||||
locks[L.dataSourceName].Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
BIN
mylog/.DS_Store
vendored
Normal file
BIN
mylog/.DS_Store
vendored
Normal file
Binary file not shown.
122
mylog/myeslog.go
122
mylog/myeslog.go
@@ -1,122 +0,0 @@
|
||||
package mylog
|
||||
|
||||
import (
|
||||
"data/config"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"public/myelastic"
|
||||
"public/myqueue"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ptr_que *myqueue.MyQueue = nil
|
||||
var elastic myelastic.MyElastic
|
||||
var isSaveFile bool = true //默认存文件
|
||||
var isSaveToEs bool = false //默认不保存
|
||||
var local_Log_file string = "log" //默认存放文件的目录
|
||||
var exe_path string
|
||||
|
||||
func init() {
|
||||
if config.IsRunTesting() { //测试时候不创建
|
||||
return
|
||||
}
|
||||
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
exe_path = filepath.Dir(path)
|
||||
|
||||
BuildDir(local_Log_file)
|
||||
ptr_que = myqueue.NewSyncQueue()
|
||||
es_path := config.GetEsAddrUrl()
|
||||
if len(es_path) > 0 {
|
||||
elastic = myelastic.OnInitES(es_path)
|
||||
elastic.CreateIndex(Http_log_index, mapping)
|
||||
}
|
||||
go onConsumerLog()
|
||||
}
|
||||
|
||||
/*
|
||||
发送日志请求
|
||||
*/
|
||||
func OnLog(es_index, es_type, es_id string, data LogInfo) {
|
||||
// local, _ := time.LoadLocation("Local")
|
||||
// data.Creat_time = time.Now().In(local)
|
||||
b, err := json.Marshal(data.Data)
|
||||
if err != nil {
|
||||
log.Println("OnLog error:", err)
|
||||
}
|
||||
data.Data = string(b)
|
||||
var info EsLogInfo
|
||||
info.Es_index = es_index
|
||||
info.Es_type = es_type
|
||||
info.Es_id = es_id
|
||||
info.Info = data
|
||||
|
||||
ptr_que.Push(info) //加入日志队列
|
||||
}
|
||||
|
||||
/*
|
||||
更新本地存储文件地址
|
||||
isSave:是否本地存储
|
||||
LogFile:本地存储相对程序位置(log/ ==> 当前可执行文件的 log/目录)
|
||||
*/
|
||||
func InitLogFileInfo(isSave, isSaveEs bool, LogFile string) {
|
||||
isSaveFile = isSave
|
||||
isSaveToEs = isSaveEs
|
||||
local_Log_file = LogFile
|
||||
if isSave {
|
||||
BuildDir(local_Log_file)
|
||||
}
|
||||
}
|
||||
|
||||
func BuildDir(logfile string) {
|
||||
os.MkdirAll(exe_path+"/"+logfile, os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
/*
|
||||
消费者 消费日志
|
||||
*/
|
||||
func onConsumerLog() {
|
||||
for {
|
||||
var info EsLogInfo
|
||||
info = ptr_que.Pop().(EsLogInfo)
|
||||
|
||||
if isSaveToEs && elastic.Client != nil {
|
||||
if !elastic.Add(info.Es_index, info.Es_type, info.Es_id, info.Info) {
|
||||
log.Println("elastic add error ")
|
||||
}
|
||||
}
|
||||
|
||||
if isSaveFile {
|
||||
saveLogTofile(info)
|
||||
}
|
||||
Debug(info)
|
||||
}
|
||||
}
|
||||
|
||||
var _f *os.File
|
||||
var _err error
|
||||
var saveFaile string
|
||||
|
||||
func saveLogTofile(info EsLogInfo) {
|
||||
|
||||
time_str := time.Now().Format("2006-01-02-15") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/%s/%s.log", exe_path, local_Log_file, time_str)
|
||||
if saveFaile != fname {
|
||||
if _f != nil {
|
||||
_f.Close()
|
||||
}
|
||||
_f, _err = os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
if _err != nil {
|
||||
log.Println(_err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(info)
|
||||
_f.WriteString(string(b) + "\r\n") //输出堆栈信息
|
||||
}
|
BIN
mylog/myeslog.go.zip
Normal file
BIN
mylog/myeslog.go.zip
Normal file
Binary file not shown.
@@ -1,21 +1,25 @@
|
||||
package mylog
|
||||
|
||||
import (
|
||||
"data/config"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/xxjwxc/public/dev"
|
||||
"github.com/xxjwxc/public/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
path = filepath.Dir(path)
|
||||
os.MkdirAll(path+"/err", os.ModePerm) //生成多级目录
|
||||
var _logerTuple logerTuple
|
||||
|
||||
type logerTuple struct {
|
||||
once sync.Once
|
||||
_path string
|
||||
}
|
||||
|
||||
const ( //
|
||||
@@ -26,7 +30,7 @@ const ( //
|
||||
|
||||
//
|
||||
func Print(log_level int, describ string) {
|
||||
log.Println(describ)
|
||||
log.Println(color.Info.Render(describ))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -34,12 +38,12 @@ func Print(log_level int, describ string) {
|
||||
func Println(describ ...interface{}) {
|
||||
for _, e := range describ {
|
||||
switch v := e.(type) {
|
||||
case string:
|
||||
log.Println(v)
|
||||
// case string:
|
||||
// log.Println(color.Info.Render(v))
|
||||
case []byte:
|
||||
log.Println(string(v))
|
||||
log.Println(color.Info.Render(string(v)))
|
||||
default:
|
||||
log.Println(v)
|
||||
log.Println(color.Info.Render(v))
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -47,25 +51,43 @@ func Println(describ ...interface{}) {
|
||||
|
||||
//
|
||||
func Info(describ string) {
|
||||
log.Println(describ)
|
||||
log.Println(color.FgGreen.Render(describ))
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
func Error(err error) {
|
||||
log.Println(err)
|
||||
SaveError(err.Error(), "err")
|
||||
err = errors.Cause(err) //获取原始对象
|
||||
log.Println(color.Error.Render(fmt.Sprintf(":Cause:%+v", err)))
|
||||
SaveError(fmt.Sprintf("%+v", err), "err")
|
||||
}
|
||||
|
||||
//打印错误信息
|
||||
func ErrorString(v ...interface{}) {
|
||||
log.Output(2, color.Error.Render(fmt.Sprint(v...)))
|
||||
}
|
||||
|
||||
//Fatal 系统级错误
|
||||
func Fatal(v ...interface{}) {
|
||||
log.Output(2, color.Error.Render(fmt.Sprint(v...)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func initPath() {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
path = filepath.Dir(path)
|
||||
_logerTuple._path = path + "/err"
|
||||
os.MkdirAll(_logerTuple._path, os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
//保存错误信息
|
||||
func SaveError(errstring, flag string) {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
path = filepath.Dir(path)
|
||||
_logerTuple.once.Do(initPath)
|
||||
|
||||
now := time.Now() //获取当前时间
|
||||
time_str := now.Format("2006-01-02_15") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/err/%s_%s.log", path, flag, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||
now := time.Now() //获取当前时间
|
||||
time_str := now.Format("2006-01-02_15") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/%s_%s.log", _logerTuple._path, flag, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||
|
||||
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
@@ -81,21 +103,16 @@ func SaveError(errstring, flag string) {
|
||||
|
||||
//
|
||||
func Debug(describ ...interface{}) {
|
||||
if config.OnIsDev() {
|
||||
if dev.OnIsDev() {
|
||||
for _, e := range describ {
|
||||
switch v := e.(type) {
|
||||
case string:
|
||||
log.Println(v)
|
||||
log.Println(color.Note.Render(v))
|
||||
case []byte:
|
||||
log.Println(string(v))
|
||||
log.Println(color.Note.Render(string(v)))
|
||||
default:
|
||||
log.Println(v)
|
||||
log.Println(color.Note.Render(fmt.Sprintf("%+v", v)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//刷新
|
||||
func Flush() {
|
||||
|
||||
}
|
||||
|
24
mymath/my_test.go
Normal file
24
mymath/my_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package mymath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_order(t *testing.T) {
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
time.Sleep(10 * time.Second)
|
||||
fmt.Println("aaaa")
|
||||
ch <- 123
|
||||
}()
|
||||
|
||||
h := <-ch
|
||||
fmt.Println("bbbb")
|
||||
fmt.Println(h)
|
||||
|
||||
fmt.Println(Gcd(9, 21))
|
||||
fmt.Println(17 * 19)
|
||||
fmt.Println(Lcm(17, 19))
|
||||
}
|
25
mymath/mymath.go
Normal file
25
mymath/mymath.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package mymath
|
||||
|
||||
import "math"
|
||||
|
||||
//Gcd 最大公约数:(辗转相除法)
|
||||
func Gcd(x, y int64) int64 {
|
||||
x = int64(math.Abs(float64(x)))
|
||||
y = int64(math.Abs(float64(y)))
|
||||
|
||||
var tmp int64
|
||||
for {
|
||||
tmp = (x % y)
|
||||
if tmp > 0 {
|
||||
x = y
|
||||
y = tmp
|
||||
} else {
|
||||
return y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Lcm 最小公倍数:((x*y)/最大公约数)
|
||||
func Lcm(x, y int64) int64 {
|
||||
return (x * y) / Gcd(x, y)
|
||||
}
|
@@ -1,43 +1,52 @@
|
||||
package myqueue
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"gopkg.in/eapache/queue.v1"
|
||||
)
|
||||
|
||||
//MyQueue queue
|
||||
type MyQueue struct {
|
||||
lock sync.Mutex
|
||||
sync.Mutex
|
||||
popable *sync.Cond
|
||||
buffer *queue.Queue
|
||||
closed bool
|
||||
count int32
|
||||
}
|
||||
|
||||
// 创建
|
||||
func NewSyncQueue() *MyQueue {
|
||||
//New 创建
|
||||
func New() *MyQueue {
|
||||
ch := &MyQueue{
|
||||
buffer: queue.New(),
|
||||
}
|
||||
ch.popable = sync.NewCond(&ch.lock)
|
||||
ch.popable = sync.NewCond(&ch.Mutex)
|
||||
return ch
|
||||
}
|
||||
|
||||
// 取出队列,(阻塞模式)
|
||||
//Pop 取出队列,(阻塞模式)
|
||||
func (q *MyQueue) Pop() (v interface{}) {
|
||||
c := q.popable
|
||||
buffer := q.buffer
|
||||
|
||||
q.lock.Lock()
|
||||
for buffer.Length() == 0 && !q.closed {
|
||||
q.Mutex.Lock()
|
||||
defer q.Mutex.Unlock()
|
||||
|
||||
for q.Len() == 0 && !q.closed {
|
||||
c.Wait()
|
||||
}
|
||||
|
||||
if buffer.Length() > 0 {
|
||||
v = buffer.Peek()
|
||||
buffer.Remove()
|
||||
if q.closed { //已关闭
|
||||
return
|
||||
}
|
||||
|
||||
q.lock.Unlock()
|
||||
if q.Len() > 0 {
|
||||
v = buffer.Peek()
|
||||
buffer.Remove()
|
||||
atomic.AddInt32(&q.count, -1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,45 +54,56 @@ func (q *MyQueue) Pop() (v interface{}) {
|
||||
func (q *MyQueue) TryPop() (v interface{}, ok bool) {
|
||||
buffer := q.buffer
|
||||
|
||||
q.lock.Lock()
|
||||
q.Mutex.Lock()
|
||||
defer q.Mutex.Unlock()
|
||||
|
||||
if buffer.Length() > 0 {
|
||||
if q.Len() > 0 {
|
||||
v = buffer.Peek()
|
||||
buffer.Remove()
|
||||
atomic.AddInt32(&q.count, -1)
|
||||
ok = true
|
||||
} else if q.closed {
|
||||
ok = true
|
||||
}
|
||||
|
||||
q.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// 插入队列,非阻塞
|
||||
func (q *MyQueue) Push(v interface{}) {
|
||||
q.lock.Lock()
|
||||
q.Mutex.Lock()
|
||||
defer q.Mutex.Unlock()
|
||||
if !q.closed {
|
||||
q.buffer.Add(v)
|
||||
atomic.AddInt32(&q.count, 1)
|
||||
q.popable.Signal()
|
||||
}
|
||||
q.lock.Unlock()
|
||||
}
|
||||
|
||||
// 获取队列长度
|
||||
func (q *MyQueue) Len() (l int) {
|
||||
q.lock.Lock()
|
||||
l = q.buffer.Length()
|
||||
q.lock.Unlock()
|
||||
return
|
||||
func (q *MyQueue) Len() int {
|
||||
return (int)(atomic.LoadInt32(&q.count))
|
||||
}
|
||||
|
||||
// Close MyQueue
|
||||
// After close, Pop will return nil without block, and TryPop will return v=nil, ok=True
|
||||
func (q *MyQueue) Close() {
|
||||
q.lock.Lock()
|
||||
q.Mutex.Lock()
|
||||
defer q.Mutex.Unlock()
|
||||
if !q.closed {
|
||||
q.closed = true
|
||||
q.popable.Signal()
|
||||
atomic.StoreInt32(&q.count, 0)
|
||||
q.popable.Broadcast() //广播
|
||||
}
|
||||
}
|
||||
|
||||
//Wait 等待队列消费完成
|
||||
func (q *MyQueue) Wait() {
|
||||
for {
|
||||
if q.closed || q.Len() == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
runtime.Gosched() //出让时间片
|
||||
}
|
||||
q.lock.Unlock()
|
||||
}
|
||||
|
105
myqueue/myqueue_test.go
Normal file
105
myqueue/myqueue_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package myqueue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWait(t *testing.T) {
|
||||
que := New()
|
||||
for i := 0; i < 10; i++ { //开启20个请求
|
||||
que.Push(i)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
fmt.Println(que.Pop().(int))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
fmt.Println(que.Pop().(int))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
que.Wait()
|
||||
fmt.Println("down")
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
que := New()
|
||||
for i := 0; i < 10; i++ { //开启20个请求
|
||||
que.Push(i)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v := que.Pop()
|
||||
if v != nil {
|
||||
fmt.Println(v.(int))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v := que.Pop()
|
||||
if v != nil {
|
||||
fmt.Println(v.(int))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
que.Close()
|
||||
que.Wait()
|
||||
fmt.Println("down")
|
||||
}
|
||||
|
||||
func TestTry(t *testing.T) {
|
||||
que := New()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v, ok := que.TryPop()
|
||||
if !ok {
|
||||
fmt.Println("no")
|
||||
time.Sleep(time.Second / 2)
|
||||
runtime.Gosched() //出让时间片
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
fmt.Println(v.(int))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v, ok := que.TryPop()
|
||||
if !ok {
|
||||
fmt.Println("no")
|
||||
time.Sleep(time.Second / 2)
|
||||
runtime.Gosched() //出让时间片
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
fmt.Println(v.(int))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 10; i++ { //开启20个请求
|
||||
que.Push(i)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
que.Wait()
|
||||
fmt.Println("down")
|
||||
}
|
31
myreflect/myreflect.go
Normal file
31
myreflect/myreflect.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package myreflect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FindTag find struct of tag string.查找struct 的tag信息
|
||||
func FindTag(obj interface{}, field, tag string) string {
|
||||
dataStructType := reflect.Indirect(reflect.ValueOf(obj)).Type()
|
||||
for i := 0; i < dataStructType.NumField(); i++ {
|
||||
fd := dataStructType.Field(i)
|
||||
if fd.Name == field {
|
||||
bb := fd.Tag
|
||||
sqlTag := bb.Get(tag)
|
||||
|
||||
if sqlTag == "-" || bb == "-" {
|
||||
return ""
|
||||
}
|
||||
|
||||
sqlTags := strings.Split(sqlTag, ",")
|
||||
sqlFieldName := fd.Name // default
|
||||
if len(sqlTags[0]) > 0 {
|
||||
sqlFieldName = sqlTags[0]
|
||||
}
|
||||
return sqlFieldName
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
18
myreflect/myreflect_test.go
Normal file
18
myreflect/myreflect_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package myreflect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ReqTest1 struct {
|
||||
AccessToken string `json:"access_token"` // access_token
|
||||
UserName string `json:"user_name" binding:"required"` // user name
|
||||
Password string `json:"password"` // password
|
||||
}
|
||||
|
||||
func TestJson(t *testing.T) {
|
||||
var ts ReqTest1
|
||||
ts.UserName = `1111`
|
||||
fmt.Println(FindTag(ts, "UserName", "json"))
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package myrunner
|
||||
|
||||
import "errors"
|
||||
import "github.com/xxjwxc/public/errors"
|
||||
|
||||
//任务执行超时
|
||||
var ErrTimeOut = errors.New("run time out")
|
||||
|
@@ -1,24 +0,0 @@
|
||||
package mysign
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
_sign_data = "_sign_data"
|
||||
)
|
||||
|
||||
//签名地址
|
||||
type Sign_client_tbl struct {
|
||||
Id int `gorm:"primary_key"`
|
||||
App_key string //key
|
||||
App_secret string //secret
|
||||
Expire_time time.Time //超时时间
|
||||
Strict_sign int //是否强制验签:0:用户自定义,1:强制
|
||||
Strict_verify int //是否强制验证:0:用户自定义,1:强制
|
||||
Token_expire_time int //token过期时间
|
||||
}
|
||||
|
||||
//签名必须带的头标记
|
||||
type Sing_head struct {
|
||||
Appid string `json:"appid,omitempty"` //appid
|
||||
Signature string `json:"signature,omitempty"` //签名
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
package mysign
|
||||
|
||||
import (
|
||||
"data/config"
|
||||
"public/mycache"
|
||||
"public/mylog"
|
||||
"public/mysqldb"
|
||||
"public/tools"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
OnInit()
|
||||
}
|
||||
|
||||
func OnInit() {
|
||||
str_db := config.GetDbUrl()
|
||||
//fmt.Println("dddddddddddddd:", str_db)
|
||||
if len(str_db) > 0 {
|
||||
var db mysqldb.MySqlDB
|
||||
defer db.OnDestoryDB()
|
||||
orm := db.OnGetDBOrm(str_db)
|
||||
if orm.HasTable(&Sign_client_tbl{}) { //有这个表
|
||||
now := time.Now()
|
||||
var list []Sign_client_tbl
|
||||
err := orm.Where("expire_time > ?", now).Find(&list).Error
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return
|
||||
}
|
||||
cache := mycache.OnGetCache(_sign_data)
|
||||
for _, v := range list { //保存数据到缓存
|
||||
cache.Add(v.App_key, v, v.Expire_time.Sub(now))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetOne(appKey string) (sign Sign_client_tbl) {
|
||||
cache := mycache.OnGetCache(_sign_data)
|
||||
tp, b := cache.Value(appKey)
|
||||
if b {
|
||||
sign = tp.(Sign_client_tbl)
|
||||
} else {
|
||||
str_db := config.GetDbUrl()
|
||||
if len(str_db) > 0 {
|
||||
var db mysqldb.MySqlDB
|
||||
defer db.OnDestoryDB()
|
||||
orm := db.OnGetDBOrm(str_db)
|
||||
if orm.HasTable(&Sign_client_tbl{}) { //有这个表
|
||||
now := time.Now()
|
||||
err := orm.Where("app_key = ? and expire_time > ?", appKey, now).Find(&sign).Error
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return
|
||||
}
|
||||
cache := mycache.OnGetCache(_sign_data)
|
||||
cache.Add(sign.App_key, sign, sign.Expire_time.Sub(now))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
生成验签
|
||||
*/
|
||||
func OnGetSign(appkey string, parm ...interface{}) string {
|
||||
var sign Sign_client_tbl
|
||||
if len(appkey) > 0 {
|
||||
sign = GetOne(appkey)
|
||||
}
|
||||
//是否强制验证码
|
||||
if sign.Id == 0 || sign.Strict_sign == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
//开始验签
|
||||
var strKey string
|
||||
for _, v := range parm {
|
||||
strKey += tools.AsString(v)
|
||||
}
|
||||
|
||||
mylog.Debug("strKey:" + strKey)
|
||||
mylog.Debug("md5:", tools.Md5Encoder(strKey))
|
||||
return tools.Md5Encoder(strKey)
|
||||
}
|
||||
|
||||
/*
|
||||
开始验签
|
||||
*/
|
||||
func OnCheckSign(appkey, signature string, parm ...interface{}) bool {
|
||||
return strings.EqualFold(signature, OnGetSign(appkey, parm...))
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package mysign
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"public/message"
|
||||
"public/tools"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_sing(t *testing.T) {
|
||||
now := time.Now()
|
||||
str := "1" + tools.GetTimeString(now)
|
||||
str += "1.0001"
|
||||
fmt.Println(str)
|
||||
ttt := tools.Md5Encoder(str)
|
||||
fmt.Println(ttt)
|
||||
fmt.Println(OnCheckSign("wwwthings", ttt, 1, now, 1.0001))
|
||||
fmt.Println(message.GetSuccessMsg())
|
||||
}
|
@@ -2,7 +2,8 @@ package mysqldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"public/mylog"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
@@ -1,36 +1,24 @@
|
||||
/*
|
||||
orm := db.OnCreatDB()
|
||||
var sum int64 = 0
|
||||
for {
|
||||
sum++
|
||||
var user User_account_tbl
|
||||
user.Id = sum
|
||||
|
||||
orm.SetTable("user_account_tbls")
|
||||
err := orm.Where("id=?", sum).Find(&user)
|
||||
if err != nil {
|
||||
log.Println("-----------:", err)
|
||||
} else {
|
||||
log.Println(user)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
*/
|
||||
package mysqldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"public/mylog"
|
||||
"github.com/xxjwxc/public/dev"
|
||||
"github.com/xxjwxc/public/errors"
|
||||
|
||||
"data/config"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
type MySqlDB struct {
|
||||
DB *gorm.DB
|
||||
*gorm.DB
|
||||
IsInit bool
|
||||
}
|
||||
|
||||
func OnInitDBOrm(dataSourceName string) (orm *MySqlDB) {
|
||||
orm = new(MySqlDB)
|
||||
orm.OnGetDBOrm(dataSourceName)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *MySqlDB) OnGetDBOrm(dataSourceName string) (orm *gorm.DB) {
|
||||
@@ -38,19 +26,20 @@ func (i *MySqlDB) OnGetDBOrm(dataSourceName string) (orm *gorm.DB) {
|
||||
var err error
|
||||
i.DB, err = gorm.Open("mysql", dataSourceName)
|
||||
if err != nil {
|
||||
mylog.Print(mylog.Log_Error, fmt.Sprintf("Got error when connect database, the error is '%v'", err))
|
||||
mylog.Error(errors.Wrap(err, "Got error when connect database:"+dataSourceName))
|
||||
return nil
|
||||
}
|
||||
i.IsInit = true
|
||||
}
|
||||
|
||||
i.DB.SingularTable(true) //全局禁用表名复数
|
||||
orm = i.DB
|
||||
|
||||
if config.OnIsDev() {
|
||||
orm.LogMode(true)
|
||||
if dev.OnIsDev() {
|
||||
i.DB.LogMode(true)
|
||||
//beedb.OnDebug = true
|
||||
} else {
|
||||
orm.SetLogger(DbLog{})
|
||||
i.DB.SetLogger(DbLog{})
|
||||
}
|
||||
orm = i.DB
|
||||
return
|
||||
}
|
||||
|
||||
@@ -60,7 +49,3 @@ func (i *MySqlDB) OnDestoryDB() {
|
||||
i.DB = nil
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
BIN
server/.DS_Store
vendored
Normal file
BIN
server/.DS_Store
vendored
Normal file
Binary file not shown.
110
server/server.go
110
server/server.go
@@ -5,28 +5,48 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"data/config"
|
||||
"github.com/xxjwxc/public/dev"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/jander/golog/logger"
|
||||
"github.com/kardianos/service"
|
||||
)
|
||||
|
||||
func OnStart(callBack func()) {
|
||||
name, displayName, desc := config.GetServiceConfig()
|
||||
type Service struct {
|
||||
name string
|
||||
displayName string
|
||||
desc string
|
||||
}
|
||||
|
||||
func On(n, dn, d string) *Service {
|
||||
return &Service{
|
||||
name: n,
|
||||
displayName: dn,
|
||||
desc: d,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (sv *Service) Start(callBack func()) {
|
||||
if len(sv.name) == 0 {
|
||||
fmt.Println(color.Error.Render("Service init faild,must first call On."))
|
||||
return
|
||||
}
|
||||
//name, displayName, desc := config.GetServiceConfig()
|
||||
p := &program{callBack}
|
||||
sc := &service.Config{
|
||||
Name: name,
|
||||
DisplayName: displayName,
|
||||
Description: desc,
|
||||
Name: sv.name,
|
||||
DisplayName: sv.displayName,
|
||||
Description: sv.desc,
|
||||
}
|
||||
s, err := service.New(p, sc)
|
||||
//var s, err = service.NewService(name, displayName, desc)
|
||||
if err != nil {
|
||||
fmt.Printf("%s unable to start: %s", displayName, err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("%s unable to start: %s", sv.displayName, err)))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Service \"%s\" do.\n", displayName)
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" do.\n", sv.displayName)))
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
var err error
|
||||
@@ -36,82 +56,94 @@ func OnStart(callBack func()) {
|
||||
{
|
||||
err = s.Install()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to install: %s\n", err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to install: %s\n", err)))
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" installed.\n", displayName)
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" installed.\n", sv.displayName)))
|
||||
}
|
||||
case "remove":
|
||||
{
|
||||
err = s.Uninstall()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to remove: %s\n", err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to remove: %s\n", err)))
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" removed.\n", displayName)
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" removed.\n", sv.displayName)))
|
||||
}
|
||||
case "run":
|
||||
{
|
||||
err = s.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to run: %s\n", err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to run: %s\n", err)))
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" run.\n", displayName)
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" run.\n", sv.displayName)))
|
||||
}
|
||||
case "debug":
|
||||
{
|
||||
dev.OnSetDev(true)
|
||||
err = s.Run()
|
||||
if err != nil {
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to debug: %s\n", err)))
|
||||
return
|
||||
}
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" run.\n", sv.displayName)))
|
||||
}
|
||||
case "start":
|
||||
{
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to start: %s\n", err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to start: %s\n", err)))
|
||||
return
|
||||
}
|
||||
fmt.Println("starting check service:", displayName)
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("starting check service:%v\n", sv.displayName)))
|
||||
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
<-ticker.C
|
||||
|
||||
st, err := IsStart(name)
|
||||
var sit ServiceTools
|
||||
st, err := sit.IsStart(sv.name)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
color.Error.Render(err)
|
||||
return
|
||||
} else {
|
||||
if st == Stopped || st == StopPending {
|
||||
fmt.Printf("Service \"%s\" is Stopped.\n", displayName)
|
||||
fmt.Println("can't to start service.")
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf("Service \"%s\" started.\n", displayName)
|
||||
|
||||
if st == Stopped || st == StopPending {
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Service \"%s\" is Stopped.\n", sv.displayName)))
|
||||
fmt.Print(color.Error.Render("can't to start service."))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" started.\n", sv.displayName)))
|
||||
}
|
||||
case "stop":
|
||||
{
|
||||
err = s.Stop()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to stop: %s\n", err)
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Failed to stop: %s\n", err)))
|
||||
return
|
||||
}
|
||||
|
||||
st, err := IsStart(name)
|
||||
var sit ServiceTools
|
||||
st, err := sit.IsStart(sv.name)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
} else {
|
||||
if st == Running || st == StartPending {
|
||||
fmt.Printf("Service \"%s\" is Started.\n", displayName)
|
||||
fmt.Println("can't to stop service.")
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Printf("Service \"%s\" stopped.\n", displayName)
|
||||
|
||||
if st == Running || st == StartPending {
|
||||
fmt.Print(color.Error.Render(fmt.Sprintf("Service \"%s\" is Started.\n", sv.displayName)))
|
||||
fmt.Print(color.Error.Render("can't to stop service."))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Print(color.Info.Render(fmt.Sprintf("Service \"%s\" stopped.\n", sv.displayName)))
|
||||
}
|
||||
}
|
||||
return
|
||||
} else {
|
||||
fmt.Print("Failed to read args\n")
|
||||
//return
|
||||
}
|
||||
|
||||
fmt.Print(color.Note.Render("Failed to read args\n"))
|
||||
|
||||
if err = s.Run(); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
@@ -132,6 +164,6 @@ func (p *program) Stop(s service.Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServiceTools interface {
|
||||
type IServiceTools interface {
|
||||
IsStart(name string) (status int, err error)
|
||||
}
|
||||
|
10
server/server_darwin.go
Normal file
10
server/server_darwin.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package server
|
||||
|
||||
type ServiceTools struct {
|
||||
//i IServiceTools
|
||||
}
|
||||
|
||||
func (s *ServiceTools) IsStart(name string) (st int, err error) {
|
||||
st = NOTFIND
|
||||
return
|
||||
}
|
@@ -6,11 +6,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type WindowsServiceTools struct {
|
||||
i ServiceTools
|
||||
type ServiceTools struct {
|
||||
//i IServiceTools
|
||||
}
|
||||
|
||||
func IsStart(name string) (st int, err error) {
|
||||
func (s *ServiceTools) IsStart(name string) (st int, err error) {
|
||||
f, _ := exec.Command("service", name, "status").Output()
|
||||
|
||||
st = NOTFIND
|
||||
|
14
server/server_test.go
Normal file
14
server/server_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func CallBack() {
|
||||
fmt.Println("aa")
|
||||
}
|
||||
|
||||
func TestDomain(t *testing.T) {
|
||||
On("n", "dn", "d").Start(CallBack)
|
||||
}
|
@@ -5,11 +5,11 @@ import (
|
||||
"github.com/btcsuite/winsvc/svc"
|
||||
)
|
||||
|
||||
type WindowsServiceTools struct {
|
||||
i ServiceTools
|
||||
type ServiceTools struct {
|
||||
//i IServiceTools
|
||||
}
|
||||
|
||||
func IsStart(name string) (st int, err error) {
|
||||
func (s *ServiceTools) IsStart(name string) (st int, err error) {
|
||||
var m *mgr.Mgr
|
||||
m, err = mgr.Connect()
|
||||
if err != nil {
|
||||
@@ -17,14 +17,14 @@ func IsStart(name string) (st int, err error) {
|
||||
}
|
||||
defer m.Disconnect()
|
||||
|
||||
s, err := m.OpenService(name)
|
||||
sv, err := m.OpenService(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer s.Close()
|
||||
defer sv.Close()
|
||||
|
||||
var ss svc.Status
|
||||
ss, err = s.Query()
|
||||
ss, err = sv.Query()
|
||||
st = int(ss.State)
|
||||
return
|
||||
}
|
||||
|
@@ -2,9 +2,11 @@ package timerDeal
|
||||
|
||||
import (
|
||||
"log"
|
||||
"public/mydef"
|
||||
"public/mylog"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/mydef"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
//检测参数
|
||||
// CheckParam 检测参数
|
||||
func CheckParam(params ...string) bool {
|
||||
for _, value := range params {
|
||||
if len(value) == 0 {
|
||||
@@ -17,14 +17,14 @@ func CheckParam(params ...string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//判断是否是手机号
|
||||
// IsPhone 判断是否是手机号
|
||||
func IsPhone(mobileNum string) bool {
|
||||
tmp := `^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$`
|
||||
reg := regexp.MustCompile(tmp)
|
||||
return reg.MatchString(mobileNum)
|
||||
}
|
||||
|
||||
//判断用户是否是邮件用户
|
||||
// IsMail 判断用户是否是邮件用户
|
||||
func IsMail(username string) (isMail bool) {
|
||||
isMail = false
|
||||
if strings.Contains(username, "@") {
|
||||
@@ -33,7 +33,7 @@ func IsMail(username string) (isMail bool) {
|
||||
return
|
||||
}
|
||||
|
||||
//判断是否在测试环境下使用
|
||||
// IsRunTesting 判断是否在测试环境下使用
|
||||
func IsRunTesting() bool {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Println(os.Args[1])
|
||||
@@ -42,7 +42,7 @@ func IsRunTesting() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
//判断是否是18或15位身份证
|
||||
// IsIdCard 判断是否是18或15位身份证
|
||||
func IsIdCard(cardNo string) bool {
|
||||
//18位身份证 ^(\d{17})([0-9]|X)$
|
||||
if m, _ := regexp.MatchString(`(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)`, cardNo); !m {
|
||||
@@ -50,3 +50,17 @@ func IsIdCard(cardNo string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var internalType = []string{"string", "bool", "int", "uint", "byte", "rune",
|
||||
"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "uintptr",
|
||||
"float32", "float64", "map", "Time"}
|
||||
|
||||
// IsInternalType 是否是内部类型
|
||||
func IsInternalType(t string) bool {
|
||||
for _, v := range internalType {
|
||||
if strings.EqualFold(t, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@@ -4,13 +4,15 @@ import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"public/mylog"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/errors"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
type RawBytes []byte
|
||||
|
100
tools/file.go
100
tools/file.go
@@ -1,14 +1,19 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"public/mylog"
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
//检查目录是否存在
|
||||
// CheckFileIsExist 检查目录是否存在
|
||||
func CheckFileIsExist(filename string) bool {
|
||||
var exist = true
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
@@ -18,20 +23,20 @@ func CheckFileIsExist(filename string) bool {
|
||||
return exist
|
||||
}
|
||||
|
||||
//创建目录
|
||||
func BuildDir(abs_dir string) error {
|
||||
return os.MkdirAll(abs_dir, os.ModePerm) //生成多级目录
|
||||
// BuildDir 创建目录
|
||||
func BuildDir(absDir string) error {
|
||||
return os.MkdirAll(path.Dir(absDir), os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
//删除文件或文件夹
|
||||
func DeleteFile(abs_dir string) error {
|
||||
return os.RemoveAll(abs_dir)
|
||||
// DeleteFile 删除文件或文件夹
|
||||
func DeleteFile(absDir string) error {
|
||||
return os.RemoveAll(absDir)
|
||||
}
|
||||
|
||||
//获取目录所有文件夹
|
||||
func GetPathDirs(abs_dir string) (re []string) {
|
||||
if CheckFileIsExist(abs_dir) {
|
||||
files, _ := ioutil.ReadDir(abs_dir)
|
||||
// GetPathDirs 获取目录所有文件夹
|
||||
func GetPathDirs(absDir string) (re []string) {
|
||||
if CheckFileIsExist(absDir) {
|
||||
files, _ := ioutil.ReadDir(absDir)
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
re = append(re, f.Name())
|
||||
@@ -41,10 +46,10 @@ func GetPathDirs(abs_dir string) (re []string) {
|
||||
return
|
||||
}
|
||||
|
||||
//获取目录所有文件夹
|
||||
func GetPathFiles(abs_dir string) (re []string) {
|
||||
if CheckFileIsExist(abs_dir) {
|
||||
files, _ := ioutil.ReadDir(abs_dir)
|
||||
// GetPathFiles 获取目录所有文件
|
||||
func GetPathFiles(absDir string) (re []string) {
|
||||
if CheckFileIsExist(absDir) {
|
||||
files, _ := ioutil.ReadDir(absDir)
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
re = append(re, f.Name())
|
||||
@@ -54,13 +59,64 @@ func GetPathFiles(abs_dir string) (re []string) {
|
||||
return
|
||||
}
|
||||
|
||||
//获取目录地址
|
||||
// GetModelPath 获取目录地址
|
||||
func GetModelPath() string {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path, _ := filepath.Abs(file)
|
||||
// if len(path) > 0 {
|
||||
// path += "/"
|
||||
// }
|
||||
path = filepath.Dir(path)
|
||||
path := filepath.Dir(file)
|
||||
path, _ = filepath.Abs(path)
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// GetCurrentDirectory 获取程序运行路径
|
||||
func GetCurrentDirectory() string {
|
||||
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
return strings.Replace(dir, "\\", "/", -1)
|
||||
}
|
||||
|
||||
// SaveToFile 写入文件
|
||||
func SaveToFile(fname string, src []string, isClear bool) bool {
|
||||
return WriteFile(fname, src, isClear)
|
||||
}
|
||||
|
||||
// WriteFile 写入文件
|
||||
func WriteFile(fname string, src []string, isClear bool) bool {
|
||||
BuildDir(fname)
|
||||
flag := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
|
||||
if !isClear {
|
||||
flag = os.O_CREATE | os.O_RDWR | os.O_APPEND
|
||||
}
|
||||
f, err := os.OpenFile(fname, flag, 0666)
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range src {
|
||||
f.WriteString(v)
|
||||
f.WriteString("\r\n")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadFile 读取文件
|
||||
func ReadFile(fname string) (src []string) {
|
||||
f, err := os.OpenFile(fname, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
rd := bufio.NewReader(f)
|
||||
for {
|
||||
line, _, err := rd.ReadLine()
|
||||
if err != nil || io.EOF == err {
|
||||
break
|
||||
}
|
||||
src = append(src, string(line))
|
||||
}
|
||||
|
||||
return src
|
||||
}
|
||||
|
13
tools/ip.go
13
tools/ip.go
@@ -5,8 +5,9 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"public/mylog"
|
||||
"strings"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
///*
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
// return
|
||||
//}
|
||||
|
||||
//获取公网IP地址
|
||||
// GetWwwIP 获取公网IP地址
|
||||
func GetWwwIP() (exip string) {
|
||||
resp, err := http.Get("http://myexternalip.com/raw")
|
||||
if err != nil {
|
||||
@@ -45,9 +46,7 @@ func GetWwwIP() (exip string) {
|
||||
return string(bytes.TrimSpace(b))
|
||||
}
|
||||
|
||||
/*
|
||||
获取内网ip
|
||||
*/
|
||||
// GetLocalIP 获取内网ip
|
||||
func GetLocalIP() (ip string) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
@@ -65,8 +64,8 @@ func GetLocalIP() (ip string) {
|
||||
return
|
||||
}
|
||||
|
||||
//获取用户ip
|
||||
func GetClientIp(r *http.Request) (ip string) {
|
||||
// GetClientIP 获取用户ip
|
||||
func GetClientIP(r *http.Request) (ip string) {
|
||||
ip = r.Header.Get("X-Real-Ip")
|
||||
if ip == "" {
|
||||
ip = strings.Split(r.RemoteAddr, ":")[0]
|
||||
|
@@ -4,11 +4,10 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/ant0ine/go-json-rest/rest"
|
||||
)
|
||||
|
||||
func JsonToForm(r *http.Request) {
|
||||
// JSONToForm tag json str to form
|
||||
func JSONToForm(r *http.Request) {
|
||||
//添加支持json 操作
|
||||
r.ParseForm()
|
||||
if len(r.Form) == 1 { //可能是json 支持json
|
||||
@@ -26,8 +25,8 @@ func JsonToForm(r *http.Request) {
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(r.Body)
|
||||
body_str := string(body)
|
||||
if len(body_str) > 0 {
|
||||
bodyStr := string(body)
|
||||
if len(bodyStr) > 0 {
|
||||
var m map[string]string
|
||||
if err := json.Unmarshal(body, &m); err == nil {
|
||||
for k, v := range m {
|
||||
@@ -39,30 +38,40 @@ func JsonToForm(r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetRequestJsonObj(r *rest.Request, v interface{}) error {
|
||||
// "github.com/ant0ine/go-json-rest/rest"
|
||||
// func GetRequestJsonObj(r *rest.Request, v interface{}) error {
|
||||
|
||||
//添加支持json 操作
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
json.Unmarshal(body, &v)
|
||||
//-----------------------------end
|
||||
return err
|
||||
}
|
||||
// //添加支持json 操作
|
||||
// body, err := ioutil.ReadAll(r.Body)
|
||||
// r.Body.Close()
|
||||
// json.Unmarshal(body, &v)
|
||||
// //-----------------------------end
|
||||
// return err
|
||||
// }
|
||||
|
||||
func GetJsonStr(obj interface{}) string {
|
||||
b, _ := json.Marshal(obj)
|
||||
// GetJSONStr obj to json string
|
||||
func GetJSONStr(obj interface{}, isFormat bool) string {
|
||||
var b []byte
|
||||
if isFormat {
|
||||
b, _ = json.MarshalIndent(obj, "", " ")
|
||||
} else {
|
||||
b, _ = json.Marshal(obj)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func JsonDecode(obj interface{}) string {
|
||||
return GetJsonStr(obj)
|
||||
// JSONDecode Json Decode
|
||||
func JSONDecode(obj interface{}) string {
|
||||
return GetJSONStr(obj, false)
|
||||
}
|
||||
|
||||
func GetJsonObj(str string, out interface{}) {
|
||||
// GetJSONObj string convert to obj
|
||||
func GetJSONObj(str string, out interface{}) {
|
||||
json.Unmarshal([]byte(str), out)
|
||||
return
|
||||
}
|
||||
|
||||
func JsonEncode(str string, out interface{}) {
|
||||
GetJsonObj(str, out)
|
||||
// JSONEncode string convert to obj
|
||||
func JSONEncode(str string, out interface{}) {
|
||||
GetJSONObj(str, out)
|
||||
}
|
||||
|
36
tools/local.go
Normal file
36
tools/local.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Getenv 获取本地系统变量
|
||||
func Getenv(key string) string {
|
||||
return os.Getenv(key)
|
||||
}
|
||||
|
||||
// GetLocalSystemLang 获取本地语言 (like:zh_CN.UTF-8)(simple:zh)
|
||||
func GetLocalSystemLang(isSimple bool) (locale string) {
|
||||
locale = Getenv("LC_ALL")
|
||||
if locale == "" {
|
||||
locale = Getenv("LANG")
|
||||
}
|
||||
if isSimple {
|
||||
locale, _ = splitLocale(locale)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func splitLocale(locale string) (string, string) {
|
||||
formattedLocale := strings.Split(locale, ".")[0]
|
||||
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)
|
||||
|
||||
pieces := strings.Split(formattedLocale, "_")
|
||||
language := pieces[0]
|
||||
territory := ""
|
||||
if len(pieces) > 1 {
|
||||
territory = strings.Split(formattedLocale, "_")[1]
|
||||
}
|
||||
return language, territory
|
||||
}
|
11
tools/reflect.go
Normal file
11
tools/reflect.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
//获取函数名
|
||||
func GetFuncName(f interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
|
||||
}
|
@@ -50,18 +50,18 @@ func GetTimeWeek(timestamp int64) int {
|
||||
}
|
||||
|
||||
//获取向上整时时间
|
||||
func GetHour0(timestamp int64, timeZone *time.Location) time.Time {
|
||||
func GetHour0(timestamp int64) time.Time {
|
||||
tm := time.Unix(timestamp, 0)
|
||||
tStr := tm.Format("2006-01-02 15") + ":00:00"
|
||||
return StrToTime(tStr, "2006-01-02 15:04:05", timeZone)
|
||||
return StrToTime(tStr, "2006-01-02 15:04:05", nil)
|
||||
}
|
||||
|
||||
//获取给定日期的零点时间
|
||||
func GetDay0(timestamp int64, timeZone *time.Location) time.Time {
|
||||
func GetDay0(timestamp int64) time.Time {
|
||||
tm := time.Unix(timestamp, 0)
|
||||
tStr := tm.Format("2006-01-02") + " 00:00:00"
|
||||
|
||||
return StrToTime(tStr, "2006-01-02 15:04:05", timeZone)
|
||||
return StrToTime(tStr, "2006-01-02 15:04:05", nil)
|
||||
}
|
||||
|
||||
//获取offset 0点时间
|
||||
@@ -92,9 +92,16 @@ func StringTimetoUnix(timestr string) int64 {
|
||||
}
|
||||
|
||||
//获取最近上个星期天的零点日期
|
||||
func GetTimeWeek0(timestamp int64) int64 {
|
||||
func GetWeek0(timestamp int64) time.Time {
|
||||
weekday := GetTimeWeek(timestamp)
|
||||
tm0 := GetDay0(timestamp, nil)
|
||||
tm0 := GetDay0(timestamp)
|
||||
return tm0.AddDate(0, 0, -1*weekday)
|
||||
}
|
||||
|
||||
//获取最近上个星期天的零点日期
|
||||
func GetUtcWeek0(timestamp int64) int64 {
|
||||
weekday := GetTimeWeek(timestamp)
|
||||
tm0 := GetDay0(timestamp)
|
||||
tm0 = tm0.AddDate(0, 0, -1*weekday)
|
||||
|
||||
return tm0.Unix()
|
||||
@@ -105,7 +112,7 @@ func GetTimeWeek0(timestamp int64) int64 {
|
||||
*/
|
||||
func GetMonth0(timestamp int64) time.Time {
|
||||
|
||||
tm0 := GetDay0(timestamp, nil)
|
||||
tm0 := GetDay0(timestamp)
|
||||
month0 := tm0.Day() - 1
|
||||
tm0 = tm0.AddDate(0, 0, -1*month0) //这个月1号
|
||||
return tm0
|
||||
|
@@ -6,31 +6,15 @@ import (
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"public/mylog"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"data/config"
|
||||
|
||||
"github.com/ant0ine/go-json-rest/rest"
|
||||
"github.com/xxjwxc/public/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
获取程序运行路径
|
||||
*/
|
||||
func GetCurrentDirectory() string {
|
||||
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
return strings.Replace(dir, "\\", "/", -1)
|
||||
}
|
||||
|
||||
func Md5Encoder(src string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(src)) // 需要加密的字符串
|
||||
@@ -74,7 +58,7 @@ func UniqueId() string {
|
||||
return GetMd5String(base64.URLEncoding.EncodeToString(b))
|
||||
}
|
||||
|
||||
//删除切片index
|
||||
// DeleteSlice 删除切片index
|
||||
func DeleteSlice(slice interface{}, index int) (interface{}, error) {
|
||||
sliceValue := reflect.ValueOf(slice)
|
||||
length := sliceValue.Len()
|
||||
@@ -99,18 +83,18 @@ func MinimumInt(rest []int) int {
|
||||
return minimum
|
||||
}
|
||||
|
||||
func LoadTemplate(list ...string) *template.Template {
|
||||
var tmp []string
|
||||
for _, v := range list {
|
||||
if CheckFileIsExist(GetModelPath() + config.Static_host[0] + v) {
|
||||
tmp = append(tmp, GetModelPath()+config.Static_host[0]+v)
|
||||
} else {
|
||||
mylog.Debug("file does not exist:" + GetModelPath() + config.Static_host[0] + v)
|
||||
panic(GetModelPath() + config.Static_host[0] + v)
|
||||
}
|
||||
}
|
||||
return template.Must(template.ParseFiles(tmp...))
|
||||
}
|
||||
// func LoadTemplate(list ...string) *template.Template {
|
||||
// var tmp []string
|
||||
// for _, v := range list {
|
||||
// if CheckFileIsExist(GetModelPath() + config.Static_host[0] + v) {
|
||||
// tmp = append(tmp, GetModelPath()+config.Static_host[0]+v)
|
||||
// } else {
|
||||
// mylog.Debug("file does not exist:" + GetModelPath() + config.Static_host[0] + v)
|
||||
// panic(GetModelPath() + config.Static_host[0] + v)
|
||||
// }
|
||||
// }
|
||||
// return template.Must(template.ParseFiles(tmp...))
|
||||
// }
|
||||
|
||||
/*
|
||||
执行模版渲染,
|
||||
@@ -118,16 +102,16 @@ func LoadTemplate(list ...string) *template.Template {
|
||||
data:传参列表
|
||||
list:模版列表
|
||||
*/
|
||||
func ExecuteTemplate(w rest.ResponseWriter, name string, data interface{}, list ...string) error {
|
||||
t := LoadTemplate(list...)
|
||||
w.(http.ResponseWriter).Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
// func ExecuteTemplate(w rest.ResponseWriter, name string, data interface{}, list ...string) error {
|
||||
// t := LoadTemplate(list...)
|
||||
// w.(http.ResponseWriter).Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
|
||||
if len(name) == 0 {
|
||||
return t.Execute(w.(http.ResponseWriter), data)
|
||||
} else {
|
||||
return t.ExecuteTemplate(w.(http.ResponseWriter), name, data)
|
||||
}
|
||||
}
|
||||
// if len(name) == 0 {
|
||||
// return t.Execute(w.(http.ResponseWriter), data)
|
||||
// } else {
|
||||
// return t.ExecuteTemplate(w.(http.ResponseWriter), name, data)
|
||||
// }
|
||||
// }
|
||||
|
||||
//按字典顺序排序
|
||||
func DictSort(res []string) (str string) {
|
||||
|
@@ -4,51 +4,79 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"public/mycache"
|
||||
"public/mylog"
|
||||
"time"
|
||||
|
||||
"github.com/silenceper/wechat"
|
||||
"github.com/bitly/go-simplejson"
|
||||
"github.com/xxjwxc/public/mycache"
|
||||
"github.com/xxjwxc/public/myhttp"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
const (
|
||||
GETTICKETURL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token="
|
||||
GETJSURL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token="
|
||||
_getTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token="
|
||||
_getJsurl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token="
|
||||
_getToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
|
||||
_getSubscribe = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="
|
||||
_cacheToken = "wx_access_token"
|
||||
_cacheTicket = "weixin_card_ticket"
|
||||
)
|
||||
|
||||
//获取微信accesstoken
|
||||
func GetAccessToken() (access_token string, err error) {
|
||||
//先从缓存中获取
|
||||
cache := mycache.OnGetCache("weixin_token")
|
||||
// GetAccessToken 获取微信accesstoken
|
||||
|
||||
//获取登录凭证
|
||||
func GetAccessToken() (accessToken string, err error) {
|
||||
//先从缓存中获取 access_token
|
||||
cache := mycache.OnGetCache(_cacheToken)
|
||||
var tp interface{}
|
||||
tp, b := cache.Value("base")
|
||||
var b bool
|
||||
tp, b = cache.Value(_cacheToken)
|
||||
if b {
|
||||
access_token = tp.(string)
|
||||
accessToken = *(tp.(*string))
|
||||
} else {
|
||||
wc := wechat.NewWechat(&cfg)
|
||||
access_token, err = wc.GetAccessToken()
|
||||
//保存缓存
|
||||
cache.Add("base", access_token, 7000*time.Second)
|
||||
var url = _getToken + wxInfo.AppID + "&secret=" + wxInfo.AppSecret
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//注入client ip
|
||||
js, err := simplejson.NewJson(body)
|
||||
if err == nil {
|
||||
accessToken, _ = js.Get("access_token").String()
|
||||
//保存缓存
|
||||
cache.Add(_cacheToken, &accessToken, time.Duration(7000)*time.Second)
|
||||
//------------------end
|
||||
}
|
||||
//----------------------end
|
||||
}
|
||||
//---------------获取 access_token --------end
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取微信卡券ticket
|
||||
func GetApiTicket() (ticket string, err error) {
|
||||
// GetAPITicket 获取微信卡券ticket
|
||||
func GetAPITicket() (ticket string, err error) {
|
||||
//先从缓存中获取
|
||||
cache := mycache.OnGetCache("weixin_card_ticket")
|
||||
cache := mycache.OnGetCache(_cacheTicket)
|
||||
var tp interface{}
|
||||
tp, b := cache.Value("base")
|
||||
tp, b := cache.Value(_cacheTicket)
|
||||
if b {
|
||||
ticket = tp.(string)
|
||||
} else {
|
||||
access_token, e := GetAccessToken()
|
||||
accessToken, e := GetAccessToken()
|
||||
if e != nil {
|
||||
mylog.Error(e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
var url = GETTICKETURL + access_token
|
||||
var url = _getTicket + accessToken
|
||||
|
||||
resp, e1 := http.Get(url)
|
||||
if e1 != nil {
|
||||
@@ -63,16 +91,16 @@ func GetApiTicket() (ticket string, err error) {
|
||||
err = e2
|
||||
return
|
||||
}
|
||||
var result ApiTicket
|
||||
var result APITicket
|
||||
json.Unmarshal(body, &result)
|
||||
ticket = result.Ticket
|
||||
//保存缓存
|
||||
cache.Add("base", ticket, 7000*time.Second)
|
||||
cache.Add(_cacheTicket, ticket, 7000*time.Second)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//获取微信js ticket
|
||||
// GetJsTicket 获取微信js ticket
|
||||
func GetJsTicket() (ticket string, err error) {
|
||||
//先从缓存中获取
|
||||
cache := mycache.OnGetCache("weixin_js_ticket")
|
||||
@@ -81,13 +109,13 @@ func GetJsTicket() (ticket string, err error) {
|
||||
if b {
|
||||
ticket = tp.(string)
|
||||
} else {
|
||||
access_token, e := GetAccessToken()
|
||||
accessToken, e := GetAccessToken()
|
||||
if e != nil {
|
||||
mylog.Error(e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
var url = GETJSURL + access_token
|
||||
var url = _getJsurl + accessToken
|
||||
|
||||
resp, e1 := http.Get(url)
|
||||
if e1 != nil {
|
||||
@@ -102,7 +130,7 @@ func GetJsTicket() (ticket string, err error) {
|
||||
err = e2
|
||||
return
|
||||
}
|
||||
var result ApiTicket
|
||||
var result APITicket
|
||||
json.Unmarshal(body, &result)
|
||||
ticket = result.Ticket
|
||||
//保存缓存
|
||||
@@ -110,3 +138,19 @@ func GetJsTicket() (ticket string, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 发送订阅消息
|
||||
func SendTemplateMsg(msg TempMsg) bool {
|
||||
accessToken, err := GetAccessToken()
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
bo, _ := json.Marshal(msg)
|
||||
resb := myhttp.OnPostJSON(_getSubscribe+accessToken, string(bo))
|
||||
|
||||
var res ResTempMsg
|
||||
json.Unmarshal(resb, &res)
|
||||
return res.Errcode == 0
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"public/mycache"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/mycache"
|
||||
)
|
||||
|
||||
//Memcache struct contains *memcache.Client
|
||||
// Gocache Memcache struct contains *memcache.Client
|
||||
type Gocache struct {
|
||||
mc *mycache.MyCache
|
||||
}
|
||||
|
@@ -11,9 +11,37 @@ type UserInfo struct {
|
||||
Privilege []string `json:"privilege"`
|
||||
Unionid string `json:"unionid"`
|
||||
}
|
||||
type ApiTicket struct {
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
Ticket string `json:"ticket"`
|
||||
Expires_in int `json:"expires_in"`
|
||||
}
|
||||
|
||||
// APITicket ...
|
||||
type APITicket struct {
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
Ticket string `json:"ticket"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
// WxInfo 微信配置信息
|
||||
type WxInfo struct {
|
||||
AppID string // 微信公众平台应用ID
|
||||
AppSecret string // 微信支付商户平台商户号
|
||||
APIKey string // 微信支付商户平台API密钥
|
||||
MchID string
|
||||
NotifyURL string
|
||||
ShearURL string
|
||||
Token string
|
||||
EncodingAESKey string
|
||||
}
|
||||
|
||||
// TempMsg 订阅消息头
|
||||
type TempMsg struct {
|
||||
Touser string `json:"touser"` // 是 接收者(用户)的 openid
|
||||
TemplateID string `json:"template_id"` // 是 所需下发的模板消息的id
|
||||
Page string `json:"page"` // 否 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
|
||||
Data map[string]map[string]string `json:"data"` //是 模板内容,不填则下发空模板
|
||||
}
|
||||
|
||||
// ResTempMsg 模版消息返回值
|
||||
type ResTempMsg struct {
|
||||
Errcode int `json:"errcode"` //
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
|
@@ -2,24 +2,26 @@ package weixin
|
||||
|
||||
import (
|
||||
"log"
|
||||
"public/tools"
|
||||
|
||||
"github.com/xxjwxc/public/tools"
|
||||
|
||||
wxpay "gopkg.in/go-with/wxpay.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
enterprisePayUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers" // 查询企业付款接口请求URL
|
||||
enterprisePayURL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers" // 查询企业付款接口请求URL
|
||||
)
|
||||
|
||||
// WxEnterprisePay 企业付款
|
||||
/*
|
||||
企业付款
|
||||
open_id:用户唯一标识
|
||||
trade_no : 商户订单号
|
||||
desc : 操作说明
|
||||
amount:付款金额 分
|
||||
企业付款
|
||||
open_id:用户唯一标识
|
||||
trade_no : 商户订单号
|
||||
desc : 操作说明
|
||||
amount:付款金额 分
|
||||
*/
|
||||
func WxEnterprisePay(open_id, trade_no, desc, ipAddr string, amount int) bool {
|
||||
c := wxpay.NewClient(pay_appId, mchId, apiKey)
|
||||
func WxEnterprisePay(openID, tradeNO, desc, ipAddr string, amount int) bool {
|
||||
c := wxpay.NewClient(wxInfo.AppID, wxInfo.MchID, wxInfo.APIKey)
|
||||
|
||||
// 附着商户证书
|
||||
err := c.WithCert(certFile, keyFile, rootcaFile)
|
||||
@@ -28,22 +30,22 @@ func WxEnterprisePay(open_id, trade_no, desc, ipAddr string, amount int) bool {
|
||||
}
|
||||
|
||||
params := make(wxpay.Params)
|
||||
nonce_str := tools.GetRandomString(16)
|
||||
nonceStr := tools.GetRandomString(16)
|
||||
// 查询企业付款接口请求参数
|
||||
params.SetString("mch_appid", c.AppId) //商户账号appid
|
||||
params.SetString("mchid", c.MchId) //商户号
|
||||
params.SetString("nonce_str", nonce_str) // 随机字符串
|
||||
params.SetString("partner_trade_no", trade_no) // 商户订单号
|
||||
params.SetString("openid", open_id) //用户openid
|
||||
params.SetString("check_name", "NO_CHECK") //校验用户姓名选项
|
||||
params.SetInt64("amount", int64(amount)) //企业付款金额,单位为分
|
||||
params.SetString("desc", desc) //企业付款操作说明信息。必填。
|
||||
params.SetString("mch_appid", c.AppId) //商户账号appid
|
||||
params.SetString("mchid", c.MchId) //商户号
|
||||
params.SetString("nonce_str", nonceStr) // 随机字符串
|
||||
params.SetString("partner_trade_no", tradeNO) // 商户订单号
|
||||
params.SetString("openid", openID) //用户openid
|
||||
params.SetString("check_name", "NO_CHECK") //校验用户姓名选项
|
||||
params.SetInt64("amount", int64(amount)) //企业付款金额,单位为分
|
||||
params.SetString("desc", desc) //企业付款操作说明信息。必填。
|
||||
params.SetString("spbill_create_ip", ipAddr)
|
||||
|
||||
params.SetString("sign", c.Sign(params)) // 签名
|
||||
|
||||
// 发送查询企业付款请求
|
||||
ret, err := c.Post(enterprisePayUrl, params, true)
|
||||
ret, err := c.Post(enterprisePayURL, params, true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -52,7 +54,7 @@ func WxEnterprisePay(open_id, trade_no, desc, ipAddr string, amount int) bool {
|
||||
resultCode := ret.GetString("result_code")
|
||||
if returnCode == "SUCCESS" && resultCode == "SUCCESS" {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
package weixin
|
||||
|
||||
import (
|
||||
"data/config"
|
||||
"public/tools"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
|
||||
"github.com/silenceper/wechat"
|
||||
wxpay "gopkg.in/go-with/wxpay.v1"
|
||||
@@ -18,28 +17,15 @@ const (
|
||||
var cfg wechat.Config
|
||||
var client *wxpay.Client
|
||||
|
||||
var pay_appId string // 微信公众平台应用ID
|
||||
var mchId string // 微信支付商户平台商户号
|
||||
var apiKey string // 微信支付商户平台API密钥
|
||||
var secret string
|
||||
var notify_url string
|
||||
var token string
|
||||
var encodingAESKey string
|
||||
var wxInfo WxInfo
|
||||
|
||||
var certFile string // 微信支付商户平台证书路径
|
||||
var keyFile string
|
||||
var rootcaFile string
|
||||
|
||||
func init() {
|
||||
wx_info := config.GetWxInfo()
|
||||
//配置微信支付参数
|
||||
pay_appId = wx_info.AppID
|
||||
mchId = wx_info.MchId
|
||||
apiKey = wx_info.Key
|
||||
secret = wx_info.AppSecret
|
||||
notify_url = wx_info.NotifyUrl
|
||||
token = wx_info.Token
|
||||
encodingAESKey = wx_info.EncodingAESKey
|
||||
// InitWxinfo 初始化配置信息
|
||||
func InitWxinfo(info WxInfo) {
|
||||
wxInfo = info
|
||||
|
||||
certFile = tools.GetModelPath() + certFileLoc
|
||||
keyFile = tools.GetModelPath() + keyFileLoc
|
||||
@@ -49,12 +35,12 @@ func init() {
|
||||
memCache := NewGocache("_winxin_access")
|
||||
//配置微信参数
|
||||
cfg = wechat.Config{
|
||||
AppID: pay_appId,
|
||||
AppSecret: secret,
|
||||
Token: token,
|
||||
EncodingAESKey: encodingAESKey,
|
||||
AppID: wxInfo.APIKey,
|
||||
AppSecret: wxInfo.AppSecret,
|
||||
Token: wxInfo.Token,
|
||||
EncodingAESKey: wxInfo.EncodingAESKey,
|
||||
Cache: memCache,
|
||||
}
|
||||
client = wxpay.NewClient(pay_appId, mchId, apiKey)
|
||||
client = wxpay.NewClient(wxInfo.AppID, wxInfo.MchID, wxInfo.APIKey)
|
||||
client.WithCert(certFile, keyFile, rootcaFile)
|
||||
}
|
||||
|
@@ -3,15 +3,16 @@ package weixin
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"public/mylog"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
/*
|
||||
小程序授权
|
||||
*/
|
||||
func SmallAppOauth(jscode string) string {
|
||||
var url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + pay_appId + "&secret=" +
|
||||
secret + "&js_code=" + jscode + "&grant_type=authorization_code&trade_type=JSAPI"
|
||||
var url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxInfo.AppID + "&secret=" +
|
||||
wxInfo.AppSecret + "&js_code=" + jscode + "&grant_type=authorization_code&trade_type=JSAPI"
|
||||
|
||||
resp, e := http.Get(url)
|
||||
if e != nil {
|
||||
|
@@ -4,20 +4,21 @@ import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"log"
|
||||
"public/message"
|
||||
"public/mylog"
|
||||
"public/tools"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/message"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
"github.com/xxjwxc/public/tools"
|
||||
|
||||
wxpay "gopkg.in/go-with/wxpay.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
unifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder" // 统一下单请求URL
|
||||
queryOrderUrl = "https://api.mch.weixin.qq.com/pay/orderquery" // 统一查询请求URL
|
||||
refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund" //退款请求URL
|
||||
unifiedOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder" // 统一下单请求URL
|
||||
queryOrderURL = "https://api.mch.weixin.qq.com/pay/orderquery" // 统一查询请求URL
|
||||
refundURL = "https://api.mch.weixin.qq.com/secapi/pay/refund" //退款请求URL
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -30,6 +31,7 @@ const (
|
||||
PAY_ERROR = -1 //支付失败
|
||||
)
|
||||
|
||||
// SmallAppUnifiedorder 小程序统一下单接口
|
||||
/*
|
||||
小程序统一下单接口
|
||||
open_id:用户唯一标识
|
||||
@@ -37,8 +39,8 @@ const (
|
||||
price_body : 支付描述
|
||||
order_id : 商户订单号
|
||||
*/
|
||||
func SmallAppUnifiedorder(open_id string, price int, price_body, order_id, client_ip string) message.MessageBody {
|
||||
if !tools.CheckParam(open_id, order_id) || price <= 0 { //参数检测
|
||||
func SmallAppUnifiedorder(openID string, price int, priceBody, orderID, clientIP string) message.MessageBody {
|
||||
if !tools.CheckParam(openID, orderID) || price <= 0 { //参数检测
|
||||
return message.GetErrorMsg(message.ParameterInvalid)
|
||||
}
|
||||
|
||||
@@ -46,19 +48,19 @@ func SmallAppUnifiedorder(open_id string, price int, price_body, order_id, clien
|
||||
// 查询企业付款接口请求参数
|
||||
params.SetString("appid", client.AppId)
|
||||
params.SetString("mch_id", client.MchId)
|
||||
params.SetString("body", price_body)
|
||||
params.SetString("body", priceBody)
|
||||
params.SetInt64("total_fee", int64(price*10))
|
||||
params.SetString("spbill_create_ip", client_ip)
|
||||
params.SetString("notify_url", notify_url)
|
||||
params.SetString("spbill_create_ip", clientIP)
|
||||
params.SetString("notify_url", wxInfo.NotifyURL)
|
||||
params.SetString("trade_type", "JSAPI")
|
||||
params.SetString("openid", open_id)
|
||||
params.SetString("openid", openID)
|
||||
params.SetString("nonce_str", tools.GetRandomString(32)) // 随机字符串
|
||||
params.SetString("out_trade_no", order_id) // 商户订单号
|
||||
params.SetString("out_trade_no", orderID) // 商户订单号
|
||||
params.SetString("sign", client.Sign(params)) // 签名 c.Sign(params)
|
||||
|
||||
log.Println("paramsparams", params)
|
||||
// 发送查询企业付款请求
|
||||
ret, err := client.Post(unifiedOrderUrl, params, true)
|
||||
ret, err := client.Post(unifiedOrderURL, params, true)
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
msg := message.GetErrorMsg(message.UnknownError)
|
||||
@@ -77,10 +79,10 @@ func SmallAppUnifiedorder(open_id string, price int, price_body, order_id, clien
|
||||
dd["signType"] = "MD5"
|
||||
dd["paySign"] = "MD5"
|
||||
//appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=&signType=MD5&timeStamp=1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111
|
||||
str := "appId=" + pay_appId + "&nonceStr=" + dd["nonceStr"] + "&package=" + dd["package"] + "&signType=MD5&timeStamp=" + dd["timeStamp"] + "&key=" + apiKey
|
||||
str := "appId=" + wxInfo.AppID + "&nonceStr=" + dd["nonceStr"] + "&package=" + dd["package"] + "&signType=MD5&timeStamp=" + dd["timeStamp"] + "&key=" + wxInfo.APIKey
|
||||
by := md5.Sum([]byte(str))
|
||||
dd["paySign"] = strings.ToUpper(fmt.Sprintf("%x", by))
|
||||
dd["order_id"] = order_id
|
||||
dd["order_id"] = orderID
|
||||
|
||||
msg := message.GetSuccessMsg()
|
||||
msg.Data = dd
|
||||
@@ -92,13 +94,14 @@ func SmallAppUnifiedorder(open_id string, price int, price_body, order_id, clien
|
||||
return msg
|
||||
}
|
||||
|
||||
// OnSelectData 统一查询接口
|
||||
/*
|
||||
统一查询接口
|
||||
open_id:用户唯一标识
|
||||
order_id : 商户订单号
|
||||
*/
|
||||
func OnSelectData(open_id, order_id string) (int, message.MessageBody) {
|
||||
if !tools.CheckParam(open_id, order_id) { //参数检测
|
||||
func OnSelectData(openID, orderID string) (int, message.MessageBody) {
|
||||
if !tools.CheckParam(openID, orderID) { //参数检测
|
||||
return 0, message.GetErrorMsg(message.ParameterInvalid)
|
||||
}
|
||||
|
||||
@@ -108,17 +111,17 @@ func OnSelectData(open_id, order_id string) (int, message.MessageBody) {
|
||||
// 查询企业付款接口请求参数
|
||||
params.SetString("appid", client.AppId)
|
||||
params.SetString("mch_id", client.MchId)
|
||||
params.SetString("out_trade_no", order_id) //商户订单号
|
||||
params.SetString("out_trade_no", orderID) //商户订单号
|
||||
params.SetString("nonce_str", tools.GetRandomString(32)) // 随机字符串
|
||||
params.SetString("sign", client.Sign(params)) // 签名 c.Sign(params)
|
||||
|
||||
// 发送查询企业付款请求
|
||||
ret := make(wxpay.Params)
|
||||
var err error
|
||||
ret, err = client.Post(queryOrderUrl, params, true)
|
||||
ret, err = client.Post(queryOrderURL, params, true)
|
||||
if err != nil { //做再次确认
|
||||
time.Sleep(time.Second * 1)
|
||||
ret, err = client.Post(queryOrderUrl, params, true)
|
||||
ret, err = client.Post(queryOrderURL, params, true)
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
msg := message.GetSuccessMsg()
|
||||
@@ -164,6 +167,7 @@ func OnSelectData(open_id, order_id string) (int, message.MessageBody) {
|
||||
return code, msg
|
||||
}
|
||||
|
||||
// RefundPay 申请退款
|
||||
/*
|
||||
申请退款
|
||||
open_id:用户唯一标识
|
||||
@@ -172,8 +176,8 @@ func OnSelectData(open_id, order_id string) (int, message.MessageBody) {
|
||||
total_fee: 订单总金额 分
|
||||
refund_fee: 退款总金额 分
|
||||
*/
|
||||
func RefundPay(open_id, order_id, refund_no string, total_fee, refund_fee int) (bool, message.MessageBody) {
|
||||
if !tools.CheckParam(open_id, order_id) { //参数检测
|
||||
func RefundPay(openID, orderID, refundNO string, totalFee, refundFee int) (bool, message.MessageBody) {
|
||||
if !tools.CheckParam(openID, orderID) { //参数检测
|
||||
return false, message.GetErrorMsg(message.ParameterInvalid)
|
||||
}
|
||||
code := false
|
||||
@@ -181,15 +185,15 @@ func RefundPay(open_id, order_id, refund_no string, total_fee, refund_fee int) (
|
||||
// 退款请求参数
|
||||
params.SetString("appid", client.AppId)
|
||||
params.SetString("mch_id", client.MchId)
|
||||
params.SetString("out_trade_no", order_id) //商户订单号
|
||||
params.SetString("out_refund_no", refund_no) //商户退款单号
|
||||
params.SetInt64("total_fee", int64(total_fee)) // 订单总金额(分)
|
||||
params.SetInt64("refund_fee", int64(refund_fee)) // 退款金额(分)
|
||||
params.SetString("out_trade_no", orderID) //商户订单号
|
||||
params.SetString("out_refund_no", refundNO) //商户退款单号
|
||||
params.SetInt64("total_fee", int64(totalFee)) // 订单总金额(分)
|
||||
params.SetInt64("refund_fee", int64(refundFee)) // 退款金额(分)
|
||||
params.SetString("nonce_str", tools.GetRandomString(32)) // 随机字符串
|
||||
params.SetString("sign", client.Sign(params)) // 签名 c.Sign(params)
|
||||
|
||||
// 发送申请退款请求
|
||||
ret, err := client.Post(refundUrl, params, true)
|
||||
ret, err := client.Post(refundURL, params, true)
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
msg := message.GetErrorMsg(message.UnknownError)
|
||||
|
28
workerpool/def.go
Normal file
28
workerpool/def.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package workerpool
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/myqueue"
|
||||
)
|
||||
|
||||
// TaskHandler process .定义函数回调体
|
||||
type TaskHandler func() error
|
||||
|
||||
// workerPool serves incoming connections via a pool of workers
|
||||
// in FILO order, i.e. the most recently stopped worker will serve the next
|
||||
// incoming connection.
|
||||
//
|
||||
// Such a scheme keeps CPU caches hot (in theory).
|
||||
type WorkerPool struct {
|
||||
//sync.Mutex
|
||||
//maxWorkersCount int //最大的工作协程数
|
||||
//start sync.Once
|
||||
closed int32
|
||||
errChan chan error //错误chan
|
||||
timeout time.Duration //最大超时时间
|
||||
wg sync.WaitGroup
|
||||
task chan TaskHandler
|
||||
waitingQueue *myqueue.MyQueue
|
||||
}
|
152
workerpool/workerpool.go
Normal file
152
workerpool/workerpool.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package workerpool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/myqueue"
|
||||
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
//New 注册工作池,并设置最大并发数
|
||||
//new workpool and set the max number of concurrencies
|
||||
func New(max int) *WorkerPool {
|
||||
if max < 1 {
|
||||
max = 1
|
||||
}
|
||||
|
||||
p := &WorkerPool{
|
||||
task: make(chan TaskHandler, 2*max),
|
||||
errChan: make(chan error, 1),
|
||||
waitingQueue: myqueue.New(),
|
||||
}
|
||||
|
||||
go p.loop(max)
|
||||
return p
|
||||
}
|
||||
|
||||
//SetTimeout 设置超时时间
|
||||
func (p *WorkerPool) SetTimeout(timeout time.Duration) {
|
||||
p.timeout = timeout
|
||||
}
|
||||
|
||||
//Add to the workpool and return immediately
|
||||
//Do 添加到工作池,并立即返回
|
||||
func (p *WorkerPool) Do(fn TaskHandler) {
|
||||
if p.IsClosed() { // 已关闭
|
||||
return
|
||||
}
|
||||
p.waitingQueue.Push(fn)
|
||||
//p.task <- fn
|
||||
}
|
||||
|
||||
//Add to the workpool and wait for execution to complete before returning
|
||||
//DoWait 添加到工作池,并等待执行完成之后再返回
|
||||
func (p *WorkerPool) DoWait(task TaskHandler) {
|
||||
if p.IsClosed() { // closed
|
||||
return
|
||||
}
|
||||
|
||||
doneChan := make(chan struct{})
|
||||
p.waitingQueue.Push(TaskHandler(func() error {
|
||||
defer close(doneChan)
|
||||
return task()
|
||||
}))
|
||||
<-doneChan
|
||||
}
|
||||
|
||||
//Waiting for the worker thread to finish executing
|
||||
//Wait 等待工作线程执行结束
|
||||
func (p *WorkerPool) Wait() error {
|
||||
p.waitingQueue.Wait() //等待队列结束
|
||||
close(p.task)
|
||||
p.wg.Wait() //等待结束
|
||||
select {
|
||||
case err := <-p.errChan:
|
||||
return err
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//Determine whether it is complete (non-blocking)
|
||||
//IsDone 判断是否完成 (非阻塞)
|
||||
func (p *WorkerPool) IsDone() bool {
|
||||
if p == nil || p.task == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return len(p.task) == 0
|
||||
}
|
||||
|
||||
//Has it been closed?
|
||||
//IsClosed 是否已经关闭
|
||||
func (p *WorkerPool) IsClosed() bool {
|
||||
if atomic.LoadInt32(&p.closed) == 1 { // closed
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *WorkerPool) startQueue() {
|
||||
for {
|
||||
fn := p.waitingQueue.Pop().(TaskHandler)
|
||||
if p.IsClosed() { // closed
|
||||
p.waitingQueue.Close()
|
||||
break
|
||||
}
|
||||
|
||||
if fn != nil {
|
||||
p.task <- fn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *WorkerPool) loop(maxWorkersCount int) {
|
||||
go p.startQueue() //Startup queue , 启动队列
|
||||
|
||||
p.wg.Add(maxWorkersCount) // Maximum number of work cycles,最大的工作协程数
|
||||
//Start Max workers, 启动max个worker
|
||||
for i := 0; i < maxWorkersCount; i++ {
|
||||
go func() {
|
||||
defer p.wg.Done()
|
||||
// worker 开始干活
|
||||
for wt := range p.task {
|
||||
if wt == nil || atomic.LoadInt32(&p.closed) == 1 { //returns immediately,有err 立即返回
|
||||
continue //It needs to be consumed before returning.需要先消费完了之后再返回,
|
||||
}
|
||||
|
||||
closed := make(chan struct{}, 1)
|
||||
// Set timeout, priority task timeout.有设置超时,优先task 的超时
|
||||
if p.timeout > 0 {
|
||||
ct, cancel := context.WithTimeout(context.Background(), p.timeout)
|
||||
go func() {
|
||||
select {
|
||||
case <-ct.Done():
|
||||
p.errChan <- ct.Err()
|
||||
//if atomic.LoadInt32(&p.closed) != 1 {
|
||||
mylog.Error(ct.Err())
|
||||
atomic.StoreInt32(&p.closed, 1)
|
||||
cancel()
|
||||
case <-closed:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err := wt() //Points of Execution.真正执行的点
|
||||
close(closed)
|
||||
if err != nil {
|
||||
select {
|
||||
case p.errChan <- err:
|
||||
//if atomic.LoadInt32(&p.closed) != 1 {
|
||||
mylog.Error(err)
|
||||
atomic.StoreInt32(&p.closed, 1)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
105
workerpool/workerpool_test.go
Normal file
105
workerpool/workerpool_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package workerpool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xxjwxc/public/errors"
|
||||
)
|
||||
|
||||
//template
|
||||
func TestWorkerPoolStart(t *testing.T) {
|
||||
wp := New(10) //Set the maximum number of threads,设置最大线程数
|
||||
for i := 0; i < 20; i++ { //Open 20 requests 开启20个请求
|
||||
ii := i
|
||||
wp.Do(func() error {
|
||||
for j := 0; j < 10; j++ {
|
||||
fmt.Println(fmt.Sprintf("%v->\t%v", ii, j))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
//time.Sleep(1 * time.Second)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
wp.Wait()
|
||||
fmt.Println("down")
|
||||
}
|
||||
|
||||
//Support for error return
|
||||
//支持错误返回
|
||||
func TestWorkerPoolError(t *testing.T) {
|
||||
wp := New(10) //Set the maximum number of threads,设置最大线程数
|
||||
for i := 0; i < 20; i++ {
|
||||
ii := i
|
||||
wp.Do(func() error {
|
||||
for j := 0; j < 10; j++ {
|
||||
fmt.Println(fmt.Sprintf("%v->\t%v", ii, j))
|
||||
if ii == 1 {
|
||||
return errors.Cause(errors.New("my test err")) //有err 立即返回
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
return nil
|
||||
//time.Sleep(1 * time.Second)
|
||||
//return errors.New("my test err")
|
||||
})
|
||||
}
|
||||
|
||||
err := wp.Wait()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("down")
|
||||
}
|
||||
|
||||
//Determine whether completion (non-blocking) is placed in the workpool and wait for execution results
|
||||
//放到工作池里面 且等待执行结果
|
||||
func TestWorkerPoolDoWait(t *testing.T) {
|
||||
wp := New(5) //Set the maximum number of threads,设置最大线程数
|
||||
for i := 0; i < 10; i++ {
|
||||
ii := i
|
||||
wp.DoWait(func() error {
|
||||
for j := 0; j < 5; j++ { //每次打印0-10的值
|
||||
fmt.Println(fmt.Sprintf("%v->\t%v", ii, j))
|
||||
// if ii == 1 {
|
||||
// return errors.New("my test err")
|
||||
// }
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
return nil
|
||||
//time.Sleep(1 * time.Second)
|
||||
//return errors.New("my test err")
|
||||
})
|
||||
}
|
||||
|
||||
err := wp.Wait()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("down")
|
||||
}
|
||||
|
||||
//Determine whether it is complete (non-blocking)
|
||||
//判断是否完成 (非阻塞)
|
||||
func TestWorkerPoolIsDone(t *testing.T) {
|
||||
wp := New(5) //Set the maximum number of threads,设置最大线程数
|
||||
for i := 0; i < 10; i++ {
|
||||
// ii := i
|
||||
wp.Do(func() error {
|
||||
for j := 0; j < 5; j++ {
|
||||
//fmt.Println(fmt.Sprintf("%v->\t%v", ii, j))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
fmt.Println(wp.IsDone())
|
||||
}
|
||||
wp.Wait()
|
||||
fmt.Println(wp.IsDone())
|
||||
fmt.Println("down")
|
||||
}
|
Reference in New Issue
Block a user