new
This commit is contained in:
xiexiaojun
2019-03-07 21:30:01 +08:00
commit 2ace0bade5
66 changed files with 5194 additions and 0 deletions

49
file/file.go Normal file
View File

@@ -0,0 +1,49 @@
package file
import (
"fmt"
"io"
"net/http"
"os"
"public/tools"
"time"
)
//上传单个文件
func UploadFile(r *http.Request, w http.ResponseWriter, field, file_type string) (result bool, file_name string) {
//接受post请求
if r.Method == "POST" {
r.ParseMultipartForm(32 << 20)
file_name = GetFileName(file_type)
//开始存储文件
{
file, _, err := r.FormFile(field) //文件name
defer file.Close()
if err != nil {
result = false
}
if !tools.CheckFileIsExist(tools.GetModelPath() + "/file/" + field + "/") {
err1 := os.Mkdir(tools.GetModelPath()+"/file/"+field+"/", os.ModePerm) //创建文件夹
if err1 != nil {
result = false
}
}
f, err := os.OpenFile(tools.GetModelPath()+"/file/"+field+"/"+file_name, os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
if err != nil {
result = false
}
io.Copy(f, file)
}
} else {
result = false
}
return
}
func GetFileName(exp string) string {
return fmt.Sprintf("%d%s.%s", tools.GetUtcTime(time.Now()), tools.GetRandomString(4), exp)
}

95
goleveldb/goleveldb.go Normal file
View File

@@ -0,0 +1,95 @@
package goleveldb
import (
"os"
"../../data/config"
"../log"
"github.com/syndtr/goleveldb/leveldb"
)
var m_db *leveldb.DB = nil
func init() {
Clear();
creat()
}
func creat(){
if m_db == nil{
var err error
m_db, err = leveldb.OpenFile(config.GetLevelDbDir(), nil)
if err != nil {
log.Print(log.Log_Error, err.Error())
m_db.Close()
m_db = nil
}
}
}
/*
清空数据
*/
func Clear() bool {
Close();
os.RemoveAll(config.GetLevelDbDir());
return true;
}
/*
关闭
*/
func Close(){
if m_db != nil{
m_db.Close()
m_db = nil;
}
}
/*
*获取
*/
func Get(key []byte) (data []byte, err error) {
data = nil
data, err = m_db.Get(key, nil)
return
}
/*
设置
*/
func Set(key, value []byte) error {
err := m_db.Put(key, value, nil)
return err
}
/*
删除
*/
func Delete(key []byte) error {
return m_db.Delete(key, nil)
}
/*
*获取
*/
func Getkv(key string) (data []byte, err error) {
return Get([]byte(key))
}
/*
*获取
*/
func Setkv(key string, value []byte) error {
return Set([]byte(key), value)
}
/*
删除
*/
func Deletekv(key string) error {
return Delete([]byte(key))
}

274
message/message.go Normal file
View File

@@ -0,0 +1,274 @@
/*
消息定义接口
*/
package message
import (
"data/config"
"encoding/json"
"fmt"
"log"
"public/tools"
"github.com/bitly/go-simplejson"
)
const ( //消息id定义
NormalMessageId = 0 ////默认的返回值为0自增
ServerMaintenance = 1 //服务器维护中 请稍后再试,服务器出错会回这个信息,暂时不用
AccountDisabled = 2 //帐号被禁用
AppidOverdue = 3 //appid过期
UnknownError = 101 //未知错误
TokenFailure = 102 //token失效
HTMLSuccess = 200 //成功
BlockingAcess = 405 //禁止访问( 禁用请求中所指定的方法)
NewReport = 2001 //新消息
NewHeart = 2002 //心跳
ParameterInvalid = 1001 //参数无效
AppidParameterInvalid = 1002 //appid参数无效
EncryptCheckError = 1003 //密文校验失败
UserNameDoNotExist = 1004 //用户名不存在或密码错误
DuplicateKeyError = 1005 //键值对重复
InValidOp = 1007 //无效操作
NotFindError = 1006 //未找到
InValidAuthorize = 1008 //授权码错误
HasusedError = 1009 //已被使用
HasActvError = 1010 //已被激活
ActvFailure = 1011 //|激活码被禁止使用
UserExisted = 1012 //用户已存在
VerifyTimeError = 1013 //验证码请求过于平凡
MailSendFaild = 1014 //邮箱发送失败
SMSSendFaild = 1015 //手机发送失败
PhoneParameterError = 1016 //手机号格式有问题
VerifyError = 1017 //验证码错误
UserNotExisted = 1018 //用户不存在
TopicExisted = 1019 //topic已经存在
TopicNotExisted = 1020 //topic不存在
BundleIdNotExisted = 1021 //bundle_id不存在
TopicStartFail = 1022 //topic开启处理失败
TopicTypeNotExisted = 1023 //topic处理类型不存在
TopicIsNotNull = 1024 //topic不能为空
DeviceNotExisted = 1025 //设备不存在
StateExisted = 1027 //状态已存在
LastMenuNotExisted = 1028 //上级菜单不存在
MenuNotExisted = 1029 //菜单不存在
UserMenuNotExisted = 1030 //用户权限不存在
DeviceIdNotExisted = 1031 //设备ID不存在
GoodsDealTypeNotExisted = 1032 //商品处理类型不存在
GoodsIdNotExisted = 1033 //商品不存在
GoodsBeInDiscount = 1034 //商品正在打折
GoodsPayTypeNotExisted = 1035 //商品可支付类型不存在
GoodsIdExisted = 1036 //商品已存在
OrderIdNotExisted = 1043 //订单不存在
GoodsBeNotInDiscount = 1044 //商品未打折
NotifyIsNotMatch = 1045 //会话不匹配
GoodsIsDiscountRecovery = 1046 //商品已恢复原价
InvitationUserNotExisted = 1047 //邀请用户不存在
// InvitationUserLevelIsFull = 1048 //邀请用户级数已满
UserNotAuthorize = 1049 //用户未授权
ApplicantIsExisted = 1050 //申请人已存在
ApplicantNotExisted = 1051 //申请人不存在
CreditOrderNotVaild = 1052 //订单无效
RepeatWxWithdraw = 1053 //微信零钱重复提现
WxWithdrawAmountError = 1054 //提现金额错误
WxWithdrawError = 1055 //微信提现失败
RepeatSubmission = 1056 //重复提交
BundleExisted = 1057 //bundle已存在
AuthExisted = 1058 //权限已存在
AuthNotExisted = 1059 //权限不存在
RoomTypeNotExisted = 1060 //房型不存在
RoomTypeExisted = 1061 //房型已存在
RoomNoNotExisted = 1062 //房间不存在
RoomNoExisted = 1063 //房间已存在
RateTypeExisted = 1064 //房价代码或房价名称已存在
RateTypeNotExisted = 1065 //房价代码不存在
FileNotExisted = 1066 //文件不存在
RoomNoInvaild = 1067 //房间未启用
ClassExisted = 1068 //班次已存在
ClassNotExisted = 1069 //班次不存在
CheckTimeError = 1070 //系统时间与营业时间不匹配
CurrentClassIsShift = 1071 //当前班次已交班
PayPriceError = 1072 //支付金额错误
StockNotEnough = 1073 //存量不足
DBSaveError = 1074 //数据存储错误
DBAddError = 1075 //数据添加错误
DBUpdateError = 1076 //数据更新错误
DBDeleteError = 1077 //数据删除错误
TimeError = 1078 //时间错误
OrderInfoError = 1079 //预定信息错误
NotVaildError = 1080 //不允许
Overdue = 1081 //已过期
MaxOverError = 1082 //超过最大值
MinOverError = 1083 //低于最小值
ExistedError = 1084 //已存在
NotBindError = 1085 //未绑定
BindError = 1086 //绑定失败
)
//消息翻译
var MessageMap = map[int]string{
NormalMessageId: "",
ServerMaintenance: "服务器维护中 请稍后再试",
AccountDisabled: "帐号被禁用",
AppidOverdue: "appid过期",
UnknownError: "未知错误",
TokenFailure: "Token失效",
HTMLSuccess: "成功",
BlockingAcess: "禁止访问",
NewReport: "新消息返回",
NewHeart: "心跳消息",
ParameterInvalid: "参数无效",
AppidParameterInvalid: "授权参数无效",
EncryptCheckError: "密文校验失败",
UserNameDoNotExist: "用户名不存在或密码错误",
DuplicateKeyError: "键值对重复",
NotFindError: "未找到",
InValidOp: "无效操作",
InValidAuthorize: "授权码错误或未找到",
HasusedError: "已被使用",
HasActvError: "已被激活",
ActvFailure: "激活码被禁止使用",
UserExisted: "用户已存在",
VerifyTimeError: "验证码请求过于平凡",
MailSendFaild: "邮箱发送失败",
SMSSendFaild: "手机发送失败",
PhoneParameterError: "手机号格式有问题",
VerifyError: "验证码错误",
UserNotExisted: "用户不存在",
TopicExisted: "Topic已存在",
TopicNotExisted: "Topic不存在",
BundleIdNotExisted: "Bundle_id不存在",
TopicStartFail: "Topic开启处理失败",
TopicTypeNotExisted: "Topic处理类型不存在",
TopicIsNotNull: "Topic不能为空",
DeviceNotExisted: "设备不存在",
StateExisted: "状态已存在",
LastMenuNotExisted: "父菜单或根菜单不存在",
MenuNotExisted: "菜单不存在",
UserMenuNotExisted: "用户权限不存在",
DeviceIdNotExisted: "设备ID不存在",
GoodsDealTypeNotExisted: "商品处理类型不存在",
GoodsIdNotExisted: "商品不存在",
GoodsBeInDiscount: "商品正在折扣期",
GoodsPayTypeNotExisted: "商品可支付类型不存在",
GoodsIdExisted: "商品已存在",
OrderIdNotExisted: "订单不存在",
GoodsBeNotInDiscount: "商品未打折",
NotifyIsNotMatch: "会话不匹配",
GoodsIsDiscountRecovery: "商品已恢复原价",
InvitationUserNotExisted: "邀请用户不存在",
// InvitationUserLevelIsFull: "邀请用户级数已满",
UserNotAuthorize: "用户未授权",
ApplicantIsExisted: "申请人已存在",
ApplicantNotExisted: "申请人不存在",
CreditOrderNotVaild: "订单无效",
RepeatWxWithdraw: "微信零钱一天内多次提现",
WxWithdrawAmountError: "微信零钱提现金额错误",
WxWithdrawError: "微信零钱提现失败",
RepeatSubmission: "重复提交",
BundleExisted: "bundle已存在",
AuthExisted: "权限已存在",
AuthNotExisted: "权限不存在",
RoomTypeNotExisted: "房型不存在",
RoomTypeExisted: "房型已存在",
RoomNoNotExisted: "房间不存在",
RoomNoExisted: "房间已存在",
RateTypeExisted: "房价代码或房价名称已存在",
RateTypeNotExisted: "房价代码不存在",
FileNotExisted: "文件不存在",
RoomNoInvaild: "房间未启用",
ClassExisted: "班次已存在",
ClassNotExisted: "班次不存在",
CheckTimeError: "系统时间与营业时间不匹配",
CurrentClassIsShift: "当前班次已完成交班",
PayPriceError: "支付金额错误",
StockNotEnough: "存量不足",
DBSaveError: "数据存储错误",
DBAddError: "数据添加错误",
DBUpdateError: "数据更新错误",
DBDeleteError: "数据删除错误",
TimeError: "时间错误",
OrderInfoError: "预定信息有误",
NotVaildError: "不允许",
Overdue: "已过期",
MaxOverError: "超过最大值",
MinOverError: "低于最小值",
ExistedError: "已存在",
NotBindError: "未绑定",
BindError: "绑定失败",
}
//
type MessageBody struct {
State bool `json:"state"`
Code int `json:"code,omitempty"`
Error string `json:"error,omitempty"`
Data interface{} `json:"data,omitempty"`
}
//获取错误消息 参数(int,string)
func GetErrorMsg(errorCode ...interface{}) (msg MessageBody) {
if len(errorCode) == 0 {
log.Println("未知")
msg.State = false
msg.Code = -1
return
}
msg.State = false
for _, e := range errorCode {
switch v := e.(type) {
case int:
msg.Code = int(int(v))
msg.Error = MessageMap[msg.Code]
case string:
msg.Error = string(v)
fmt.Println(v)
case interface{}:
{
if config.OnIsDev() {
msg.Error = onCheckParam(v)
}
}
}
}
return
}
func onCheckParam(op interface{}) string {
//过滤可不填项
b, _ := json.Marshal(op)
js, _ := simplejson.NewJson(b)
mp, _ := js.Map()
for k, v := range mp {
tmp := tools.AsString(v)
if len(tmp) > 0 && tmp != "0" { //过滤
delete(mp, k)
}
}
//----------------------end
b, _ = json.Marshal(mp)
return string(b)
}
//成功消息
func GetSuccessMsg(errorCode ...int) (msg MessageBody) {
msg.State = true
if len(errorCode) == 0 {
msg.Code = NormalMessageId
} else {
msg.Code = errorCode[0]
}
msg.Error = MessageMap[msg.Code]
return
}

20
message/msg_test.go Normal file
View File

@@ -0,0 +1,20 @@
package message
import (
"fmt"
"testing"
)
type Test struct {
State bool `json:"state"`
Code int `json:"code"`
Error string `json:"error"`
}
func Test_sing(t *testing.T) {
var test Test
test.State = true
test.Error = ""
fmt.Println(onCheckParam(test))
}

53
myaes/myaes.go Normal file
View File

@@ -0,0 +1,53 @@
package myaes
import "crypto/cipher"
type Tobytes struct {
Cip cipher.Block
Pdgtext []byte
}
//使用AES加密文本,加密的文本不能为空
func (a *Tobytes) Encrypt(src []byte) (dst []byte) {
src = a.padding(src)
dst = make([]byte, len(src))
var index int = 0
for len(src) > 0 {
a.Cip.Encrypt(dst[index:index+a.Cip.BlockSize()], src)
index += a.Cip.BlockSize()
src = src[a.Cip.BlockSize():]
}
return dst
}
//使用AES解密文本
func (a *Tobytes) Decrypt(src []byte) (dst []byte) {
if len(src)%a.Cip.BlockSize() != 0 {
return src
}
dst = make([]byte, len(src))
var index int = 0
for len(src) > 0 {
a.Cip.Decrypt(dst[index:index+a.Cip.BlockSize()], src)
index += a.Cip.BlockSize()
src = src[a.Cip.BlockSize():]
}
return a.unpadding(dst)
}
//使用AES加密文本的时候文本必须定长,即必须是16,24,32的整数倍,
func (a *Tobytes) padding(src []byte) (dst []byte) {
pdg := a.Cip.BlockSize() - len(src)%a.Cip.BlockSize()
p := a.Pdgtext[:pdg]
p[pdg-1] = byte(pdg)
return append(src, p...)
}
//使用AES解密文本,解密收删除padding的文本
func (a *Tobytes) unpadding(src []byte) (dst []byte) {
length := len(src)
if length <= 0 {
return src
}
return src[:(length - int(src[length-1]))]
}

35
mycache/my_test.go Normal file
View File

@@ -0,0 +1,35 @@
package mycache
import (
"fmt"
"testing"
"time"
)
// Tweet is a structure used for serializing/deserializing data in Elasticsearch.
type Tweet struct {
User string `json:"user"`
Message string `json:"message"`
Retweets int `json:"retweets"`
Image string `json:"image,omitempty"`
Created time.Time `json:"created,omitempty"`
Tags []string `json:"tags,omitempty"`
Location string `json:"location,omitempty"`
}
func Test_cache(t *testing.T) {
//获取
cache := OnGetCache("_cache")
var tp interface{}
tp, b := cache.Value("key")
if b {
tmp := tp.(Tweet)
fmt.Println(tmp)
} else {
var tmp Tweet
//添加
cache.Add("key", tmp, 24*time.Hour)
}
return
}

77
mycache/mycache.go Normal file
View File

@@ -0,0 +1,77 @@
/*
key/value 内存缓存,支持基于超时的自动无效功能
*/
package mycache
import (
"time"
"github.com/muesli/cache2go"
)
type MyCache struct {
cache *cache2go.CacheTable
}
/*
初始化一个cache
cachename 缓存名字
*/
func OnGetCache(cachename string) (mc MyCache) {
mc.cache = cache2go.Cache(cachename)
return
}
/*
添加一个缓存
lifeSpan:缓存时间0表示永不超时
*/
func (mc *MyCache) Add(key interface{}, value interface{}, lifeSpan time.Duration) *cache2go.CacheItem {
return mc.cache.Add(key, lifeSpan, value)
}
/*
查找一个cache
value 返回的值
*/
func (mc *MyCache) Value(key interface{}) (value interface{}, b bool) {
b = false
res, err := mc.cache.Value(key)
if err == nil {
value = res.Data()
b = true
return
}
return
}
/*
判断key是否存在
*/
func (mc *MyCache) IsExist(key interface{}) bool {
return mc.cache.Exists(key)
}
/*
删除一个cache
*/
func (mc *MyCache) Delete(key interface{}) error {
_, err := mc.cache.Delete(key)
return err
}
/*
获取原始cache2go操作类
*/
func (mc *MyCache) GetCache2go() *cache2go.CacheTable {
return mc.cache
}
/*
清空表內容
*/
func (mc *MyCache) Clear() bool {
mc.cache.Flush()
return true
}

54
mycatch/mycatch.go Normal file
View File

@@ -0,0 +1,54 @@
/*
错误信息日志记录(panic信息不可度量的)
注意:每个 goroutine 开始部分都需要写上:defer mycatch.Dmp()
类似于
go func(){
defer mycatch.Dmp()
}()
*/
package mycatch
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime/debug"
"time"
)
func Dmp() {
errstr := ""
if err := recover(); err != nil {
errstr += (fmt.Sprintf("%v\r\n", err)) //输出panic信息
errstr += ("--------------------------------------------\r\n")
}
errstr += (string(debug.Stack())) //输出堆栈信息
OnPrintErr(errstr)
}
func OnPrintErr(errstring string) {
file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
path = filepath.Dir(path)
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-当前时间(年月日时分秒)
fmt.Println("panic to file ", fname)
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
return
}
defer f.Close()
f.WriteString("=========================" + now.Format("2006-01-02 15:04:05 ========================= \r\n"))
f.WriteString(errstring) //输出堆栈信息
f.WriteString("=========================end=========================")
}

