Browse Source

Merge branch 'master' of https://app.yhyue.com/moapp/jybase

wangshan 2 years ago
parent
commit
8e2760635a

+ 10 - 0
common/common.go

@@ -12,6 +12,7 @@ import (
 	"math"
 	"math/big"
 	mathRand "math/rand"
+	"net/http"
 	"reflect"
 	"regexp"
 	"runtime"
@@ -781,3 +782,12 @@ func StrFormat(s string) string {
 	}
 	return fmt.Sprintf("\"%s\"", s)
 }
+
+//判断是否是微信访问
+func IsWxBrowser(Request *http.Request) bool {
+	if strings.Index(Request.UserAgent(), "MicroMessenger") > -1 || strings.Index(Request.UserAgent(), "Wechat") > -1 {
+		return true
+	} else {
+		return false
+	}
+}

+ 5 - 1
common/config.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"errors"
 	"io/ioutil"
+	"log"
 
 	"os"
 	"strings"
@@ -22,7 +23,10 @@ func ReadConfig(config ...interface{}) {
 		r, _ = os.Open(filepath)
 		defer r.Close()
 		bs, _ := ioutil.ReadAll(r)
-		json.Unmarshal(bs, config[1])
+		err := json.Unmarshal(bs, config[1])
+		if err != nil {
+			log.Println(config[0].(string), " json格式异常")
+		}
 	} else {
 		r, _ = os.Open("./config.json")
 		defer r.Close()

+ 142 - 0
dfa/interestanalysis.go

@@ -0,0 +1,142 @@
+/**
+ *兴趣分析
+ *
+ */
+package dfa
+
+import (
+	"log"
+	"strings"
+)
+
+//DFA实现
+type DFA struct {
+	link        map[string]interface{} //存放or
+	linkAnd     map[string]int         //存放and
+	linkAndWord map[string]interface{} //存放and中的拆分词
+
+}
+
+//添加词组,用于初始化,该方法是可以调用多次的
+func (d *DFA) AddWord(words ...string) {
+	if d.link == nil {
+		d.link = make(map[string]interface{})
+		d.linkAnd = make(map[string]int)
+		d.linkAndWord = make(map[string]interface{})
+	}
+	var nowMap *map[string]interface{}
+	for _, key := range words {
+		keys := strings.Split(key, "+")
+		lenkeys := len(keys)
+		if lenkeys > 1 {
+			d.linkAnd[key] = lenkeys
+			for k := 0; k < lenkeys; k++ {
+				minKey := keys[k]
+				nowMap = &d.linkAndWord
+				for i := 0; i < len(minKey); i++ {
+					kc := minKey[i : i+1]
+					if v, ok := (*nowMap)[kc]; ok {
+						nowMap, _ = v.(*map[string]interface{})
+					} else {
+						newMap := map[string]interface{}{}
+						newMap["YN"] = "N"
+						(*nowMap)[kc] = &newMap
+						nowMap = &newMap
+					}
+					if i == len(minKey)-1 {
+						(*nowMap)["YN"] = "Y"
+						if (*nowMap)["key"] == nil {
+							(*nowMap)["key"] = make(map[string]int)
+						}
+						(*nowMap)["key"].(map[string]int)[key] = k
+					}
+				}
+			}
+		} else {
+			nowMap = &d.link
+			for i := 0; i < len(key); i++ {
+				kc := key[i : i+1]
+				if v, ok := (*nowMap)[kc]; ok {
+					nowMap, _ = v.(*map[string]interface{})
+				} else {
+					newMap := map[string]interface{}{}
+					newMap["YN"] = "N"
+					(*nowMap)[kc] = &newMap
+					nowMap = &newMap
+				}
+
+				if i == len(key)-1 {
+					(*nowMap)["YN"] = "Y"
+				}
+			}
+		}
+	}
+}
+func (d *DFA) Clear() {
+	d.link = nil
+}
+
+//从给定的内容中找出匹配上的关键词
+func (d *DFA) Analy(src string) []string {
+	if d.link == nil {
+		log.Println("请先添加词组")
+		return []string{}
+	}
+	keywords := []string{}
+	tempMap := make(map[string][]bool)
+	for i := 0; i < len(src); i++ {
+		nowMap := &d.link
+		length := 0 // 匹配标识数默认为0
+		//flag := false // 敏感词结束标识位:用于敏感词只有1位的情况
+		for j := i; j < len(src); j++ {
+			word := src[j : j+1]
+			nowMap, _ = (*nowMap)[word].(*map[string]interface{})
+			if nowMap != nil {
+				length = length + 1
+				tag, _ := (*nowMap)["YN"].(string)
+				if "Y" == tag {
+					//flag = true
+					keywords = append(keywords, src[i:i+length])
+				}
+			} else {
+				break
+			}
+		}
+		nowMap = &d.linkAndWord
+		length = 0
+		for j := i; j < len(src); j++ {
+			word := src[j : j+1]
+			nowMap, _ = (*nowMap)[word].(*map[string]interface{})
+			if nowMap != nil {
+				length = length + 1
+				tag, _ := (*nowMap)["YN"].(string)
+				if "Y" == tag {
+					mkeys := (*nowMap)["key"].(map[string]int)
+					for k, v := range mkeys {
+						tempBool := tempMap[k]
+						if tempBool == nil {
+							tempBool = make([]bool, d.linkAnd[k])
+							tempMap[k] = tempBool
+						}
+						tempBool[v] = true
+					}
+				}
+			} else {
+				break
+			}
+		}
+	}
+	for k, v := range tempMap {
+		ball := true
+		for _, m := range v {
+			if !m {
+				ball = false
+				break
+			}
+		}
+		if ball {
+			keywords = append(keywords, k)
+		}
+	}
+	return keywords
+}

+ 45 - 0
dfa/interestanalysis_test.go

@@ -0,0 +1,45 @@
+package dfa
+
+import (
+	"log"
+	"strings"
+	"testing"
+	"time"
+)
+
+var d *DFA = &DFA{}
+
+func copyMap(m map[string]int) (m2 map[string]int) {
+	m2 = make(map[string]int)
+	for k, v := range m {
+		m2[k] = v
+	}
+	return m2
+}
+
+func TestAnaly(t *testing.T) {
+	d.AddWord("办公", "办+楼", "河+省", "完+你们8")
+	log.Println(strings.Split("河+南+", "+")[2])
+	t1 := time.Now()
+	log.Println(d.Analy("这胡省锦河涛写给江泽民的信我们你们于办公楼上你完就是啊。"), "=====")
+	log.Println(time.Now().Sub(t1).Seconds())
+	d.Clear()
+	//log.Println(d.Analy("这是胡锦涛写给江泽民的信啊。"))
+
+}
+
+func Test_Label(t *testing.T) {
+	log.Println("000----")
+
+	for _, v := range []int{1, 2, 3, 4, 5} {
+		log.Println(v)
+	L1:
+		for _, vv := range []string{"a", "b", "c", "d"} {
+			log.Println(vv)
+			if vv == "add" {
+				break L1
+			}
+		}
+	}
+	log.Println("111----")
+}

+ 14 - 11
encrypt/encryptarticle.go

@@ -9,6 +9,7 @@ import (
 //正文
 var SE = &SimpleEncrypt{Key: "topnet2015topnet2015"}
 var SE2 = &SimpleEncrypt{Key: "2017jianyu"}
+var SE3 = &SimpleEncrypt{Key: "entservice"}
 
 //百度
 var BSE = &SimpleEncrypt{Key: "HNtopnet2017jy"}
@@ -40,17 +41,19 @@ func CommonEncodeArticle(stype string, keys ...string) (id string) {
 
 //通用解密
 func CommonDecodeArticle(stype string, id string) (res []string) {
-	switch stype {
-	case "content":
-		res = BDecodeArticleId2ByCheck(id, SE, SE2)
-	case "bdprivate":
-		res = BDecodeArticleId2ByCheck(id, BSE, BSE2)
-	case "mailprivate":
-		res = BDecodeArticleId2ByCheck(id, ESE, ESE2)
-	case "indexcontent":
-		res = BDecodeArticleId2ByCheck(id, ISE, ISE2)
-	}
-	return
+        switch stype {
+        case "content":
+	      res = BDecodeArticleId2ByCheck(id, SE, SE2)
+        case "bdprivate":
+	      res = BDecodeArticleId2ByCheck(id, BSE, BSE2)
+        case "mailprivate":
+	      res = BDecodeArticleId2ByCheck(id, ESE, ESE2)
+        case "indexcontent":
+	      res = BDecodeArticleId2ByCheck(id, ISE, ISE2)
+        case "advancedProject":
+	      res = BDecodeArticleId2ByCheck(id, SE, SE2)
+        }
+        return
 }
 
 //短地址加密,二次加密带校验和

+ 3 - 0
esv1/elasticutil.go

@@ -365,6 +365,9 @@ var SR = strings.Replace
 func MakeQuery(query, order, fileds string, start, limit int) string {
 	res := AnalyQuery(query, "", QStr)
 	if len(res) > 10 {
+		if strings.Contains(res, "###剑鱼###") {
+			res = strings.ReplaceAll(res, "###剑鱼###", "\\\"")
+		}
 		res = SR(SR(SR(SR(res, ",$and", "", -1), "$and", "", -1), ",$or", "", -1), "$or", "", -1)
 		if len(fileds) > 0 {
 			//"_source":["account_number","balance"]

+ 18 - 0
fsnotify/README.md

@@ -0,0 +1,18 @@
+#fsnotify监控文件
+
+## 第一版-wangshan
+#“sword->%s”:应用模块名称;“./test.json”:监控文件位置和名称;“true”:是否初始化;“func()”:逻辑处理;
+
+#fs.FSNotifyFUNC("sword->%s", "./test.json", true, func() {
+#	log.Println("------------")
+#	util.ReadConfig("./test.json", &TC)
+#})
+***
+
+## 20220325更新-wangshan
+#fs.GetNewWatch().WatchDir("./tmp", true, func() {
+#	util.ReadConfig("./tmp/ws.json", &WSConf)
+#	log.Println("name:", WSConf.Name)
+#})
+
+#默认5秒内 重复操作无效!!!

+ 113 - 0
fsnotify/fsnotify.go

@@ -0,0 +1,113 @@
+package fsnotify
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/fsnotify/fsnotify"
+)
+
+var applyAction = map[string]int64{}
+var applyTime int64 = 5
+
+type Watch struct {
+	watch *fsnotify.Watcher
+}
+
+//
+func GetNewWatch() *Watch {
+	watch, _ := fsnotify.NewWatcher()
+	return &Watch{
+		watch: watch,
+	}
+}
+
+//
+func (w *Watch) WatchDir(dir string, b bool, f func()) {
+	go func(b bool) {
+		if b {
+			f()
+		}
+	}(b)
+	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+		//判断是否为目录,只监控目录
+		if info.IsDir() {
+			path, err := filepath.Abs(path)
+			if err != nil {
+				return err
+			}
+			err = w.watch.Add(path)
+			if err != nil {
+				return err
+			}
+			fmt.Println("监控:", path)
+		}
+		return nil
+	})
+	go func() {
+		for {
+			select {
+			case ev := <-w.watch.Events:
+				{
+					if strings.HasSuffix(ev.Name, ".json") && ev.Op&fsnotify.Write == fsnotify.Write {
+						go f()
+					}
+				}
+			case err := <-w.watch.Errors:
+				{
+					fmt.Println("error:", err)
+					return
+				}
+			}
+		}
+	}()
+}
+
+//
+func FSNotifyFUNC(name, dir string, flag bool, f func()) {
+	if flag {
+		f()
+	}
+	watch, err := fsnotify.NewWatcher()
+	if err != nil {
+		log.Println("watch new err", err)
+		return
+	}
+	defer watch.Close()
+	log.Println("dir:", dir)
+	err = watch.Add("../tmp")
+	if err != nil {
+		log.Println("watch add err", err)
+		return
+	}
+	go func() {
+		for {
+			select {
+			case ev := <-watch.Events:
+				{
+					if ev.Op&fsnotify.Write == fsnotify.Write {
+						now := time.Now().Unix()
+						//5秒之内 同一个文件不作操作
+						if applyAction[fmt.Sprintf(name, ev.Name)] != 0 && now-applyAction[fmt.Sprintf(name, ev.Name)] < applyTime {
+							continue
+						}
+						log.Println("修改文件 : ", fmt.Sprintf(name, ev.Name))
+						applyAction[fmt.Sprintf(name, ev.Name)] = now
+						time.Sleep(1 * time.Second)
+						//更新应用版本号
+						f()
+					}
+				}
+			case err := <-watch.Errors:
+				{
+					log.Println("watch error : ", err)
+					return
+				}
+			}
+		}
+	}()
+}

+ 1 - 1
fsw/fsw_test.go

@@ -9,7 +9,7 @@ func TestMatch(t *testing.T) {
 	ReadFswDict("./baidu_fsw.dict")
 	ret := Match("这是什么啊,怎么会有胡锦涛的温总理名字")
 	log.Println(ret)
-	ret2 := Repl("这是什么啊,怎么会有胡锦涛的名字,还有江泽民,我去,什么玩意")
+	ret2 := Repl("这是什么啊,怎么台独会有胡锦涛的名字,还有江泽民,我去,什么玩意")
 	log.Println(ret2)
 }
 

+ 2 - 0
go-xweb/httpsession/IsRedisStore.go

@@ -4,4 +4,6 @@ package httpsession
 var (
 	IsRedisSessionStore  = false
 	RedisSessionLockSize = 20
+	RedisNotLoginKey     = ""   //是否登录是标识
+	RedisNotLoginExpire  = 1800 //未登录用户session的失效时间为30分钟
 )

+ 1 - 1
go-xweb/httpsession/manager.go

@@ -67,7 +67,6 @@ func (manager *Manager) Session(req *http.Request, rw http.ResponseWriter) *Sess
 		println("error:", err.Error())
 		return nil
 	}
-
 	if !manager.generator.IsValid(id) {
 		id = manager.generator.Gen(req)
 		manager.transfer.Set(req, rw, id)
@@ -82,6 +81,7 @@ func (manager *Manager) Session(req *http.Request, rw http.ResponseWriter) *Sess
 		cookie, _ := req.Cookie(manager.transfer.(*CookieTransfer).Name)
 		cookie.Path = "/"
 		cookie.Secure = false
+		cookie.Domain = manager.transfer.(*CookieTransfer).Domain
 		cookie.MaxAge = int(manager.transfer.(*CookieTransfer).MaxAge / time.Second)
 		http.SetCookie(rw, cookie)
 	}

+ 6 - 4
go-xweb/httpsession/memorystore.go

@@ -53,9 +53,11 @@ func (node *sessionNode) SetMultiple(m map[string]interface{}) {
 	node.lock.Unlock()
 }
 
-func (node *sessionNode) Del(key string) {
+func (node *sessionNode) Del(keys ...string) {
 	node.lock.Lock()
-	delete(node.kvs, key)
+	for _, v := range keys {
+		delete(node.kvs, v)
+	}
 	node.last = time.Now()
 	node.lock.Unlock()
 }
@@ -191,12 +193,12 @@ func (store *MemoryStore) Add(id Id) {
 	store.lock.Unlock()
 }
 
-func (store *MemoryStore) Del(id Id, key string) bool {
+func (store *MemoryStore) Del(id Id, keys ...string) bool {
 	store.lock.RLock()
 	node, ok := store.nodes[id]
 	store.lock.RUnlock()
 	if ok {
-		node.Del(key)
+		node.Del(keys...)
 	}
 	return true
 }

+ 39 - 14
go-xweb/httpsession/redissessionstore.go

@@ -44,10 +44,14 @@ func (store *redisStore) GetMultiple(id Id) map[string]interface{} {
 		lock(id).Unlock()
 		return m
 	}
-	redis.SetExpire("session", string(id), int(store.maxAge.Seconds()))
+	json.Unmarshal(*bs, &m)
+	timeout := int(store.maxAge.Seconds())
+	if RedisNotLoginKey != "" && m[RedisNotLoginKey] == nil {
+		timeout = RedisNotLoginExpire
+	}
+	redis.SetExpire("session", string(id), timeout)
 	store.last = time.Now()
 	lock(id).Unlock()
-	json.Unmarshal(*bs, &m)
 	return m
 }
 
@@ -70,27 +74,41 @@ func (store *redisStore) SetMultiple(id Id, m map[string]interface{}) {
 	for k, v := range m {
 		userdata[k] = v
 	}
+	timeout := int(store.maxAge.Seconds())
+	if RedisNotLoginKey != "" && userdata[RedisNotLoginKey] == nil {
+		timeout = RedisNotLoginExpire
+	}
 	putdata, _ := json.Marshal(userdata)
-	redis.PutBytes("session", string(id), &putdata, int(store.maxAge.Seconds()))
+	redis.PutBytes("session", string(id), &putdata, timeout)
 }
 
 func (store *redisStore) Add(id Id) {
 
 }
 
-func (store *redisStore) Del(id Id, key string) bool {
+func (store *redisStore) Del(id Id, keys ...string) bool {
 	lock(id).Lock()
 	defer lock(id).Unlock()
 	bs, err := redis.GetBytes("session", string(id))
 	if err != nil {
-		return true
+		return false
 	}
 	var userdata map[string]interface{}
-	json.Unmarshal(*bs, &userdata)
-	delete(userdata, key)
+	if json.Unmarshal(*bs, &userdata) != nil {
+		return false
+	}
+	for _, key := range keys {
+		delete(userdata, key)
+	}
+	timeout := int(store.maxAge.Seconds())
+	if RedisNotLoginKey != "" && userdata[RedisNotLoginKey] == nil {
+		timeout = RedisNotLoginExpire
+	}
 	putdata, _ := json.Marshal(userdata)
-	redis.PutBytes("session", string(id), &putdata, int(store.maxAge.Seconds()))
-	return true
+	if redis.PutBytes("session", string(id), &putdata, timeout) == nil {
+		return true
+	}
+	return false
 }
 
 //根据自定义字段,更新
@@ -102,11 +120,19 @@ func (store *redisStore) UpdateByCustomField(findkey string, findvalue interface
 		return false
 	}
 	var data map[string]interface{}
-	json.Unmarshal(*bs, &data)
+	if json.Unmarshal(*bs, &data) != nil {
+		return false
+	}
+	timeout := int(store.maxAge.Seconds())
+	if RedisNotLoginKey != "" && data[RedisNotLoginKey] == nil {
+		timeout = RedisNotLoginExpire
+	}
 	data[setkey] = setvalue
 	putdata, _ := json.Marshal(data)
-	redis.PutBytes("session", findkey, &putdata, int(store.maxAge.Seconds()))
-	return true
+	if redis.PutBytes("session", findkey, &putdata, timeout) == nil {
+		return true
+	}
+	return false
 }
 
 func (store *redisStore) Exist(id Id) bool {
@@ -119,8 +145,7 @@ func (store *redisStore) Exist(id Id) bool {
 func (store *redisStore) Clear(id Id) bool {
 	lock(id).Lock()
 	defer lock(id).Unlock()
-	redis.Del("session", string(id))
-	return true
+	return redis.Del("session", string(id))
 }
 
 func (store *redisStore) Run() error {

+ 7 - 3
go-xweb/httpsession/session.go

@@ -23,7 +23,7 @@ func (session *Session) Get(key string) interface{} {
 	return session.manager.store.Get(session.id, key)
 }
 
-func (session *Session) GetMultiple(keys ...string) map[string]interface{} {
+func (session *Session) GetMultiple() map[string]interface{} {
 	return session.manager.store.GetMultiple(session.id)
 }
 
@@ -35,8 +35,12 @@ func (session *Session) SetMultiple(m map[string]interface{}) {
 	session.manager.store.SetMultiple(session.id, m)
 }
 
-func (session *Session) Del(key string) bool {
-	return session.manager.store.Del(session.id, key)
+func (session *Session) Del(keys ...string) bool {
+	return session.manager.store.Del(session.id, keys...)
+}
+
+func (session *Session) Clear() bool {
+	return session.manager.store.Clear(session.id)
 }
 
 func (session *Session) Invalidate(rw http.ResponseWriter) {

+ 1 - 1
go-xweb/httpsession/store.go

@@ -9,7 +9,7 @@ type Store interface {
 	GetMultiple(id Id) map[string]interface{}
 	Set(id Id, key string, value interface{})
 	SetMultiple(id Id, m map[string]interface{})
-	Del(id Id, key string) bool
+	Del(id Id, keys ...string) bool
 	Clear(id Id) bool
 	Add(id Id)
 	Exist(id Id) bool

+ 1 - 0
go-xweb/httpsession/transfer.go

@@ -80,6 +80,7 @@ func (transfer *CookieTransfer) Set(req *http.Request, rw http.ResponseWriter, i
 			cookie.MaxAge = int(transfer.MaxAge / time.Second)
 			//cookie.Expires = time.Now().Add(transfer.maxAge)
 		}
+		cookie.Domain = transfer.Domain
 	}
 	http.SetCookie(rw, cookie)
 }

+ 1 - 1
go-xweb/xweb/action.go

@@ -709,7 +709,7 @@ func (c *Action) Render(tmpl string, params ...*T) error {
 }
 
 //仅生成网页内容
-var regInclude = regexp.MustCompile(`\{\{\s*include\s*"(.*?\.html)"\}\}`)
+var regInclude = regexp.MustCompile(`\{\{\s*include\s*"(.*?\.html)".*\}\}`)
 
 func (c *Action) NamedRender4Cache(name, content string, params ...*T) ([]byte, error) {
 	c.f["oinclude"] = c.Include

+ 3 - 0
go-xweb/xweb/template.go

@@ -366,6 +366,9 @@ func newIncludeIntmpl(rootDir string, content []byte) []byte {
 			b = true
 			tpl := regInclude.FindSubmatch(m)[1]
 			fpath := filepath.Join(rootDir, string(tpl))
+			if strings.Contains(string(m), "OUTSIDE") {
+				fpath = string(tpl)
+			}
 			c, err := ioutil.ReadFile(fpath)
 			if err != nil {
 				return []byte{}

+ 2 - 0
go.mod

@@ -7,9 +7,11 @@ require (
 	github.com/coscms/tagfast v0.0.0-20150925144250-2b69b2496250
 	github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
 	github.com/donnie4w/go-logger v0.0.0-20170827050443-4740c51383f4
+	github.com/fsnotify/fsnotify v1.4.9
 	github.com/garyburd/redigo v1.6.2
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/golang-jwt/jwt/v4 v4.4.2
+	github.com/gomodule/redigo v1.8.9
 	github.com/howeyc/fsnotify v0.9.0
 	github.com/olivere/elastic/v7 v7.0.22
 	github.com/zeromicro/go-zero v1.3.5

+ 3 - 0
go.sum

@@ -122,6 +122,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
 github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
@@ -196,6 +197,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
+github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=

+ 19 - 0
mail/gmail.go

@@ -214,3 +214,22 @@ func gSend(retry int, auth *GmailAuth, m *gomail.Message, to string) bool {
 	}
 	return status
 }
+
+//先取模后轮询获取一个mail实例
+func PollingMail(email string, array []*GmailAuth, f func(g *GmailAuth) bool) bool {
+	if len(array) == 0 {
+		return false
+	}
+	index := len(email) % len(array)
+	if f(array[index]) {
+		return true
+	}
+	for i := 0; i < len(array); i++ {
+		if i == index {
+			continue
+		} else if f(array[i]) {
+			return true
+		}
+	}
+	return false
+}

+ 114 - 45
mongodb/mongodb.go

@@ -28,6 +28,18 @@ func NewMgo(addr, db string, size int) *MongodbSim {
 	return mgo
 }
 
+func NewMgoWithUser(addr, db, uname, upwd string, size int) *MongodbSim {
+	mgo := &MongodbSim{
+		MongodbAddr: addr,
+		Size:        size,
+		DbName:      db,
+		UserName:    uname,
+		Password:    upwd,
+	}
+	mgo.InitPool()
+	return mgo
+}
+
 type Bluk struct {
 	ms     *MgoSess
 	writes []mongo.WriteModel
@@ -135,7 +147,6 @@ type MgoSess struct {
 	fields interface{}
 	limit  int64
 	skip   int64
-	pipe   []map[string]interface{}
 	all    interface{}
 	M      *MongodbSim
 }
@@ -178,9 +189,12 @@ func (ms *MgoSess) Sort(sorts ...string) *MgoSess {
 	ms.sorts = sorts
 	return ms
 }
-func (ms *MgoSess) Pipe(p []map[string]interface{}) *MgoSess {
-	ms.pipe = p
-	return ms
+func (ms *MgoSess) Pipe(p []map[string]interface{}) *pipe {
+	pe := &pipe{
+		ms:       ms,
+		pipeline: p,
+	}
+	return pe
 }
 func (ms *MgoSess) Insert(doc interface{}) error {
 	_, err := ms.M.C.Database(ms.db).Collection(ms.coll).InsertOne(ms.M.Ctx, doc)
@@ -235,53 +249,58 @@ func (ms *MgoSess) One(v *map[string]interface{}) {
 	}
 }
 func (ms *MgoSess) All(v *[]map[string]interface{}) {
-	cur, err := ms.M.C.Database(ms.db).Collection(ms.coll).Aggregate(ms.M.Ctx, ms.pipe)
+	of := options.Find()
+	if ms.fields != nil {
+		of.SetProjection(ms.fields)
+	}
+	if len(ms.sorts) > 0 {
+		of.SetSort(ms.toSort())
+	}
+	if ms.skip > 0 {
+		of.SetSkip(ms.skip)
+	}
+	if ms.limit > 0 {
+		of.SetLimit(ms.limit)
+	}
+	cur, err := ms.M.C.Database(ms.db).Collection(ms.coll).Find(ms.M.Ctx, ms.query, of)
 	if err == nil && cur.Err() == nil {
 		cur.All(ms.M.Ctx, v)
 	}
 }
+func (ms *MgoSess) toSort() bson.D {
+	sort := bson.D{}
+	for _, k := range ms.sorts {
+		switch k[:1] {
+		case "-":
+			sort = append(sort, bson.E{k[1:], -1})
+		case "+":
+			sort = append(sort, bson.E{k[1:], 1})
+		default:
+			sort = append(sort, bson.E{k, 1})
+		}
+	}
+	return sort
+}
 func (ms *MgoSess) Iter() *MgoIter {
 	it := &MgoIter{}
 	coll := ms.M.C.Database(ms.db).Collection(ms.coll)
-	var cur *mongo.Cursor
-	var err error
-	if ms.query != nil {
-		find := options.Find()
-		if ms.skip > 0 {
-			find.SetSkip(ms.skip)
-		}
-		if ms.limit > 0 {
-			find.SetLimit(ms.limit)
-		}
-		find.SetBatchSize(100)
-		if len(ms.sorts) > 0 {
-			sort := bson.D{}
-			for _, k := range ms.sorts {
-				switch k[:1] {
-				case "-":
-					sort = append(sort, bson.E{k[1:], -1})
-				case "+":
-					sort = append(sort, bson.E{k[1:], 1})
-				default:
-					sort = append(sort, bson.E{k, 1})
-				}
-			}
-			find.SetSort(sort)
-		}
-		if ms.fields != nil {
-			find.SetProjection(ms.fields)
-		}
-		cur, err = coll.Find(ms.M.Ctx, ms.query, find)
-		if err != nil {
-			log.Println("mgo find err", err.Error())
-		}
-	} else if ms.pipe != nil {
-		aggregate := options.Aggregate()
-		aggregate.SetBatchSize(100)
-		cur, err = coll.Aggregate(ms.M.Ctx, ms.pipe, aggregate)
-		if err != nil {
-			log.Println("mgo aggregate err", err.Error())
-		}
+	find := options.Find()
+	if ms.skip > 0 {
+		find.SetSkip(ms.skip)
+	}
+	if ms.limit > 0 {
+		find.SetLimit(ms.limit)
+	}
+	find.SetBatchSize(100)
+	if len(ms.sorts) > 0 {
+		find.SetSort(ms.toSort())
+	}
+	if ms.fields != nil {
+		find.SetProjection(ms.fields)
+	}
+	cur, err := coll.Find(ms.M.Ctx, ms.query, find)
+	if err != nil {
+		log.Println("mgo find err", err.Error())
 	}
 	if err == nil {
 		it.Cursor = cur
@@ -290,6 +309,33 @@ func (ms *MgoSess) Iter() *MgoIter {
 	return it
 }
 
+type pipe struct {
+	ms       *MgoSess
+	pipeline []map[string]interface{}
+}
+
+func (p *pipe) All(v *[]map[string]interface{}) {
+	cur, err := p.ms.M.C.Database(p.ms.db).Collection(p.ms.coll).Aggregate(p.ms.M.Ctx, p.pipeline)
+	if err == nil && cur.Err() == nil {
+		cur.All(p.ms.M.Ctx, v)
+	}
+}
+func (p *pipe) Iter() *MgoIter {
+	it := &MgoIter{}
+	coll := p.ms.M.C.Database(p.ms.db).Collection(p.ms.coll)
+	aggregate := options.Aggregate()
+	aggregate.SetBatchSize(100)
+	cur, err := coll.Aggregate(p.ms.M.Ctx, p.pipeline, aggregate)
+	if err != nil {
+		log.Println("mgo aggregate err", err.Error())
+	}
+	if err == nil {
+		it.Cursor = cur
+		it.Ctx = p.ms.M.Ctx
+	}
+	return it
+}
+
 type MongodbSim struct {
 	MongodbAddr string
 	Size        int
@@ -365,6 +411,21 @@ func (m *MongodbSim) Close() {
 	<-m.pool
 }
 
+//新建表并生成索引
+func (m *MongodbSim) CreateIndex(c string, models []mongo.IndexModel) bool {
+	defer catch()
+	m.Open()
+	defer m.Close()
+	coll := m.C.Database(m.DbName).Collection(c)
+	names, err := coll.Indexes().CreateMany(m.Ctx, models)
+	if err == nil && len(names) > 0 {
+		return true
+	} else {
+		log.Println("CreateIndex Error:", err)
+		return false
+	}
+}
+
 func (m *MongodbSim) Save(c string, doc interface{}) string {
 	defer catch()
 	m.Open()
@@ -781,7 +842,7 @@ func ToObjectIds(ids []string) []primitive.ObjectID {
 
 //自动添加更新时间
 func autoUpdateTime(db, coll string, ue *bson.M) {
-	if db == "qfw" && coll == "user" {
+	if coll == "user" {
 		set := ObjToM((*ue)["$set"])
 		if *set == nil {
 			set = &bson.M{}
@@ -790,3 +851,11 @@ func autoUpdateTime(db, coll string, ue *bson.M) {
 		(*ue)["$set"] = set
 	}
 }
+
+func IsObjectIdHex(hex string) bool {
+	_, err := primitive.ObjectIDFromHex(hex)
+	if err != nil {
+		return false
+	}
+	return true
+}

+ 6 - 4
mysql/mysql.go

@@ -258,7 +258,7 @@ func (m *Mysql) SelectBySql(q string, args ...interface{}) *[]map[string]interfa
 func (m *Mysql) SelectBySqlByTx(tx *sql.Tx, q string, args ...interface{}) *[]map[string]interface{} {
 	return m.Select(0, nil, tx, q, args...)
 }
-func (m *Mysql) Select(bath int, f func(l *[]map[string]interface{}), tx *sql.Tx, q string, args ...interface{}) *[]map[string]interface{} {
+func (m *Mysql) Select(bath int, f func(l *[]map[string]interface{}) bool, tx *sql.Tx, q string, args ...interface{}) *[]map[string]interface{} {
 	var stmtOut *sql.Stmt
 	var err error
 	if tx == nil {
@@ -306,7 +306,9 @@ func (m *Mysql) Select(bath int, f func(l *[]map[string]interface{}), tx *sql.Tx
 		}
 		list = append(list, ret)
 		if bath > 0 && len(list) == bath {
-			f(&list)
+			if !f(&list) {
+				break
+			}
 			list = []map[string]interface{}{}
 		}
 	}
@@ -316,10 +318,10 @@ func (m *Mysql) Select(bath int, f func(l *[]map[string]interface{}), tx *sql.Tx
 	}
 	return &list
 }
-func (m *Mysql) SelectByBath(bath int, f func(l *[]map[string]interface{}), q string, args ...interface{}) {
+func (m *Mysql) SelectByBath(bath int, f func(l *[]map[string]interface{}) bool, q string, args ...interface{}) {
 	m.SelectByBathByTx(bath, f, nil, q, args...)
 }
-func (m *Mysql) SelectByBathByTx(bath int, f func(l *[]map[string]interface{}), tx *sql.Tx, q string, args ...interface{}) {
+func (m *Mysql) SelectByBathByTx(bath int, f func(l *[]map[string]interface{}) bool, tx *sql.Tx, q string, args ...interface{}) {
 	m.Select(bath, f, tx, q, args...)
 }
 func (m *Mysql) FindOne(tableName string, query map[string]interface{}, fields, order string) *map[string]interface{} {

+ 31 - 8
redis/redis.go

@@ -15,7 +15,7 @@ var RedisPool map[string]*redigo.Pool
 
 //初始化redis 1为多个连接池,2为共用一个连接池
 func InitRedis(addrs string) {
-	InitRedisBySize(addrs, 300, 30, 240)
+	InitRedisBySize(addrs, 80, 10, 240)
 }
 
 func InitRedisBySize(addrs string, maxSize, maxIdle, timeout int) {
@@ -369,20 +369,27 @@ func DelByPattern(key string) {
 **/
 //自增计数器
 func Incr(code, key string) int64 {
+	ret, err := IncrByErr(code, key)
+	if nil != err {
+		log.Println("redisutil-INCR-Error", err)
+	}
+	return ret
+}
+
+//自增计数器
+func IncrByErr(code, key string) (int64, error) {
 	defer catch()
 	conn := RedisPool[code].Get()
 	defer conn.Close()
 	ret, err := conn.Do("INCR", key)
 	if nil != err {
-		log.Println("redisutil-INCR-Error", err)
+		return 0, err
+	}
+	if res, ok := ret.(int64); ok {
+		return res, nil
 	} else {
-		if res, ok := ret.(int64); ok {
-			return res
-		} else {
-			return 0
-		}
+		return 0, nil
 	}
-	return 0
 }
 
 //自减
@@ -656,3 +663,19 @@ func catch() {
 		}
 	}
 }
+
+//获取到期时间 -1未设置时间永久 -2到期
+func GetTTL(code, key string) int64 {
+	defer catch()
+	conn := RedisPool[code].Get()
+	defer conn.Close()
+	ret, err := conn.Do("TTL", key)
+	if nil != err {
+		log.Println("redisutil-GetError", err)
+		return 0
+	}
+	if res, ok := ret.(int64); ok {
+		return res
+	}
+	return 0
+}

+ 70 - 0
redis/redisloginutil.go

@@ -0,0 +1,70 @@
+package redis
+
+import (
+	"log"
+	"strings"
+	"time"
+
+	redisLogin "github.com/gomodule/redigo/redis"
+)
+
+var RedisLoginPool *redisLogin.Pool
+
+func InitRedisLogin(addrs string) {
+	addr := strings.Split(addrs, ",")
+	for _, v := range addr {
+		saddr := strings.Split(v, "=")
+		if saddr[0] == "login" {
+			RedisLoginPool = &redisLogin.Pool{MaxActive: 10, MaxIdle: 5,
+				IdleTimeout: time.Duration(10) * time.Second, Dial: func() (redisLogin.Conn, error) {
+					c, err := redisLogin.Dial("tcp", saddr[1])
+					if err != nil {
+						return nil, err
+					}
+					return c, nil
+				}}
+		}
+	}
+
+}
+
+//
+func SetLoginVal(key, value string) {
+	conn := RedisLoginPool.Get()
+	defer conn.Close()
+	conn.Do("PUBLISH", key, value)
+}
+
+//
+func GetLoginVal(key string, wxFunc func(wxParams []string) bool) {
+	for {
+		defer catch()
+	L:
+		for {
+			conn := RedisLoginPool.Get()
+			defer conn.Close()
+			if conn.Err() == nil {
+				psc := redisLogin.PubSubConn{Conn: conn}
+				if err := psc.Subscribe(redisLogin.Args{}.AddFlat(key)...); err != nil {
+					log.Println(err)
+				}
+				for {
+					msg := psc.Receive()
+					//					go func(msg interface{}) {
+					switch n := msg.(type) {
+					case error:
+						log.Println("wxlogin err", msg)
+						break L
+					case redisLogin.Message:
+						res := string(n.Data)
+						param := strings.Split(res, ",")
+						go wxFunc(param)
+					}
+					//					}(msg)
+				}
+			}
+			time.Sleep(2 * time.Second)
+		}
+		time.Sleep(1 * time.Second)
+	}
+}

+ 41 - 0
rpc/credit.go

@@ -0,0 +1,41 @@
+// credit
+package rpc
+
+import (
+	"net/rpc"
+)
+
+//客户端远程调用封装
+type RpcCall struct {
+	Addr string //rpc服务地址
+}
+
+type CreditData struct {
+	Code       string //积分代码
+	Uid        string //用户ID
+	Umid       string //用户m_open_id
+	Num        int    //积分值
+	OtherParam map[string]interface{}
+}
+
+//增加积分
+func (rc *RpcCall) InCreadit(param *CreditData, replay *int) error {
+	client, err := rpc.DialHTTP("tcp", rc.Addr)
+	defer client.Close()
+	if err != nil {
+		return err
+	}
+	err = client.Call("CreditRpc.InCreadit", param, replay)
+	return err
+}
+
+//消费积分
+func (rc *RpcCall) OutCreadit(param *CreditData, replay *int) error {
+	client, err := rpc.DialHTTP("tcp", rc.Addr)
+	defer client.Close()
+	if err != nil {
+		return err
+	}
+	err = client.Call("CreditRpc.OutCreadit", param, replay)
+	return err
+}

+ 8 - 0
rpc/follow.go

@@ -0,0 +1,8 @@
+// follow
+package rpc
+
+type FollowData struct {
+	UserId      string `json:"userId"`
+	Server      string `json:"server"`
+	Projectname string `json:"projectname"`
+}

+ 17 - 0
rpc/log.go

@@ -0,0 +1,17 @@
+// credit
+package rpc
+
+import (
+	"net/rpc"
+)
+
+//rpc日志采集
+func (rc *RpcCall) AccessLog(json string) error {
+	client, err := rpc.DialHTTP("tcp", rc.Addr)
+	defer client.Close()
+	if err != nil {
+		return err
+	}
+	err = client.Call("RpcAccessLog.Log", json, nil)
+	return err
+}

+ 102 - 0
rpc/options.go

@@ -0,0 +1,102 @@
+package rpc
+import (
+	"errors"
+	"math/rand"
+	"sync"
+	"time"
+)
+
+var (
+	errClosed   = errors.New("pool is closed")
+	errInvalid  = errors.New("invalid config")
+	errRejected = errors.New("connection is nil. rejecting")
+	errTargets  = errors.New("targets server is empty")
+)
+
+func init() {
+	rand.NewSource(time.Now().UnixNano())
+}
+
+//Options pool options
+type Options struct {
+	lock sync.RWMutex
+	//targets node
+	Targets *[]string
+	//targets channel
+	input chan *[]string
+
+	//InitTargets init targets
+	InitTargets []string
+	// init connection
+	InitCap int
+	// max connections
+	MaxCap       int
+	DialTimeout  time.Duration
+	IdleTimeout  time.Duration
+	ReadTimeout  time.Duration
+	WriteTimeout time.Duration
+}
+
+// Input is the input channel
+func (o *Options) Input() chan<- *[]string {
+	return o.input
+}
+
+// update targets
+func (o *Options) update() {
+	//init targets
+	o.Targets = &o.InitTargets
+
+	go func() {
+		for targets := range o.input {
+			if targets == nil {
+				continue
+			}
+
+			o.lock.Lock()
+			o.Targets = targets
+			o.lock.Unlock()
+		}
+	}()
+
+}
+
+// NewOptions returns a new newOptions instance with sane defaults.
+func NewOptions() *Options {
+	o := &Options{}
+	o.InitCap = 5
+	o.MaxCap = 100
+	o.DialTimeout = 5 * time.Second
+	o.ReadTimeout = 5 * time.Second
+	o.WriteTimeout = 5 * time.Second
+	o.IdleTimeout = 60 * time.Second
+	return o
+}
+
+// validate checks a Config instance.
+func (o *Options) validate() error {
+	if o.InitTargets == nil ||
+		o.InitCap <= 0 ||
+		o.MaxCap <= 0 ||
+		o.InitCap > o.MaxCap ||
+		o.DialTimeout == 0 ||
+		o.ReadTimeout == 0 ||
+		o.WriteTimeout == 0 {
+		return errInvalid
+	}
+	return nil
+}
+
+//nextTarget next target implement load balance
+func (o *Options) nextTarget() string {
+	o.lock.RLock()
+	defer o.lock.RUnlock()
+
+	tlen := len(*o.Targets)
+	if tlen <= 0 {
+		return ""
+	}
+
+	//rand server
+	return (*o.Targets)[rand.Int()%tlen]
+}

+ 84 - 0
rpc/order.go

@@ -0,0 +1,84 @@
+package rpc
+
+//数据导出线下支付
+type DateExportData struct {
+	ImgSrc    string `json:"imgSrc"`
+	OrderCode string `json:"orderCode"`
+}
+
+//对公转账完成回调参数
+type TransferAccountsParam struct {
+	ImgSrc    string `json:"imgSrc"`
+	OrderCode string `json:"orderCode"`
+}
+
+//创建订单
+type JyPayOrderParam struct {
+	Price       int                    `json:"price"`
+	ProductType string                 `json:"productType"`
+	Ip          string                 `json:"ip"`
+	Openid      string                 `json:"openid"`
+	PayWay      string                 `json:"payWay"`
+	Userid      string                 `json:"userid"`
+	Phone       string                 `json:"phone"`
+	Detail      map[string]interface{} `json:"detail"`
+	LotteryId   string                 `json:"lotteryId"`  //卡券id
+	UseProduct  string                 `json:"useProduct"` //产品id
+}
+
+//修改订单
+type JyPayOrderChangeParam struct {
+	ProductType string `json:"productType"`
+	OrderCode   string `json:"orderCode"`
+	PayWay      string `json:"payWay"`
+	Openid      string `json:"openid"`
+	Ip          string `json:"ip"`
+}
+
+//关闭订单
+type JyPayOrderCloseParam struct {
+	ProductType string `json:"productType"`
+	OrderCode   string `json:"orderCode"`
+}
+
+/*
+code -1:失败
+err  错误信息
+*/
+type JyPayOrderResult struct {
+	Status    int    `json:"status"`
+	Err       string `json:"err"`
+	OrderCode string `json:"orderCode"`
+	PayStr    string `json:"payStr"`
+}
+
+type CreateEntReq struct {
+	Name        string
+	Phone       string
+	OrderCode   string
+}
+
+type CreateEntRes struct {
+	Status int    `json:"status"`
+	Err    string `json:"err"`
+	Id     int `json:"id"`
+}
+
+//分享完成 订单处理
+type JYShareUserIdsRes struct {
+	ShareUserInfo []shareUserInfo //被分享者+分享者等用户信息
+}
+
+// shareUserInfo
+type shareUserInfo struct {
+	UserId     string `json:"userId"`     //用户id
+	TimeExpand int    `json:"timeExpand"` //延长时间
+	Remark     string `json:"remark"`     //备注
+}
+
+//分享完成 订单处理结果
+type JYShareResp struct {
+	Error_code int64       `json:"error_code"`
+	Error_msg  string      `json:"error_msg"`
+	Data       interface{} `json:"data"`
+}

+ 23 - 0
rpc/push.go

@@ -0,0 +1,23 @@
+package rpc
+
+type PushData struct {
+	Mopenid  string
+	PushType map[string]string
+	Words    string
+}
+type FollowPush struct {
+	ProjectName string
+	ProjectCode string
+	InfoId      string
+	FollowId    string
+	UserId      string
+	OpenId      string
+	Flag        int
+}
+type FollowPushEnt struct {
+	Entname  string
+	InfoId   string
+	FollowId string
+	OpenId   string
+	Flag     int
+}

+ 28 - 0
rpc/rpc_test.go

@@ -0,0 +1,28 @@
+// rpc_test
+package rpc
+
+import (
+	"log"
+	"testing"
+)
+
+func Test_InCreadit(t *testing.T) {
+	rc := new(RpcCall)
+	rc.Addr = "127.0.0.1:8765"
+	otherParam := make(map[string]interface{})
+	otherParam["name"] = "zhangsan"
+	otherParam["age"] = 18
+	err := rc.InCreadit(&CreditData{Code: "1", Uid: "2", Num: 3, OtherParam: otherParam}, 0)
+	log.Println("err:", err)
+}
+
+func Test_OutCreadit(t *testing.T) {
+	rc := new(RpcCall)
+	rc.Addr = "127.0.0.1:8765"
+	otherParam := make(map[string]interface{})
+	otherParam["name"] = "zhangsan"
+	otherParam["age"] = 18
+	replay := 0
+	err := rc.OutCreadit(&CreditData{Code: "1", Uid: "2", Num: 3, OtherParam: otherParam}, &replay)
+	log.Println("err:", err)
+}

+ 21 - 13
rpc/rpccall.go

@@ -8,24 +8,12 @@ import (
 	util "app.yhyue.com/moapp/jybase/common"
 )
 
-type TmplItem struct {
-	Value string `json:"value,omitempty"`
-	Color string `json:"color,omitempty"`
-}
-
-type WxTmplMsg struct {
-	OpenId   string //用户id
-	Url      string
-	TplId    string
-	TmplData map[string]*TmplItem
-}
-
 /*通用的微信发模板消息方法
  *成功:repl=="Y"
  */
 func WxSendTmplMsg(address string, p *WxTmplMsg) (bool, error) {
 	defer util.Catch()
-	var repl string
+	var repl RpcResult
 	client, err := rpc.DialHTTP("tcp", address)
 	if err != nil {
 		log.Println(p.OpenId, err)
@@ -40,6 +28,26 @@ func WxSendTmplMsg(address string, p *WxTmplMsg) (bool, error) {
 	return repl == "Y", nil
 }
 
+/*微信推送消息rpc接口
+ *成功:repl=="Y"
+ */
+func WxPush(address, serviceMethod string, p *NotifyMsg) (bool, string) {
+	defer util.Catch()
+	var repl RpcResult
+	client, err := rpc.DialHTTP("tcp", address)
+	if err != nil {
+		log.Println(p.Openid, err.Error())
+		return false, ""
+	}
+	defer client.Close()
+	err = client.Call(serviceMethod, p, &repl)
+	if err != nil {
+		log.Println(p.Openid, err.Error())
+		return false, ""
+	}
+	return repl == "Y", string(repl)
+}
+
 //app推送消息rpc接口
 func AppPush(address string, m map[string]interface{}) bool {
 	defer util.Catch()

+ 214 - 0
rpc/rpcpool.go

@@ -0,0 +1,214 @@
+package rpc
+
+import (
+	"bufio"
+	"encoding/gob"
+	"fmt"
+	"io"
+	"net"
+	"net/rpc"
+	"sync"
+	"time"
+)
+
+//RPCPool pool info
+type RPCPool struct {
+	Mu          sync.Mutex
+	IdleTimeout time.Duration
+	conns       chan *rpcIdleConn
+	factory     func() (*rpc.Client, error)
+	close       func(*rpc.Client) error
+}
+
+type rpcIdleConn struct {
+	conn *rpc.Client
+	t    time.Time
+}
+
+//Get get from pool
+func (c *RPCPool) Get() (*rpc.Client, error) {
+	c.Mu.Lock()
+	conns := c.conns
+	c.Mu.Unlock()
+
+	if conns == nil {
+		return nil, errClosed
+	}
+	for {
+		select {
+		case wrapConn := <-conns:
+			if wrapConn == nil {
+				return nil, errClosed
+			}
+			//判断是否超时,超时则丢弃
+			if timeout := c.IdleTimeout; timeout > 0 {
+				if wrapConn.t.Add(timeout).Before(time.Now()) {
+					//丢弃并关闭该链接
+					c.close(wrapConn.conn)
+					continue
+				}
+			}
+			return wrapConn.conn, nil
+		case <-time.After(50 * time.Millisecond):
+			conn, err := c.factory()
+			if err != nil {
+				return nil, err
+			}
+			return conn, nil
+		}
+	}
+}
+
+//Put put back to pool
+func (c *RPCPool) Put(conn *rpc.Client) error {
+	if conn == nil {
+		return errRejected
+	}
+
+	c.Mu.Lock()
+	defer c.Mu.Unlock()
+
+	if c.conns == nil {
+		return c.close(conn)
+	}
+
+	select {
+	case c.conns <- &rpcIdleConn{conn: conn, t: time.Now()}:
+		return nil
+	default:
+		//连接池已满,直接关闭该链接
+		return c.close(conn)
+	}
+}
+
+//Close close all connection
+func (c *RPCPool) Close() {
+	c.Mu.Lock()
+	conns := c.conns
+	c.conns = nil
+	c.factory = nil
+	closeFun := c.close
+	c.close = nil
+	c.Mu.Unlock()
+
+	if conns == nil {
+		return
+	}
+
+	close(conns)
+	for wrapConn := range conns {
+		closeFun(wrapConn.conn)
+	}
+}
+
+//IdleCount idle connection count
+func (c *RPCPool) IdleCount() int {
+	c.Mu.Lock()
+	conns := c.conns
+	c.Mu.Unlock()
+	return len(conns)
+}
+
+//Codec ...
+type Codec struct {
+	Timeout time.Duration
+	Closer  io.ReadWriteCloser
+	Decoder *gob.Decoder
+	Encoder *gob.Encoder
+	EncBuf  *bufio.Writer
+}
+
+//WriteRequest ...
+func (c *Codec) WriteRequest(r *rpc.Request, body interface{}) (err error) {
+	if err = c.timeoutCoder(r, "write request"); err != nil {
+		return
+	}
+
+	if err = c.timeoutCoder(body, "write request body"); err != nil {
+		return
+	}
+
+	return c.EncBuf.Flush()
+}
+
+//ReadResponseHeader ...
+func (c *Codec) ReadResponseHeader(r *rpc.Response) error {
+	return c.Decoder.Decode(r)
+}
+
+//ReadResponseBody ...
+func (c *Codec) ReadResponseBody(body interface{}) error {
+	return c.Decoder.Decode(body)
+}
+
+//Close ...
+func (c *Codec) Close() error {
+	return c.Closer.Close()
+}
+
+func (c *Codec) timeoutCoder(e interface{}, msg string) error {
+	if c.Timeout < 0 {
+		c.Timeout = time.Second * 5
+	}
+
+	echan := make(chan error, 1)
+	go func() { echan <- c.Encoder.Encode(e) }()
+
+	select {
+	case e := <-echan:
+		return e
+	case <-time.After(c.Timeout):
+		return fmt.Errorf("Timeout %s", msg)
+	}
+}
+
+//NewRPCPool init rpc pool
+func NewRPCPool(o *Options) (*RPCPool, error) {
+	if err := o.validate(); err != nil {
+		return nil, err
+	}
+
+	//init pool
+	pool := &RPCPool{
+		conns: make(chan *rpcIdleConn, o.MaxCap),
+		factory: func() (*rpc.Client, error) {
+			target := o.nextTarget()
+			if target == "" {
+				return nil, errTargets
+			}
+
+			conn, err := net.DialTimeout("tcp", target, o.DialTimeout)
+			if err != nil {
+				return nil, err
+			}
+
+			encBuf := bufio.NewWriter(conn)
+			p := rpc.NewClientWithCodec(&Codec{
+				Closer:  conn,
+				Decoder: gob.NewDecoder(conn),
+				Encoder: gob.NewEncoder(encBuf),
+				EncBuf:  encBuf,
+				Timeout: o.WriteTimeout,
+			})
+
+			return p, err
+		},
+		close:       func(v *rpc.Client) error { return v.Close() },
+		IdleTimeout: o.IdleTimeout,
+	}
+
+	//danamic update targets
+	o.update()
+
+	//init make conns
+	for i := 0; i < o.InitCap; i++ {
+		conn, err := pool.factory()
+		if err != nil {
+			pool.Close()
+			return nil, err
+		}
+		pool.conns <- &rpcIdleConn{conn: conn, t: time.Now()}
+	}
+
+	return pool, nil
+}

+ 55 - 0
rpc/weixin.go

@@ -0,0 +1,55 @@
+package rpc
+
+type NotifyMsg struct {
+	Openid      string //用户id
+	Remark      string //消息内容,其他属性待加
+	Result      string //
+	Detail      string //
+	Title       string
+	Url         string
+	Date        string
+	Service     string
+	Color       string
+	DetailColor string
+	TplId       string
+}
+
+type RpcResult string
+
+//红包
+type BonusMsg struct {
+	Mchbillno   string `json:"mch_billno"`   //订单号
+	Sendname    string `json:"send_name"`    //红包发送者名称
+	Reopenid    string `json:"re_openid"`    //接受人openid
+	Totalamount int    `json:"total_amount"` //金额,单位分
+	Totalnum    int    `json:"total_num"`    //发放总人数
+	Wishing     string `json:"wishing"`      //祝福语128字以内
+	Actname     string `json:"act_name"`     //活动名称
+	Remark      string `json:"remark"`       //说明
+}
+type Article struct {
+	Title       string `json:"title"`
+	Description string `json:"description"`
+	PicUrl      string `json:"picurl"`
+	Url         string `json:"url"`
+}
+type News struct {
+	ToUser   string //用户id
+	Articles []Article
+}
+type CustomMsg struct {
+	Url  string
+	Data map[string]interface{}
+}
+
+type TmplItem struct {
+	Value string `json:"value,omitempty"`
+	Color string `json:"color,omitempty"`
+}
+
+type WxTmplMsg struct {
+	OpenId   string //用户id
+	Url      string
+	TplId    string
+	TmplData map[string]*TmplItem
+}

+ 1 - 2
sms/sms_test.go

@@ -1,12 +1,11 @@
 package sms
 
 import (
-	"qfw/util/sms"
 	"testing"
 	"time"
 )
 
 func TestSendSms(t *testing.T) {
-	sms.SendSms("15639297172", "1", "#company#=企业服务网&#code#=D323")
+	SendSms("192.168.3.11:932", "02", "15037870765", "用户")
 	time.Sleep(2 * time.Minute)
 }

+ 122 - 0
sort/sort.go

@@ -0,0 +1,122 @@
+// sort
+package sort
+
+import (
+	"sort"
+
+	. "app.yhyue.com/moapp/jybase/common"
+)
+
+type SortObject struct {
+	Key    string
+	Value  int
+	Values []interface{}
+}
+
+type SortStruct []*SortObject
+
+func (list SortStruct) Len() int {
+	return len(list)
+}
+
+func (list SortStruct) Less(i, j int) bool {
+	if list[i].Value > list[j].Value {
+		return true
+	} else if list[i].Value < list[j].Value {
+		return false
+	} else if list[i].Value == list[j].Value {
+		if len(list[i].Values) > 0 {
+			t1 := IntAll(list[i].Values[0])
+			t2 := IntAll(list[j].Values[0])
+			if t1 > t2 {
+				return true
+			} else {
+				return false
+			}
+		}
+		return true
+	} else {
+		return list[i].Key < list[j].Key
+	}
+}
+
+func (list SortStruct) Swap(i, j int) {
+	var temp *SortObject = list[i]
+	list[i] = list[j]
+	list[j] = temp
+}
+
+func SortMap(list []*SortObject) []*SortObject {
+	ls := SortStruct(list)
+	sort.Sort(ls)
+	return ls
+}
+
+//通用排序
+type ComSortKey struct {
+	Keys  []string //排序的key
+	Order int      //1:正排 -1:倒排
+	Type  string   //排序的key的数据类型:string float int
+}
+type ComSortList struct {
+	SortKeys []*ComSortKey
+	List     []*map[string]interface{}
+}
+
+func (s *ComSortList) Len() int {
+	return len(s.List)
+}
+
+func (s *ComSortList) Less(i, j int) bool {
+	for _, v := range s.SortKeys {
+		var i_v interface{}
+		var j_v interface{}
+		for _, key := range v.Keys {
+			if i_v == nil {
+				i_v = (*s.List[i])[key]
+			}
+			if j_v == nil {
+				j_v = (*s.List[j])[key]
+			}
+			if i_v != nil && j_v != nil {
+				break
+			}
+		}
+		if i_v == j_v {
+			continue
+		}
+		if v.Type == "string" {
+			return ObjToString(i_v) > ObjToString(j_v) && v.Order < 0
+		} else if v.Type == "float" {
+			return Float64All(i_v) > Float64All(j_v) && v.Order < 0
+		} else {
+			return Int64All(i_v) > Int64All(j_v) && v.Order < 0
+		}
+	}
+	return false
+}
+
+func (s *ComSortList) Swap(i, j int) {
+	s.List[i], s.List[j] = s.List[j], s.List[i]
+}
+
+//合并数组
+func (s *ComSortList) Merge(key string, o interface{}, maxLen int) *ComSortList {
+	repeat := map[string]bool{}
+	for _, v := range s.List {
+		repeat[ObjToString((*v)[key])] = true
+	}
+	os, _ := o.([]interface{})
+	for _, v := range os {
+		vm, _ := v.(map[string]interface{})
+		if repeat[ObjToString(vm[key])] {
+			continue
+		}
+		s.List = append(s.List, &vm)
+	}
+	sort.Sort(s)
+	if maxLen > 0 && len(s.List) > maxLen {
+		s.List = s.List[:maxLen]
+	}
+	return s
+}

+ 175 - 1
usercenter/userCenter.go

@@ -1,9 +1,10 @@
-package util
+package usercenter
 
 import (
 	"encoding/json"
 	"io/ioutil"
 	"log"
+	"app.yhyue.com/moapp/jybase/mongodb"
 	"net/http"
 	"strings"
 
@@ -16,6 +17,7 @@ var ContentType_Json = "application/json"
 var UserCenterAdd = "/userCenter/user/add"
 var UserCenterUpdate = "/userCenter/user/updateById"
 var UserCenterDelete = "/userCenter/user/deleteById"
+var UserCenterGetUserIdentity = "/userCenter/user/identity"
 
 /*
  修改header 的post请求
@@ -80,3 +82,175 @@ func PostUserCenter(url, contentTpe, userid string, data map[string]interface{},
 	}
 	return dataM, true
 }
+
+// usercenter
+type UserInfo struct {
+	S_openid     string //微信openid
+	A_openid     string //app 微信openid
+	Phone        string //手机号
+	Nickname     string //昵称
+	Headimg      string //头像
+	Company      string //公司
+	Position     string //职位
+	Password     string //密码
+	Unionid      string //unionid
+	Base_user_id int64  //用户中台base_user的主键id,
+}
+
+//获取base_user需要的数据
+func GetInfoForBaseUser(mg mongodb.MongodbSim, userid string) *UserInfo {
+	if userid == "" {
+		return nil
+	}
+	data, ok := mg.FindById("user", userid, `{"base_user_id":1,"s_m_openid":1,"a_m_openid":1,"s_m_phone":1,"s_phone":1,"s_nickname":1,"s_jyname":1,"s_headimageurl":1,"s_headimage":1,"s_company":1,"s_password":1,"s_unionid":1}`)
+	if ok && data != nil && len(*data) > 0 {
+		userinfo := &UserInfo{
+			Base_user_id: Int64All((*data)["base_user_id"]),
+		}
+		if s_openid := ObjToString((*data)["s_m_openid"]); s_openid != "" {
+			userinfo.S_openid = s_openid
+		}
+		if a_openid := ObjToString((*data)["a_m_openid"]); a_openid != "" {
+			userinfo.A_openid = a_openid
+		}
+		phone := ObjToString((*data)["s_phone"])
+		if phone == "" {
+			phone = ObjToString((*data)["s_m_phone"])
+		}
+		if phone != "" {
+			userinfo.Phone = phone
+		}
+		nickname := ObjToString((*data)["s_nickname"])
+		if nickname == "" {
+			nickname = ObjToString((*data)["s_jyname"])
+		}
+		if nickname != "" {
+			userinfo.Nickname = nickname
+		}
+		if unionid := ObjToString((*data)["s_unionid"]); unionid != "" {
+			userinfo.Unionid = unionid
+		}
+		if password := ObjToString((*data)["s_password"]); password != "" {
+			userinfo.Password = password
+		}
+		if headimg := ObjToString((*data)["s_headimageurl"]); headimg != "" {
+			userinfo.Headimg = headimg
+		}
+		return userinfo
+	}
+	return nil
+}
+
+//获取mongodb中的base_user_id
+func GetBaseUserId(mg mongodb.MongodbSim, userid string) int64 {
+	if userid == "" {
+		return 0
+	}
+	data, ok := mg.FindById("user", userid, `{"base_user_id":1}`)
+	if ok && data != nil && len(*data) > 0 {
+		return Int64All((*data)["base_user_id"])
+	}
+	return 0
+}
+
+//更新用户中台相关
+func UpdateBaseUser(mgo mongodb.MongodbSim, href, userId string, ck *http.Cookie) {
+	formdata := map[string]interface{}{
+		"appid": "10000",
+	}
+	userinfo := GetInfoForBaseUser(mgo, userId)
+	if userinfo == nil {
+		return
+	}
+	formdata["id"] = userinfo.Base_user_id
+
+	if userinfo.A_openid != "" {
+		formdata["a_openid"] = userinfo.A_openid
+	}
+	if userinfo.S_openid != "" {
+		formdata["s_openid"] = userinfo.S_openid
+	}
+
+	if userinfo.Company != "" {
+		formdata["company"] = userinfo.Company
+	}
+
+	if userinfo.Headimg != "" {
+		formdata["headimg"] = userinfo.Headimg
+	}
+
+	if userinfo.Password != "" {
+		formdata["password"] = userinfo.Password
+	}
+
+	if userinfo.Nickname != "" {
+		formdata["nickname"] = userinfo.Nickname
+	}
+
+	if userinfo.Phone != "" {
+		formdata["phone"] = userinfo.Phone
+	}
+
+	if userinfo.Unionid != "" {
+		formdata["unionid"] = userinfo.Unionid
+	}
+
+	ret, ok := PostUserCenter(href+UserCenterUpdate, ContentType_Json, userId, formdata, ck)
+	if ret != nil && ok {
+		status := IntAllDef((*ret)["status"], 0)
+		if status != 1 {
+			log.Printf("mysql同步数据失败,base_user_id:%s ,user_id :%s  ,%+v", formdata["id"], userId, formdata)
+		}
+	}
+}
+
+//新增用户中台信息。并绑定mongodb表
+func AddBaseUser(mgo mongodb.MongodbSim, href, userId string, formdata map[string]interface{}, ck *http.Cookie) {
+	ret, ok := PostUserCenter(href+UserCenterAdd, ContentType_Json, userId, formdata, ck)
+	if ret != nil && ok {
+		base_id := Int64All((*ret)["id"])
+		if base_id == 0 {
+			log.Printf("新增用户中台获取base_user_id失败,userid:%s", userId)
+			return
+		}
+		//获取到mysql的用户id存入user表中
+		if ok := mgo.UpdateById("user", userId, map[string]interface{}{
+			"$set": map[string]interface{}{"base_user_id": base_id},
+		}); !ok {
+			log.Printf("mysql同步失败,base_user_id:%s ,userid:%s", base_id, userId)
+		}
+	}
+}
+
+type UserIdentity struct {
+	PersonId          int64  //自然人id
+	UserAccountId     int64  //个人账户id
+	EntAccountId      int64  //企业账户id
+	EntUserAccountId  int64  //企业雇员账户id
+	UserPositionId    int64  // 个人职位id
+	EntUserPositionId int64  // 企业雇员职位id
+	UserName          string //昵称
+}
+
+//获取用户中台服务 用户相关账户参数
+func GetUserIdentity(href, userId string, baseUserId, entId int64, ck *http.Cookie) *UserIdentity {
+	ret, ok := PostUserCenter(href+UserCenterGetUserIdentity, ContentType_Json, userId,
+		map[string]interface{}{
+			"appId":     "10000",
+			"newUserId": baseUserId,
+			"entId":     entId,
+		}, ck)
+	if ret != nil && ok {
+		return &UserIdentity{
+			PersonId:          Int64All((*ret)["personId"]),
+			EntAccountId:      Int64All((*ret)["entAccountId"]),
+			UserAccountId:     Int64All((*ret)["userAccountId"]),
+			EntUserAccountId:  Int64All((*ret)["entUserAccountId"]),
+			UserPositionId:    Int64All((*ret)["userPositionId"]),
+			EntUserPositionId: Int64All((*ret)["entUserPositionId"]),
+			UserName:          ObjToString((*ret)["userName"]),
+		}
+	}
+
+	return nil
+}