Zippytal-Node/zoneChatsDBHandler.go
2022-08-28 22:17:30 +02:00

376 lines
8.9 KiB
Go

package localserver
import (
"encoding/binary"
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/dgraph-io/badger/v3"
)
type ChatFile struct {
ChatId string `json:"chatId"`
Owner string `json:"owner"`
Name string `json:"name"`
Size int `json:"size"`
UploadTime string `json:"uploadTime"`
}
type ChatMessage struct {
ID uint64 `json:"id"`
From string `json:"from"`
IsResponse bool `json:"isResponse"`
ResponseOf *ChatMessage `json:"responseOf"`
Tags []string `json:"tags"`
Content string `json:"content"`
Date string `json:"date"`
File *ChatFile `json:"file"`
}
type ZoneChatDBHandler struct {
ChatID string
ZoneID string
PreviousId uint64
ItemCount uint64
db func(func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
const bufferSize = 8
func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *ZoneChatDBHandler, err error) {
zoneChatDBHandler = &ZoneChatDBHandler{
db: func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "chats", chatID)).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
},
ChatID: chatID,
ZoneID: zoneId,
lock: new(sync.RWMutex),
}
err = zoneChatDBHandler.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt)
defer it.Close()
var counter uint64 = 1
var itemCounter uint64 = 0
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
counter = chatMessage.ID
itemCounter++
return
}); err != nil {
return err
}
}
zoneChatDBHandler.PreviousId = counter
zoneChatDBHandler.ItemCount = itemCounter
return nil
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) calculateNewChatCount(previousId uint64) ( count uint,err error) {
err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt)
defer it.Close()
count = 0
b := make([]byte,bufferSize)
binary.BigEndian.PutUint64(b,previousId)
for it.Seek(b); it.Valid(); it.Next() {
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
count++
return
}); err != nil {
return err
}
}
if count > 0 {
count--
}
return nil
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) revertPreviousId() (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
defer it.Close()
it.Rewind()
if it.Valid() {
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
zcdbh.PreviousId = chatMessage.ID
return
}); err != nil {
return err
}
} else {
zcdbh.PreviousId = 1
}
return nil
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) updateDbCallbackFolder(newChatId string) {
zcdbh.db = func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zcdbh.ZoneID, "chats", newChatId)).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
}
}
func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
b := make([]byte, bufferSize)
zcdbh.PreviousId++
binary.BigEndian.PutUint64(b, zcdbh.PreviousId)
chatMessage.ID = zcdbh.PreviousId
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) (err error) {
if updateErr := txn.Set(b, bs); updateErr != nil {
return updateErr
}
return nil
})
return
}); err != nil {
return
}
return
}
func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) {
if err = zcdbh.db(func(d *badger.DB) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
err = d.Update(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key)
if err = txn.Delete(b); err != nil {
return
}
zcdbh.ItemCount--
return
})
return
}); err != nil {
return
}
return
}
func (zcdbh *ZoneChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
if err = zcdbh.DeleteChatMessage(key); err != nil {
return
}
err = os.Remove(filepath.Join("data", "zones", zcdbh.ZoneID, "chats", zcdbh.ChatID, "__files__", filename))
return
}
func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, done bool, err error) {
zcdbh.lock.RLock()
defer zcdbh.lock.RUnlock()
err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
b := make([]byte, bufferSize)
if lastIndex <= 0 {
binary.BigEndian.PutUint64(b, uint64(zcdbh.PreviousId))
} else {
binary.BigEndian.PutUint64(b, uint64(lastIndex))
}
x := 0
defer it.Close()
defer func() {
if x < limit {
done = true
}
}()
chatMessages = make([]*ChatMessage, 0)
for it.Seek(b); it.Valid(); it.Next() {
if x >= limit {
break
}
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
l = int(chatMessage.ID)
chatMessages = append(chatMessages, chatMessage)
return
}); err != nil {
return err
}
x++
}
return
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMessages []*ChatFile, l int, err error) {
zcdbh.lock.RLock()
defer zcdbh.lock.RUnlock()
err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions
opt.Reverse = true
it := txn.NewIterator(opt)
b := make([]byte, bufferSize)
var li int
if lastIndex <= 0 {
binary.BigEndian.PutUint64(b, uint64(zcdbh.PreviousId))
li = int(zcdbh.PreviousId)
} else {
binary.BigEndian.PutUint64(b, uint64(lastIndex))
li = lastIndex
}
x := 0
y := 0
defer func() {
if li > x {
l = li - x
} else if li == 0 {
if zcdbh.PreviousId > uint64(x) {
l = int(zcdbh.PreviousId) - x
} else {
l = 0
}
} else {
l = 0
}
}()
defer it.Close()
chatMessages = make([]*ChatFile, 0)
for it.Seek(b); it.Valid(); it.Next() {
if y >= limit || x >= int(zcdbh.PreviousId) {
break
}
item := it.Item()
if err = item.Value(func(val []byte) (err error) {
var chatMessage *ChatMessage
if err = json.Unmarshal(val, &chatMessage); err != nil {
return err
}
if chatMessage.File != nil {
chatMessages = append(chatMessages, chatMessage.File)
l = lastIndex - x
y++
}
return
}); err != nil {
return err
}
x++
}
return
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) {
zcdbh.lock.RLock()
defer zcdbh.lock.RUnlock()
err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, uint64(index))
item, err := txn.Get(b)
if err != nil {
return
}
err = item.Value(func(val []byte) error {
return json.Unmarshal(val, &chatMessage)
})
return
})
return
})
return
}
func (zcdbh *ZoneChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key)
chatMessage, err := zcdbh.GetChatMessage(key)
if err != nil {
return
}
chatMessage.Content = newContent
bs, err := json.Marshal(chatMessage)
if err != nil {
return
}
if err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) (err error) {
if updateErr := txn.Set(b, bs); updateErr != nil {
return updateErr
}
return nil
})
return
}); err != nil {
return
}
return
}