3
mydef/mydef.go Normal file
View File

@@ -0,0 +1,3 @@
package mydef
type ParamsCallFunc func(...interface{})

59
mydraw/my_test.go Normal file
View File

@@ -0,0 +1,59 @@
package mydraw
import (
"fmt"
"public/mydraw"
"testing"
)
func TestMytest(t *testing.T) {
pen, b := mydraw.OnGetPen("./luximr.ttf", 0, 0, 0, 255)
if b {
var hdc mydraw.HDC
hdc.SetBg("./src.png")
pen.Dpi = 200
pen.FontSize = 16
pen.StartPoint.X = 150
pen.StartPoint.Y = 78
hdc.DrawText(pen, "哈哈")
pen.FontSize = 12
pen.StartPoint.X = 150
pen.StartPoint.Y = 160
hdc.DrawText(pen, "男")
pen.StartPoint.X = 350
pen.StartPoint.Y = 160
hdc.DrawText(pen, "汉")
pen.StartPoint.X = 150
pen.StartPoint.Y = 240
hdc.DrawText(pen, "1996")
pen.StartPoint.X = 300
pen.StartPoint.Y = 240
hdc.DrawText(pen, "6")
pen.StartPoint.X = 370
pen.StartPoint.Y = 240
hdc.DrawText(pen, "26")
pen.StartPoint.X = 150
pen.StartPoint.Y = 275
str := []rune("北京市海淀区西北旺东路100号中关村科技园")
//str := "北京市海淀区西北旺东路100号中关村科技园"
for i := 0; i < len(str); i += 11 {
var end = i + 11
if end > len(str) {
end = len(str)
}
pen.StartPoint.Y += 40
tmp := str[i:end]
hdc.DrawText(pen, string(tmp))
}
pen.StartPoint.X = 300
pen.StartPoint.Y = 520
hdc.DrawText(pen, "310666196606266666")
b = hdc.Save("./out.png")
fmt.Println(b)
}
}

126
mydraw/mydraw.go Normal file
View File

@@ -0,0 +1,126 @@
package mydraw
import (
"fmt"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"log"
"os"
"public/mylog"
"strings"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
)
type Pen struct {
FontSize float64
Dpi float64
Font *truetype.Font
StartPoint image.Point
Color *image.Uniform
}
type HDC struct {
//Bg image.Image
Rgba *image.RGBA
}
//获取画笔
func OnGetPen(fontPath string, R, G, B, A uint8) (pen Pen, b bool) {
b = false
pen.Color = image.NewUniform(color.RGBA{R: R, G: G, B: B, A: A})
pen.Dpi = 72
pen.FontSize = 10
pen.StartPoint = image.Point{0, 0}
// 读字体数据
fontBytes, err := ioutil.ReadFile(fontPath)
if err != nil {
log.Println(err)
return
}
pen.Font, err = freetype.ParseFont(fontBytes)
if err != nil {
log.Println(err)
return
}
b = true
return
}
func (this *HDC) SetBg(imagePath string) bool {
file, _ := os.Open(imagePath)
defer file.Close()
//var err error
img, _, err := image.Decode(file)
if err != nil {
fmt.Println("err = ", err)
return false
}
this.Rgba = image.NewRGBA(img.Bounds())
draw.Draw(this.Rgba, this.Rgba.Bounds(), img, image.ZP, draw.Src)
return true
}
func (this *HDC) GetBgSize() (w, h int) {
b := this.Rgba.Bounds()
w = b.Max.X
h = b.Max.Y
return
}
//图片上画文字
func (this *HDC) DrawText(pen Pen, text string) bool {
if this.Rgba == nil {
return false
}
c := freetype.NewContext()
c.SetDPI(pen.Dpi)
c.SetFont(pen.Font)
c.SetFontSize(pen.FontSize)
c.SetClip(this.Rgba.Bounds())
c.SetDst(this.Rgba)
//c.SetSrc(image.NewUniform(color.RGBA{255, 255, 255, 255}))
c.SetSrc(pen.Color)
// Draw the text.
pt := freetype.Pt(pen.StartPoint.X, pen.StartPoint.Y+int(c.PointToFixed(pen.FontSize)>>6))
for _, s := range strings.Split(text, "\r\n") {
_, err := c.DrawString(s, pt)
if err != nil {
mylog.Println("c.DrawString(%s) error(%v)", s, err)
return false
}
pt.Y += c.PointToFixed(pen.FontSize * 1.5)
}
return false
}
//保存图片
func (this *HDC) Save(imagePath string) bool {
output, err := os.OpenFile(imagePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
mylog.Error(err)
return false
}
defer output.Close()
if strings.HasSuffix(imagePath, ".png") || strings.HasSuffix(imagePath, ".PNG") {
err = png.Encode(output, this.Rgba)
} else {
err = jpeg.Encode(output, this.Rgba, nil)
}
if err != nil {
mylog.Println("image encode error(%v)", err)
//mylog.Error(err)
return false
}
return true
}

50
myecharts/common.go Normal file
View File

@@ -0,0 +1,50 @@
package myecharts
func getDefaltOption() EcOption {
return EcOption{
XAxis: EcxAxis{Type: "category"},
YAxis: EcxAxis{Type: "value"},
Legend: EcLegend{Show: true},
}
}
// 设置显示x轴还是y轴且设置数据内容
//data 为轴坐标内容
func (ep *EcOption) OnSetAxis(data []string, axisLabel AxisLabel, isy bool) {
V := EcxAxis{Type: "value", AxisLabel: axisLabel}
k := EcxAxis{Type: "category", Data: data}
if isy {
ep.YAxis = k
ep.XAxis = V
} else {
ep.XAxis = k
ep.YAxis = V
}
}
//图例组件。(顶部分类器)
func (ep *EcOption) OnSetLegend(data []string) {
ep.Legend.Data = data
ep.Legend.Show = true
}
//添加一个数据
func (ep *EcOption) OnAddOneSeries(name string, data interface{}) {
var tmp = EcSeries{Name: name, Type: ep._type, Data: data}
ep.Series = append(ep.Series, tmp)
}
//添加一个数据
func (ep *EcOption) OnAddOneSeriesInt(name string, data []int) {
var tmp []interface{}
for _, v := range data {
tmp = append(tmp, float32(v))
}
ep.OnAddOneSeries(name, tmp)
}
//
func (ep *EcOption) SetEcToolTip(ecToolTip EcToolTip) {
//EcToolTip{Show: true, Trigger: "axis", AxisPointer: EcAxisPointer{Type: "shadow"}}
ep.Tooltip = ecToolTip
}

90
myecharts/def.go Normal file
View File

@@ -0,0 +1,90 @@
package myecharts
//echarts option 根数据
type EcOption struct {
Color []string `json:"color,omitempty"` //调色盘颜色列表。如果系列没有设置颜色,则会依次循环从该列表中取颜色作为系列颜色。
//标题组件,包含主标题和副标题。
Title EcTitle `json:"title,omitempty"`
Tooltip EcToolTip `json:"tooltip,omitempty"`
Grid EcGrid `json:"grid,omitempty"`
XAxis EcxAxis `json:"xAxis,omitempty"` //直角坐标系 grid 中的 x 轴
YAxis EcxAxis `json:"yAxis,omitempty"` //直角坐标系 grid 中的 y 轴
Legend EcLegend `json:"legend,omitempty"` //图例组件。
Series []EcSeries `json:"series,omitempty"` //数据内容
Toolbox Toolbox `json:"toolbox,omitempty"` //
_type string
}
//系列列表。每个系列通过 type 决定自己的图表类型
type EcSeries struct {
Name string `json:"name,omitempty"` //系列名称
Type string `json:"type,omitempty"` //line:线 bar:柱状图
Data interface{} `json:"data,omitempty"` //系列中的数据内容数组
}
//图例组件。
type EcLegend struct {
Show bool `json:"show,omitempty"`
Data []string `json:"data,omitempty"` //图例的数据数组
}
//直角坐标系内绘图网格
type EcxAxis struct {
Type string `json:"type,omitempty"`
Data []string `json:"data,omitempty"`
AxisLabel AxisLabel `json:"axisLabel,omitempty"`
}
//
type AxisLabel struct {
Formatter string `json:"formatter,omitempty"`
}
//直角坐标系内绘图网格
type EcGrid struct {
Left string `json:"left,omitempty"` //组件离容器左侧的距离。
Right string `json:"right,omitempty"`
Bottom string `json:"bottom,omitempty"`
ContainLabel bool `json:"containLabel,omitempty"` //grid 区域是否包含坐标轴的刻度标签
}
//提示框组件。
type EcToolTip struct {
Show bool `json:"show,omitempty"`
/*
触发类型。
'item' 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
'axis' 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
'none' 什么都不触发。
*/
Trigger string `json:"trigger,omitempty"`
//坐标轴指示器配置项。
AxisPointer EcAxisPointer `json:"axisPointer,omitempty"`
}
//坐标轴指示器配置项。
type EcAxisPointer struct {
/*
'line' 直线指示器
'shadow' 阴影指示器
'none' 无指示器
'cross' 十字准星指示器
*/
Type string `json:"type,omitempty"`
}
//标题组件,包含主标题和副标题。
type EcTitle struct {
Text string `json:"text,omitempty"` //主标题文本,支持使用 \n 换行。
SubText string `json:"subtext,omitempty"` //副标题文本,支持使用 \n 换行。
}
//
type Toolbox struct {
Show bool `json:"show,omitempty"` //
Feature Feature `json:"feature,omitempty"` //
}
//
type Feature struct {
}

