You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
3.6 KiB
Go

/**
* @Author: jager
* @Email: lhj168os@gmail.com
* @File: fund
* @Date: 2021/12/1 3:05 下午
* @package: fund
* @Version: v1.0.0
*
* @Description:
*
*/
package fund
import (
"encoding/json"
"fmt"
"github.com/jageros/hawox/errcode"
"github.com/jageros/hawox/httpc"
"github.com/jageros/hawox/logx"
"regexp"
"strconv"
"sync"
"time"
)
const (
baseUrl = "http://fundgz.1234567.com.cn/js/%s.js"
)
var (
jsonStr = regexp.MustCompile(`{(.*?)}`)
fds = &funds{fdsMap: map[string]*fund{}}
)
type fund struct {
Code string `json:"fundcode"`
FName string `json:"name"`
UnitVal string `json:"dwjz"`
EstimateVal string `json:"gsz"`
RisePer string `json:"gszzl"`
UpdateTime string `json:"gztime"`
CheckTime time.Time
}
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
f.CheckTime = time.Now()
}
return err
}
func (f *fund) Msg() string {
now := time.Now()
h := now.Hour()
if h > 9 && h < 15 && now.Sub(f.CheckTime) > time.Minute*5 {
err := f.Update()
if err != nil {
logx.Error(err)
}
}
var rise string
last, err1 := strconv.ParseFloat(f.UnitVal, 64)
cur, err2 := strconv.ParseFloat(f.EstimateVal, 64)
if err1 == nil && err2 == nil {
rise = fmt.Sprintf("%.5f", cur-last)
}
msg := fmt.Sprintf(msgTemplate, f.FName, f.UpdateTime, f.UnitVal, f.EstimateVal, rise, f.RisePer)
return msg
}
type funds struct {
fdsMap map[string]*fund
mx sync.RWMutex
}
func (fs *funds) getFund(code string) *fund {
fs.mx.RLock()
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{},
}
}
func FundsMsg(codes ...string) string {
if len(codes) <= 0 {
return ""
}
//var msg = "基金定投估值 >>>\n"
msg := ""
for _, code := range codes {
fd := fds.getFund(code)
if fd == nil {
fd_, err := NewFund(code)
if err == nil {
fd = fd_
fds.addFund(fd_)
} else {
logx.Error(err)
continue
}
}
msg += fd.Msg()
}
return msg
}
func NewFund(code string) (*fund, error) {
url := fmt.Sprintf(baseUrl, code)
result, err := httpc.Request(httpc.GET, url, httpc.FORM, nil, nil)
if err != nil {
return nil, err
}
ss := jsonStr.FindStringSubmatch(string(result))
if len(ss) <= 0 {
return nil, errcode.New(404, "找不到基金:"+code)
}
ff := &fund{}
err = json.Unmarshal([]byte(ss[0]), ff)
return ff, err
}
const msgTemplate = `%s
更新时间:%s
单位净值:%s 估算净值:%s
估算涨幅:(%s) %s%%
`
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{}{
"touser": openid,
"template_id": "SQXWp3RiYySb2GYG-vMYDsSIm-KZNM9szVpFOryUQGQ",
"data": map[string]interface{}{
"keyword": map[string]interface{}{
"value": msg,
"color": "#173177",
},
},
}
return arg
}