189 lines
4.4 KiB
Go
189 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"git.gammaspectra.live/P2Pool/consensus/v3/monero/address"
|
|
bolt "go.etcd.io/bbolt"
|
|
"log"
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Subscription struct {
|
|
Address *address.Address `json:"address"`
|
|
Nick string `json:"nick"`
|
|
}
|
|
|
|
type DB struct {
|
|
db *bolt.DB
|
|
}
|
|
|
|
var refByNick = []byte("refByNick")
|
|
var refByAddr = []byte("refByAddr")
|
|
|
|
func NewDB(path string) (*DB, error) {
|
|
if db, err := bolt.Open(path, 0666, &bolt.Options{Timeout: time.Second * 5}); err != nil {
|
|
return nil, err
|
|
} else {
|
|
if err = db.Update(func(tx *bolt.Tx) error {
|
|
if _, err := tx.CreateBucketIfNotExists(refByNick); err != nil {
|
|
return err
|
|
} else if _, err := tx.CreateBucketIfNotExists(refByAddr); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
return &DB{
|
|
db: db,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (db *DB) GetByNick(nick string) (result []*Subscription) {
|
|
_ = db.db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket(refByNick)
|
|
if buf := b.Get([]byte(strings.ToLower(nick))); buf != nil {
|
|
var addrs []*address.Address
|
|
if err := json.Unmarshal(buf, &addrs); err != nil {
|
|
return err
|
|
}
|
|
for _, a := range addrs {
|
|
result = append(result, &Subscription{
|
|
Address: a,
|
|
Nick: nick,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
return result
|
|
}
|
|
|
|
func (db *DB) GetByAddress(a *address.Address) (result []*Subscription) {
|
|
_ = db.db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket(refByAddr)
|
|
if buf := b.Get([]byte(a.ToBase58())); buf != nil {
|
|
var nicks []string
|
|
if err := json.Unmarshal(buf, &nicks); err != nil {
|
|
return err
|
|
}
|
|
for _, nick := range nicks {
|
|
result = append(result, &Subscription{
|
|
Address: a,
|
|
Nick: nick,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
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 {
|
|
|
|
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 !slices.Contains(nicks, strings.ToLower(sub.Nick)) {
|
|
nicks = append(nicks, strings.ToLower(sub.Nick))
|
|
}
|
|
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 !slices.ContainsFunc(addresses, func(a *address.Address) bool {
|
|
return a.Compare(sub.Address) == 0
|
|
}) {
|
|
addresses = append(addresses, sub.Address)
|
|
}
|
|
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
|
|
}
|