26
myecharts/myecharts.go Normal file
View File

@@ -0,0 +1,26 @@
package myecharts
//获取线图基础数据
/*
t_str
line:线
bar:柱
pie:饼
scatter:散点(气泡) effectScatter:带有涟漪特效动画的散点 radar:雷达
tree:树 treemap:面积 sunburst:旭日图 boxplot:箱形图 candlestick:K线图 sankey:桑基图
heatmap:热力图 map:地图 parallel: 平行坐标系的系列 lines:线图 graph:关系图
funnel:漏斗图 gauge:仪表盘 pictorialBar:象形柱图 themeRiver:主题河流 custom:自定义系列
*/
func OnGetBaseInfo(t_str string) (ec EcOption) {
ec = getDefaltOption()
ec._type = t_str
return ec
}
/*
获取基础柱状图
*/
func OnGetBarInfo(ecToolTip EcToolTip) (ec EcOption) {
ec = OnGetBaseInfo("bar")
return ec
}

391
myelastic/myelastic.go Normal file
View File

@@ -0,0 +1,391 @@
package myelastic
import (
"context"
"encoding/json"
"errors"
"log"
"reflect"
"strings"
"time"
"github.com/olivere/elastic"
)
//
type MyElastic struct {
Client *elastic.Client
Err error
Ctx context.Context
}
//
func OnInitES(url string) MyElastic {
var es MyElastic
es.Ctx = context.Background()
es.Client, es.Err = elastic.NewClient(elastic.SetURL(url))
if es.Err != nil {
log.Println(es.Err)
//mylog.Error(es.Err)
//panic(es.Err)
}
return es
}
//func (es *MyElastic) Model(refs interface{}) *MyElastic {
// if reflect.ValueOf(refs).Type().Kind() != reflect.Ptr {
// mylog.Println("Model: attempt to Model into a pointer")
// panic(0)
// }
// es.Element = refs
// return es
//}
/*
创建索引(相当于数据库)
mapping 如果为空("")则表示不创建模型
*/
func (es *MyElastic) CreateIndex(index_name, mapping string) (result bool) {
es.Err = nil
exists, err := es.Client.IndexExists(index_name).Do(es.Ctx)
if err != nil {
es.Err = err
log.Println(es.Err)
return false
}
if !exists {
var re *elastic.IndicesCreateResult
if len(mapping) == 0 {
re, es.Err = es.Client.CreateIndex(index_name).Do(es.Ctx)
} else {
re, es.Err = es.Client.CreateIndex(index_name).BodyString(mapping).Do(es.Ctx)
}
if es.Err != nil {
log.Println(es.Err)
return false
}
return re.Acknowledged
}
return false
}
/*
排序查询
返回json数据集合
*/
func (es *MyElastic) SortQuery(index_name string, builder []elastic.Sorter, query []elastic.Query) (bool, []string) {
searchResult := es.Client.Search().Index(index_name)
if len(builder) > 0 {
for _, v := range builder {
searchResult = searchResult.SortBy(v)
}
}
if len(query) > 0 {
for _, v := range query {
searchResult = searchResult.Query(v)
}
}
es_result, err := searchResult.Do(es.Ctx) // execute
if err != nil {
log.Println(es.Err)
return false, nil
}
//log.Println("Found a total of %d entity\n", es_result.TotalHits())
if es_result.Hits.TotalHits > 0 {
var result []string
//log.Println("Found a total of %d entity\n", searchResult.Hits.TotalHits)
for _, hit := range es_result.Hits.Hits {
result = append(result, string(*hit.Source))
}
return true, result
} else {
// No hits
return true, nil
}
}
/*
排序查询
返回原始Hit
builder排序
agg聚合 类似group_by sum
query查询
*/
func (es *MyElastic) SortQueryReturnHits(index_name string, from, size int, builder []elastic.Sorter, query []elastic.Query) (bool, []*elastic.SearchHit) {
searchResult := es.Client.Search().Index(index_name)
if len(builder) > 0 {
for _, v := range builder {
searchResult = searchResult.SortBy(v)
}
}
if len(query) > 0 {
for _, v := range query {
searchResult = searchResult.Query(v)
}
}
if size > 0 {
searchResult = searchResult.From(from)
searchResult = searchResult.Size(size)
}
es_result, err := searchResult.Do(es.Ctx) // execute
if err != nil {
log.Println(es.Err)
return false, nil
}
// log.Println("wwwwww", es_result.Aggregations)
if es_result.Hits.TotalHits > 0 {
return true, es_result.Hits.Hits
} else {
return true, nil
}
}
/*
添加记录,覆盖添加
*/
func (es *MyElastic) Add(index_name, type_name, id string, data interface{}) (result bool) {
result = false
// Index a tweet (using JSON serialization)
if len(id) > 0 {
_, es.Err = es.Client.Index().
Index(index_name).
Type(type_name).
Id(id).
BodyJson(data).
Do(es.Ctx)
} else {
_, es.Err = es.Client.Index().
Index(index_name).
Type(type_name).
BodyJson(data).
Do(es.Ctx)
}
if es.Err != nil {
log.Println(es.Err)
return false
}
_, es.Err = es.Client.Flush().Index(index_name).Do(es.Ctx)
if es.Err != nil {
log.Println(es.Err)
return false
}
return true
}
/*
添加记录,覆盖添加
index_name
type_name
query interface{} //查询条件
out *[]Param //查询结果
*/
func (es *MyElastic) SearchMap(index_name, type_name string, query interface{}, out *[]map[string]interface{}) (result bool) {
es_search := es.Client.Search()
if len(type_name) > 0 {
es_search = es_search.Type(type_name)
}
if len(index_name) > 0 {
es_search = es_search.Index(index_name)
}
var es_result *elastic.SearchResult
es_result, es.Err = es_search.Source(query).Do(es.Ctx)
if es.Err != nil {
log.Println(es.Err)
return false
}
if es_result.Hits == nil {
log.Println(errors.New("expected SearchResult.Hits != nil; got nil"))
return false
}
for _, hit := range es_result.Hits.Hits {
tmp := make(map[string]interface{})
err := json.Unmarshal(*hit.Source, &tmp)
if err != nil {
log.Println(es.Err)
} else {
*out = append(*out, tmp)
}
}
return true
}
/*
添加记录,覆盖添加
index_name
type_name
query interface{} //查询条件
out *[]Param //查询结果
*/
func (es *MyElastic) Search(index_name, type_name string, query interface{}, out interface{}) (result bool) {
sliceValue := reflect.Indirect(reflect.ValueOf(out))
if sliceValue.Kind() != reflect.Slice {
log.Println(errors.New("needs a pointer to a slice"))
return false
}
sliceElementType := sliceValue.Type().Elem()
es_search := es.Client.Search()
if len(type_name) > 0 {
es_search = es_search.Type(type_name)
}
if len(index_name) > 0 {
es_search = es_search.Index(index_name)
}
var es_result *elastic.SearchResult
es_result, es.Err = es_search.Source(query).Do(es.Ctx)
if es.Err != nil {
log.Println(es.Err)
return false
}
if es_result.Hits == nil {
log.Println(errors.New("expected SearchResult.Hits != nil; got nil"))
return false
}
for _, hit := range es_result.Hits.Hits {
newValue := reflect.New(sliceElementType)
item := make(map[string]interface{})
err := json.Unmarshal(*hit.Source, &item)
//fmt.Println(string(*hit.Source))
err = scanMapIntoStruct(newValue.Interface(), item)
if err != nil {
log.Println(err)
}
if err != nil {
log.Println(err)
} else {
sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface()))))
//out = append(out, tmp)
}
}
return true
}
func scanMapIntoStruct(obj interface{}, objMap map[string]interface{}) error {
dataStruct := reflect.Indirect(reflect.ValueOf(obj))
if dataStruct.Kind() != reflect.Struct {
return errors.New("expected a pointer to a struct")
}
dataStructType := dataStruct.Type()
for i := 0; i < dataStructType.NumField(); i++ {
field := dataStructType.Field(i)
fieldv := dataStruct.Field(i)
err := scanMapElement(fieldv, field, objMap)
if err != nil {
return err
}
}
return nil
}
func scanMapElement(fieldv reflect.Value, field reflect.StructField, objMap map[string]interface{}) error {
objFieldName := field.Name
bb := field.Tag
sqlTag := bb.Get("json")
if bb.Get("json") == "-" || sqlTag == "-" || reflect.ValueOf(bb).String() == "-" {
return nil
}
sqlTags := strings.Split(sqlTag, ",")
sqlFieldName := objFieldName
if len(sqlTags[0]) > 0 {
sqlFieldName = sqlTags[0]
}
data, ok := objMap[sqlFieldName]
if !ok || data == nil {
return nil
}
// fmt.Println("================")
// fmt.Println(field.Type.Kind())
// fmt.Println(sqlFieldName)
var v interface{}
switch field.Type.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x := int(data.(float64))
v = x
case reflect.Slice:
if fieldv.Type().String() == "[]uint8" {
x := []byte(data.(string))
v = x
} else if fieldv.Type().String() == "[]string" {
mp := data.([]interface{})
var ss []string
for _, v := range mp {
ss = append(ss, v.(string))
}
v = ss
} else if fieldv.Type().String() == "[]int" {
mp := data.([]interface{})
var ss []int
for _, v := range mp {
ss = append(ss, int(v.(float64)))
}
v = ss
} else {
v = data
}
case reflect.Struct:
if fieldv.Type().String() == "time.Time" {
x, err := time.Parse("2006-01-02 15:04:05", data.(string))
if err != nil {
x, err = time.Parse("2006-01-02 15:04:05.000 -0700", data.(string))
if err != nil {
if err != nil {
x, err = time.Parse("2006-01-02T15:04:05.999999999Z07:00", data.(string))
if err != nil {
return errors.New("unsupported time format: " + data.(string))
}
}
}
}
v = x
} else {
v = data
}
default:
v = data
}
fieldv.Set(reflect.ValueOf(v))
// fmt.Println("================")
return nil
}

BIN
myelastic/test.rar Normal file

Binary file not shown.

87
myfile/myfile.go Normal file
View File

