Added unsubscribe, help context

This commit is contained in:
DataHoarder 2023-04-26 06:54:50 +02:00
parent 17ff7124df
commit 9512fcb206
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
2 changed files with 160 additions and 43 deletions

View file

@ -13,8 +13,10 @@ import (
)
type command struct {
Match *regexp.Regexp
Handle func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool
Help string
Description string
Match *regexp.Regexp
Handle func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool
}
var guestUserRegex = regexp.MustCompile("^Guest[0-9]+_*$")
@ -26,9 +28,20 @@ func isNickAllowed(nick string) error {
return nil
}
func filterEntriesForChannel(bot *hbot.Bot, message *hbot.Message, entries []*channelEntry) (result []*channelEntry) {
for _, e := range entries {
if e.ApiEndpoint != "" && (message.To == bot.Nick || e.Channel == message.To) {
result = append(result, e)
}
}
return result
}
var commands = []command{
{
Match: regexp.MustCompile("^\\.(status|shares)[ \\t]*"),
Help: ".status",
Description: "Displays your pool and share status across all subscriptions to your nick",
Match: regexp.MustCompile("(?i)^\\.(status|shares)[ \t]*"),
Handle: func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool {
subs := db.GetByNick(message.Name)
if len(subs) == 0 {
@ -51,52 +64,50 @@ var commands = []command{
var hasResults bool
var results []*result
for i := range entries {
e := entries[i]
if e.ApiEndpoint != "" && (message.To == bot.Nick || e.Channel == message.To) {
func() {
e.ChainLock.RLock()
defer e.ChainLock.RUnlock()
var tr []*result
for _, sub := range subs {
var r result
r.Tip = e.Tip
r.Endpoint = e.ApiEndpoint
r.Address = sub.Address
r.Consensus = e.Consensus
for _, e := range filterEntriesForChannel(bot, message, entries) {
func(e *channelEntry) {
e.ChainLock.RLock()
defer e.ChainLock.RUnlock()
r.SharesPosition = NewPositionChart(30, uint64(e.Tip.WindowDepth))
r.UnclesPosition = NewPositionChart(30, uint64(e.Tip.WindowDepth))
tr = append(tr, &r)
}
var tr []*result
for _, sub := range subs {
var r result
r.Tip = e.Tip
r.Endpoint = e.ApiEndpoint
r.Address = sub.Address
r.Consensus = e.Consensus
e.IterateWindow(func(b *index.SideBlock, weight types.Difficulty) {
for _, r := range tr {
r.TotalWeight = r.TotalWeight.Add(weight)
if b.MinerAddress.Compare(r.Address) == 0 {
r.MinerId = b.Miner
r.YourWeight = r.YourWeight.Add(weight)
if b.IsUncle() {
r.UnclesPosition.Add(int(e.Tip.SideHeight-b.SideHeight), 1)
r.UncleCount++
} else {
r.SharesPosition.Add(int(e.Tip.SideHeight-b.SideHeight), 1)
r.ShareCount++
}
r.SharesPosition = NewPositionChart(30, uint64(e.Tip.WindowDepth))
r.UnclesPosition = NewPositionChart(30, uint64(e.Tip.WindowDepth))
tr = append(tr, &r)
}
e.IterateWindow(func(b *index.SideBlock, weight types.Difficulty) {
for _, r := range tr {
r.TotalWeight = r.TotalWeight.Add(weight)
if b.MinerAddress.Compare(r.Address) == 0 {
r.MinerId = b.Miner
r.YourWeight = r.YourWeight.Add(weight)
if b.IsUncle() {
r.UnclesPosition.Add(int(e.Tip.SideHeight-b.SideHeight), 1)
r.UncleCount++
} else {
r.SharesPosition.Add(int(e.Tip.SideHeight-b.SideHeight), 1)
r.ShareCount++
}
}
})
for _, r := range tr {
if r.ShareCount > 0 || r.UncleCount > 0 {
results = append(results, r)
hasResults = true
}
}
})
}()
}
for _, r := range tr {
if r.ShareCount > 0 || r.UncleCount > 0 {
results = append(results, r)
hasResults = true
}
}
}(e)
}
if !hasResults {
@ -123,7 +134,9 @@ var commands = []command{
},
{
Match: regexp.MustCompile("^\\.(sub|subscribe)[ \\t]+(4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)[ \\t]*"),
Help: ".subscribe MONERO_ADDRESS",
Description: "Subscribes your nick, while online, to shares and payouts specified by MONERO_ADDRESS. You can have multiple subscriptions.",
Match: regexp.MustCompile("(?i)^\\.(sub|subscribe)[ \t]+(4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)[ \t]*"),
Handle: func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool {
if err := isNickAllowed(message.Name); err != nil {
bot.Msg(replyTo, fmt.Sprintf("Cannot subscribe: %s", err))
@ -142,6 +155,9 @@ var commands = []command{
}); err == nil {
bot.Msg(replyTo, fmt.Sprintf("Subscribed your nick to shares found by %s%s%s while you are online. You can private message this bot for any commands instead of using public channels.", FormatItalic, utils.Shorten(addr.ToBase58(), 10), FormatReset))
for _, e := range entries {
if e.ApiEndpoint == "" {
continue
}
func() {
e.ChainLock.RLock()
defer e.ChainLock.RUnlock()
@ -169,4 +185,46 @@ var commands = []command{
}
},
},
{
Help: ".unsubscribe MONERO_ADDRESS",
Description: "Unsubscribes your nick from shares and payouts specified by MONERO_ADDRESS.",
Match: regexp.MustCompile("(?i)^\\.(unsub|unsubscribe)[ \t]+(4[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)[ \t]*"),
Handle: func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool {
addr := address.FromBase58(matches[2])
if addr == nil {
bot.Msg(replyTo, "Cannot unsubscribe: Invalid Monero address")
return true
}
sub := &Subscription{
Address: addr,
Nick: message.Name,
}
if err := db.Unsubscribe(sub); err != nil {
bot.Msg(replyTo, fmt.Sprintf("Cannot unsubscribe: %s", err))
return true
} else {
bot.Msg(replyTo, fmt.Sprintf("Unsubscribed your nick from shares found by %s%s%s", FormatItalic, utils.Shorten(addr.ToBase58(), 10), FormatReset))
return true
}
},
},
{
Help: ".unsubscribe",
Description: "Unsubscribes from all subscriptions tied to your nick",
//fallback unsubscribe for everything
Match: regexp.MustCompile("(?i)^[.!]?(unsub|unsubscribe)[ \t]*"),
Handle: func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool {
removed := 0
for _, sub := range db.GetByNick(message.Name) {
db.Unsubscribe(sub)
removed++
}
bot.Msg(replyTo, fmt.Sprintf("Unsubscribed your nick from %d subscriptions.", removed))
return true
},
},
}

59
db.go
View file

@ -82,6 +82,65 @@ func (db *DB) GetByAddress(a *address.Address) (result []*Subscription) {
return result
}
func (db *DB) Unsubscribe(sub *Subscription) error {
if err := db.db.Update(func(tx *bolt.Tx) error {
b1 := tx.Bucket(refByAddr)
var nicks []string
if k := b1.Get([]byte(sub.Address.ToBase58())); k != nil {
if err := json.Unmarshal(k, &nicks); err != nil {
return err
}
}
if i := slices.Index(nicks, strings.ToLower(sub.Nick)); i != -1 {
nicks = slices.Delete(nicks, i, i+1)
if len(nicks) == 0 {
if err := b1.Delete([]byte(sub.Address.ToBase58())); err != nil {
return err
}
} else {
if buf, err := json.Marshal(nicks); err != nil {
return err
} else if err = b1.Put([]byte(sub.Address.ToBase58()), buf); err != nil {
return err
}
}
}
b2 := tx.Bucket(refByNick)
var addresses []*address.Address
if k := b2.Get([]byte(strings.ToLower(sub.Nick))); k != nil {
if err := json.Unmarshal(k, &addresses); err != nil {
return err
}
}
if i := slices.IndexFunc(addresses, func(a *address.Address) bool {
return a.Compare(sub.Address) == 0
}); i != -1 {
addresses = slices.Delete(addresses, i, i+1)
if len(addresses) == 0 {
if err := b2.Delete([]byte(strings.ToLower(sub.Nick))); err != nil {
return err
}
} else {
if buf, err := json.Marshal(addresses); err != nil {
return err
} else if err = b2.Put([]byte(strings.ToLower(sub.Nick)), buf); err != nil {
return err
}
}
}
return nil
}); err != nil {
log.Printf("[DB] bolt error: %s", err)
return err
}
return nil
}
func (db *DB) Store(sub *Subscription) error {
if err := db.db.Update(func(tx *bolt.Tx) error {