finish
This commit is contained in:
6
Makefile
6
Makefile
@@ -4,7 +4,7 @@ plats = linux darwin
|
|||||||
arch ?= amd64
|
arch ?= amd64
|
||||||
archs = amd64 arm arm64
|
archs = amd64 arm arm64
|
||||||
|
|
||||||
all: stock ss
|
all: stock
|
||||||
|
|
||||||
define build_app
|
define build_app
|
||||||
@echo 'building $(1) ...'
|
@echo 'building $(1) ...'
|
||||||
@@ -17,10 +17,6 @@ stock:
|
|||||||
$(call build_app,stock,$(plat),$(arch))
|
$(call build_app,stock,$(plat),$(arch))
|
||||||
.PHONY: stock
|
.PHONY: stock
|
||||||
|
|
||||||
ss:
|
|
||||||
$(call build_app,ss,$(plat),$(arch))
|
|
||||||
.PHONY: ss
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-@rm -f builder/*
|
-@rm -f builder/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/**
|
|
||||||
* @Author: jager
|
|
||||||
* @Email: lhj168os@gmail.com
|
|
||||||
* @File: main
|
|
||||||
* @Date: 2021/12/20 2:24 下午
|
|
||||||
* @package: ss
|
|
||||||
* @Version: v1.0.0
|
|
||||||
*
|
|
||||||
* @Description:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/jageros/hawox/contextx"
|
|
||||||
"github.com/jageros/hawox/httpx"
|
|
||||||
"github.com/jageros/hawox/logx"
|
|
||||||
"net/http"
|
|
||||||
"stock/msg"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
ctx, cancel := contextx.Default()
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
logx.Init(logx.DebugLevel, logx.SetCaller(), logx.SetRequest())
|
|
||||||
defer logx.Sync()
|
|
||||||
|
|
||||||
httpx.InitializeHttpServer(ctx, func(engine *gin.Engine) {
|
|
||||||
r := engine.Group("/api")
|
|
||||||
r.GET("/sayhello", func(c *gin.Context) {
|
|
||||||
httpx.PkgMsgWrite(c, map[string]interface{}{"say": "hello world!"})
|
|
||||||
})
|
|
||||||
r.POST("/receive", func(c *gin.Context) {
|
|
||||||
rMsg := &msg.RData{}
|
|
||||||
err := c.BindXML(rMsg)
|
|
||||||
if err != nil {
|
|
||||||
logx.Error(err)
|
|
||||||
} else {
|
|
||||||
logx.Info(rMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
wMsg := &xml{
|
|
||||||
ToUserName: rMsg.FromUserName,
|
|
||||||
FromUserName: rMsg.ToUserName,
|
|
||||||
CreateTime: int(time.Now().Unix()),
|
|
||||||
MsgType: "text",
|
|
||||||
Content: "收到,谢谢!",
|
|
||||||
}
|
|
||||||
c.XML(http.StatusOK, wMsg)
|
|
||||||
|
|
||||||
//c.XML(http.StatusOK, wMsg)
|
|
||||||
|
|
||||||
//err = msg.Rcv(rMsg.FromUserName)
|
|
||||||
//if err != nil {
|
|
||||||
// logx.Error(err)
|
|
||||||
//}
|
|
||||||
|
|
||||||
//c.String(http.StatusOK, "success")
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/receive", func(c *gin.Context) {
|
|
||||||
echostr := c.Query("echostr")
|
|
||||||
logx.Infof("=== %s ===", echostr)
|
|
||||||
c.String(http.StatusOK, echostr)
|
|
||||||
})
|
|
||||||
}, func(s *httpx.Server) {
|
|
||||||
s.Mode = "debug"
|
|
||||||
s.Port = 8567
|
|
||||||
})
|
|
||||||
err := ctx.Wait()
|
|
||||||
logx.Infof("Stop With: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type xml struct {
|
|
||||||
ToUserName string `xml:"ToUserName"`
|
|
||||||
FromUserName string `xml:"FromUserName"`
|
|
||||||
CreateTime int `xml:"CreateTime"`
|
|
||||||
MsgType string `xml:"MsgType"`
|
|
||||||
Content string `xml:"Content"`
|
|
||||||
}
|
|
||||||
@@ -46,8 +46,14 @@ func main() {
|
|||||||
logx.Fatal(err)
|
logx.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer.AddTicker(time.Second*1200, func() {
|
||||||
|
logx.Info("开始保存用户数据进MongoDB...")
|
||||||
|
user.SaveAll()
|
||||||
|
logx.Info("保存用户数进MongoDB结束!")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
stockCodes := user.Codes(false)
|
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()) {
|
||||||
@@ -80,12 +86,17 @@ func main() {
|
|||||||
logx.Info("今天不是交易日!")
|
logx.Info("今天不是交易日!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
text := fund.FundsMsg(fundCodes...)
|
|
||||||
if text == "" {
|
fund.Clear()
|
||||||
logx.Errorf("收集基金数据为空!")
|
user.ForEachUser(func(u module.IUser) bool {
|
||||||
return
|
codes := u.Codes(true)
|
||||||
|
stk := fund.NewFundArg(codes...)
|
||||||
|
err = wxgzh.Send(u.OpenID(), stk)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
}
|
}
|
||||||
err := msg.Send(text)
|
return true
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logx.Errorf("dingtalk.SendMsg(基金信息) err: %v", err)
|
logx.Errorf("dingtalk.SendMsg(基金信息) err: %v", err)
|
||||||
} else {
|
} else {
|
||||||
@@ -93,9 +104,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if len(stockCodes) > 0 {
|
||||||
err = stock.Init(stockCodes...)
|
err = stock.Init(stockCodes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logx.Fatal(err)
|
logx.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Go(func(ctx contextx.Context) error {
|
ctx.Go(func(ctx contextx.Context) error {
|
||||||
@@ -152,20 +165,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
return true
|
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
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -185,7 +184,13 @@ func main() {
|
|||||||
})
|
})
|
||||||
}, func(s *httpx.Server) {
|
}, func(s *httpx.Server) {
|
||||||
s.Mode = "debug"
|
s.Mode = "debug"
|
||||||
s.Port = 8567
|
s.Port = 16888
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.Go(func(ctx contextx.Context) error {
|
||||||
|
<-ctx.Done()
|
||||||
|
user.SaveAll()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err = ctx.Wait() // 等待停止信号
|
err = ctx.Wait() // 等待停止信号
|
||||||
|
|||||||
89
fund/fund.go
89
fund/fund.go
@@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/jageros/hawox/logx"
|
"github.com/jageros/hawox/logx"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -28,17 +29,45 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
jsonStr = regexp.MustCompile(`{(.*?)}`)
|
jsonStr = regexp.MustCompile(`{(.*?)}`)
|
||||||
|
|
||||||
|
fds = &funds{fdsMap: map[string]*fund{}}
|
||||||
)
|
)
|
||||||
|
|
||||||
type fund struct {
|
type fund struct {
|
||||||
Code string `json:"fundcode"`
|
Code string `json:"fundcode"`
|
||||||
Name string `json:"name"`
|
FName string `json:"name"`
|
||||||
UnitVal string `json:"dwjz"`
|
UnitVal string `json:"dwjz"`
|
||||||
EstimateVal string `json:"gsz"`
|
EstimateVal string `json:"gsz"`
|
||||||
RisePer string `json:"gszzl"`
|
RisePer string `json:"gszzl"`
|
||||||
UpdateTime string `json:"gztime"`
|
UpdateTime string `json:"gztime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fund) Name() string {
|
||||||
|
return f.FName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fund) Update() error {
|
||||||
|
url := fmt.Sprintf(baseUrl, f.Code)
|
||||||
|
result, err := httpc.Request(httpc.GET, url, httpc.FORM, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ss := jsonStr.FindStringSubmatch(string(result))
|
||||||
|
if len(ss) <= 0 {
|
||||||
|
return errcode.New(404, "找不到基金:"+f.Code)
|
||||||
|
}
|
||||||
|
ff := &fund{}
|
||||||
|
err = json.Unmarshal([]byte(ss[0]), ff)
|
||||||
|
if err == nil {
|
||||||
|
f.FName = ff.FName
|
||||||
|
f.UnitVal = ff.UnitVal
|
||||||
|
f.EstimateVal = ff.EstimateVal
|
||||||
|
f.RisePer = ff.RisePer
|
||||||
|
f.UpdateTime = ff.UpdateTime
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fund) Msg() string {
|
func (f *fund) Msg() string {
|
||||||
var rise string
|
var rise string
|
||||||
last, err1 := strconv.ParseFloat(f.UnitVal, 64)
|
last, err1 := strconv.ParseFloat(f.UnitVal, 64)
|
||||||
@@ -46,17 +75,35 @@ func (f *fund) Msg() string {
|
|||||||
if err1 == nil && err2 == nil {
|
if err1 == nil && err2 == nil {
|
||||||
rise = fmt.Sprintf("%.5f", cur-last)
|
rise = fmt.Sprintf("%.5f", cur-last)
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf(msgTemplate, f.Name, f.UpdateTime, f.UnitVal, f.EstimateVal, rise, f.RisePer)
|
msg := fmt.Sprintf(msgTemplate, f.FName, f.UpdateTime, f.UnitVal, f.EstimateVal, rise, f.RisePer)
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
type funds struct {
|
type funds struct {
|
||||||
codes []string
|
fdsMap map[string]*fund
|
||||||
|
mx sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFunds(codes ...string) *funds {
|
func (fs *funds) getFund(code string) *fund {
|
||||||
return &funds{
|
fs.mx.RLock()
|
||||||
codes: codes,
|
defer fs.mx.RUnlock()
|
||||||
|
if fd, ok := fs.fdsMap[code]; ok {
|
||||||
|
return fd
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *funds) addFund(fd *fund) {
|
||||||
|
fs.mx.Lock()
|
||||||
|
defer fs.mx.Unlock()
|
||||||
|
fs.fdsMap[fd.Code] = fd
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clear() {
|
||||||
|
fds.mx.Lock()
|
||||||
|
defer fds.mx.Unlock()
|
||||||
|
fds = &funds{
|
||||||
|
fdsMap: map[string]*fund{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,17 +114,23 @@ func FundsMsg(codes ...string) string {
|
|||||||
//var msg = "基金定投估值 >>>\n"
|
//var msg = "基金定投估值 >>>\n"
|
||||||
msg := ""
|
msg := ""
|
||||||
for _, code := range codes {
|
for _, code := range codes {
|
||||||
fd, err := newFund(code)
|
fd := fds.getFund(code)
|
||||||
if err != nil {
|
if fd == nil {
|
||||||
|
fd_, err := NewFund(code)
|
||||||
|
if err == nil {
|
||||||
|
fd = fd_
|
||||||
|
fds.addFund(fd_)
|
||||||
|
} else {
|
||||||
logx.Error(err)
|
logx.Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
msg += fd.Msg()
|
msg += fd.Msg()
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFund(code string) (*fund, error) {
|
func NewFund(code string) (*fund, error) {
|
||||||
url := fmt.Sprintf(baseUrl, code)
|
url := fmt.Sprintf(baseUrl, code)
|
||||||
result, err := httpc.Request(httpc.GET, url, httpc.FORM, nil, nil)
|
result, err := httpc.Request(httpc.GET, url, httpc.FORM, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -99,13 +152,27 @@ const msgTemplate = `%s
|
|||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (fs *funds) Arg(openid string) map[string]interface{} {
|
type fundArg struct {
|
||||||
|
codes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFundArg(codes ...string) *fundArg {
|
||||||
|
return &fundArg{
|
||||||
|
codes: codes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fa *fundArg) Arg(openid string) map[string]interface{} {
|
||||||
|
msg := FundsMsg(fa.codes...)
|
||||||
|
if msg == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
arg := map[string]interface{}{
|
arg := map[string]interface{}{
|
||||||
"touser": openid,
|
"touser": openid,
|
||||||
"template_id": "SQXWp3RiYySb2GYG-vMYDsSIm-KZNM9szVpFOryUQGQ",
|
"template_id": "SQXWp3RiYySb2GYG-vMYDsSIm-KZNM9szVpFOryUQGQ",
|
||||||
"data": map[string]interface{}{
|
"data": map[string]interface{}{
|
||||||
"keyword": map[string]interface{}{
|
"keyword": map[string]interface{}{
|
||||||
"value": FundsMsg(fs.codes...),
|
"value": msg,
|
||||||
"color": "#173177",
|
"color": "#173177",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
baseUrl = "https://hq.sinajs.cn/"
|
baseUrl = "https://hq.sinajs.cn/"
|
||||||
fds *stocks
|
fds = &stocks{stkMap: map[string]*stock{}}
|
||||||
mx sync.RWMutex
|
mx sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ type stock struct {
|
|||||||
values []string
|
values []string
|
||||||
lastRise float64
|
lastRise float64
|
||||||
nowRise float64
|
nowRise float64
|
||||||
|
nowRiseStr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stock) Code() string {
|
func (s *stock) Code() string {
|
||||||
@@ -55,6 +56,7 @@ func (s *stock) notify() bool {
|
|||||||
|
|
||||||
rs := (nowPrice - lastPrice) / lastPrice * 100
|
rs := (nowPrice - lastPrice) / lastPrice * 100
|
||||||
s.nowRise = rs
|
s.nowRise = rs
|
||||||
|
s.nowRiseStr = fmt.Sprintf("%.2f%%", s.nowRise)
|
||||||
if (s.lastRise == 0 && rs != 0) || rs-s.lastRise >= cfg.ThresholdValue || s.lastRise-rs >= cfg.ThresholdValue {
|
if (s.lastRise == 0 && rs != 0) || rs-s.lastRise >= cfg.ThresholdValue || s.lastRise-rs >= cfg.ThresholdValue {
|
||||||
s.lastRise = rs
|
s.lastRise = rs
|
||||||
return true
|
return true
|
||||||
@@ -63,7 +65,21 @@ func (s *stock) notify() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stock) rise() string {
|
func (s *stock) rise() string {
|
||||||
return fmt.Sprintf("%.2f%%", s.nowRise)
|
if s.nowRiseStr != "" {
|
||||||
|
return s.nowRiseStr
|
||||||
|
}
|
||||||
|
lastPrice, err := strconv.ParseFloat(s.values[2], 64)
|
||||||
|
if err != nil || lastPrice == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
nowPrice, err := strconv.ParseFloat(s.values[3], 64)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := (nowPrice - lastPrice) / lastPrice * 100
|
||||||
|
s.nowRiseStr = fmt.Sprintf("%.2f%%", rs)
|
||||||
|
return s.nowRiseStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stock) buyCount() string {
|
func (s *stock) buyCount() string {
|
||||||
@@ -144,18 +160,18 @@ func (s *stock) Msg() string {
|
|||||||
// ==========================
|
// ==========================
|
||||||
|
|
||||||
func Init(codes ...string) error {
|
func Init(codes ...string) error {
|
||||||
fds = &stocks{}
|
fds = &stocks{stkMap: map[string]*stock{}}
|
||||||
return fds.AddCodes(codes...)
|
return fds.AddCodes(codes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
type stocks struct {
|
type stocks struct {
|
||||||
//codes []string
|
|
||||||
//ss []*stock
|
|
||||||
stkMap map[string]*stock
|
stkMap map[string]*stock
|
||||||
mx sync.RWMutex
|
mx sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sk *stocks) getStocks(codes ...string) *stocks {
|
func (sk *stocks) getStocks(codes ...string) *stocks {
|
||||||
|
mx.RLock()
|
||||||
|
defer mx.RUnlock()
|
||||||
var stks = &stocks{}
|
var stks = &stocks{}
|
||||||
for _, code := range codes {
|
for _, code := range codes {
|
||||||
stks.stkMap[code] = sk.stkMap[code]
|
stks.stkMap[code] = sk.stkMap[code]
|
||||||
@@ -181,6 +197,9 @@ func (sk *stocks) AddCodes(codes ...string) error {
|
|||||||
}
|
}
|
||||||
cds = append(cds, code)
|
cds = append(cds, code)
|
||||||
}
|
}
|
||||||
|
if len(cds) <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
stks, err := newStocks(cds...)
|
stks, err := newStocks(cds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -227,6 +246,17 @@ 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
|
||||||
|
for _, s := range sk.stkMap {
|
||||||
|
msg := s.Msg()
|
||||||
|
resp = resp + msg + "\n"
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk *stocks) msg() string {
|
||||||
sk.mx.RLock()
|
sk.mx.RLock()
|
||||||
defer sk.mx.RUnlock()
|
defer sk.mx.RUnlock()
|
||||||
var resp string
|
var resp string
|
||||||
@@ -240,12 +270,16 @@ func (sk *stocks) Msg() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sk *stocks) Arg(openid string) map[string]interface{} {
|
func (sk *stocks) Arg(openid string) map[string]interface{} {
|
||||||
|
msg := sk.msg()
|
||||||
|
if msg == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
arg := map[string]interface{}{
|
arg := map[string]interface{}{
|
||||||
"touser": openid,
|
"touser": openid,
|
||||||
"template_id": "yWuLbhAy7TTuqdeB9-VS6CR_t2rZQ8MHkJ62MF3VlS8",
|
"template_id": "yWuLbhAy7TTuqdeB9-VS6CR_t2rZQ8MHkJ62MF3VlS8",
|
||||||
"data": map[string]interface{}{
|
"data": map[string]interface{}{
|
||||||
"keyword": map[string]interface{}{
|
"keyword": map[string]interface{}{
|
||||||
"value": sk.Msg(),
|
"value": msg,
|
||||||
"color": "#173177",
|
"color": "#173177",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -253,15 +287,28 @@ func (sk *stocks) Arg(openid string) map[string]interface{} {
|
|||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetStock(code string) (*stock, error) {
|
||||||
|
if fds == nil {
|
||||||
|
fds = &stocks{stkMap: map[string]*stock{}}
|
||||||
|
}
|
||||||
|
err := fds.AddCodes(code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mx.RLock()
|
||||||
|
defer mx.RUnlock()
|
||||||
|
if fd, ok := fds.stkMap[code]; ok {
|
||||||
|
return fd, nil
|
||||||
|
}
|
||||||
|
return nil, errcode.New(1, "没有此股票数据")
|
||||||
|
}
|
||||||
|
|
||||||
func GetStocks(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, "股票代码为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
mx.Lock()
|
|
||||||
defer mx.Unlock()
|
|
||||||
if fds == nil {
|
if fds == nil {
|
||||||
fds = &stocks{}
|
fds = &stocks{stkMap: map[string]*stock{}}
|
||||||
}
|
}
|
||||||
err := fds.AddCodes(codes...)
|
err := fds.AddCodes(codes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -291,8 +338,13 @@ func newStocks(codes ...string) ([]*stock, error) {
|
|||||||
for _, s := range strs {
|
for _, s := range strs {
|
||||||
ss := strings.Split(s, "\"")
|
ss := strings.Split(s, "\"")
|
||||||
if len(ss) >= 2 {
|
if len(ss) >= 2 {
|
||||||
|
vs := strings.Split(ss[1], ",")
|
||||||
|
if len(vs) < 32 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
v := &stock{
|
v := &stock{
|
||||||
values: strings.Split(ss[1], ","),
|
code: ss[0][13:19],
|
||||||
|
values: vs,
|
||||||
}
|
}
|
||||||
stks = append(stks, v)
|
stks = append(stks, v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jageros/hawox/attribute"
|
"github.com/jageros/hawox/attribute"
|
||||||
|
"github.com/jageros/hawox/logx"
|
||||||
"stock/module"
|
"stock/module"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -37,6 +38,17 @@ func LoadAllUserIntoCache() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SaveAll() {
|
||||||
|
mx.Lock()
|
||||||
|
defer mx.Unlock()
|
||||||
|
for _, u := range users {
|
||||||
|
err := u.attr.Save(true)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetUser(openId string) (*User, error) {
|
func GetUser(openId string) (*User, error) {
|
||||||
mx.RLock()
|
mx.RLock()
|
||||||
u, ok := users[openId]
|
u, ok := users[openId]
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ import (
|
|||||||
"github.com/jageros/hawox/httpc"
|
"github.com/jageros/hawox/httpc"
|
||||||
"github.com/jageros/hawox/logx"
|
"github.com/jageros/hawox/logx"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"stock/fund"
|
||||||
"stock/module"
|
"stock/module"
|
||||||
|
"stock/stock"
|
||||||
"stock/user"
|
"stock/user"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -52,6 +54,11 @@ type IArg interface {
|
|||||||
Arg(openid string) map[string]interface{}
|
Arg(openid string) map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IMsg interface {
|
||||||
|
Msg() string
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
func getAccessToken(update bool) (string, error) {
|
func getAccessToken(update bool) (string, error) {
|
||||||
if !update && time.Now().Unix() < expiresIn {
|
if !update && time.Now().Unix() < expiresIn {
|
||||||
return accessToken, nil
|
return accessToken, nil
|
||||||
@@ -77,6 +84,9 @@ func send(openID string, arg IArg, recall bool) error {
|
|||||||
url := fmt.Sprintf(sendUrl, token)
|
url := fmt.Sprintf(sendUrl, token)
|
||||||
|
|
||||||
msg := arg.Arg(openID)
|
msg := arg.Arg(openID)
|
||||||
|
if msg == nil {
|
||||||
|
return errcode.New(1, "arg == nil")
|
||||||
|
}
|
||||||
resp := &Resp{}
|
resp := &Resp{}
|
||||||
err = httpc.RequestWithInterface(httpc.POST, url, httpc.JSON, msg, nil, resp)
|
err = httpc.RequestWithInterface(httpc.POST, url, httpc.JSON, msg, nil, resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -146,7 +156,8 @@ func Handle(c *gin.Context) {
|
|||||||
FromUserName: rMsg.ToUserName,
|
FromUserName: rMsg.ToUserName,
|
||||||
MsgType: "text",
|
MsgType: "text",
|
||||||
CreateTime: time.Now().Unix(),
|
CreateTime: time.Now().Unix(),
|
||||||
Content: "订阅股票:+st股票代码(例如:+st600905)\n订阅基金:+fd基金代码(例如:+fd161725)\n" +
|
Content: "查询股票:=st股票代码(例如:=st600905)\n查询基金:=fd基金代码(例如:=fd161725)\n\n" +
|
||||||
|
"订阅股票:+st股票代码(例如:+st600905)\n订阅基金:+fd基金代码(例如:+fd161725)\n\n" +
|
||||||
"取消订阅股票:-st股票代码(例如:-st600905)\n取消订阅基金:-fd基金代码(例如:-fd161725)",
|
"取消订阅股票:-st股票代码(例如:-st600905)\n取消订阅基金:-fd基金代码(例如:-fd161725)",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +170,55 @@ func Handle(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case len(rMsg.Content) < 9:
|
||||||
|
break
|
||||||
|
|
||||||
|
case strings.HasPrefix(rMsg.Content, "="):
|
||||||
|
code := rMsg.Content[3:]
|
||||||
|
isFund := rMsg.Content[1:3] == "fd"
|
||||||
|
var im IMsg
|
||||||
|
if isFund {
|
||||||
|
im, err = fund.NewFund(code)
|
||||||
|
} else {
|
||||||
|
im, err = stock.GetStock(code)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
wMsg.Content = "查询出错:\n" + err.Error()
|
||||||
|
} else {
|
||||||
|
wMsg.Content = "查询成功:\n" + im.Msg()
|
||||||
|
}
|
||||||
|
|
||||||
case strings.HasPrefix(rMsg.Content, "+"):
|
case strings.HasPrefix(rMsg.Content, "+"):
|
||||||
u.Subscribe(rMsg.Content[1:3] == "fd", rMsg.Content[3:])
|
code := rMsg.Content[3:]
|
||||||
wMsg.Content = "订阅成功!"
|
isFund := rMsg.Content[1:3] == "fd"
|
||||||
|
var im IMsg
|
||||||
|
if isFund {
|
||||||
|
im, err = fund.NewFund(code)
|
||||||
|
} else {
|
||||||
|
im, err = stock.GetStock(code)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
wMsg.Content = "订阅出错:\n" + err.Error()
|
||||||
|
} else {
|
||||||
|
u.Subscribe(isFund, code)
|
||||||
|
wMsg.Content = "订阅成功:\n" + im.Msg()
|
||||||
|
}
|
||||||
|
|
||||||
case strings.HasPrefix(rMsg.Content, "-"):
|
case strings.HasPrefix(rMsg.Content, "-"):
|
||||||
u.UnSubscribe(rMsg.Content[1:3] == "fd", rMsg.Content[3:])
|
code := rMsg.Content[3:]
|
||||||
wMsg.Content = "成功取消订阅!"
|
isFund := rMsg.Content[1:3] == "fd"
|
||||||
|
var im IMsg
|
||||||
|
if isFund {
|
||||||
|
im, err = fund.NewFund(code)
|
||||||
|
} else {
|
||||||
|
im, err = stock.GetStock(code)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
wMsg.Content = "取消订阅:\n" + err.Error()
|
||||||
|
} else {
|
||||||
|
wMsg.Content = "成功取消订阅:" + im.Name()
|
||||||
|
}
|
||||||
|
u.UnSubscribe(isFund, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user