@@ -0,0 +1,87 @@
package myfile
import (
"fmt"
"io"
"net/http"
"os"
"public/tools"
"time"
)
//上传单个文件
func UploadOneFile(r *http.Request, field, file_type, dir string) (result bool, file_name string) {
//接受post请求
if r.Method == "POST" {
r.ParseMultipartForm(32 << 20)
file_name = getFileName(file_type)
//开始存储文件
{
file, _, err := r.FormFile(field) //文件name
defer file.Close()
if err != nil {
result = false
}
if !tools.CheckFileIsExist(tools.GetModelPath() + "/file/" + dir + "/") {
err1 := os.Mkdir(tools.GetModelPath()+"/file/"+dir+"/", os.ModePerm) //创建文件夹
if err1 != nil {
result = false
}
}
f, err := os.OpenFile(tools.GetModelPath()+"/file/"+dir+"/"+file_name, os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
if err != nil {
result = false
}
io.Copy(f, file)
result = true
}
} else {
result = false
}
return
}
//多文件上传
func UploadMoreFile(r *http.Request, field, file_type, dir string) (result bool, optionDirs []string) {
//接受post请求
if r.Method == "POST" {
r.ParseMultipartForm(32 << 20)
files := r.MultipartForm.File[field]
l := len(files)
// optionDirs := make([]string, l)
for i := 0; i < l; i++ {
file, err := files[i].Open()
defer file.Close()
if err != nil {
result = false
}
file_name := getFileName(file_type)
if !tools.CheckFileIsExist(tools.GetModelPath() + "/file/" + dir + "/") {
err1 := os.Mkdir(tools.GetModelPath()+"/file/"+dir+"/", os.ModePerm) //创建文件夹
if err1 != nil {
result = false
}
}
f, err := os.OpenFile(tools.GetModelPath()+"/file/"+dir+"/"+file_name, os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
if err != nil {
result = false
}
io.Copy(f, file)
optionDirs = append(optionDirs, file_name)
result = true
}
} else {
result = false
}
return
}
func getFileName(exp string) string {
return fmt.Sprintf("%d%s.%s", tools.GetUtcTime(time.Now()), tools.GetRandomString(4), exp)
}

132
myhttp/myfile.go Normal file
View File

@@ -0,0 +1,132 @@
package myhttp
import (
"bytes"
"data/config"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
"public/mylog"
"public/tools"
"time"
)
/*
多文件上传
dir:空则使用文件后缀做dir
*/
func UploadMoreFile(r *http.Request, dir string) (result bool, optionDirs []string) {
//接受post请求
if r.Method == "POST" {
r.ParseMultipartForm(32 << 20)
if r.MultipartForm == nil {
result = false
} else {
for _, files := range r.MultipartForm.File {
for _, v := range files {
var _dir = dir
file, _ := v.Open()
defer file.Close()
ext := getFileType(v.Filename)
if len(ext) == 0 {
continue
}
if len(_dir) == 0 {
_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) //生成多级目录
}
//存在则覆盖
f, err := os.OpenFile(abs_dir+file_name,
os.O_WRONLY|os.O_CREATE, 0666)
defer f.Close()
if err != nil {
mylog.Error(err)
result = false
return
}
io.Copy(f, file)
optionDirs = append(optionDirs, config.Url_host+config.File_host+"/"+_dir+"/"+file_name)
result = true
}
}
}
} else {
result = false
}
return
}
func getFileName(exp string) string {
return fmt.Sprintf("%d%s.%s", tools.GetUtcTime(time.Now()), tools.GetRandomString(4), exp)
}
//获取文件后缀
func getFileType(exp string) string {
fileSuffix := path.Ext(exp) //获取文件后缀
if len(fileSuffix) > 1 {
return fileSuffix[1:]
}
return ""
}
//模拟客戶端文件上传
//fieldname注意与服务器端保持一致
func PostFile(filename, fieldname string, targetUrl string) (e error, result string) {
bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)
//关键的一步操作
fileWriter, err := bodyWriter.CreateFormFile(fieldname, filename)
if err != nil {
fmt.Println("error writing to buffer")
e = err
return
}
//打开文件句柄操作
fh, err := os.Open(filename)
if err != nil {
fmt.Println("error opening file")
e = err
return
}
defer fh.Close()
//iocopy
_, err = io.Copy(fileWriter, fh)
if err != nil {
e = err
return
}
contentType := bodyWriter.FormDataContentType()
bodyWriter.Close()
resp, err := http.Post(targetUrl, contentType, bodyBuf)
if err != nil {
e = err
return
}
defer resp.Body.Close()
resp_body, err := ioutil.ReadAll(resp.Body)
if err != nil {
e = err
return
}
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
result = string(resp_body)
return
}

143
myhttp/myhttp.go Normal file
View File

@@ -0,0 +1,143 @@
package myhttp
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"public/mylog"
)
//发送修改密码
func OnPostJson(url, jsonstr string) []byte {
//解析这个 URL 并确保解析没有出错。
body := bytes.NewBuffer([]byte(jsonstr))
resp, err := http.Post(url, "application/json;charset=utf-8", body)
if err != nil {
return []byte("")
}
defer resp.Body.Close()
body1, err1 := ioutil.ReadAll(resp.Body)
if err1 != nil {
return []byte("")
}
return body1
}
//发送get 请求
func OnGetJson(url, params string) string {
//解析这个 URL 并确保解析没有出错。
var urls = url
if len(params) > 0 {
urls += "?" + params
}
resp, err := http.Get(urls)
if err != nil {
return ""
}
defer resp.Body.Close()
body1, err1 := ioutil.ReadAll(resp.Body)
if err1 != nil {
return ""
}
return string(body1)
}
//发送get 请求 返回对象
func SendGet(url, params string, obj interface{}) bool {
//解析这个 URL 并确保解析没有出错。
var urls = url
if len(params) > 0 {
urls += "?" + params
}
resp, err := http.Get(urls)
if err != nil {
mylog.Error(err)
return false
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
mylog.Error(err)
return false
}
log.Println((string(body)))
err = json.Unmarshal([]byte(body), &obj)
return err == nil
}
//发送GET请求
func SendGetEx(url string, reponse interface{}) bool {
resp, e := http.Get(url)
if e != nil {
mylog.Error(e)
return false
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
mylog.Error(e)
return false
}
mylog.Debug(string(body))
err = json.Unmarshal(body, &reponse)
return err == nil
}
//form 方式发送post请求
func OnPostForm(url string, data url.Values) (body []byte) {
resp, err := http.PostForm(url, data)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
return
}
//发送POST请求
func SendPost(requestBody interface{}, responseBody interface{}, url string) bool {
postData, err := json.Marshal(requestBody)
client := &http.Client{}
req, _ := http.NewRequest("POST", url, bytes.NewReader(postData))
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json;charset=utf-8")
// req.Header.Add("Authorization", authorization)
resp, e := client.Do(req)
if e != nil {
mylog.Error(e)
return false
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
mylog.Error(e)
return false
}
// result := string(body)
mylog.Debug(string(body))
err = json.Unmarshal(body, &responseBody)
return err == nil
}
//像指定client 发送json 包
//msg message.MessageBody
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 {
panic(err)
}
fmt.Fprintf(w, string(js))
}

64
myleveldb/my_test.go Normal file
View File

@@ -0,0 +1,64 @@
package myleveldb
import (
"fmt"
"public/myleveldb"
"testing"
"time"
)
// Tweet is a structure used for serializing/deserializing data in Elasticsearch.
type Tweet struct {
User string `json:"user"`
Message string `json:"message"`
Retweets int `json:"retweets"`
Image string `json:"image,omitempty"`
Created time.Time `json:"created,omitempty"`
Tags []string `json:"tags,omitempty"`
Location string `json:"location,omitempty"`
}
func Test_order(t *testing.T) {
fmt.Println("ssss")
//初始化db
ldb := myleveldb.OnInitDB("./database")
defer ldb.OnDestoryDB()
// var www Tweet
// www.Location = "xiexiaojun"
// www.Created = time.Now()
// www.Tags = append(www.Tags, "12334444", "ssss", "wwwww")
// b := ldb.Add([]byte("wwww"), www)
// fmt.Println(b)
// fmt.Println(www.Tags)
var eee Tweet
bb := ldb.Get("wwww", &eee)
fmt.Println(bb)
fmt.Println(eee.Location)
fmt.Println(eee.Created)
fmt.Println(eee.Tags)
// var temp []myleveldb.Param
// for i := 0; i < 10; i++ {
// var www Tweet
// www.Location = "xiexiaojun" + strconv.Itoa(i)
// www.Created = time.Now()
// temp = append(temp, myleveldb.Param{"key" + strconv.Itoa(i), www})
// }
//bbb := ldb.AddList(temp)
//fmt.Println(bbb)
bb = ldb.Get("key9", &eee)
fmt.Println(bb)
fmt.Println(eee.Location)
fmt.Println(eee.Created)
fmt.Println(eee.Tags)
var tmp []myleveldb.Param
bb = ldb.Model(&Tweet{}).Find(&tmp, "key3", "key7") //查找
fmt.Println(tmp)
return
}

172
myleveldb/myleveldb.go Normal file
View File

@@ -0,0 +1,172 @@
package myleveldb
import (
"public/mylog"
"public/tools"
"reflect"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/util"
)
type Param struct {
Key string
Value interface{}
}
func OnInitDB(dataSourceName string) MyLevelDB {
var L MyLevelDB
L.DB, L.E = leveldb.OpenFile(dataSourceName, nil)
if L.E != nil {
mylog.Error(L.E)
}
// L.op = &opt.ReadOptions{
// false,
// opt.NoStrict,
// }
return L
}
type MyLevelDB struct {
DB *leveldb.DB
E error
//op *opt.ReadOptions
Value interface{}
}
func (L *MyLevelDB) OnDestoryDB() {
if L.DB != nil {
L.DB.Close()
L.DB = nil
}
}
//获取数据
func (L *MyLevelDB) Get(key string, value interface{}) (b bool) {
if L.DB != nil {
var err error
var by []byte
if by, err = L.DB.Get([]byte(key), nil /*L.op*/); err != nil {
//mylog.Error(err)
} else {
if err := tools.DecodeByte(by, value); err != nil {
//错误处理
mylog.Error(err)
} else {
return true
}
}
}
return false
}
func (L *MyLevelDB) Model(refs interface{}) *MyLevelDB {
if reflect.ValueOf(refs).Type().Kind() == reflect.Ptr {
mylog.Println("Model: attempt to Model into a non-pointer")
panic(0)
}
L.Value = refs
return L
}
//模糊查找
/*
t value的类型
values 为返回结果
args 传一个参数:表示模糊搜索
args 传2个参数:表示范围搜索
*/
func (L *MyLevelDB) Find(values *[]Param, args ...string) (b bool) {
if L.DB != nil && L.Value != nil {
n := len(args)
var it iterator.Iterator
if n == 1 { //模糊查找
it = L.DB.NewIterator(util.BytesPrefix([]byte(args[0])), nil)
} else {
it = L.DB.NewIterator(&util.Range{Start: []byte(args[0]), Limit: []byte(args[1])}, nil)
}
for it.Next() {
tmp := L.Value
if err := tools.DecodeByte(it.Value(), tmp); err != nil {
//错误处理
mylog.Error(err)
}
*values = append(*values, Param{string(it.Key()), tmp})
}
it.Release()
//iter := L.DB.NewIterator(nil, nil)
} else {
if L.Value == nil {
panic("not call Model()")
}
mylog.Print(mylog.Log_Error, "not init.")
}
return false
}
//添加数据
//注意:只支持基础类型
func (L *MyLevelDB) Add(key string, value interface{}) bool {
if L.DB != nil {
by, err := tools.EncodeByte(value)
if err != nil {
//错误处理
mylog.Error(err)
return false
}
if err = L.DB.Put([]byte(key), by, nil); err != nil {
mylog.Error(err)
} else {
return true
}
}
return false
}
//添加一组数据(比一个一个添加速度快很多)
//注意:只支持基础类型
func (L *MyLevelDB) AddList(array []Param) bool {
if L.DB != nil {
batch := new(leveldb.Batch)
for _, p := range array {
by, err := tools.EncodeByte(p.Value)
if err != nil {
//错误处理
mylog.Error(err)
return false
}
batch.Put([]byte(p.Key), by)
}
err := L.DB.Write(batch, nil)
if err != nil {
//错误处理
mylog.Error(err)
return false
} else {
return true
}
}
return false
}
/*
删除
*/
func (L *MyLevelDB) Delete(key string) bool {
if L.DB != nil {
err := L.DB.Delete([]byte(key), nil)
if err != nil {
mylog.Error(err)
return false
}
return true
}
return false
}

Binary file not shown.

83
mylog/def.go Normal file
View File

@@ -0,0 +1,83 @@
package mylog
import (
"time"
)
/*
日志详细信息
*/
type LogInfo struct {
Service string `json:"service"` //服务名
Group string `json:"group"` //服务组
Type string `json:"type"` //日志的类型()
Action string `json:"action"` //动作
Path string `json:"path"` //路径,地址,深度
Ip string `json:"ip"` //ip地址
Topic string `json:"topic"`
Bundle string `json:"bundle"`
Pid string `json:"pid"`
Data interface{} `json:"data"`
Creat_time time.Time `json:"created"`
}
/*
向es发送数据结构信息
*/
type EsLogInfo struct {
Info LogInfo `json:"loginfo"` //信息
Es_index string `json:"es_index"` //索引
Es_type string `json:"es_type"` //类型
Es_id string `json:"es_id"` //id
}
const (
Http_log_index = "http_log"
)
const mapping = `
{
"settings":{
"number_of_shards": 1,
"number_of_replicas": 5
},
"mappings":{
"` + Http_log_index + `":{
"properties":{
"service":{
"type":"keyword"
},
"group":{
"type":"keyword"
},
"type":{
"type":"text"
},
"action":{
"type":"keyword"
},
"path":{
"type":"text"
},
"ip":{
"type":"text"
},
"topic":{
"type":"keyword"
},
"bundle":{
"type":"keyword"
},
"pid":{
"type":"keyword"
},
"data":{
"type":"text"
},
"created":{
"type":"date"
}
}
}
}
}`

122
mylog/myeslog.go Normal file
View File

@@ -0,0 +1,122 @@
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") //输出堆栈信息
}

101
mylog/mylog.go Normal file
View File

@@ -0,0 +1,101 @@
package mylog
import (
"data/config"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime/debug"
"time"
)
func init() {
file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
path = filepath.Dir(path)
os.MkdirAll(path+"/err", os.ModePerm) //生成多级目录
}
const ( //
Log_Error = iota //打印 Error 及以上级别
Log_warning //打印 warning 及以上级别
Log_Info //默认的返回值为0自增 //打印 Info 及以上级别
)
//
func Print(log_level int, describ string) {
log.Println(describ)
return
}
//
func Println(describ ...interface{}) {
for _, e := range describ {
switch v := e.(type) {
case string:
log.Println(v)
case []byte:
log.Println(string(v))
default:
log.Println(v)
}
}
return
}
//
func Info(describ string) {
log.Println(describ)
return
}
//
func Error(err error) {
log.Println(err)
SaveError(err.Error(), "err")
}
//保存错误信息
func SaveError(errstring, flag string) {
file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
path = filepath.Dir(path)
now := time.Now() //获取当前时间
time_str := now.Format("2006-01-02_15") //设定时间格式
fname := fmt.Sprintf("%s/err/%s_%s.log", path, flag, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
return
}
defer f.Close()
f.WriteString("=========================" + now.Format("2006-01-02 15:04:05 ========================= \r\n"))
f.WriteString(errstring + "\r\n") //输出堆栈信息
f.WriteString(string(debug.Stack()) + "\r\n") //输出堆栈信息)
f.WriteString("=========================end=========================\r\n")
}
//
func Debug(describ ...interface{}) {
if config.OnIsDev() {
for _, e := range describ {
switch v := e.(type) {
case string:
log.Println(v)
case []byte:
log.Println(string(v))
default:
log.Println(v)
}
}
}
}
//刷新
func Flush() {
}

