livenote: support pin and expiry time

This commit is contained in:
c9s 2024-11-11 16:52:09 +08:00
parent c289c2daf5
commit 0b2fdd471e
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
4 changed files with 89 additions and 2 deletions

View File

@ -1,6 +1,9 @@
package livenote package livenote
import "sync" import (
"sync"
"time"
)
type Object interface { type Object interface {
ObjectID() string ObjectID() string
@ -13,9 +16,15 @@ type LiveNote struct {
ChannelID string `json:"channelId"` ChannelID string `json:"channelId"`
Pin bool `json:"pin"`
TimeToLive time.Duration `json:"timeToLive"`
Object Object Object Object
cachedObjID string cachedObjID string
postedTime time.Time
} }
func NewLiveNote(object Object) *LiveNote { func NewLiveNote(object Object) *LiveNote {
@ -33,6 +42,14 @@ func (n *LiveNote) ObjectID() string {
return n.cachedObjID return n.cachedObjID
} }
func (n *LiveNote) SetTimeToLive(du time.Duration) {
n.TimeToLive = du
}
func (n *LiveNote) SetPostedTime(tt time.Time) {
n.postedTime = tt
}
func (n *LiveNote) SetObject(object Object) { func (n *LiveNote) SetObject(object Object) {
n.Object = object n.Object = object
} }
@ -45,6 +62,19 @@ func (n *LiveNote) SetChannelID(channelID string) {
n.ChannelID = channelID n.ChannelID = channelID
} }
func (n *LiveNote) SetPin(enabled bool) {
n.Pin = enabled
}
func (n *LiveNote) IsExpired(now time.Time) bool {
if n.postedTime.IsZero() || n.TimeToLive == 0 {
return false
}
expiryTime := n.postedTime.Add(n.TimeToLive)
return now.After(expiryTime)
}
type Pool struct { type Pool struct {
notes map[string]*LiveNote notes map[string]*LiveNote
mu sync.Mutex mu sync.Mutex
@ -64,6 +94,10 @@ func (p *Pool) Get(obj Object) *LiveNote {
for _, note := range p.notes { for _, note := range p.notes {
if note.ObjectID() == objID { if note.ObjectID() == objID {
if note.IsExpired(time.Now()) {
return nil
}
return note return note
} }
} }
@ -79,6 +113,10 @@ func (p *Pool) Update(obj Object) *LiveNote {
for _, note := range p.notes { for _, note := range p.notes {
if note.ObjectID() == objID { if note.ObjectID() == objID {
if note.IsExpired(time.Now()) {
break
}
// update the object inside the note // update the object inside the note
note.SetObject(obj) note.SetObject(obj)
return note return note

View File

@ -1,5 +1,7 @@
package livenote package livenote
import "time"
type Option interface{} type Option interface{}
type OptionCompare struct { type OptionCompare struct {
@ -29,3 +31,21 @@ func Comment(text string, users ...string) *OptionComment {
Users: users, Users: users,
} }
} }
type OptionTimeToLive struct {
Duration time.Duration
}
func TimeToLive(du time.Duration) *OptionTimeToLive {
return &OptionTimeToLive{Duration: du}
}
type OptionPin struct {
Value bool
}
func Pin(value bool) *OptionPin {
return &OptionPin{
Value: value,
}
}

View File

@ -52,6 +52,8 @@ func (t *notifyTask) addMsgOption(opts ...slack.MsgOption) {
// To use this notifier, you need to setup the slack app permissions: // To use this notifier, you need to setup the slack app permissions:
// - channels:read // - channels:read
// - chat:write // - chat:write
//
// When using "pins", you will need permission: "pins:write"
type Notifier struct { type Notifier struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
@ -236,6 +238,9 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
var commentHandles []string var commentHandles []string
var comments []string var comments []string
var shouldCompare bool var shouldCompare bool
var shouldPin bool
var ttl time.Duration = 0
for _, opt := range opts { for _, opt := range opts {
switch val := opt.(type) { switch val := opt.(type) {
case *livenote.OptionOneTimeMention: case *livenote.OptionOneTimeMention:
@ -245,6 +250,10 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
commentHandles = append(commentHandles, val.Users...) commentHandles = append(commentHandles, val.Users...)
case *livenote.OptionCompare: case *livenote.OptionCompare:
shouldCompare = val.Value shouldCompare = val.Value
case *livenote.OptionPin:
shouldPin = val.Value
case *livenote.OptionTimeToLive:
ttl = val.Duration
} }
} }
@ -260,6 +269,10 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
note := n.liveNotePool.Update(obj) note := n.liveNotePool.Update(obj)
curObj = note.Object curObj = note.Object
if ttl > 0 {
note.SetTimeToLive(ttl)
}
if shouldCompare && prevObj != nil { if shouldCompare && prevObj != nil {
diffs, err := dynamic.Compare(curObj, prevObj) diffs, err := dynamic.Compare(curObj, prevObj)
if err != nil { if err != nil {
@ -331,6 +344,18 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
note.SetChannelID(respCh) note.SetChannelID(respCh)
note.SetMessageID(respTs) note.SetMessageID(respTs)
note.SetPostedTime(time.Now())
if shouldPin {
note.SetPin(true)
if err := n.client.AddPinContext(ctx, respCh, slack.ItemRef{
Channel: respCh,
Timestamp: respTs,
}); err != nil {
log.WithError(err).Warnf("unable to pin the slack message: %s", respTs)
}
}
if len(firstTimeTags) > 0 { if len(firstTimeTags) > 0 {
n.queueTask(n.ctx, notifyTask{ n.queueTask(n.ctx, notifyTask{

View File

@ -2,6 +2,7 @@ package livenote
import ( import (
"context" "context"
"time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -66,7 +67,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
bbgo.PostLiveNote(&k, bbgo.PostLiveNote(&k,
livenote.OneTimeMention(s.UserID), livenote.OneTimeMention(s.UserID),
livenote.Comment("please check the deposit"), livenote.Comment("please check the deposit"),
livenote.CompareObject(true)) livenote.CompareObject(true),
livenote.TimeToLive(time.Minute),
// livenote.Pin(true),
)
} }
// register our kline event handler // register our kline event handler