2018-05-31 21:24:59 +00:00
|
|
|
package boltdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"strconv"
|
|
|
|
|
2020-04-22 23:06:36 +00:00
|
|
|
bolt "go.etcd.io/bbolt"
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
"github.com/khlieng/dispatch/pkg/session"
|
|
|
|
"github.com/khlieng/dispatch/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
bucketUsers = []byte("Users")
|
2020-06-15 08:58:51 +00:00
|
|
|
bucketNetworks = []byte("Networks")
|
2018-05-31 21:24:59 +00:00
|
|
|
bucketChannels = []byte("Channels")
|
2020-05-06 02:19:55 +00:00
|
|
|
bucketOpenDMs = []byte("OpenDMs")
|
2018-05-31 21:24:59 +00:00
|
|
|
bucketMessages = []byte("Messages")
|
|
|
|
bucketSessions = []byte("Sessions")
|
|
|
|
)
|
|
|
|
|
|
|
|
// BoltStore implements storage.Store, storage.MessageStore and storage.SessionStore
|
|
|
|
type BoltStore struct {
|
|
|
|
db *bolt.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(path string) (*BoltStore, error) {
|
|
|
|
db, err := bolt.Open(path, 0600, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
db.Update(func(tx *bolt.Tx) error {
|
|
|
|
tx.CreateBucketIfNotExists(bucketUsers)
|
2020-06-15 08:58:51 +00:00
|
|
|
tx.CreateBucketIfNotExists(bucketNetworks)
|
2018-05-31 21:24:59 +00:00
|
|
|
tx.CreateBucketIfNotExists(bucketChannels)
|
2020-05-06 02:19:55 +00:00
|
|
|
tx.CreateBucketIfNotExists(bucketOpenDMs)
|
2018-05-31 21:24:59 +00:00
|
|
|
tx.CreateBucketIfNotExists(bucketMessages)
|
|
|
|
tx.CreateBucketIfNotExists(bucketSessions)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return &BoltStore{
|
|
|
|
db,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) Close() {
|
|
|
|
s.db.Close()
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Users() ([]*storage.User, error) {
|
2018-06-01 02:16:38 +00:00
|
|
|
var users []*storage.User
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketUsers)
|
|
|
|
|
2018-08-10 18:24:29 +00:00
|
|
|
return b.ForEach(func(k, v []byte) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
user := storage.User{
|
2018-08-10 18:24:29 +00:00
|
|
|
IDBytes: make([]byte, 8),
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
2018-08-10 18:24:29 +00:00
|
|
|
user.Unmarshal(v)
|
2018-05-31 21:24:59 +00:00
|
|
|
copy(user.IDBytes, k)
|
|
|
|
|
2018-06-01 02:16:38 +00:00
|
|
|
users = append(users, &user)
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return users, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) SaveUser(user *storage.User) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketUsers)
|
|
|
|
|
2018-08-10 18:24:29 +00:00
|
|
|
if user.ID == 0 {
|
|
|
|
user.ID, _ = b.NextSequence()
|
|
|
|
user.IDBytes = idToBytes(user.ID)
|
|
|
|
}
|
2018-05-31 21:24:59 +00:00
|
|
|
user.Username = strconv.FormatUint(user.ID, 10)
|
|
|
|
|
|
|
|
data, err := user.Marshal(nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b.Put(user.IDBytes, data)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) DeleteUser(user *storage.User) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-05-19 22:23:16 +00:00
|
|
|
err := tx.Bucket(bucketUsers).Delete(user.IDBytes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
|
|
|
|
2020-05-19 22:23:16 +00:00
|
|
|
return deletePrefix(user.IDBytes,
|
2020-06-15 08:58:51 +00:00
|
|
|
tx.Bucket(bucketNetworks),
|
2020-05-19 22:23:16 +00:00
|
|
|
tx.Bucket(bucketChannels),
|
|
|
|
tx.Bucket(bucketOpenDMs),
|
|
|
|
)
|
2018-05-31 21:24:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Network(user *storage.User, address string) (*storage.Network, error) {
|
|
|
|
var network *storage.Network
|
2019-01-27 07:53:07 +00:00
|
|
|
|
|
|
|
err := s.db.View(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketNetworks)
|
|
|
|
id := networkID(user, address)
|
2019-01-27 07:53:07 +00:00
|
|
|
|
|
|
|
v := b.Get(id)
|
|
|
|
if v == nil {
|
|
|
|
return storage.ErrNotFound
|
|
|
|
} else {
|
2020-06-15 08:58:51 +00:00
|
|
|
network = &storage.Network{}
|
|
|
|
network.Unmarshal(v)
|
2019-01-27 07:53:07 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return network, err
|
2019-01-27 07:53:07 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Networks(user *storage.User) ([]*storage.Network, error) {
|
|
|
|
var networks []*storage.Network
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
c := tx.Bucket(bucketNetworks).Cursor()
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
for k, v := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, v = c.Next() {
|
2020-06-15 08:58:51 +00:00
|
|
|
network := storage.Network{}
|
|
|
|
network.Unmarshal(v)
|
|
|
|
networks = append(networks, &network)
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return networks, nil
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) SaveNetwork(user *storage.User, network *storage.Network) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketNetworks)
|
|
|
|
data, _ := network.Marshal(nil)
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return b.Put(networkID(user, network.Host), data)
|
2018-05-31 21:24:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) RemoveNetwork(user *storage.User, address string) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
networkID := networkID(user, address)
|
|
|
|
err := tx.Bucket(bucketNetworks).Delete(networkID)
|
2020-05-19 22:23:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-05-06 02:19:55 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return deletePrefix(networkID,
|
2020-05-19 22:23:16 +00:00
|
|
|
tx.Bucket(bucketChannels),
|
|
|
|
tx.Bucket(bucketOpenDMs),
|
|
|
|
)
|
2018-05-31 21:24:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) SetNick(user *storage.User, nick, address string) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketNetworks)
|
|
|
|
id := networkID(user, address)
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
network := storage.Network{}
|
2018-05-31 21:24:59 +00:00
|
|
|
v := b.Get(id)
|
|
|
|
if v != nil {
|
2020-06-15 08:58:51 +00:00
|
|
|
network.Unmarshal(v)
|
|
|
|
network.Nick = nick
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
data, _ := network.Marshal(nil)
|
2018-05-31 21:24:59 +00:00
|
|
|
return b.Put(id, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) SetNetworkName(user *storage.User, name, address string) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketNetworks)
|
|
|
|
id := networkID(user, address)
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
network := storage.Network{}
|
2018-05-31 21:24:59 +00:00
|
|
|
v := b.Get(id)
|
|
|
|
if v != nil {
|
2020-06-15 08:58:51 +00:00
|
|
|
network.Unmarshal(v)
|
|
|
|
network.Name = name
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
data, _ := network.Marshal(nil)
|
2018-05-31 21:24:59 +00:00
|
|
|
return b.Put(id, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Channels(user *storage.User) ([]*storage.Channel, error) {
|
2018-06-01 02:16:38 +00:00
|
|
|
var channels []*storage.Channel
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
|
|
|
c := tx.Bucket(bucketChannels).Cursor()
|
|
|
|
|
|
|
|
for k, v := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, v = c.Next() {
|
|
|
|
channel := storage.Channel{}
|
|
|
|
channel.Unmarshal(v)
|
2018-06-01 02:16:38 +00:00
|
|
|
channels = append(channels, &channel)
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return channels, nil
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) SaveChannel(user *storage.User, channel *storage.Channel) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketChannels)
|
|
|
|
data, _ := channel.Marshal(nil)
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return b.Put(channelID(user, channel.Network, channel.Name), data)
|
2018-05-31 21:24:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) RemoveChannel(user *storage.User, network, channel string) error {
|
2018-05-31 21:24:59 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketChannels)
|
2020-06-15 08:58:51 +00:00
|
|
|
id := channelID(user, network, channel)
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
return b.Delete(id)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) HasChannel(user *storage.User, network, channel string) bool {
|
|
|
|
has := false
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketChannels)
|
|
|
|
has = b.Get(channelID(user, network, channel)) != nil
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return has
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) OpenDMs(user *storage.User) ([]storage.Tab, error) {
|
2020-05-06 02:19:55 +00:00
|
|
|
var openDMs []storage.Tab
|
|
|
|
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
|
|
|
c := tx.Bucket(bucketOpenDMs).Cursor()
|
|
|
|
|
|
|
|
for k, _ := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, _ = c.Next() {
|
|
|
|
tab := bytes.Split(k[8:], []byte{0})
|
|
|
|
openDMs = append(openDMs, storage.Tab{
|
2020-06-15 08:58:51 +00:00
|
|
|
Network: string(tab[0]),
|
|
|
|
Name: string(tab[1]),
|
2020-05-06 02:19:55 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return openDMs, nil
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) AddOpenDM(user *storage.User, network, nick string) error {
|
2020-05-06 02:19:55 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketOpenDMs)
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return b.Put(channelID(user, network, nick), nil)
|
2020-05-06 02:19:55 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) RemoveOpenDM(user *storage.User, network, nick string) error {
|
2020-05-06 02:19:55 +00:00
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketOpenDMs)
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
return b.Delete(channelID(user, network, nick))
|
2020-05-06 02:19:55 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-03 01:04:38 +00:00
|
|
|
func (s *BoltStore) logMessage(tx *bolt.Tx, message *storage.Message) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b, err := tx.Bucket(bucketMessages).CreateBucketIfNotExists([]byte(message.Network + ":" + message.To))
|
2020-06-03 01:04:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := message.Marshal(nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b.Put([]byte(message.ID), data)
|
|
|
|
}
|
|
|
|
|
2018-05-31 21:24:59 +00:00
|
|
|
func (s *BoltStore) LogMessage(message *storage.Message) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
2020-06-03 01:04:38 +00:00
|
|
|
return s.logMessage(tx, message)
|
|
|
|
})
|
|
|
|
}
|
2018-05-31 21:24:59 +00:00
|
|
|
|
2020-06-03 01:04:38 +00:00
|
|
|
func (s *BoltStore) LogMessages(messages []*storage.Message) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
for _, message := range messages {
|
|
|
|
err := s.logMessage(tx, message)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-05-31 21:24:59 +00:00
|
|
|
}
|
|
|
|
|
2020-06-03 01:04:38 +00:00
|
|
|
return nil
|
2018-05-31 21:24:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Messages(network, channel string, count int, fromID string) ([]storage.Message, bool, error) {
|
2018-05-31 21:24:59 +00:00
|
|
|
messages := make([]storage.Message, count)
|
|
|
|
hasMore := false
|
|
|
|
|
|
|
|
s.db.View(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketMessages).Bucket([]byte(network + ":" + channel))
|
2018-05-31 21:24:59 +00:00
|
|
|
if b == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
c := b.Cursor()
|
|
|
|
|
|
|
|
if fromID != "" {
|
|
|
|
c.Seek([]byte(fromID))
|
|
|
|
|
|
|
|
for k, v := c.Prev(); count > 0 && k != nil; k, v = c.Prev() {
|
|
|
|
count--
|
|
|
|
messages[count].Unmarshal(v)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for k, v := c.Last(); count > 0 && k != nil; k, v = c.Prev() {
|
|
|
|
count--
|
|
|
|
messages[count].Unmarshal(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Next()
|
|
|
|
k, _ := c.Prev()
|
|
|
|
hasMore = k != nil
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if count == 0 {
|
|
|
|
return messages, hasMore, nil
|
|
|
|
} else if count < len(messages) {
|
|
|
|
return messages[count:], hasMore, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, false, nil
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) MessagesByID(network, channel string, ids []string) ([]storage.Message, error) {
|
2018-05-31 21:24:59 +00:00
|
|
|
messages := make([]storage.Message, len(ids))
|
|
|
|
|
|
|
|
err := s.db.View(func(tx *bolt.Tx) error {
|
2020-06-15 08:58:51 +00:00
|
|
|
b := tx.Bucket(bucketMessages).Bucket([]byte(network + ":" + channel))
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
for i, id := range ids {
|
|
|
|
messages[i].Unmarshal(b.Get([]byte(id)))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return messages, err
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func (s *BoltStore) Sessions() ([]*session.Session, error) {
|
2018-06-01 02:16:38 +00:00
|
|
|
var sessions []*session.Session
|
2018-05-31 21:24:59 +00:00
|
|
|
|
|
|
|
err := s.db.View(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketSessions)
|
|
|
|
|
|
|
|
return b.ForEach(func(_ []byte, v []byte) error {
|
|
|
|
session := session.Session{}
|
|
|
|
_, err := session.Unmarshal(v)
|
2018-06-01 02:16:38 +00:00
|
|
|
sessions = append(sessions, &session)
|
2018-05-31 21:24:59 +00:00
|
|
|
return err
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return sessions, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) SaveSession(session *session.Session) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
b := tx.Bucket(bucketSessions)
|
|
|
|
|
|
|
|
data, err := session.Marshal(nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b.Put([]byte(session.Key()), data)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *BoltStore) DeleteSession(key string) error {
|
|
|
|
return s.db.Batch(func(tx *bolt.Tx) error {
|
|
|
|
return tx.Bucket(bucketSessions).Delete([]byte(key))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-19 22:23:16 +00:00
|
|
|
func deletePrefix(prefix []byte, buckets ...*bolt.Bucket) error {
|
|
|
|
for _, b := range buckets {
|
|
|
|
c := b.Cursor()
|
|
|
|
|
|
|
|
for k, _ := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, _ = c.Next() {
|
|
|
|
err := b.Delete(k)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func networkID(user *storage.User, address string) []byte {
|
2018-05-31 21:24:59 +00:00
|
|
|
id := make([]byte, 8+len(address))
|
|
|
|
copy(id, user.IDBytes)
|
|
|
|
copy(id[8:], address)
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
2020-06-15 08:58:51 +00:00
|
|
|
func channelID(user *storage.User, network, channel string) []byte {
|
|
|
|
id := make([]byte, 8+len(network)+1+len(channel))
|
2018-05-31 21:24:59 +00:00
|
|
|
copy(id, user.IDBytes)
|
2020-06-15 08:58:51 +00:00
|
|
|
copy(id[8:], network)
|
|
|
|
copy(id[8+len(network)+1:], channel)
|
2018-05-31 21:24:59 +00:00
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
|
|
|
func idToBytes(i uint64) []byte {
|
|
|
|
b := make([]byte, 8)
|
|
|
|
binary.BigEndian.PutUint64(b, i)
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func idFromBytes(b []byte) uint64 {
|
|
|
|
return binary.BigEndian.Uint64(b)
|
|
|
|
}
|