144
mynsq/mynsq.go Normal file
View File

@@ -0,0 +1,144 @@
package mynsq
import (
"data/config"
"log"
"public/mylog"
"github.com/nsqio/go-nsq"
)
var producer *nsq.Producer = nil
var consumerMap map[int]*nsq.Consumer = nil
var cosumerTopics map[string][]int = nil
func init() {
consumerMap = make(map[int]*nsq.Consumer)
cosumerTopics = make(map[string][]int)
cnf := nsq.NewConfig()
var err error
producer, err = nsq.NewProducer(config.GetNsqAddr(), cnf)
if err != nil {
mylog.Print(mylog.Log_Error, err.Error())
panic(err)
}
}
//发消息
func ProduceMsg(topic string, message []byte) bool {
if producer == nil {
//channel 锁住
cnf := nsq.NewConfig()
var err error
producer, err = nsq.NewProducer(config.GetNsqAddr(), cnf)
if err != nil {
mylog.Print(mylog.Log_Error, err.Error())
return false
}
}
if producer != nil {
err := producer.Publish(topic, message)
if err != nil {
mylog.Print(mylog.Log_Error, err.Error())
return false
} else {
return true
}
}
return false
}
//单个nsqd处理消息
//index 表示consumer 索引(用于开关使用)
func StartConsumeMsg(index int, topic, channel, nsqd string, handler nsq.Handler) bool {
StopConsumeMsgByIndex(index)
//第一次初始化 进入
if consumerMap[index] == nil {
conf := nsq.NewConfig()
//最大允许向两台NSQD服务器接受消息默认是1
//config.MaxInFlight = 2
var err error
consumerMap[index], err = nsq.NewConsumer(topic, channel, conf)
if nil != err {
log.Println(err)
mylog.Print(mylog.Log_Error, err.Error())
return false
}
//开始正式启动(后台,非阻塞方式)
consumerMap[index].AddHandler(handler)
err = consumerMap[index].ConnectToNSQD(nsqd)
if nil != err {
log.Println(err)
mylog.Print(mylog.Log_Error, err.Error())
return false
}
cosumerTopics[topic] = append(cosumerTopics[topic], index)
return true
}
return false
}
func GetConsumeSize() int {
return len(consumerMap)
}
//停止消费
func StopConsumeMsgByIndex(index int) {
if consumerMap[index] != nil {
consumerMap[index].Stop()
consumerMap[index] = nil
for k, v := range cosumerTopics {
for i := range v {
if v[i] == index {
cosumerTopics[k] = append(v[:i], v[i+1:]...)
break
}
}
}
}
}
//停止某个topic下全部消费
func StopConsumeMsgByTopic(topic string) {
v, ok := cosumerTopics[topic]
if ok {
for i := range v {
if consumerMap[v[i]] != nil {
consumerMap[v[i]].Stop()
consumerMap[v[i]] = nil
}
}
}
var temp []int
cosumerTopics[topic] = temp
}
//停止所有topic的全部消费
func StopAllConsumeMsg() {
cosumerTopics = make(map[string][]int)
size := GetConsumeSize()
for i := 0; i < size; i++ {
StopConsumeMsgByIndex(i)
}
consumerMap = make(map[int]*nsq.Consumer)
}
//func TestNSQ() {
// for k, v := range cosumerTopics {
// log.Println("topic is", k)
// for _, vv := range v {
// log.Println("consumer index is", vv)
// log.Println("consumer is ", consumerMap[vv])
// }
// }
//}

89
myqueue/myqueue.go Normal file
View File

@@ -0,0 +1,89 @@
package myqueue
import (
"sync"
"gopkg.in/eapache/queue.v1"
)
type MyQueue struct {
lock sync.Mutex
popable *sync.Cond
buffer *queue.Queue
closed bool
}
// 创建
func NewSyncQueue() *MyQueue {
ch := &MyQueue{
buffer: queue.New(),
}
ch.popable = sync.NewCond(&ch.lock)
return ch
}
// 取出队列,(阻塞模式)
func (q *MyQueue) Pop() (v interface{}) {
c := q.popable
buffer := q.buffer
q.lock.Lock()
for buffer.Length() == 0 && !q.closed {
c.Wait()
}
if buffer.Length() > 0 {
v = buffer.Peek()
buffer.Remove()
}
q.lock.Unlock()
return
}
//试着取出队列非阻塞模式返回ok == false 表示空
func (q *MyQueue) TryPop() (v interface{}, ok bool) {
buffer := q.buffer
q.lock.Lock()
if buffer.Length() > 0 {
v = buffer.Peek()
buffer.Remove()
ok = true
} else if q.closed {
ok = true
}
q.lock.Unlock()
return
}
// 插入队列,非阻塞
func (q *MyQueue) Push(v interface{}) {
q.lock.Lock()
if !q.closed {
q.buffer.Add(v)
q.popable.Signal()
}
q.lock.Unlock()
}
// 获取队列长度
func (q *MyQueue) Len() (l int) {
q.lock.Lock()
l = q.buffer.Length()
q.lock.Unlock()
return
}
// 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()
if !q.closed {
q.closed = true
q.popable.Signal()
}
q.lock.Unlock()
}

9
myrunner/error.go Normal file
View File

@@ -0,0 +1,9 @@
package myrunner
import "errors"
//任务执行超时
var ErrTimeOut = errors.New("run time out")
//任务执行中断
var ErrInterruput = errors.New("run interruput")

102
myrunner/myrunner.go Normal file
View File

@@ -0,0 +1,102 @@
package myrunner
import (
"os"
"os/signal"
"time"
)
//后台执行任何限时任务,而且我们还可以控制这个执行者,比如强制终止它等
type Runner struct {
tasks []func() //要执行的任务
complete chan error //用于通知任务全部完成
timeout <-chan time.Time //这些任务在多久内完成 只能接收
interrupt chan os.Signal //可以控制强制终止的信号
}
//工厂方法
func New(tm time.Duration) *Runner {
return &Runner{
complete: make(chan error), //同步通道main routine等待一致要任务完成或者被强制终止
timeout: time.After(tm),
interrupt: make(chan os.Signal, 1), //至少接收到一个操作系统的中断信息
}
}
//
func (r *Runner) Add(tasks ...func()) {
r.tasks = append(r.tasks, tasks...)
}
//
func (r *Runner) run() error {
for _, task := range r.tasks {
if r.isInterrupt() {
return ErrInterruput
}
task()
}
return nil
}
//检查是否接收到了中断信号
func (r *Runner) isInterrupt() bool {
select {
case <-r.interrupt:
signal.Stop(r.interrupt)
return true
default:
return false
}
}
//开始执行所有任务,并且监视通道事件
func (r *Runner) Start() error {
//希望接收哪些系统信号
signal.Notify(r.interrupt, os.Interrupt) //如果有系统中断的信号发给r.interrupt
go func() {
r.complete <- r.run()
}()
select {
case err := <-r.complete:
return err
case <-r.timeout:
return ErrTimeOut
}
}
/*
调用示例:
func main() {
log.Println("...开始执行任务...")
timeout := 2 * time.Second
r := New(timeout)
r.Add(createTask(0), createTask(1), createTask(2))
if err := r.Start(); err != nil {
switch err {
case ErrTimeOut:
log.Println(err)
os.Exit(1) //退出
case ErrInterruput:
log.Println(err)
os.Exit(2)
default:
break
}
}
log.Println("...任务执行结束...")
}
func createTask(param int) func() {
return func() {
log.Printf("正在执行任务%d", param)
time.Sleep(time.Duration(param) * time.Second)
}
}
*/

24
mysign/def.go Normal file
View File

@@ -0,0 +1,24 @@
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"` //签名
}

96
mysign/sign.go Normal file
View File

@@ -0,0 +1,96 @@
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...))
}

20
mysign/sign_test.go Normal file
View File

@@ -0,0 +1,20 @@
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())
}

59
mysqlbeedb/mysqlbeedb.go Normal file
View File

@@ -0,0 +1,59 @@
/*
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 mysqlbeedb
import (
"database/sql"
"fmt"
"public/mylog"
"data/config"
"github.com/astaxie/beedb"
_ "github.com/go-sql-driver/mysql"
)
type MySqlDB struct {
DB *sql.DB
}
func (i *MySqlDB) OnGetDBOrm(dataSourceName string) (orm beedb.Model) {
if i.DB == nil {
var err error
i.DB, err = sql.Open("mysql", dataSourceName)
if err != nil {
mylog.Print(mylog.Log_Error, fmt.Sprintf("Got error when connect database, the error is '%v'", err))
}
}
orm = beedb.New(i.DB)
if config.OnIsDev() {
beedb.OnDebug = true
}
return
}
func (i *MySqlDB) OnDestoryDB() {
if i.DB != nil {
i.DB.Close()
i.DB = nil
}
}

36
mysqldb/log.go Normal file
View File

@@ -0,0 +1,36 @@
package mysqldb
import (
"fmt"
"public/mylog"
"github.com/jinzhu/gorm"
)
var LogFormatter = func(values ...interface{}) (messages []interface{}) {
if len(values) > 1 {
var (
currentTime = "\t[" + gorm.NowFunc().Format("2006-01-02 15:04:05") + "]"
source = fmt.Sprintf("(%v)\t", values[1])
)
messages = []interface{}{source, currentTime}
messages = append(messages, "\t [")
messages = append(messages, values[2:]...)
messages = append(messages, "]")
}
return
}
//
type DbLog struct {
gorm.Logger
}
//
func (db DbLog) Print(values ...interface{}) {
msg := LogFormatter(values...)
str := fmt.Sprint(msg...)
mylog.SaveError(str, "sql")
}

66
mysqldb/mysqldb.go Normal file
View File

@@ -0,0 +1,66 @@
/*
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"
"data/config"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
)
type MySqlDB struct {
DB *gorm.DB
}
func (i *MySqlDB) OnGetDBOrm(dataSourceName string) (orm *gorm.DB) {
if i.DB == nil {
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))
}
}
i.DB.SingularTable(true) //全局禁用表名复数
orm = i.DB
if config.OnIsDev() {
orm.LogMode(true)
//beedb.OnDebug = true
} else {
orm.SetLogger(DbLog{})
}
return
}
func (i *MySqlDB) OnDestoryDB() {
if i.DB != nil {
i.DB.Close()
i.DB = nil
}
}
func init() {
}

Binary file not shown.

208
mywebsocket/mywebsocket.go Normal file
View File

@@ -0,0 +1,208 @@
package mywebsocket
/*
说明:第一个包 初始化client唯一id。消息id为100
*/
import (
"encoding/json"
"net/http"
"public/mycache"
"public/mylog"
"sync"
"time"
"github.com/ant0ine/go-json-rest/rest"
"golang.org/x/net/websocket"
)
type ClientBody struct {
Code int `json:"code,omitempty"`
Data interface{} `json:"data,omitempty"`
}
type WSMessageType uint8
const (
WS_Login WSMessageType = 1 // 链接
WS_Close WSMessageType = 2 // 断线
)
type HandlerReadFunc func(string, string, ClientBody, *websocket.Conn) //ID , MESSAGEID,内容
type HandlerStateFunc func(string, string, WSMessageType) //状态发声改变回调
var mutex sync.Mutex
/*
写数据
pathExp:请求的根路径
clientid:发送人id
body:发送内容
*/
func WriteData(pathExp string, clientid string, body ClientBody) bool {
wb, err := json.Marshal(body)
if err != nil {
mylog.Debug("error:", err.Error())
return false
}
cache := mycache.OnGetCache("websocket" + pathExp)
tp, b := cache.Value(clientid)
if b {
b_r := false
tmp := tp.([]*websocket.Conn)
for i := 0; i < len(tmp); i++ {
if _, err = tmp[i].Write(wb); err != nil {
mylog.Debug("Can't send", err.Error())
defer tmp[i].Close()
} else {
b_r = true
}
}
return b_r
} else {
mylog.Debug("not find client:" + clientid)
return false
}
}
//websocket 初始化接口
/*
pathExp 域,
handlerFunc 读到的消息回调
stateFunc 连接消息回调
timeOut 读取超时回调(0则永不超时)
isMult 是否多用户登录
*/
func InitWebSocket(pathExp string, handlerFunc HandlerReadFunc, stateFunc HandlerStateFunc, timeOut time.Duration, isMult bool) *rest.Route {
wsHandler := websocket.Handler(func(ws *websocket.Conn) {
mylog.Debug("enter")
var err error
var msg = make([]byte, 1024)
var n int
n, err = ws.Read(msg)
if err != nil {
mylog.Debug("ws:close")
return
}
var clientid string
var clientBody ClientBody
err = json.Unmarshal(msg[:n], &clientBody)
if err != nil {
mylog.Debug("Unmarshal:" + err.Error())
return
} else {
if clientBody.Code != 100 {
mylog.Debug("messageid error")
return
}
clientid = clientBody.Data.(string)
//保存缓存
cache := mycache.OnGetCache("websocket" + pathExp)
var tmp []*websocket.Conn
mutex.Lock()
tp, b := cache.Value(clientid)
if b && isMult { //多用户
tmp = tp.([]*websocket.Conn)
}
tmp = append(tmp, ws)
cache.Add(clientid, tmp, 2*time.Hour) //2小时过期
mutex.Unlock()
//------------------end
mylog.Debug("init success:" + clientid)
if stateFunc != nil {
stateFunc(pathExp, clientid, WS_Login)
}
}
ch := make(chan bool, 1)
if timeOut > 0 {
go func(ws *websocket.Conn) {
var after <-chan time.Time
loop:
after = time.After(timeOut)
for {
select {
case b := <-ch: //继续下一个等待
if !b {
break
} else {
goto loop
}
case <-after: //超时处理
mylog.Print(mylog.Log_Info, "time out:"+clientid)
ws.Close()
break
}
}
}(ws)
}
for {
n, err = ws.Read(msg)
if err != nil {
if timeOut > 0 {
ch <- false
}
mylog.Debug("ws:close")
break
} else if timeOut > 0 {
ch <- true
}
var body ClientBody
err = json.Unmarshal(msg[:n], &body)
if err != nil {
mylog.Debug("r:" + err.Error())
} else {
if handlerFunc != nil {
handlerFunc(pathExp, clientid, body, ws)
}
}
}
//删除缓存
cache := mycache.OnGetCache("websocket" + pathExp)
var tmp []*websocket.Conn
mutex.Lock()
tp, b := cache.Value(clientid)
if b {
tmp = tp.([]*websocket.Conn)
}
i := 0
for ; i < len(tmp); i++ {
if tmp[i] == ws {
tmp = append(tmp[:i], tmp[i+1:]...) // 最后面的“...”不能省略
break
}
}
if i == 0 || len(tmp) == 0 || !isMult {
cache.Delete(clientid)
mylog.Debug("delete all: " + clientid)
} else {
cache.Add(clientid, tmp, 2*time.Hour) //2小时过期
mylog.Debug("delete one: " + clientid)
}
mutex.Unlock()
if stateFunc != nil {
stateFunc(pathExp, clientid, WS_Close)
}
//------------------end
})
return rest.Get(pathExp, func(w rest.ResponseWriter, r *rest.Request) {
//mylog.Debug("-------------")
wsHandler.ServeHTTP(w.(http.ResponseWriter), r.Request)
})
}

