wxgzh
This commit is contained in:
@@ -24,9 +24,11 @@ var (
|
|||||||
QywxRobotUrl = ""
|
QywxRobotUrl = ""
|
||||||
DingTalkSecret = ""
|
DingTalkSecret = ""
|
||||||
DingTalkRobotUrl = ""
|
DingTalkRobotUrl = ""
|
||||||
|
WxgzhAppid = ""
|
||||||
|
WxgzhSecret = ""
|
||||||
TianApiKey = ""
|
TianApiKey = ""
|
||||||
UpdateDuration = time.Second * 60 // 默认一分钟
|
UpdateDuration = time.Second * 60 // 默认一分钟
|
||||||
ThresholdValue float64 = 1 // 默认1%
|
ThresholdValue float64 = 1 // 默认1%
|
||||||
StockCodes = []string{"600905", "600032", "002531", "600733", "000825", "002939"} // 三峡能源, 浙江新能, 天顺风能, 北汽蓝谷, 太钢不锈, 长城证券
|
StockCodes = []string{"600905", "600032", "002531", "600733", "000825", "002939"} // 三峡能源, 浙江新能, 天顺风能, 北汽蓝谷, 太钢不锈, 长城证券
|
||||||
FundCodes = []string{"006229", "162412", "008359", "161725", "012314", "162719", "501057"}
|
FundCodes = []string{"006229", "162412", "008359", "161725", "012314", "162719", "501057"}
|
||||||
)
|
)
|
||||||
@@ -35,6 +37,8 @@ func load(v *viper.Viper) {
|
|||||||
QywxRobotUrl = v.GetString("qywxRobotUrl")
|
QywxRobotUrl = v.GetString("qywxRobotUrl")
|
||||||
DingTalkSecret = v.GetString("dingTalkSecret")
|
DingTalkSecret = v.GetString("dingTalkSecret")
|
||||||
DingTalkRobotUrl = v.GetString("dingTalkRobotUrl")
|
DingTalkRobotUrl = v.GetString("dingTalkRobotUrl")
|
||||||
|
WxgzhAppid = v.GetString("wxgzhAppid")
|
||||||
|
WxgzhSecret = v.GetString("wxgzhSecret")
|
||||||
TianApiKey = v.GetString("tianApiKey")
|
TianApiKey = v.GetString("tianApiKey")
|
||||||
updates := v.GetInt("updateSecond")
|
updates := v.GetInt("updateSecond")
|
||||||
if updates > 0 {
|
if updates > 0 {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/jageros/hawox/attribute"
|
||||||
"github.com/jageros/hawox/contextx"
|
"github.com/jageros/hawox/contextx"
|
||||||
"github.com/jageros/hawox/httpx"
|
"github.com/jageros/hawox/httpx"
|
||||||
"github.com/jageros/hawox/logx"
|
"github.com/jageros/hawox/logx"
|
||||||
@@ -10,8 +11,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"stock/cfg"
|
"stock/cfg"
|
||||||
"stock/fund"
|
"stock/fund"
|
||||||
|
"stock/module"
|
||||||
"stock/msg"
|
"stock/msg"
|
||||||
"stock/stock"
|
"stock/stock"
|
||||||
|
"stock/user"
|
||||||
|
"stock/wxgzh"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,6 +36,19 @@ func main() {
|
|||||||
|
|
||||||
timer.Initialize(ctx) // 定时器初始化
|
timer.Initialize(ctx) // 定时器初始化
|
||||||
|
|
||||||
|
// 初始化MongoDB
|
||||||
|
attribute.Initialize(ctx, func(opt *attribute.Option) {
|
||||||
|
opt.DBName = "stock-fund"
|
||||||
|
})
|
||||||
|
|
||||||
|
err = user.LoadAllUserIntoCache()
|
||||||
|
if err != nil {
|
||||||
|
logx.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stockCodes := user.Codes(false)
|
||||||
|
fundCodes := user.Codes(true)
|
||||||
|
|
||||||
timer.RunEveryDay(9, 25, 0, func() {
|
timer.RunEveryDay(9, 25, 0, func() {
|
||||||
if !stock.IsSellDay(time.Now()) {
|
if !stock.IsSellDay(time.Now()) {
|
||||||
logx.Info("今天不是交易日!")
|
logx.Info("今天不是交易日!")
|
||||||
@@ -63,7 +80,7 @@ func main() {
|
|||||||
logx.Info("今天不是交易日!")
|
logx.Info("今天不是交易日!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
text := fund.FundsMsg(cfg.FundCodes...)
|
text := fund.FundsMsg(fundCodes...)
|
||||||
if text == "" {
|
if text == "" {
|
||||||
logx.Errorf("收集基金数据为空!")
|
logx.Errorf("收集基金数据为空!")
|
||||||
return
|
return
|
||||||
@@ -76,11 +93,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
err = stock.Init(stockCodes...)
|
||||||
|
if err != nil {
|
||||||
|
logx.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Go(func(ctx contextx.Context) error {
|
ctx.Go(func(ctx contextx.Context) error {
|
||||||
ss, err := stock.NewStocks(cfg.StockCodes...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
var opened, closed bool
|
var opened, closed bool
|
||||||
@@ -95,7 +113,7 @@ func main() {
|
|||||||
if !closed {
|
if !closed {
|
||||||
if stock.HasClose(time.Now()) {
|
if stock.HasClose(time.Now()) {
|
||||||
logx.Info("--- 已闭市 ---")
|
logx.Info("--- 已闭市 ---")
|
||||||
ss.Clear()
|
stock.Clear()
|
||||||
} else {
|
} else {
|
||||||
logx.Info("--- 未开市 ---")
|
logx.Info("--- 未开市 ---")
|
||||||
}
|
}
|
||||||
@@ -111,7 +129,7 @@ func main() {
|
|||||||
logx.Infof("--- 交易中 ---")
|
logx.Infof("--- 交易中 ---")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ss.Update()
|
err = stock.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
count++
|
count++
|
||||||
logx.Errorf("Update ErrCount=%d err=%v", count, err)
|
logx.Errorf("Update ErrCount=%d err=%v", count, err)
|
||||||
@@ -121,19 +139,33 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
text := ss.Msg()
|
user.ForEachUser(func(u module.IUser) bool {
|
||||||
if text == "" {
|
codes := u.Codes(false)
|
||||||
logx.Info("已更新数据,未超过阈值,无警告!")
|
stk, err := stock.GetStocks(codes...)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
logx.Error(err)
|
||||||
err = msg.Send(text)
|
} else {
|
||||||
if err != nil {
|
err = wxgzh.Send(u.OpenID(), stk)
|
||||||
count++
|
if err != nil {
|
||||||
logx.Errorf("SendMsg ErrCount=%d err=%v", count, err)
|
logx.Error(err)
|
||||||
if count > 10 {
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
//text := ss.Msg()
|
||||||
|
//if text == "" {
|
||||||
|
// logx.Info("已更新数据,未超过阈值,无警告!")
|
||||||
|
// continue
|
||||||
|
//}
|
||||||
|
//err = msg.Send(text)
|
||||||
|
//if err != nil {
|
||||||
|
// count++
|
||||||
|
// logx.Errorf("SendMsg ErrCount=%d err=%v", count, err)
|
||||||
|
// if count > 10 {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -143,21 +175,12 @@ func main() {
|
|||||||
r.GET("/sayhello", func(c *gin.Context) {
|
r.GET("/sayhello", func(c *gin.Context) {
|
||||||
httpx.PkgMsgWrite(c, map[string]interface{}{"say": "hello world!"})
|
httpx.PkgMsgWrite(c, map[string]interface{}{"say": "hello world!"})
|
||||||
})
|
})
|
||||||
r.POST("/receive", func(c *gin.Context) {
|
|
||||||
msgs := &msg.RData{}
|
|
||||||
err := c.BindXML(msgs)
|
|
||||||
if err != nil {
|
|
||||||
logx.Error(err)
|
|
||||||
} else {
|
|
||||||
logx.Info(msgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.String(http.StatusOK, "success")
|
r.POST("/receive", wxgzh.Handle)
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/receive", func(c *gin.Context) {
|
r.GET("/receive", func(c *gin.Context) {
|
||||||
echostr := c.Query("echostr")
|
echostr := c.Query("echostr")
|
||||||
logx.Infof("=== %s ===", echostr)
|
logx.Infof("配置接口 %s", echostr)
|
||||||
c.String(http.StatusOK, echostr)
|
c.String(http.StatusOK, echostr)
|
||||||
})
|
})
|
||||||
}, func(s *httpx.Server) {
|
}, func(s *httpx.Server) {
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ qywxRobotUrl: ""
|
|||||||
|
|
||||||
# 钉钉群机器人的secret
|
# 钉钉群机器人的secret
|
||||||
dingTalkSecret: ""
|
dingTalkSecret: ""
|
||||||
|
# 钉钉群机器人发消息的链接
|
||||||
# 钉钉群机器人发消息额链接
|
|
||||||
dingTalkRobotUrl: ""
|
dingTalkRobotUrl: ""
|
||||||
|
|
||||||
|
# 微信公众号appid
|
||||||
|
wxgzhAppid: ""
|
||||||
|
# 微信公众号secret
|
||||||
|
wxgzhSecret: ""
|
||||||
|
|
||||||
# 天行数据获取节假日的api的key (https://www.tianapi.com/apiview/139)
|
# 天行数据获取节假日的api的key (https://www.tianapi.com/apiview/139)
|
||||||
tianApiKey: ""
|
tianApiKey: ""
|
||||||
|
|
||||||
|
|||||||
29
fund/fund.go
29
fund/fund.go
@@ -27,7 +27,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jsonStr = regexp.MustCompile(`{(.*?)}`)
|
jsonStr = regexp.MustCompile(`{(.*?)}`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type fund struct {
|
type fund struct {
|
||||||
@@ -50,11 +50,22 @@ func (f *fund) Msg() string {
|
|||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type funds struct {
|
||||||
|
codes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFunds(codes ...string) *funds {
|
||||||
|
return &funds{
|
||||||
|
codes: codes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func FundsMsg(codes ...string) string {
|
func FundsMsg(codes ...string) string {
|
||||||
if len(codes) <= 0 {
|
if len(codes) <= 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
var msg = "基金定投估值 >>>\n"
|
//var msg = "基金定投估值 >>>\n"
|
||||||
|
msg := ""
|
||||||
for _, code := range codes {
|
for _, code := range codes {
|
||||||
fd, err := newFund(code)
|
fd, err := newFund(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,3 +98,17 @@ const msgTemplate = `%s
|
|||||||
估算涨幅:(%s) %s%%
|
估算涨幅:(%s) %s%%
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func (fs *funds) Arg(openid string) map[string]interface{} {
|
||||||
|
arg := map[string]interface{}{
|
||||||
|
"touser": openid,
|
||||||
|
"template_id": "SQXWp3RiYySb2GYG-vMYDsSIm-KZNM9szVpFOryUQGQ",
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"keyword": map[string]interface{}{
|
||||||
|
"value": FundsMsg(fs.codes...),
|
||||||
|
"color": "#173177",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return arg
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,11 +13,14 @@
|
|||||||
package fund
|
package fund
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"stock/wxgzh"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Fund(t *testing.T) {
|
func Test_Fund(t *testing.T) {
|
||||||
msg := FundsMsg()
|
f := NewFunds("006229", "162412")
|
||||||
fmt.Println(msg)
|
err := wxgzh.Send("o-KDV6NbRaanYz55fJuSgyR0qxxU", f)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -35,6 +35,7 @@ require (
|
|||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
github.com/tal-tech/go-zero v1.2.1 // indirect
|
github.com/tal-tech/go-zero v1.2.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||||
|
github.com/xiaonanln/go-xnsyncutil v0.0.5 // indirect
|
||||||
go.opentelemetry.io/otel v1.0.0-RC2 // indirect
|
go.opentelemetry.io/otel v1.0.0-RC2 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.0.0-RC2 // indirect
|
go.opentelemetry.io/otel/trace v1.0.0-RC2 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
@@ -47,7 +48,9 @@ require (
|
|||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
|
gopkg.in/eapache/queue.v1 v1.1.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -422,6 +422,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
|
|||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/xiaonanln/go-xnsyncutil v0.0.5 h1:1kan2cg95e0quhKEBafu1lNG3UVI44BF0ThlJGa+lJQ=
|
||||||
|
github.com/xiaonanln/go-xnsyncutil v0.0.5/go.mod h1:PbwFumxH1s5Zc5mPk3A9GFaS/FdIP5WHobaRwQLS8xY=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
@@ -821,6 +823,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc=
|
||||||
|
gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
@@ -829,6 +833,8 @@ gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdOD
|
|||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
|||||||
21
module/user.go
Normal file
21
module/user.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @Author: jager
|
||||||
|
* @Email: lhj168os@gmail.com
|
||||||
|
* @File: user
|
||||||
|
* @Date: 2021/12/21 3:17 下午
|
||||||
|
* @package: module
|
||||||
|
* @Version: v1.0.0
|
||||||
|
*
|
||||||
|
* @Description:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package module
|
||||||
|
|
||||||
|
type IUser interface {
|
||||||
|
OpenID() string
|
||||||
|
Codes(isFund bool) []string
|
||||||
|
HasSubscribed(isFund bool, code string) bool
|
||||||
|
Subscribe(isFund bool, codes ...string)
|
||||||
|
UnSubscribe(isFund bool, codes ...string)
|
||||||
|
}
|
||||||
297
stock/stock.go
297
stock/stock.go
@@ -9,10 +9,13 @@ import (
|
|||||||
"stock/cfg"
|
"stock/cfg"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
baseUrl = "https://hq.sinajs.cn/"
|
baseUrl = "https://hq.sinajs.cn/"
|
||||||
|
fds *stocks
|
||||||
|
mx sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
type IStock interface {
|
type IStock interface {
|
||||||
@@ -28,6 +31,14 @@ type stock struct {
|
|||||||
nowRise float64
|
nowRise float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stock) Code() string {
|
||||||
|
return s.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stock) Name() string {
|
||||||
|
return s.values[0]
|
||||||
|
}
|
||||||
|
|
||||||
func (s *stock) update(values []string) {
|
func (s *stock) update(values []string) {
|
||||||
s.values = values
|
s.values = values
|
||||||
}
|
}
|
||||||
@@ -130,41 +141,84 @@ func (s *stock) Msg() string {
|
|||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================
|
||||||
|
|
||||||
|
func Init(codes ...string) error {
|
||||||
|
fds = &stocks{}
|
||||||
|
return fds.AddCodes(codes...)
|
||||||
|
}
|
||||||
|
|
||||||
type stocks struct {
|
type stocks struct {
|
||||||
codes []string
|
//codes []string
|
||||||
ss []*stock
|
//ss []*stock
|
||||||
|
stkMap map[string]*stock
|
||||||
|
mx sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sk *stocks) Clear() {
|
func (sk *stocks) getStocks(codes ...string) *stocks {
|
||||||
if len(sk.ss) <= 0 {
|
var stks = &stocks{}
|
||||||
return
|
for _, code := range codes {
|
||||||
|
stks.stkMap[code] = sk.stkMap[code]
|
||||||
}
|
}
|
||||||
sk.ss = []*stock{}
|
return stks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sk *stocks) Update() error {
|
func (sk *stocks) Codes() []string {
|
||||||
str, err := getStockStr(sk.codes)
|
var codes []string
|
||||||
|
for code := range sk.stkMap {
|
||||||
|
codes = append(codes, code)
|
||||||
|
}
|
||||||
|
return codes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk *stocks) AddCodes(codes ...string) error {
|
||||||
|
sk.mx.Lock()
|
||||||
|
defer sk.mx.Unlock()
|
||||||
|
var cds []string
|
||||||
|
for _, code := range codes {
|
||||||
|
if _, ok := sk.stkMap[code]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cds = append(cds, code)
|
||||||
|
}
|
||||||
|
stks, err := newStocks(cds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, stk := range stks {
|
||||||
|
sk.stkMap[stk.Code()] = stk
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk *stocks) Clear() {
|
||||||
|
sk.mx.Lock()
|
||||||
|
defer sk.mx.Unlock()
|
||||||
|
for _, fd := range fds.stkMap {
|
||||||
|
fd.lastRise = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk *stocks) Update() error {
|
||||||
|
sk.mx.Lock()
|
||||||
|
sk.mx.Unlock()
|
||||||
|
str, err := getStockStr(sk.Codes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
strs := strings.Split(str, ";\n")
|
strs := strings.Split(str, ";\n")
|
||||||
if len(sk.ss) == 0 {
|
for _, s := range strs {
|
||||||
sk.ss = []*stock{}
|
ss := strings.Split(s, "\"")
|
||||||
for _, s := range strs {
|
if len(ss) >= 2 {
|
||||||
ss := strings.Split(s, "\"")
|
v := &stock{
|
||||||
if len(ss) >= 2 {
|
code: ss[0][13:19],
|
||||||
v := &stock{
|
values: strings.Split(ss[1], ","),
|
||||||
values: strings.Split(ss[1], ","),
|
|
||||||
}
|
|
||||||
sk.ss = append(sk.ss, v)
|
|
||||||
}
|
}
|
||||||
}
|
if skk, ok := sk.stkMap[v.code]; ok {
|
||||||
} else {
|
skk.update(v.values)
|
||||||
l := len(sk.ss)
|
} else {
|
||||||
for i, s := range strs {
|
sk.stkMap[v.code] = v
|
||||||
ss := strings.Split(s, "\"")
|
|
||||||
if len(ss) >= 2 && i < l {
|
|
||||||
sk.ss[i].update(strings.Split(ss[1], ","))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,8 +227,10 @@ func (sk *stocks) Update() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sk *stocks) Msg() string {
|
func (sk *stocks) Msg() string {
|
||||||
|
sk.mx.RLock()
|
||||||
|
defer sk.mx.RUnlock()
|
||||||
var resp string
|
var resp string
|
||||||
for _, s := range sk.ss {
|
for _, s := range sk.stkMap {
|
||||||
if s.notify() {
|
if s.notify() {
|
||||||
msg := s.Msg()
|
msg := s.Msg()
|
||||||
resp = resp + msg + "\n"
|
resp = resp + msg + "\n"
|
||||||
@@ -183,33 +239,65 @@ func (sk *stocks) Msg() string {
|
|||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
type IArg interface {
|
func (sk *stocks) Arg(openid string) map[string]interface{} {
|
||||||
Arg(openId string) map[string]interface{}
|
arg := map[string]interface{}{
|
||||||
}
|
"touser": openid,
|
||||||
|
"template_id": "yWuLbhAy7TTuqdeB9-VS6CR_t2rZQ8MHkJ62MF3VlS8",
|
||||||
func (sk *stocks) ForEachStock(f func(stk IArg) error) error {
|
"data": map[string]interface{}{
|
||||||
for _, k := range sk.ss {
|
"keyword": map[string]interface{}{
|
||||||
err := f(k)
|
"value": sk.Msg(),
|
||||||
if err != nil {
|
"color": "#173177",
|
||||||
return err
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
return nil
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStocks(codes ...string) (*stocks, error) {
|
func GetStocks(codes ...string) (*stocks, error) {
|
||||||
if len(codes) <= 0 {
|
if len(codes) <= 0 {
|
||||||
return nil, errcode.New(1, "股票代码为空")
|
return nil, errcode.New(1, "股票代码为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &stocks{
|
mx.Lock()
|
||||||
codes: codes,
|
defer mx.Unlock()
|
||||||
|
if fds == nil {
|
||||||
|
fds = &stocks{}
|
||||||
}
|
}
|
||||||
err := s.Update()
|
err := fds.AddCodes(codes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s, nil
|
return fds.getStocks(codes...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update() error {
|
||||||
|
return fds.Update()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clear() {
|
||||||
|
fds.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStocks(codes ...string) ([]*stock, error) {
|
||||||
|
if len(codes) <= 0 {
|
||||||
|
return nil, errcode.New(1, "股票代码为空")
|
||||||
|
}
|
||||||
|
str, err := getStockStr(codes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
strs := strings.Split(str, ";\n")
|
||||||
|
var stks []*stock
|
||||||
|
for _, s := range strs {
|
||||||
|
ss := strings.Split(s, "\"")
|
||||||
|
if len(ss) >= 2 {
|
||||||
|
v := &stock{
|
||||||
|
values: strings.Split(ss[1], ","),
|
||||||
|
}
|
||||||
|
stks = append(stks, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPrefix(code string) string {
|
func addPrefix(code string) string {
|
||||||
@@ -251,66 +339,67 @@ const msgTemplate = `%s
|
|||||||
前五总买单:%s 前五总卖单:%s
|
前五总买单:%s 前五总卖单:%s
|
||||||
`
|
`
|
||||||
|
|
||||||
func (s *stock) Arg(openId string) map[string]interface{} {
|
//
|
||||||
|
//func (s *stock) Arg(openId string) map[string]interface{} {
|
||||||
arg := map[string]interface{}{
|
//
|
||||||
"touser": openId,
|
// arg := map[string]interface{}{
|
||||||
"template_id": "L7fOGJURj-1HF4cIpFizCOOiAMqER3PG-pfgn37Dalw",
|
// "touser": openId,
|
||||||
|
// "template_id": "L7fOGJURj-1HF4cIpFizCOOiAMqER3PG-pfgn37Dalw",
|
||||||
"data": map[string]interface{}{
|
//
|
||||||
"first": map[string]interface{}{
|
// "data": map[string]interface{}{
|
||||||
"value": s.values[0],
|
// "first": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[0],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword1": map[string]interface{}{
|
// },
|
||||||
"value": fmt.Sprintf("%s %s", s.values[30], s.values[31]),
|
// "keyword1": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": fmt.Sprintf("%s %s", s.values[30], s.values[31]),
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword2": map[string]interface{}{
|
// },
|
||||||
"value": s.values[2],
|
// "keyword2": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[2],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword3": map[string]interface{}{
|
// },
|
||||||
"value": s.values[1],
|
// "keyword3": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[1],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword4": map[string]interface{}{
|
// },
|
||||||
"value": s.values[3],
|
// "keyword4": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[3],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword5": map[string]interface{}{
|
// },
|
||||||
"value": s.rise(),
|
// "keyword5": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.rise(),
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword6": map[string]interface{}{
|
// },
|
||||||
"value": s.values[4],
|
// "keyword6": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[4],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword7": map[string]interface{}{
|
// },
|
||||||
"value": s.values[5],
|
// "keyword7": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.values[5],
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword8": map[string]interface{}{
|
// },
|
||||||
"value": s.tradingVolume(),
|
// "keyword8": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.tradingVolume(),
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword9": map[string]interface{}{
|
// },
|
||||||
"value": numFormat(s.values[9]),
|
// "keyword9": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": numFormat(s.values[9]),
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword10": map[string]interface{}{
|
// },
|
||||||
"value": s.buyCount(),
|
// "keyword10": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.buyCount(),
|
||||||
},
|
// "color": "#173177",
|
||||||
"keyword11": map[string]interface{}{
|
// },
|
||||||
"value": s.sellCount(),
|
// "keyword11": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": s.sellCount(),
|
||||||
},
|
// "color": "#173177",
|
||||||
"remark": map[string]interface{}{
|
// },
|
||||||
"value": "欢迎再次购买!",
|
// "remark": map[string]interface{}{
|
||||||
"color": "#173177",
|
// "value": "欢迎再次购买!",
|
||||||
},
|
// "color": "#173177",
|
||||||
},
|
// },
|
||||||
}
|
// },
|
||||||
return arg
|
// }
|
||||||
}
|
// return arg
|
||||||
|
//}
|
||||||
|
|||||||
@@ -14,32 +14,71 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jageros/hawox/attribute"
|
"github.com/jageros/hawox/attribute"
|
||||||
|
"stock/module"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var users sync.Map
|
var (
|
||||||
|
users = map[string]*User{}
|
||||||
|
mx sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
func LoadAllUserIntoCache() error {
|
func LoadAllUserIntoCache() error {
|
||||||
attrs, err := attribute.LoadAll("user")
|
attrs, err := attribute.LoadAll("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
mx.Lock()
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
u := &User{attr: attr}
|
u := &User{attr: attr}
|
||||||
users.Store(attr.GetAttrID(), u)
|
users[u.OpenID()] = u
|
||||||
}
|
}
|
||||||
|
mx.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUser(openId string) (*User, error) {
|
func GetUser(openId string) (*User, error) {
|
||||||
u, ok := users.Load(openId)
|
mx.RLock()
|
||||||
|
u, ok := users[openId]
|
||||||
|
mx.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return u.(*User), nil
|
return u, nil
|
||||||
}
|
}
|
||||||
us, err := newUser(openId)
|
us, err := newUser(openId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
users.Store(openId, us)
|
mx.Lock()
|
||||||
|
users[openId] = us
|
||||||
|
mx.Unlock()
|
||||||
return us, nil
|
return us, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ForEachUser(f func(u module.IUser) bool) {
|
||||||
|
mx.Lock()
|
||||||
|
defer mx.Unlock()
|
||||||
|
for _, u := range users {
|
||||||
|
if !f(u) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Codes(isFund bool) []string {
|
||||||
|
var codes = map[string]struct{}{}
|
||||||
|
ForEachUser(func(u module.IUser) bool {
|
||||||
|
cds := u.Codes(isFund)
|
||||||
|
for _, cd := range cds {
|
||||||
|
if _, ok := codes[cd]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
codes[cd] = struct{}{}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
var cods []string
|
||||||
|
for code := range codes {
|
||||||
|
cods = append(cods, code)
|
||||||
|
}
|
||||||
|
return cods
|
||||||
|
}
|
||||||
|
|||||||
10
user/user.go
10
user/user.go
@@ -14,11 +14,13 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jageros/hawox/attribute"
|
"github.com/jageros/hawox/attribute"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
attr *attribute.AttrMgr
|
attr *attribute.AttrMgr
|
||||||
|
mx sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUser(openId string) (*User, error) {
|
func newUser(openId string) (*User, error) {
|
||||||
@@ -38,6 +40,8 @@ func (u *User) OpenID() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) Codes(isFund bool) []string {
|
func (u *User) Codes(isFund bool) []string {
|
||||||
|
u.mx.RLock()
|
||||||
|
defer u.mx.RUnlock()
|
||||||
key := "stock"
|
key := "stock"
|
||||||
if isFund {
|
if isFund {
|
||||||
key = "fund"
|
key = "fund"
|
||||||
@@ -56,6 +60,8 @@ func (u *User) Codes(isFund bool) []string {
|
|||||||
|
|
||||||
// HasSubscribed 查询用户是否订阅此票
|
// HasSubscribed 查询用户是否订阅此票
|
||||||
func (u *User) HasSubscribed(isFund bool, code string) bool {
|
func (u *User) HasSubscribed(isFund bool, code string) bool {
|
||||||
|
u.mx.RLock()
|
||||||
|
defer u.mx.RUnlock()
|
||||||
key := "stock"
|
key := "stock"
|
||||||
if isFund {
|
if isFund {
|
||||||
key = "fund"
|
key = "fund"
|
||||||
@@ -73,6 +79,8 @@ func (u *User) HasSubscribed(isFund bool, code string) bool {
|
|||||||
|
|
||||||
// Subscribe 订阅股票或基金
|
// Subscribe 订阅股票或基金
|
||||||
func (u *User) Subscribe(isFund bool, codes ...string) {
|
func (u *User) Subscribe(isFund bool, codes ...string) {
|
||||||
|
u.mx.Lock()
|
||||||
|
defer u.mx.Unlock()
|
||||||
key := "stock"
|
key := "stock"
|
||||||
if isFund {
|
if isFund {
|
||||||
key = "fund"
|
key = "fund"
|
||||||
@@ -95,6 +103,8 @@ func (u *User) Subscribe(isFund bool, codes ...string) {
|
|||||||
|
|
||||||
// UnSubscribe 取消订阅股票或基金
|
// UnSubscribe 取消订阅股票或基金
|
||||||
func (u *User) UnSubscribe(isFund bool, codes ...string) {
|
func (u *User) UnSubscribe(isFund bool, codes ...string) {
|
||||||
|
u.mx.Lock()
|
||||||
|
defer u.mx.Unlock()
|
||||||
key := "stock"
|
key := "stock"
|
||||||
if isFund {
|
if isFund {
|
||||||
key = "fund"
|
key = "fund"
|
||||||
|
|||||||
104
wxgzh/wxgzh.go
104
wxgzh/wxgzh.go
@@ -14,9 +14,14 @@ package wxgzh
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jageros/hawox/errcode"
|
"github.com/jageros/hawox/errcode"
|
||||||
"github.com/jageros/hawox/httpc"
|
"github.com/jageros/hawox/httpc"
|
||||||
"stock/stock"
|
"github.com/jageros/hawox/logx"
|
||||||
|
"net/http"
|
||||||
|
"stock/module"
|
||||||
|
"stock/user"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,21 +48,8 @@ type AccessToken struct {
|
|||||||
Errmsg string `json:"errmsg"`
|
Errmsg string `json:"errmsg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RData struct {
|
type IArg interface {
|
||||||
ToUserName string `xml:"ToUserName"`
|
Arg(openid string) map[string]interface{}
|
||||||
FromUserName string `xml:"FromUserName"`
|
|
||||||
CreateTime int `xml:"CreateTime"`
|
|
||||||
MsgType string `xml:"MsgType"`
|
|
||||||
Content string `xml:"Content"`
|
|
||||||
MsgID int64 `xml:"MsgId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type xml struct {
|
|
||||||
ToUserName string `xml:"ToUserName"`
|
|
||||||
FromUserName string `xml:"FromUserName"`
|
|
||||||
CreateTime int `xml:"CreateTime"`
|
|
||||||
MsgType string `xml:"MsgType"`
|
|
||||||
Content string `xml:"Content"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccessToken(update bool) (string, error) {
|
func getAccessToken(update bool) (string, error) {
|
||||||
@@ -77,16 +69,16 @@ func getAccessToken(update bool) (string, error) {
|
|||||||
return resp.AccessToken, nil
|
return resp.AccessToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(openID string, stk stock.IArg, recall bool) error {
|
func send(openID string, arg IArg, recall bool) error {
|
||||||
token, err := getAccessToken(false)
|
token, err := getAccessToken(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf(sendUrl, token)
|
url := fmt.Sprintf(sendUrl, token)
|
||||||
|
|
||||||
arg := stk.Arg(openID)
|
msg := arg.Arg(openID)
|
||||||
resp := &Resp{}
|
resp := &Resp{}
|
||||||
err = httpc.RequestWithInterface(httpc.POST, url, httpc.JSON, arg, nil, resp)
|
err = httpc.RequestWithInterface(httpc.POST, url, httpc.JSON, msg, nil, resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -97,7 +89,7 @@ func send(openID string, stk stock.IArg, recall bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if recall {
|
if recall {
|
||||||
return send(openID, stk, false)
|
return send(openID, arg, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errcode.New(int32(resp.Errcode), resp.Errmsg)
|
return errcode.New(int32(resp.Errcode), resp.Errmsg)
|
||||||
@@ -105,6 +97,76 @@ func send(openID string, stk stock.IArg, recall bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Send(openId string, stk stock.IArg) error {
|
func Send(openId string, stk IArg) error {
|
||||||
return send(openId, stk, true)
|
return send(openId, stk, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendAll(stk IArg) error {
|
||||||
|
user.ForEachUser(func(u module.IUser) bool {
|
||||||
|
if u.HasSubscribed(false, "") {
|
||||||
|
err := Send(u.OpenID(), stk)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rData struct {
|
||||||
|
ToUserName string `xml:"ToUserName"`
|
||||||
|
FromUserName string `xml:"FromUserName"`
|
||||||
|
CreateTime int64 `xml:"CreateTime"`
|
||||||
|
MsgType string `xml:"MsgType"`
|
||||||
|
Content string `xml:"Content"`
|
||||||
|
MsgID int64 `xml:"MsgId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type xml struct {
|
||||||
|
ToUserName string `xml:"ToUserName"`
|
||||||
|
FromUserName string `xml:"FromUserName"`
|
||||||
|
CreateTime int64 `xml:"CreateTime"`
|
||||||
|
MsgType string `xml:"MsgType"`
|
||||||
|
Content string `xml:"Content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Handle(c *gin.Context) {
|
||||||
|
rMsg := &rData{}
|
||||||
|
err := c.BindXML(rMsg)
|
||||||
|
if err != nil {
|
||||||
|
c.String(http.StatusOK, err.Error())
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wMsg := &xml{
|
||||||
|
ToUserName: rMsg.FromUserName,
|
||||||
|
FromUserName: rMsg.ToUserName,
|
||||||
|
MsgType: "text",
|
||||||
|
CreateTime: time.Now().Unix(),
|
||||||
|
Content: "订阅股票:+st股票代码(例如:+st600905)\n订阅基金:+fd基金代码(例如:+fd161725)\n" +
|
||||||
|
"取消订阅股票:-st股票代码(例如:-st600905)\n取消订阅基金:-fd基金代码(例如:-fd161725)",
|
||||||
|
}
|
||||||
|
|
||||||
|
if rMsg.MsgType == "text" {
|
||||||
|
u, err := user.GetUser(rMsg.FromUserName)
|
||||||
|
if err != nil {
|
||||||
|
c.String(http.StatusOK, err.Error())
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(rMsg.Content, "+"):
|
||||||
|
u.Subscribe(rMsg.Content[1:3] == "fd", rMsg.Content[3:])
|
||||||
|
wMsg.Content = "订阅成功!"
|
||||||
|
case strings.HasPrefix(rMsg.Content, "-"):
|
||||||
|
u.UnSubscribe(rMsg.Content[1:3] == "fd", rMsg.Content[3:])
|
||||||
|
wMsg.Content = "成功取消订阅!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.XML(http.StatusOK, wMsg)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user