View File

@@ -0,0 +1,41 @@
package serializing
import(
"bytes"
"encoding/gob"
)
/*
适用类型二进制到struct相互转换
使用方法:
b, err := serializing.Encode(data)
if err != nil {
//错误处理
}
if err := serializing.Decode(b, &to); err != nil {
//错误处理
}
*/
/*
功能:序列化
*/
func Encode(data interface{})([]byte, error){
buf := bytes.NewBuffer(nil)
enc := gob.NewEncoder(buf)
err := enc.Encode(data)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
/*
功能:反序列化
*/
func Decode(data []byte,to interface{}) error{
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
return dec.Decode(to)
}

12
server/def.go Normal file
View File

@@ -0,0 +1,12 @@
package server
const (
Stopped = 1
StartPending = 2
StopPending = 3
Running = 4
ContinuePending = 5
PausePending = 6
Paused = 7
NOTFIND = 8
)

137
server/server.go Normal file
View File

@@ -0,0 +1,137 @@
package server
import (
"fmt"
"os"
"time"
"data/config"
"github.com/jander/golog/logger"
"github.com/kardianos/service"
)
func OnStart(callBack func()) {
name, displayName, desc := config.GetServiceConfig()
p := &program{callBack}
sc := &service.Config{
Name: name,
DisplayName: displayName,
Description: 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)
return
}
fmt.Printf("Service \"%s\" do.\n", displayName)
if len(os.Args) > 1 {
var err error
verb := os.Args[1]
switch verb {
case "install":
{
err = s.Install()
if err != nil {
fmt.Printf("Failed to install: %s\n", err)
return
}
fmt.Printf("Service \"%s\" installed.\n", displayName)
}
case "remove":
{
err = s.Uninstall()
if err != nil {
fmt.Printf("Failed to remove: %s\n", err)
return
}
fmt.Printf("Service \"%s\" removed.\n", displayName)
}
case "run":
{
err = s.Run()
if err != nil {
fmt.Printf("Failed to run: %s\n", err)
return
}
fmt.Printf("Service \"%s\" run.\n", displayName)
}
case "start":
{
err = s.Start()
if err != nil {
fmt.Printf("Failed to start: %s\n", err)
return
}
fmt.Println("starting check service:", displayName)
ticker := time.NewTicker(1 * time.Second)
<-ticker.C
st, err := IsStart(name)
if err != nil {
fmt.Println(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)
}
case "stop":
{
err = s.Stop()
if err != nil {
fmt.Printf("Failed to stop: %s\n", err)
return
}
st, err := IsStart(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)
}
}
return
} else {
fmt.Print("Failed to read args\n")
//return
}
if err = s.Run(); err != nil {
logger.Error(err)
}
}
type program struct {
callBack func()
}
func (p *program) Start(s service.Service) error {
go p.run()
return nil
}
func (p *program) run() {
p.callBack()
}
func (p *program) Stop(s service.Service) error {
return nil
}
type ServiceTools interface {
IsStart(name string) (status int, err error)
}

32
server/server_linux.go Normal file
View File

@@ -0,0 +1,32 @@
package server
import (
"fmt"
"os/exec"
"strings"
)
type WindowsServiceTools struct {
i ServiceTools
}
func IsStart(name string) (st int, err error) {
f, _ := exec.Command("service", name, "status").Output()
st = NOTFIND
str := string(f)
a := strings.Split(str, "\n")
for _, v := range a {
if strings.Index(v, "Active:") > 0 {
fmt.Println("====info===:", v)
if strings.Index(v, "inactive") > 0 { //不活动的
st = Stopped
} else if strings.Index(v, "activating") > 0 { //活动的
st = Running
}
break
}
}
return
}

30
server/server_windows.go Normal file
View File

@@ -0,0 +1,30 @@
package server
import (
"github.com/btcsuite/winsvc/mgr"
"github.com/btcsuite/winsvc/svc"
)
type WindowsServiceTools struct {
i ServiceTools
}
func IsStart(name string) (st int, err error) {
var m *mgr.Mgr
m, err = mgr.Connect()
if err != nil {
return 0, err
}
defer m.Disconnect()
s, err := m.OpenService(name)
if err != nil {
return 0, err
}
defer s.Close()
var ss svc.Status
ss, err = s.Query()
st = int(ss.State)
return
}

15
sign/def.go Normal file
View File

@@ -0,0 +1,15 @@
package sign
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_verify int //是否强制验证:0用户自定义1强制
}

93
sign/sign.go Normal file
View File

@@ -0,0 +1,93 @@
package sign
import (
"data/config"
"public/mycache"
"public/mylog"
"public/mysqldb"
"public/tools"
"strings"
"time"
)
func init() {
OnInit()
}
func OnInit() {
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()
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) {
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 {
cache := mycache.OnGetCache(_sign_data)
tp, b := cache.Value(appkey)
if b {
sign = tp.(Sign_client_tbl)
} else {
sign = getOne(appkey)
}
}
if sign.Id == 0 {
return ""
}
//开始验签
var strKey string
for _, v := range parm {
strKey += tools.AsString(v)
}
return tools.Md5Encoder(strKey)
}
/*
开始验签
*/
func OnCheckSign(appkey, signature string, parm ...interface{}) bool {
return strings.EqualFold(signature, OnGetSign(appkey, parm))
}

20
sign/sign_test.go Normal file
View File

@@ -0,0 +1,20 @@
package sign
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())
}

8
timerDeal/cron.go Normal file
View File

@@ -0,0 +1,8 @@
package timerDeal
//cron
// c := cron.New()
// c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
// c.AddFunc("@hourly", func() { fmt.Println("Every hour") })
// c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
// c.Start()

37
timerDeal/timerDeal.go Normal file
View File

@@ -0,0 +1,37 @@
package timerDeal
import (
"log"
"time"
)
type TimerDeal struct {
f_list []func()
f_d_timeout time.Duration
}
//增加一个回调
func (t *TimerDeal) AddOneCall(f func()) {
t.f_list = append(t.f_list, f)
}
//设置超时时间
func (t *TimerDeal) SetCallBackTimer(d time.Duration) {
t.f_d_timeout = d
}
func (t *TimerDeal) OnSart() {
//time.Tick()
go t.onTick()
}
func (t *TimerDeal) onTick() {
ticker := time.NewTicker(t.f_d_timeout)
for {
time := <-ticker.C
for _, v := range t.f_list {
v()
}
log.Println("timer callback:", time.String())
}
}

47
timerDeal/timetask.go Normal file
View File

@@ -0,0 +1,47 @@
package timerDeal
import (
"log"
"public/mydef"
"public/mylog"
"time"
)
/*
主要为定时任务
*/
/*
超时回调
t:超时时间
fun:回调接口
args:回调接口传入的参数
*/
func OnDealTimeOut(t time.Duration, fun mydef.ParamsCallFunc, parms ...interface{}) {
go func() {
ticker := time.NewTicker(t)
<-ticker.C
mylog.Debug("timer 执行.....")
//以下为定时执行的操作
fun(parms...)
}()
}
/*
每月事件
day : 几号
hour, min, sec : 几点(当天的0点偏移秒数)
callback : 时间回调
*/
func OnPeMonth(day int, hour, min, sec int, callback func()) {
go func() {
for {
next := time.Now().AddDate(0, 1, 0)
next = time.Date(next.Year(), next.Month(), day, hour, min, sec, 0, next.Location())
t := time.NewTimer(next.Sub(time.Now()))
log.Println("next time callback:", next)
<-t.C
callback()
}
}()
}

52
tools/check.go Normal file
View File

@@ -0,0 +1,52 @@
package tools
import (
"fmt"
"os"
"regexp"
"strings"
)
//检测参数
func CheckParam(params ...string) bool {
for _, value := range params {
if len(value) == 0 {
return false
}
}
return true
}
//判断是否是手机号
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)
}
//判断用户是否是邮件用户
func IsMail(username string) (isMail bool) {
isMail = false
if strings.Contains(username, "@") {
isMail = true //是邮箱
}
return
}
//判断是否在测试环境下使用
func IsRunTesting() bool {
if len(os.Args) > 1 {
fmt.Println(os.Args[1])
return strings.HasPrefix(os.Args[1], "-test")
}
return false
}
//判断是否是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 {
return false
}
return true
}

139
tools/convert.go Normal file
View File

@@ -0,0 +1,139 @@
package tools
import (
"bytes"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"public/mylog"
"regexp"
"strconv"
"strings"
"time"
)
type RawBytes []byte
var errNilPtr = errors.New("destination pointer is nil")
func cloneBytes(b []byte) []byte {
if b == nil {
return nil
} else {
c := make([]byte, len(b))
copy(c, b)
return c
}
}
func AsString(src interface{}) string {
switch v := src.(type) {
case string:
return v
case []byte:
return string(v)
case int:
return strconv.Itoa(v)
case int32:
return strconv.FormatInt(int64(v), 10)
case int64:
return strconv.FormatInt(v, 10)
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 64)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case time.Time:
return GetTimeStr(v)
case bool:
return strconv.FormatBool(v)
default:
{
b, _ := json.Marshal(v)
mylog.Println(string(b))
return string(b)
}
}
return fmt.Sprintf("%v", src)
}
//编码二进制
func EncodeByte(data interface{}) ([]byte, error) {
buf := bytes.NewBuffer(nil)
enc := gob.NewEncoder(buf)
err := enc.Encode(data)
if err != nil {
mylog.Error(err)
return nil, err
}
return buf.Bytes(), nil
}
//解码二进制
func DecodeByte(data []byte, to interface{}) error {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
return dec.Decode(to)
}
//byte转16进制字符串
func ByteToHex(data []byte) string {
buffer := new(bytes.Buffer)
for _, b := range data {
s := strconv.FormatInt(int64(b&0xff), 16)
if len(s) == 1 {
buffer.WriteString("0")
}
buffer.WriteString(s)
}
return buffer.String()
}
//16进制字符串转[]byte
func HexToBye(hex string) []byte {
length := len(hex) / 2
slice := make([]byte, length)
rs := []rune(hex)
for i := 0; i < length; i++ {
s := string(rs[i*2 : i*2+2])
value, _ := strconv.ParseInt(s, 16, 10)
slice[i] = byte(value & 0xFF)
}
return slice
}
//Emoji表情解码
func UnicodeEmojiDecode(s string) string {
//emoji表情的数据表达式
re := regexp.MustCompile("\\[[\\\\u0-9a-zA-Z]+\\]")
//提取emoji数据表达式
reg := regexp.MustCompile("\\[\\\\u|]")
src := re.FindAllString(s, -1)
for i := 0; i < len(src); i++ {
e := reg.ReplaceAllString(src[i], "")
p, err := strconv.ParseInt(e, 16, 32)
if err == nil {
s = strings.Replace(s, src[i], string(rune(p)), -1)
}
}
return s
}
//Emoji表情转换
func UnicodeEmojiCode(s string) string {
ret := ""
rs := []rune(s)
for i := 0; i < len(rs); i++ {
if len(string(rs[i])) == 4 {
u := `[\u` + strconv.FormatInt(int64(rs[i]), 16) + `]`
ret += u
} else {
ret += string(rs[i])
}
}
return ret
}

66
tools/file.go Normal file
View File

@@ -0,0 +1,66 @@
package tools
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"public/mylog"
)
//检查目录是否存在
func CheckFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
mylog.Debug(filename + " not exist")
exist = false
}
return exist
}
//创建目录
func BuildDir(abs_dir string) error {
return os.MkdirAll(abs_dir, os.ModePerm) //生成多级目录
}
//删除文件或文件夹
func DeleteFile(abs_dir string) error {
return os.RemoveAll(abs_dir)
}
//获取目录所有文件夹
func GetPathDirs(abs_dir string) (re []string) {
if CheckFileIsExist(abs_dir) {
files, _ := ioutil.ReadDir(abs_dir)
for _, f := range files {
if f.IsDir() {
re = append(re, f.Name())
}
}
}
return
}
//获取目录所有文件夹
func GetPathFiles(abs_dir string) (re []string) {
if CheckFileIsExist(abs_dir) {
files, _ := ioutil.ReadDir(abs_dir)
for _, f := range files {
if !f.IsDir() {
re = append(re, f.Name())
}
}
}
return
}
//获取目录地址
func GetModelPath() string {
file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
// if len(path) > 0 {
// path += "/"
// }
path = filepath.Dir(path)
return path
}

75
tools/ip.go Normal file
View File

@@ -0,0 +1,75 @@
package tools
import (
"bytes"
"io/ioutil"
"net"
"net/http"
"public/mylog"
"strings"
)
///*
// 获取外网ip
//*/
//func GetWwwIP() (ip string) {
// ip = ""
// resp, err := http.Get("http://myexternalip.com/raw")
// if err != nil {
// mylog.Error(err)
// return
// }
// defer resp.Body.Close()
// body, err := ioutil.ReadAll(resp.Body)
// if err != nil {
// return
// }
// ip = string(body)
// ip = strings.Split(ip, "\n")[0]
// return
//}
//获取公网IP地址
func GetWwwIP() (exip string) {
resp, err := http.Get("http://myexternalip.com/raw")
if err != nil {
return ""
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ""
}
return string(bytes.TrimSpace(b))
}
/*
获取内网ip
*/
func GetLocalIP() (ip string) {
addrs, err := net.InterfaceAddrs()
if err != nil {
mylog.Error(err)
return
}
for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
ip = ipnet.IP.String()
break
}
}
}
return
}
//获取用户ip
func GetClientIp(r *http.Request) (ip string) {
ip = r.Header.Get("X-Real-Ip")
if ip == "" {
ip = strings.Split(r.RemoteAddr, ":")[0]
}
return
}

68
tools/json.go Normal file
View File

@@ -0,0 +1,68 @@
package tools
import (
"encoding/json"
"io/ioutil"
"net/http"
"github.com/ant0ine/go-json-rest/rest"
)
func JsonToForm(r *http.Request) {
//添加支持json 操作
r.ParseForm()
if len(r.Form) == 1 { //可能是json 支持json
for key, value := range r.Form {
if len(value[0]) == 0 {
delete(r.Form, key)
var m map[string]string
if err := json.Unmarshal([]byte(key), &m); err == nil {
for k, v := range m {
r.Form[k] = []string{v}
}
}
}
}
}
body, _ := ioutil.ReadAll(r.Body)
body_str := string(body)
if len(body_str) > 0 {
var m map[string]string
if err := json.Unmarshal(body, &m); err == nil {
for k, v := range m {
r.Form[k] = []string{v}
}
}
}
//-----------------------------end
return
}
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
}
func GetJsonStr(obj interface{}) string {
b, _ := json.Marshal(obj)
return string(b)
}
func JsonDecode(obj interface{}) string {
return GetJsonStr(obj)
}
func GetJsonObj(str string, out interface{}) {
json.Unmarshal([]byte(str), out)
return
}
func JsonEncode(str string, out interface{}) {
GetJsonObj(str, out)
}

13
tools/mybase64.go Normal file
View File

@@ -0,0 +1,13 @@
package tools
import (
"encoding/base64"
)
func Base64Encode(src []byte) string {
return base64.StdEncoding.EncodeToString(src)
}
func Base64Decode(src []byte) ([]byte, error) {
return base64.StdEncoding.DecodeString(string(src))
}

47
tools/rand.go Normal file
View File

@@ -0,0 +1,47 @@
package tools
import (
"math/rand"
"time"
)
//生成随机字符串
var _bytes []byte = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
var r *rand.Rand
func GetRandomString(n int) string {
result := []byte{}
if r == nil {
r = rand.New(rand.NewSource(time.Now().UnixNano()))
}
for i := 0; i < n; i++ {
result = append(result, _bytes[r.Intn(len(_bytes))])
}
return string(result)
}
//生成随机整数 digit位数
func GenerateRangeNum(digit int) int {
var max, min int = 1, 1
if digit > 0 {
for i := 0; i < digit; i++ {
max = max * 10
}
for i := 0; i < digit-1; i++ {
min = min * 10
}
}
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}
//生成随机整数 digit位数
func GetGetRandInt(min int, max int) int {
if min > max {
min = 0
max = 0
}
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}

97
tools/str.go Normal file
View File

@@ -0,0 +1,97 @@
package tools
import (
"strconv"
"strings"
"github.com/axgle/mahonia"
)
//int数组转字符串
func FormatInt(list []int, seg string) string {
s := make([]string, len(list))
for i := range list {
s[i] = strconv.Itoa(list[i])
}
return strings.Join(s, seg)
}
//字符串去除特殊字符
//func DealStr(str, replace string) string {
// var s string = strings.TrimSpace(str) //去除尾部空格
// strings.Replace(s, replace, "", -1)
// return s
//}
//截取字符串 不包括str
func Substr(str string, start, length int) string {
rs := []rune(str)
rl := len(rs)
end := 0
if start < 0 {
start = rl - 1 + start
}
end = start + length
if start > end {
start, end = end, start
}
if start < 0 {
start = 0
}
if start > rl {
start = rl
}
if end < 0 {
end = 0
}
if end > rl {
end = rl
}
return string(rs[start:end])
}
//查找字符串最小值
func MinimumString(rest []string) string {
minimum := rest[0]
for _, v := range rest {
if v := v; v < minimum {
minimum = v
}
}
return minimum
}
//字符集转换
func ConvertToString(src string, srcCode string, tagCode string) string {
srcCoder := mahonia.NewDecoder(srcCode)
srcResult := srcCoder.ConvertString(src)
tagCoder := mahonia.NewDecoder(tagCode)
_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
return string(cdata)
}
//系统转其他
func ConvertString(src string, tagCode string) string {
enc := mahonia.NewEncoder(tagCode)
return enc.ConvertString(src)
}
//
func GetGBK(src string) string {
return string(ConvertString(src, "gbK"))
}
//反转字符串
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}

186
tools/timeTools.go Normal file
View File

@@ -0,0 +1,186 @@
package tools
import (
"fmt"
"strings"
"time"
)
//获取本地时间戳
func GetUtcTime(tm time.Time) int64 {
return tm.Unix() //- 8*60*60
}
//当前时间向上取整点
func GetHour(timestamp int64) int {
// formaTime := time.Format("2006-01-02 15:04:05")
tm := time.Unix(timestamp, 0)
return tm.Hour()
}
//获取offset天的现在时间:注意时区
func GetLastDayCurrentTime(timestamp int64, offset int) time.Time {
tm := time.Unix(timestamp, 0)
yesDay := tm.AddDate(0, 0, 1*offset)
return yesDay
}
//获取给定时间的星期
func GetTimeWeek(timestamp int64) int {
tm := time.Unix(timestamp, 0)
weekDay := tm.Weekday().String()
var week int = 0
switch weekDay {
case "Monday":
week = 1
case "Tuesday":
week = 2
case "Wednesday":
week = 3
case "Thursday":
week = 4
case "Friday":
week = 5
case "Saturday":
week = 6
default:
week = 0
}
return week
}
//获取向上整时时间
func GetHour0(timestamp int64, timeZone *time.Location) 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)
}
//获取给定日期的零点时间
func GetDay0(timestamp int64, timeZone *time.Location) 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)
}
//获取offset 0点时间
func GetUtcDay0(now time.Time, timeZone *time.Location) int64 {
tm := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
return tm.Unix()
}
//字符串转时间
func StrToTime(tStr, format string, timeZone *time.Location) time.Time {
if len(format) == 0 {
format = "2006-01-02 15:04:05"
}
if timeZone == nil {
//chinaLocal, _ := time.LoadLocation("Local")
timeZone = time.Local
}
ti, _ := time.ParseInLocation(format, tStr, timeZone)
return ti
}
/*
给定字符串时间转换成本地时间戳
*/
func StringTimetoUnix(timestr string) int64 {
return StrToTime(timestr, "2006-01-02 15:04:05", time.Local).Unix()
}
//获取最近上个星期天的零点日期
func GetTimeWeek0(timestamp int64) int64 {
weekday := GetTimeWeek(timestamp)
tm0 := GetDay0(timestamp, nil)
tm0 = tm0.AddDate(0, 0, -1*weekday)
return tm0.Unix()
}
/*
获取给定时间的当月1号零点时间
*/
func GetMonth0(timestamp int64) time.Time {
tm0 := GetDay0(timestamp, nil)
month0 := tm0.Day() - 1
tm0 = tm0.AddDate(0, 0, -1*month0) //这个月1号
return tm0
}
//整点执行操作
func TimerByHour(f func()) {
for {
now := time.Now()
// 计算下一个整点
next := now.Add(time.Hour * 1)
next = time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), 0, 0, 0, next.Location())
t := time.NewTimer(next.Sub(now))
<-t.C
//以下为定时执行的操作
f()
}
}
//时间戳转换为time
func UnixToTime(timestamp int64) time.Time {
return time.Unix(timestamp, 0)
}
//获取本地时间
func GetLocalTime(tm time.Time) time.Time {
local, _ := time.LoadLocation("Local")
return tm.In(local)
//return tm.Add(8 * 60 * 60 * time.Second)
}
//获取系统时间的格式
func GetSysTimeLayout() string {
t := time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC)
strLayout := strings.Replace(t.String(), "+0000 UTC", "", -1)
return strings.TrimSpace(strLayout)
}
func FormatTime(tm time.Time, for_str string) string {
return tm.Format(for_str)
}
func GetTimeStr(tm time.Time) string {
return FormatTime(tm, "2006-01-02 15:04:05")
}
func GetDayStr(tm time.Time) string {
return FormatTime(tm, "2006-01-02")
}
//json marsh 重写
type Time struct {
time.Time
}
func (t *Time) UnmarshalJSON(data []byte) (err error) {
tmp := string(data)
str := `"2006-01-02 15:04:05"`
if len(tmp) <= 20 {
str = `"2006-01-02"`
}
if tmp != `""` {
now, err1 := time.ParseInLocation(str, tmp, time.Local)
err = err1
*t = Time{now}
}
return
}
func (t Time) MarshalJSON() ([]byte, error) {
var stamp = fmt.Sprintf(`"%s"`, t.Format("2006-01-02 15:04:05"))
return []byte(stamp), nil
}
func (t Time) String() string {
return t.Format("2006-01-02 15:04:05")
}

154
tools/tools.go Normal file
View File

@@ -0,0 +1,154 @@
package tools
import (
"crypto/md5"
crand "crypto/rand"
"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"
)
/*
获取程序运行路径
*/
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)) // 需要加密的字符串
// fmt.Printf("%x\n", h.Sum(nil)) // 输出加密结
ret := fmt.Sprintf("%x", h.Sum(nil))
return strings.ToUpper(ret)
}
//合并数组
func Copy(dest []interface{}, src []interface{}) (result []interface{}) {
result = make([]interface{}, len(dest)+len(src))
copy(result, dest)
copy(result[len(dest):], src)
return
}
//删除数组
func DeleteArray(src []interface{}, index int) (result []interface{}) {
result = append(src[:index], src[(index+1):]...)
return
}
//生成32位md5字串
func GetMd5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
//获取总页数
func GetTotalPageNum(pageSize, totalCount int) int {
return (totalCount + pageSize - 1) / pageSize
}
//生成32位guid
func UniqueId() string {
b := make([]byte, 48)
if _, err := io.ReadFull(crand.Reader, b); err != nil {
return ""
}
return GetMd5String(base64.URLEncoding.EncodeToString(b))
}
//删除切片index
func DeleteSlice(slice interface{}, index int) (interface{}, error) {
sliceValue := reflect.ValueOf(slice)
length := sliceValue.Len()
if slice == nil || length == 0 || (length-1) < index {
return nil, errors.New("error")
}
if length-1 == index {
return sliceValue.Slice(0, index).Interface(), nil
} else {
return reflect.AppendSlice(sliceValue.Slice(0, index), sliceValue.Slice(index+1, length)).Interface(), nil
}
}
//查找int最小值
func MinimumInt(rest []int) int {
minimum := rest[0]
for _, v := range rest {
if v < minimum {
minimum = v
}
}
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...))
}
/*
执行模版渲染,
name:模版名字,""则无名字
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")
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) {
sort.Strings(res)
if len(res) > 0 {
for _, v := range res {
str += v
}
}
return
}
//SHA1加密
func Sha1Encrypt(str string) string {
h := sha1.New()
h.Write([]byte(str))
bs := h.Sum(nil)
return fmt.Sprintf("%x", bs)
}
//中文字符切割时有问题。采用此方式不会有问题
func GetUtf8Str(str string) []rune {
return []rune(str)
}

139
tools/zip.go Normal file
View File

@@ -0,0 +1,139 @@
package tools
import (
"archive/zip"
"bytes"
"io"
"os"
"path/filepath"
)
func IsZip(zipPath string) bool {
f, err := os.Open(zipPath)
if err != nil {
return false
}
defer f.Close()
buf := make([]byte, 4)
if n, err := f.Read(buf); err != nil || n < 4 {
return false
}
return bytes.Equal(buf, []byte("PK\x03\x04"))
}
func Unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
if err := os.MkdirAll(target, 0755); err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode())
continue
}
//------------注入
dir := filepath.Dir(path)
if len(dir) > 0 {
if _, err = os.Stat(dir); os.IsNotExist(err) {
err = os.MkdirAll(dir, 0755)
if err != nil {
return err
}
}
}
//---------------------end
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close()
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}
//压缩文件
//files 文件数组可以是不同dir下的文件或者文件夹
//dest 压缩文件存放地址
func Compress(files []*os.File, dest string) error {
d, _ := os.Create(dest)
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
for _, file := range files {
err := compress(file, "", w)
if err != nil {
return err
}
}
return nil
}
func compress(file *os.File, prefix string, zw *zip.Writer) error {
info, err := file.Stat()
if err != nil {
return err
}
if info.IsDir() {
if len(prefix) == 0 {
prefix = info.Name()
} else {
prefix = prefix + "/" + info.Name()
}
fileInfos, err := file.Readdir(-1)
if err != nil {
return err
}
for _, fi := range fileInfos {
f, err := os.Open(file.Name() + "/" + fi.Name())
if err != nil {
return err
}
err = compress(f, prefix, zw)
if err != nil {
return err
}
}
} else {
header, err := zip.FileInfoHeader(info)
if len(prefix) == 0 {
header.Name = header.Name
} else {
header.Name = prefix + "/" + header.Name
}
if err != nil {
return err
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(writer, file)
file.Close()
if err != nil {
return err
}
}
return nil
}

112
weixin/base.go Normal file
View File

@@ -0,0 +1,112 @@
package weixin
import (
"encoding/json"
"io/ioutil"
"net/http"
"public/mycache"
"public/mylog"
"time"
"github.com/silenceper/wechat"
)
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="
)
//获取微信accesstoken
func GetAccessToken() (access_token string, err error) {
//先从缓存中获取
cache := mycache.OnGetCache("weixin_token")
var tp interface{}
tp, b := cache.Value("base")
if b {
access_token = tp.(string)
} else {
wc := wechat.NewWechat(&cfg)
access_token, err = wc.GetAccessToken()
//保存缓存
cache.Add("base", access_token, 7000*time.Second)
}
return
}
//获取微信卡券ticket
func GetApiTicket() (ticket string, err error) {
//先从缓存中获取
cache := mycache.OnGetCache("weixin_card_ticket")
var tp interface{}
tp, b := cache.Value("base")
if b {
ticket = tp.(string)
} else {
access_token, e := GetAccessToken()
if e != nil {
mylog.Error(e)
err = e
return
}
var url = GETTICKETURL + access_token
resp, e1 := http.Get(url)
if e1 != nil {
mylog.Error(e1)
err = e1
return
}
defer resp.Body.Close()
body, e2 := ioutil.ReadAll(resp.Body)
if e2 != nil {
mylog.Error(e2)
err = e2
return
}
var result ApiTicket
json.Unmarshal(body, &result)
ticket = result.Ticket
//保存缓存
cache.Add("base", ticket, 7000*time.Second)
}
return
}
//获取微信js ticket
func GetJsTicket() (ticket string, err error) {
//先从缓存中获取
cache := mycache.OnGetCache("weixin_js_ticket")
var tp interface{}
tp, b := cache.Value("base")
if b {
ticket = tp.(string)
} else {
access_token, e := GetAccessToken()
if e != nil {
mylog.Error(e)
err = e
return
}
var url = GETJSURL + access_token
resp, e1 := http.Get(url)
if e1 != nil {
mylog.Error(e1)
err = e1
return
}
defer resp.Body.Close()
body, e2 := ioutil.ReadAll(resp.Body)
if e2 != nil {
mylog.Error(e2)
err = e2
return
}
var result ApiTicket
json.Unmarshal(body, &result)
ticket = result.Ticket
//保存缓存
cache.Add("base", ticket, 7000*time.Second)
}
return
}

39
weixin/cache.go Normal file
View File

@@ -0,0 +1,39 @@
package weixin
import (
"public/mycache"
"time"
)
//Memcache struct contains *memcache.Client
type Gocache struct {
mc *mycache.MyCache
}
//NewGocache create new cache2go
func NewGocache(server string) *Gocache {
mc := mycache.OnGetCache(server)
return &Gocache{&mc}
}
//Get return cached value
func (mem *Gocache) Get(key string) interface{} {
v, _ := mem.mc.Value(key)
return v
}
// IsExist check value exists in memcache.
func (mem *Gocache) IsExist(key string) bool {
return mem.mc.IsExist(key)
}
//Set cached value with key and expire time.
func (mem *Gocache) Set(key string, val interface{}, timeout time.Duration) (err error) {
mem.mc.Add(key, val, timeout)
return nil
}
//Delete value in memcache.
func (mem *Gocache) Delete(key string) error {
return mem.mc.Delete(key)
}

19
weixin/def.go Normal file
View File

@@ -0,0 +1,19 @@
package weixin
type UserInfo struct {
OpenID string `json:"openid"`
Nickname string `json:"nickname"`
Sex int32 `json:"sex"`
Province string `json:"province"`
City string `json:"city"`
Country string `json:"country"`
HeadImgURL string `json:"headimgurl"`
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"`
}

58
weixin/enterprisePay.go Normal file
View File

@@ -0,0 +1,58 @@
package weixin
import (
"log"
"public/tools"
wxpay "gopkg.in/go-with/wxpay.v1"
)
const (
enterprisePayUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers" // 查询企业付款接口请求URL
)
/*
企业付款
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)
// 附着商户证书
err := c.WithCert(certFile, keyFile, rootcaFile)
if err != nil {
log.Fatal(err)
}
params := make(wxpay.Params)
nonce_str := 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("spbill_create_ip", ipAddr)
params.SetString("sign", c.Sign(params)) // 签名
// 发送查询企业付款请求
ret, err := c.Post(enterprisePayUrl, params, true)
if err != nil {
log.Fatal(err)
}
log.Print(ret)
returnCode := ret.GetString("return_code")
resultCode := ret.GetString("result_code")
if returnCode == "SUCCESS" && resultCode == "SUCCESS" {
return true
} else {
return false
}
}

60
weixin/init.go Normal file
View File

@@ -0,0 +1,60 @@
package weixin
import (
"data/config"
"public/tools"
"github.com/silenceper/wechat"
wxpay "gopkg.in/go-with/wxpay.v1"
)
const (
// 微信支付商户平台证书路径
certFileLoc = "/cert/apiclient_cert.pem"
keyFileLoc = "/cert/apiclient_key.pem"
rootcaFileLoc = "/cert/rootca.pem"
)
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 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
certFile = tools.GetModelPath() + certFileLoc
keyFile = tools.GetModelPath() + keyFileLoc
rootcaFile = tools.GetModelPath() + rootcaFileLoc
//使用memcache保存access_token也可选择redis或自定义cache
memCache := NewGocache("_winxin_access")
//配置微信参数
cfg = wechat.Config{
AppID: pay_appId,
AppSecret: secret,
Token: token,
EncodingAESKey: encodingAESKey,
Cache: memCache,
}
client = wxpay.NewClient(pay_appId, mchId, apiKey)
client.WithCert(certFile, keyFile, rootcaFile)
}

29
weixin/oauth.go Normal file
View File

@@ -0,0 +1,29 @@
package weixin
import (
"io/ioutil"
"net/http"
"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"
resp, e := http.Get(url)
if e != nil {
mylog.Error(e)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
mylog.Error(e)
return ""
}
return string(body)
}

210
weixin/pay.go Normal file
View File

@@ -0,0 +1,210 @@
package weixin
import (
"crypto/md5"
"fmt"
"log"
"public/message"
"public/mylog"
"public/tools"
"strconv"
"strings"
"time"
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
)
const (
PAY_SUCCESS = 1 //支付成功
PAY_REFUND = 2 //转入退款
PAY_CLOSED = 3 //已关闭
PAY_NOTPAY = 4 //未支付
PAY_REVOKED = 5 //已撤销
PAY_USERPAYING = 6 //支付中
PAY_ERROR = -1 //支付失败
)
/*
小程序统一下单接口
open_id:用户唯一标识
price : 预支付价钱
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 { //参数检测
return message.GetErrorMsg(message.ParameterInvalid)
}
params := make(wxpay.Params)
// 查询企业付款接口请求参数
params.SetString("appid", client.AppId)
params.SetString("mch_id", client.MchId)
params.SetString("body", price_body)
params.SetInt64("total_fee", int64(price*10))
params.SetString("spbill_create_ip", client_ip)
params.SetString("notify_url", notify_url)
params.SetString("trade_type", "JSAPI")
params.SetString("openid", open_id)
params.SetString("nonce_str", tools.GetRandomString(32)) // 随机字符串
params.SetString("out_trade_no", order_id) // 商户订单号
params.SetString("sign", client.Sign(params)) // 签名 c.Sign(params)
log.Println("paramsparams", params)
// 发送查询企业付款请求
ret, err := client.Post(unifiedOrderUrl, params, true)
if err != nil {
mylog.Error(err)
msg := message.GetErrorMsg(message.UnknownError)
return msg
}
//-----------------------end
//ret["order_id"] = order_tbl.Order_id
fmt.Println(ret)
if ret["result_code"] == "SUCCESS" { //再次签名
dd := make(map[string]string)
dd["timeStamp"] = strconv.FormatInt(tools.GetUtcTime(time.Now()), 10)
dd["nonceStr"] = tools.GetRandomString(32)
dd["package"] = "prepay_id=" + ret["prepay_id"]
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
by := md5.Sum([]byte(str))
dd["paySign"] = strings.ToUpper(fmt.Sprintf("%x", by))
dd["order_id"] = order_id
msg := message.GetSuccessMsg()
msg.Data = dd
return msg
}
msg := message.GetErrorMsg(message.InValidOp)
msg.Data = ret
return msg
}
/*
统一查询接口
open_id:用户唯一标识
order_id 商户订单号
*/
func OnSelectData(open_id, order_id string) (int, message.MessageBody) {
if !tools.CheckParam(open_id, order_id) { //参数检测
return 0, message.GetErrorMsg(message.ParameterInvalid)
}
code := 0
params := make(wxpay.Params)
// 查询企业付款接口请求参数
params.SetString("appid", client.AppId)
params.SetString("mch_id", client.MchId)
params.SetString("out_trade_no", order_id) //商户订单号
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)
if err != nil { //做再次确认
time.Sleep(time.Second * 1)
ret, err = client.Post(queryOrderUrl, params, true)
if err != nil {
mylog.Error(err)
msg := message.GetSuccessMsg()
return code, msg
}
}
//-----------------------end
msg := message.GetSuccessMsg(message.NormalMessageId)
/*
SUCCESS—支付成功
REFUND—转入退款
NOTPAY—未支付
CLOSED—已关闭
REVOKED—已撤销刷卡支付
USERPAYING--用户支付中
PAYERROR--支付失败(其他原因,如银行返回失败)
*/
if ret["trade_state"] == "SUCCESS" {
code = PAY_SUCCESS
} else if ret["trade_state"] == "REFUND" {
code = PAY_REFUND
} else if ret["trade_state"] == "CLOSED" {
code = PAY_CLOSED
} else if ret["trade_state"] == "NOTPAY" {
code = PAY_NOTPAY
} else if ret["trade_state"] == "REVOKED" {
code = PAY_REVOKED
} else if ret["trade_state"] == "USERPAYING" {
code = PAY_USERPAYING
} else {
code = PAY_ERROR
}
if ret["trade_state"] == "SUCCESS" { //支付成功
msg.State = true
} else {
msg.State = false
}
msg.Data = ret
return code, msg
}
/*
申请退款
open_id:用户唯一标识
order_id 商户订单号
refund_no商户退款单号
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) { //参数检测
return false, message.GetErrorMsg(message.ParameterInvalid)
}
code := false
params := make(wxpay.Params)
// 退款请求参数
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("nonce_str", tools.GetRandomString(32)) // 随机字符串
params.SetString("sign", client.Sign(params)) // 签名 c.Sign(params)
// 发送申请退款请求
ret, err := client.Post(refundUrl, params, true)
if err != nil {
mylog.Error(err)
msg := message.GetErrorMsg(message.UnknownError)
return code, msg
}
//-----------------------end
msg := message.GetSuccessMsg(message.NormalMessageId)
if ret["result_code"] == "SUCCESS" { //申请成功
msg.State = true
code = true
} else {
msg.State = false
}
msg.Data = ret
return code, msg
}