add notifications and chat tracking

This commit is contained in:
Loïs BIBEHE 2022-09-10 02:56:52 +02:00
parent a4ee2b4048
commit 5dcb013c12
Signed by: Lois
GPG Key ID: 782967C8C0F78E79
13 changed files with 551 additions and 259 deletions

View File

@ -17,6 +17,7 @@ import (
) )
var NodeToken string var NodeToken string
var NodeID string
type LocalServerConfig struct { type LocalServerConfig struct {
configFilePath string configFilePath string
@ -78,11 +79,11 @@ func (l *LocalServerConfig) startup() (err error) {
l.PrivateKeyPath = "" l.PrivateKeyPath = ""
l.Token = "" l.Token = ""
bss, marshallErr := json.Marshal(map[string]interface{}{ bss, marshallErr := json.Marshal(map[string]interface{}{
"type": "create_node", "type": "create_node",
"from": id, "from": id,
"to": "serv", "to": "serv",
"token": "", "token": "",
"peerType":"node", "peerType": "node",
"payload": map[string]string{ "payload": map[string]string{
"nodeId": id, "nodeId": id,
"nodeKey": string(key), "nodeKey": string(key),
@ -114,6 +115,7 @@ func (l *LocalServerConfig) startup() (err error) {
return return
} }
logger.Println(config) logger.Println(config)
NodeID = l.NodeId
l.NodeId = config["nodeId"] l.NodeId = config["nodeId"]
l.PrivateKeyPath = config["privKeyPath"] l.PrivateKeyPath = config["privKeyPath"]
l.Token = config["token"] l.Token = config["token"]
@ -136,9 +138,9 @@ func (l *LocalServerConfig) authenticate() (err error) {
return return
} }
body, err := json.Marshal(map[string]interface{}{ body, err := json.Marshal(map[string]interface{}{
"type": "login_key_node", "type": "login_key_node",
"from": l.NodeId, "from": l.NodeId,
"peerType":"node", "peerType": "node",
"payload": map[string]string{ "payload": map[string]string{
"id": l.NodeId, "id": l.NodeId,
"signature": sig, "signature": sig,
@ -160,6 +162,7 @@ func (l *LocalServerConfig) authenticate() (err error) {
return return
} }
err = l.handleLoginResponse(payload) err = l.handleLoginResponse(payload)
NodeID = l.NodeId
return return
} }

View File

@ -135,10 +135,10 @@ func loadHostedSquads(token string, hostId string) (squads []*Squad, err error)
em := NewEncryptionManager() em := NewEncryptionManager()
sig := em.SignRequestHMAC(hostId) sig := em.SignRequestHMAC(hostId)
body, err := json.Marshal(map[string]interface{}{ body, err := json.Marshal(map[string]interface{}{
"type": LIST_HOSTED_SQUADS_BY_HOST, "type": LIST_HOSTED_SQUADS_BY_HOST,
"mac": sig, "mac": sig,
"from": hostId, "from": hostId,
"peerType":"node", "peerType": "node",
"payload": map[string]string{ "payload": map[string]string{
"host": hostId, "host": hostId,
"lastIndex": "0", "lastIndex": "0",

View File

@ -284,7 +284,7 @@ func (zach *ZoneAudioChannelsHandler) AddNewAudioChannel(channelName string, own
ID: channelName, ID: channelName,
Owner: owner, Owner: owner,
ChannelType: channelType, ChannelType: channelType,
Members: append(m,owner), Members: append(m, owner),
} }
bs, jsonErr := json.Marshal(baseConfig) bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil { if jsonErr != nil {

View File

@ -10,31 +10,32 @@ import (
) )
type ZoneChatTrackingDB struct { type ZoneChatTrackingDB struct {
db func(cb func(*badger.DB) (err error)) (err error) ZoneID string
lock *sync.RWMutex db func(cb func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
} }
func NewZoneChatTracking(zoneId,chatId string,members ...string) (*ZoneChatTrackingDB,error) { func NewZoneChatTracking(zoneId, chatId string, members ...string) (*ZoneChatTrackingDB, error) {
if _,dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__")); os.IsNotExist(dirErr) { if _, dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "chats", chatId, "__tracking__")); os.IsNotExist(dirErr) {
_ = os.MkdirAll(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__"),0700) _ = os.MkdirAll(filepath.Join("data", "zones", zoneId, "chats", chatId, "__tracking__"), 0700)
} }
db := func(f func(*badger.DB) (err error)) (err error) { db := func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "chats", chatId,"__tracking__")).WithLogger(dbLogger)) db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zoneId, "chats", chatId, "__tracking__")).WithLogger(dbLogger))
if err != nil { if err != nil {
return
}
defer db.Close()
err = f(db)
return return
} }
lock := new(sync.RWMutex) defer db.Close()
err = f(db)
return
}
lock := new(sync.RWMutex)
if err := db(func(d *badger.DB) (err error) { if err := db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error { err = d.Update(func(txn *badger.Txn) error {
b := make([]byte,bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b,0) binary.BigEndian.PutUint64(b, 0)
for _, member := range members { for _, member := range members {
if _,rerr := txn.Get([]byte(member)); rerr == badger.ErrKeyNotFound { if _, rerr := txn.Get([]byte(member)); rerr == badger.ErrKeyNotFound {
txn.Set([]byte(member),b) _ = txn.Set([]byte(member), b)
} else if rerr != nil { } else if rerr != nil {
return rerr return rerr
} }
@ -45,21 +46,34 @@ func NewZoneChatTracking(zoneId,chatId string,members ...string) (*ZoneChatTrack
return return
} }
return return
});err != nil { }); err != nil {
return nil,err return nil, err
} }
return &ZoneChatTrackingDB{db,lock},nil return &ZoneChatTrackingDB{zoneId, db, lock}, nil
} }
func (zctdb *ZoneChatTrackingDB) Initialize(lastIndex uint64,users ...string) (err error) { func (zctdb *ZoneChatTrackingDB) Initialize(lastIndex uint64, users ...string) (err error) {
for _, user := range users { for _, user := range users {
if err = zctdb.SetUserLastIndex(user,lastIndex);err != nil { if err = zctdb.SetUserLastIndex(user, lastIndex); err != nil {
return return
} }
} }
return return
} }
func (zctdb *ZoneChatTrackingDB) updateDBCallbackFolder(newChatId string) {
db := func(f func(*badger.DB) (err error)) (err error) {
db, err := badger.Open(badger.DefaultOptions(filepath.Join("data", "zones", zctdb.ZoneID, "chats", newChatId, "__tracking__")).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
}
zctdb.db = db
}
func (zctdb *ZoneChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err error) { func (zctdb *ZoneChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err error) {
zctdb.lock.Lock() zctdb.lock.Lock()
defer zctdb.lock.Unlock() defer zctdb.lock.Unlock()
@ -69,7 +83,7 @@ func (zctdb *ZoneChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err
opt := badger.DefaultIteratorOptions opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt) it := txn.NewIterator(opt)
defer it.Close() defer it.Close()
for it.Rewind();it.Valid();it.Next() { for it.Rewind(); it.Valid(); it.Next() {
item := it.Item() item := it.Item()
if err = item.Value(func(val []byte) error { if err = item.Value(func(val []byte) error {
li := binary.BigEndian.Uint64(val) li := binary.BigEndian.Uint64(val)
@ -88,9 +102,9 @@ func (zctdb *ZoneChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err
} }
err = d.Update(func(txn *badger.Txn) error { err = d.Update(func(txn *badger.Txn) error {
for _, key := range keys { for _, key := range keys {
b := make([]byte,bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b,lastIndex) binary.BigEndian.PutUint64(b, lastIndex)
if updateErr := txn.Set(key,b); updateErr != nil { if updateErr := txn.Set(key, b); updateErr != nil {
return updateErr return updateErr
} }
} }
@ -101,14 +115,14 @@ func (zctdb *ZoneChatTrackingDB) RevertTrackingLastIndex(lastIndex uint64) (err
return return
} }
func (zctdb *ZoneChatTrackingDB) SetUserLastIndex(userId string,lastIndex uint64) (err error) { func (zctdb *ZoneChatTrackingDB) SetUserLastIndex(userId string, lastIndex uint64) (err error) {
zctdb.lock.Lock() zctdb.lock.Lock()
defer zctdb.lock.Unlock() defer zctdb.lock.Unlock()
err = zctdb.db(func(d *badger.DB) (err error) { err = zctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error { err = d.Update(func(txn *badger.Txn) error {
b := make([]byte,bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b,lastIndex) binary.BigEndian.PutUint64(b, lastIndex)
updateErr := txn.Set([]byte(userId),b) updateErr := txn.Set([]byte(userId), b)
return updateErr return updateErr
}) })
return return
@ -116,16 +130,16 @@ func (zctdb *ZoneChatTrackingDB) SetUserLastIndex(userId string,lastIndex uint64
return return
} }
func (zctdb *ZoneChatTrackingDB) GetUserLastIndex(userId string) (index uint,err error) { func (zctdb *ZoneChatTrackingDB) GetUserLastIndex(userId string) (index uint, err error) {
zctdb.lock.Lock() zctdb.lock.Lock()
defer zctdb.lock.Unlock() defer zctdb.lock.Unlock()
err = zctdb.db(func(d *badger.DB) (err error) { err = zctdb.db(func(d *badger.DB) (err error) {
err = d.Update(func(txn *badger.Txn) error { err = d.Update(func(txn *badger.Txn) error {
item,rerr := txn.Get([]byte(userId)) item, rerr := txn.Get([]byte(userId))
if rerr != nil { if rerr != nil {
return rerr return rerr
} }
item.Value(func(val []byte) error { _ = item.Value(func(val []byte) error {
index = uint(binary.BigEndian.Uint64(val)) index = uint(binary.BigEndian.Uint64(val))
return nil return nil
}) })

View File

@ -35,7 +35,7 @@ type ZoneChatDBHandler struct {
PreviousId uint64 PreviousId uint64
ItemCount uint64 ItemCount uint64
db func(func(*badger.DB) (err error)) (err error) db func(func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex lock *sync.RWMutex
} }
const bufferSize = 8 const bufferSize = 8
@ -53,7 +53,7 @@ func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *Zone
}, },
ChatID: chatID, ChatID: chatID,
ZoneID: zoneId, ZoneID: zoneId,
lock: new(sync.RWMutex), lock: new(sync.RWMutex),
} }
err = zoneChatDBHandler.db(func(d *badger.DB) (err error) { err = zoneChatDBHandler.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error { err = d.View(func(txn *badger.Txn) error {
@ -85,26 +85,23 @@ func NewZoneChatDBHandler(zoneId string, chatID string) (zoneChatDBHandler *Zone
return return
} }
func (zcdbh *ZoneChatDBHandler) calculateNewChatCount(previousId uint64) ( count uint,err error) { func (zcdbh *ZoneChatDBHandler) calculateNewChatCount(previousId uint64) (count uint, err error) {
err = zcdbh.db(func(d *badger.DB) (err error) { err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error { err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions opt := badger.DefaultIteratorOptions
it := txn.NewIterator(opt) it := txn.NewIterator(opt)
defer it.Close() defer it.Close()
count = 0 count = 0
b := make([]byte,bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b,previousId) binary.BigEndian.PutUint64(b, previousId)
for it.Seek(b); it.Valid(); it.Next() { if previousId == 0 || previousId == 1 {
item := it.Item() count++
if err = item.Value(func(val []byte) (err error) { for it.Rewind(); it.Valid(); it.Next() {
var chatMessage *ChatMessage count++
if err = json.Unmarshal(val, &chatMessage); err != nil { }
return err } else {
} for it.Seek(b); it.Valid(); it.Next() {
count++ count++
return
}); err != nil {
return err
} }
} }
if count > 0 { if count > 0 {
@ -118,8 +115,6 @@ func (zcdbh *ZoneChatDBHandler) calculateNewChatCount(previousId uint64) ( count
} }
func (zcdbh *ZoneChatDBHandler) revertPreviousId() (err error) { func (zcdbh *ZoneChatDBHandler) revertPreviousId() (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
err = zcdbh.db(func(d *badger.DB) (err error) { err = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) error { err = d.View(func(txn *badger.Txn) error {
opt := badger.DefaultIteratorOptions opt := badger.DefaultIteratorOptions
@ -162,8 +157,6 @@ func (zcdbh *ZoneChatDBHandler) updateDbCallbackFolder(newChatId string) {
} }
func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) { func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
b := make([]byte, bufferSize) b := make([]byte, bufferSize)
zcdbh.PreviousId++ zcdbh.PreviousId++
binary.BigEndian.PutUint64(b, zcdbh.PreviousId) binary.BigEndian.PutUint64(b, zcdbh.PreviousId)
@ -188,8 +181,6 @@ func (zcdbh *ZoneChatDBHandler) AddNewChatMessage(chatMessage *ChatMessage) (err
func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) { func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) {
if err = zcdbh.db(func(d *badger.DB) (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) { err = d.Update(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key) binary.BigEndian.PutUint64(b, key)
@ -207,8 +198,6 @@ func (zcdbh *ZoneChatDBHandler) DeleteChatMessage(key uint64) (err error) {
} }
func (zcdbh *ZoneChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) { func (zcdbh *ZoneChatDBHandler) DeleteChatFile(filename string, key uint64) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
if err = zcdbh.DeleteChatMessage(key); err != nil { if err = zcdbh.DeleteChatMessage(key); err != nil {
return return
} }
@ -217,8 +206,6 @@ func (zcdbh *ZoneChatDBHandler) DeleteChatFile(filename string, key uint64) (err
} }
func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chatMessages []*ChatMessage, l int, done bool, err error) { 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 = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) { err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions opt := badger.DefaultIteratorOptions
@ -264,8 +251,6 @@ func (zcdbh *ZoneChatDBHandler) ListChatMessages(lastIndex int, limit int) (chat
} }
func (zcdbh *ZoneChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMessages []*ChatFile, l int, err error) { 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 = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) { err = d.View(func(txn *badger.Txn) (err error) {
opt := badger.DefaultIteratorOptions opt := badger.DefaultIteratorOptions
@ -326,8 +311,6 @@ func (zcdbh *ZoneChatDBHandler) ListChatFiles(lastIndex int, limit int) (chatMes
} }
func (zcdbh *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatMessage, err error) { 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 = zcdbh.db(func(d *badger.DB) (err error) {
err = d.View(func(txn *badger.Txn) (err error) { err = d.View(func(txn *badger.Txn) (err error) {
b := make([]byte, bufferSize) b := make([]byte, bufferSize)
@ -347,8 +330,6 @@ func (zcdbh *ZoneChatDBHandler) GetChatMessage(index uint64) (chatMessage *ChatM
} }
func (zcdbh *ZoneChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) { func (zcdbh *ZoneChatDBHandler) ModifyChatMessage(key uint64, newContent string) (err error) {
zcdbh.lock.Lock()
defer zcdbh.lock.Unlock()
b := make([]byte, bufferSize) b := make([]byte, bufferSize)
binary.BigEndian.PutUint64(b, key) binary.BigEndian.PutUint64(b, key)
chatMessage, err := zcdbh.GetChatMessage(key) chatMessage, err := zcdbh.GetChatMessage(key)

View File

@ -16,7 +16,7 @@ import (
const ( const (
LIST_LATEST_CHATS = "list_latest_chats" LIST_LATEST_CHATS = "list_latest_chats"
READ_LATEST_MESSAGE = "read_latest_message" READ_LATEST_MESSAGE = "read_latest_message"
LIST_LATEST_FILES = "list_latest_files" LIST_LATEST_FILES = "list_latest_files"
LIST_CHATS = "list_chats" LIST_CHATS = "list_chats"
GET_CHATS = "get_chats" GET_CHATS = "get_chats"
@ -39,7 +39,7 @@ const (
const ( const (
CHAT_NAME_EDITED = "chat_name_edited" CHAT_NAME_EDITED = "chat_name_edited"
CHAT_TYPE_EDITED = "chat_type_edited" CHAT_TYPE_EDITED = "chat_type_edited"
CHAT_MESSAGE_LIST = "chat_messages_list" CHAT_MESSAGE_LIST = "chat_messages_list"
CHAT_FILES_LIST = "chat_files_list" CHAT_FILES_LIST = "chat_files_list"
CHAT_MEMBER_ADDED = "chat_member_added" CHAT_MEMBER_ADDED = "chat_member_added"
CHAT_MEMBER_REMOVED = "chat_member_removed" CHAT_MEMBER_REMOVED = "chat_member_removed"
@ -68,17 +68,18 @@ type ChatConfig struct {
} }
type Chat struct { type Chat struct {
ChatId string `json:"chatId"` ChatId string `json:"chatId"`
ChatType string `json:"chatType"` ChatType string `json:"chatType"`
Owner string `json:"owner"` Owner string `json:"owner"`
Members []string `json:"members"` Members []string `json:"members"`
LastReadIndex uint `json:"lastReadIndex"` LastReadIndex uint `json:"lastReadIndex"`
Unread uint `json:"unread"` Unread uint `json:"unread"`
DB *ZoneChatDBHandler `json:"-"` DB *ZoneChatDBHandler `json:"-"`
Tracking *ZoneChatTrackingDB `json:"-"` Tracking *ZoneChatTrackingDB `json:"-"`
} }
type ZoneChatsHandler struct { type ZoneChatsHandler struct {
ZoneName string
ZoneId string ZoneId string
HostId string HostId string
ChatFSInstance *ChatFSInstance ChatFSInstance *ChatFSInstance
@ -92,17 +93,17 @@ type ZoneChatsHandler struct {
init bool init bool
} }
func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneChatsHandler *ZoneChatsHandler, err error) { func NewZoneChatsHandler(hostId, zoneId, zoneName, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneChatsHandler *ZoneChatsHandler, err error) {
var dirs []fs.DirEntry var dirs []fs.DirEntry
dirs, err = os.ReadDir(filepath.Join("data", "zones", zoneId, "chats")) dirs, err = os.ReadDir(filepath.Join("data", "zones", zoneId, "chats"))
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
logger.Printf("creating chat directory for zone %s...\n", zoneId) logger.Printf("creating chat directory for zone %s...\n", zoneId)
mkdirErr := os.MkdirAll(filepath.Join("data", "zones", zoneId, "chats", "general"), 0700) mkdirErr := os.MkdirAll(filepath.Join("data", "zones", zoneId, "chats", GENERAL), 0700)
if mkdirErr != nil { if mkdirErr != nil {
return nil, mkdirErr return nil, mkdirErr
} }
file, ferr := os.Create(filepath.Join("data", "zones", zoneId, "chats", "general", "chatConfig.json")) file, ferr := os.Create(filepath.Join("data", "zones", zoneId, "chats", GENERAL, "chatConfig.json"))
if ferr != nil { if ferr != nil {
return nil, ferr return nil, ferr
} }
@ -110,7 +111,7 @@ func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []strin
ChatId: GENERAL, ChatId: GENERAL,
Owner: owner, Owner: owner,
ChatType: "public", ChatType: "public",
Members: authorizedMembers, Members: []string{},
} }
bs, jsonErr := json.Marshal(baseConfig) bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil { if jsonErr != nil {
@ -134,10 +135,6 @@ func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []strin
if err != nil { if err != nil {
return nil, err return nil, err
} }
zoneChatTracking,err := NewZoneChatTracking(zoneId, chat.Name())
if err != nil {
return nil, err
}
var bs []byte var bs []byte
bs, err = os.ReadFile(filepath.Join("data", "zones", zoneId, "chats", chat.Name(), "chatConfig.json")) bs, err = os.ReadFile(filepath.Join("data", "zones", zoneId, "chats", chat.Name(), "chatConfig.json"))
if err != nil { if err != nil {
@ -148,8 +145,9 @@ func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []strin
if err = json.Unmarshal(bs, &c); err != nil { if err = json.Unmarshal(bs, &c); err != nil {
return nil, err return nil, err
} }
if err = zoneChatTracking.Initialize(0,c.Members...); err != nil { zoneChatTracking, err := NewZoneChatTracking(zoneId, c.ChatId, c.Members...)
return nil,err if err != nil {
return nil, err
} }
logger.Println("chats data :", c.ChatId, c.ChatType, c.Owner, c.Members) logger.Println("chats data :", c.ChatId, c.ChatType, c.Owner, c.Members)
c.DB = zoneChatDBHandler c.DB = zoneChatDBHandler
@ -160,6 +158,7 @@ func NewZoneChatsHandler(hostId, zoneId, owner string, authorizedMembers []strin
chatFSFlag := uint32(0) chatFSFlag := uint32(0)
zoneChatsHandler = &ZoneChatsHandler{ zoneChatsHandler = &ZoneChatsHandler{
HostId: hostId, HostId: hostId,
ZoneName: zoneName,
ChatFSInstance: NewChatFSInstance(zoneId, owner, authorizedMembers), ChatFSInstance: NewChatFSInstance(zoneId, owner, authorizedMembers),
ChatFSInstanceFlag: &chatFSFlag, ChatFSInstanceFlag: &chatFSFlag,
ZoneId: zoneId, ZoneId: zoneId,
@ -200,6 +199,8 @@ func (zch *ZoneChatsHandler) sendDataChannelMessage(reqType string, from string,
return jsonErr return jsonErr
} }
err = zch.DataChannels[to].DataChannel.SendText(string(bs)) err = zch.DataChannels[to].DataChannel.SendText(string(bs))
} else {
err = fmt.Errorf("no corresponding dataChannel")
} }
return return
}); err != nil { }); err != nil {
@ -250,7 +251,7 @@ func (zch *ZoneChatsHandler) signalCandidate(from string, to string, candidate *
}) })
select { select {
case <-d: case <-d:
case err = <-e: case <-e:
} }
return return
} }
@ -262,7 +263,6 @@ func (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (er
err = fmt.Errorf("id of wrong type") err = fmt.Errorf("id of wrong type")
return return
} }
fmt.Println("chat from get chats", id.(string))
_ = atomicallyExecute(zch.ChatFlag, func() (err error) { _ = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[id.(string)]; ok { if _, ok := zch.Chats[id.(string)]; ok {
logger.Println(zch.Chats[id.(string)]) logger.Println(zch.Chats[id.(string)])
@ -271,36 +271,25 @@ func (zch *ZoneChatsHandler) GetChats(userId string, chatsId ...interface{}) (er
return return
}) })
} }
fmt.Println("first loop done")
for _, chat := range chats { for _, chat := range chats {
fmt.Println(chat.ChatId) index, err := chat.Tracking.GetUserLastIndex(userId)
index,err := chat.Tracking.GetUserLastIndex(userId)
if err != nil { if err != nil {
fmt.Println("there")
fmt.Println(err)
return err return err
} }
chat.DB.lock.RLock() unread, err := chat.DB.calculateNewChatCount(uint64(index))
defer chat.DB.lock.RUnlock()
unread,err := chat.DB.calculateNewChatCount(uint64(index))
if err != nil { if err != nil {
fmt.Println("over there")
fmt.Println(err)
return err return err
} }
chat.LastReadIndex = index chat.LastReadIndex = index
chat.Unread = unread chat.Unread = unread
} }
fmt.Println(chats) done, e := zch.sendDataChannelMessage(GET_CHATS_RESPONSE, "node", userId, map[string]interface{}{
done,e := zch.sendDataChannelMessage(GET_CHATS_RESPONSE,"node",userId,map[string]interface{}{ "chats": chats,
"chats": chats, })
}) select {
select { case <-done:
case <-done: case err = <-e:
fmt.Println("done") }
case terr :=<-e:
fmt.Println(terr)
}
return return
} }
@ -324,7 +313,7 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
if mkdirErr != nil { if mkdirErr != nil {
return mkdirErr return mkdirErr
} }
mkdirErr = os.Mkdir(filepath.Join("data", "zones", zch.ZoneId, "chats", chatName,"__tracking__"), 0700) mkdirErr = os.Mkdir(filepath.Join("data", "zones", zch.ZoneId, "chats", chatName, "__tracking__"), 0700)
if mkdirErr != nil { if mkdirErr != nil {
return mkdirErr return mkdirErr
} }
@ -333,16 +322,21 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
return ferr return ferr
} }
m := make([]string, 0, len(members)) m := make([]string, 0, len(members))
for _, member := range members { if chatType == PRIVATE {
if mbr, ok := member.(string); ok && mbr != owner { for _, member := range members {
m = append(m, mbr) if mbr, ok := member.(string); ok && mbr != owner {
m = append(m, mbr)
}
} }
m = append(m, owner)
} else {
m = zch.ZoneMembersId
} }
baseConfig := &ChatConfig{ baseConfig := &ChatConfig{
ChatId: chatName, ChatId: chatName,
Owner: owner, Owner: owner,
ChatType: chatType, ChatType: chatType,
Members: append(m,owner), Members: m,
} }
bs, jsonErr := json.Marshal(baseConfig) bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil { if jsonErr != nil {
@ -359,11 +353,11 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
if err != nil { if err != nil {
return err return err
} }
zoneChatTrackingDB,err := NewZoneChatTracking(zch.ZoneId,chatName) zoneChatTrackingDB, err := NewZoneChatTracking(zch.ZoneId, chatName)
if err != nil { if err != nil {
return err return err
} }
if err = zoneChatTrackingDB.Initialize(1,baseConfig.Members...); err != nil { if err = zoneChatTrackingDB.Initialize(1, baseConfig.Members...); err != nil {
return err return err
} }
var c Chat var c Chat
@ -387,10 +381,24 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
}) })
select { select {
case <-done: case <-done:
case err = <-e: case <-e:
return
} }
} }
bs, err := json.Marshal(map[string]any{
"zoneId": zch.ZoneId,
"chatId": chatName,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "added_in_chat",
"title": "Added in zone text channel 💬",
"body": fmt.Sprintf("Added in channel %s in zone %s", c.ChatId, zch.ZoneName),
"isPushed": true,
"payload": string(bs),
"recipients": members,
})
return return
} }
switch c.ChatType { switch c.ChatType {
@ -402,7 +410,10 @@ func (zch *ZoneChatsHandler) AddNewChat(chatName string, owner string, chatType
return return
}) })
case PRIVATE: case PRIVATE:
err = newChatForMembers(c.Members) err = atomicallyExecute(zch.ChatFlag, func() (err error) {
err = newChatForMembers(c.Members)
return
})
} }
return return
} }
@ -426,11 +437,24 @@ func (zch *ZoneChatsHandler) DeleteChat(chatId string) (err error) {
}) })
select { select {
case <-done: case <-done:
continue case <-e:
case err = <-e:
return
} }
} }
bs, err := json.Marshal(map[string]any{
"zoneId": zch.ZoneId,
"chatId": chatId,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]any{
"type": "removed_from_chat",
"title": "Removed from zone text channel ⛔️",
"body": fmt.Sprintf("You have no longer access to the channel %s in zone %s", chatId, zch.ZoneName),
"isPushed": true,
"payload": string(bs),
"recipients": members,
})
return return
} }
switch zch.Chats[chatId].ChatType { switch zch.Chats[chatId].ChatType {
@ -485,9 +509,10 @@ func (zch *ZoneChatsHandler) EditChatName(chatId string, newChatId string) (err
ChatType: chatConfig.ChatType, ChatType: chatConfig.ChatType,
Members: chatConfig.Members, Members: chatConfig.Members,
DB: zch.Chats[chatId].DB, DB: zch.Chats[chatId].DB,
Tracking:zch.Chats[chatId].Tracking, Tracking: zch.Chats[chatId].Tracking,
} }
chat.DB.updateDbCallbackFolder(newChatId) chat.DB.updateDbCallbackFolder(newChatId)
chat.Tracking.updateDBCallbackFolder(newChatId)
_ = atomicallyExecute(zch.ChatFlag, func() (err error) { _ = atomicallyExecute(zch.ChatFlag, func() (err error) {
defer delete(zch.Chats, chatId) defer delete(zch.Chats, chatId)
zch.Chats[newChatId] = chat zch.Chats[newChatId] = chat
@ -540,6 +565,9 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
return return
} }
chatConfig.ChatType = chatType chatConfig.ChatType = chatType
if chatType == PUBLIC {
chatConfig.Members = zch.ZoneMembersId
}
bs, err = json.Marshal(&chatConfig) bs, err = json.Marshal(&chatConfig)
f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
defer func() { defer func() {
@ -557,19 +585,14 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
ChatType: chatType, ChatType: chatType,
Members: chatConfig.Members, Members: chatConfig.Members,
DB: zch.Chats[chatId].DB, DB: zch.Chats[chatId].DB,
Tracking:zch.Chats[chatId].Tracking, Tracking: zch.Chats[chatId].Tracking,
} }
switch chatType { switch chatType {
case BROADCAST: case BROADCAST:
fallthrough fallthrough
case PUBLIC: case PUBLIC:
var members = []string{}
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
members = append(members, zch.ZoneMembersId...)
return
})
for _, member := range zch.ZoneMembersId { for _, member := range zch.ZoneMembersId {
if pubErr := zch.SetChatPublicForUser(chatId, member); pubErr != nil { if pubErr := zch.AddChatMembers(chatId, []any{member}); pubErr != nil {
logger.Println(pubErr) logger.Println(pubErr)
} }
zch.sendDataChannelMessage(CHAT_TYPE_EDITED, "node", member, map[string]interface{}{ zch.sendDataChannelMessage(CHAT_TYPE_EDITED, "node", member, map[string]interface{}{
@ -578,11 +601,6 @@ func (zch *ZoneChatsHandler) EditChatType(chatId string, chatType string) (err e
}) })
} }
case PRIVATE: case PRIVATE:
var members = []string{}
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
members = append(members, zch.ZoneMembersId...)
return
})
for _, member := range zch.ZoneMembersId { for _, member := range zch.ZoneMembersId {
if pubErr := zch.SetChatPrivateForUser(chatId, member); pubErr != nil { if pubErr := zch.SetChatPrivateForUser(chatId, member); pubErr != nil {
logger.Println(pubErr) logger.Println(pubErr)
@ -636,6 +654,21 @@ memberLoop:
"chatId": chatId, "chatId": chatId,
}) })
} }
bs, err = json.Marshal(map[string]any{
"zoneId": zch.ZoneId,
"chatId": chatId,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "added_in_chat",
"title": "Added in zone text channel 💬",
"body": fmt.Sprintf("Added in channel %s in zone %s", chatId, zch.ZoneName),
"isPushed": true,
"payload": string(bs),
"recipients": chatMembers,
})
bs, err = json.Marshal(&chatConfig) bs, err = json.Marshal(&chatConfig)
f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) f, err := os.OpenFile(filepath.Join("data", "zones", zch.ZoneId, "chats", chatId, "chatConfig.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
defer func() { defer func() {
@ -655,49 +688,48 @@ memberLoop:
DB: zch.Chats[chatId].DB, DB: zch.Chats[chatId].DB,
Tracking: zch.Chats[chatId].Tracking, Tracking: zch.Chats[chatId].Tracking,
} }
chat.DB.lock.Lock()
lastIndex := chat.DB.PreviousId
chat.DB.lock.Unlock()
_ = atomicallyExecute(zch.ChatFlag, func() (err error) { _ = atomicallyExecute(zch.ChatFlag, func() (err error) {
lastIndex := chat.DB.PreviousId
zch.Chats[chatId] = chat zch.Chats[chatId] = chat
return
}) var chmb []string
var chmb []string if chat.ChatType == PRIVATE {
if chat.ChatType == PRIVATE { chmb = chat.Members
chmb = chat.Members } else {
} else { chmb = zch.ZoneMembersId
chmb = zch.ZoneMembersId }
} broadcastLoop:
broadcastLoop: for _, member := range chmb {
for _, member := range chmb { for _, m := range addedMembers {
for _, m := range addedMembers { if err = chat.Tracking.SetUserLastIndex(member, lastIndex); err != nil {
if err = chat.Tracking.SetUserLastIndex(member,lastIndex); err != nil { return
return
}
if member == m {
done, e := zch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
"chat": chat,
})
select {
case <-done:
case err = <-e:
logger.Println(err)
} }
continue broadcastLoop if member == m {
} done, e := zch.sendDataChannelMessage(ADDED_IN_CHAT, "node", member, map[string]interface{}{
if _, ok := zch.DataChannels[member]; ok { "chat": chat,
done, e := zch.sendDataChannelMessage(CHAT_MEMBER_ADDED, "node", member, map[string]interface{}{ })
"userId": m, select {
"chatId": chat.ChatId, case <-done:
}) case err = <-e:
select { logger.Println(err)
case <-done: }
case err = <-e: continue broadcastLoop
logger.Println(err) }
if _, ok := zch.DataChannels[member]; ok {
done, e := zch.sendDataChannelMessage(CHAT_MEMBER_ADDED, "node", member, map[string]interface{}{
"userId": m,
"chatId": chat.ChatId,
})
select {
case <-done:
case err = <-e:
logger.Println(err)
}
} }
} }
} }
} return
})
return return
} }
@ -770,6 +802,21 @@ func (zch *ZoneChatsHandler) RemoveChatMember(chatId string, chatMember string)
"userId": chatMember, "userId": chatMember,
"chatId": chatId, "chatId": chatId,
}) })
bs, err = json.Marshal(map[string]any{
"zoneId": zch.ZoneId,
"chatId": chatId,
})
if err != nil {
return
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "removed_from_chat",
"title": "Removed from zone text channel ⛔️",
"body": fmt.Sprintf("You have no longer access to the channel %s in zone %s", chatId, zch.ZoneName),
"isPushed": true,
"payload": string(bs),
"recipients": []string{chatMember},
})
done, e := zch.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", chatMember, map[string]interface{}{ done, e := zch.sendDataChannelMessage(REMOVED_FROM_CHAT, "node", chatMember, map[string]interface{}{
"chatId": chatId, "chatId": chatId,
"userId": chatMember, "userId": chatMember,
@ -803,10 +850,10 @@ broadcastLoop:
return return
} }
func(zch *ZoneChatsHandler) ReadLastMessage(userId,chatId string) (err error) { func (zch *ZoneChatsHandler) ReadLastMessage(userId, chatId string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) { err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatId]; ok { if chat, ok := zch.Chats[chatId]; ok {
err = chat.Tracking.SetUserLastIndex(userId,chat.DB.PreviousId) err = chat.Tracking.SetUserLastIndex(userId, chat.DB.PreviousId)
} }
return return
}) })
@ -823,7 +870,7 @@ func (zch *ZoneChatsHandler) ListLatestChatMessages(userId, chatId string, lastI
if err != nil { if err != nil {
return return
} }
err = chat.Tracking.SetUserLastIndex(userId,chat.DB.PreviousId) err = chat.Tracking.SetUserLastIndex(userId, chat.DB.PreviousId)
} }
return return
}); err != nil { }); err != nil {
@ -876,9 +923,12 @@ func (zch *ZoneChatsHandler) AddChatMessage(userId, chatId, content string, isRe
Tags: make([]string, 0), Tags: make([]string, 0),
Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"), Date: time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST"),
} }
var chatType string
var chatMembers []string
if err = atomicallyExecute(zch.ChatFlag, func() (err error) { if err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if chat, ok := zch.Chats[chatId]; ok { if chat, ok := zch.Chats[chatId]; ok {
chatType = chat.ChatType
chatMembers = chat.Members
if isResponse { if isResponse {
parentMessage, getErr := chat.DB.GetChatMessage(chatResponseId) parentMessage, getErr := chat.DB.GetChatMessage(chatResponseId)
if err != nil { if err != nil {
@ -900,37 +950,63 @@ func (zch *ZoneChatsHandler) AddChatMessage(userId, chatId, content string, isRe
}); err != nil { }); err != nil {
return return
} }
_ = atomicallyExecute(zch.ChatFlag, func() (err error) {
chat := zch.Chats[chatId] notifyActivity := func(done <-chan struct{}, e <-chan error, member string) {
logger.Println(chat.ChatType) select {
switch chat.ChatType { case <-done:
case BROADCAST: case <-e:
fallthrough _ = atomicallyExecute(zch.ChatFlag, func() (err error) {
case PUBLIC: if chat, ok := zch.Chats[chatId]; ok {
for _, v := range zch.ZoneMembersId { li, err := chat.Tracking.GetUserLastIndex(member)
done, e := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", v, map[string]interface{}{ if err != nil {
"chatMessage": chatMessage, return err
"chatId": chatId, }
}) count, err := chat.DB.calculateNewChatCount(uint64(li))
select { if err != nil {
case <-done: return err
case err = <-e: }
if count == 1 {
bs, err := json.Marshal(map[string]any{
"zoneId": zch.ZoneId,
"chatId": chatId,
})
if err != nil {
return err
}
zch.sendZoneRequest(CREATE_NOTIFICATION, "node", map[string]interface{}{
"type": "new_chat_activity",
"title": "Unread messages 👀",
"body": fmt.Sprintf("New messages in channel %s of %s", chatId, zch.ZoneName),
"isPushed": true,
"payload": string(bs),
"recipients": []string{member},
})
}
} }
} return
case PRIVATE: })
for _, v := range chat.Members {
done, e := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", v, map[string]interface{}{
"chatMessage": chatMessage,
"chatId": chatId,
})
select {
case <-done:
case err = <-e:
}
}
} }
return }
}) switch chatType {
case BROADCAST:
fallthrough
case PUBLIC:
for _, v := range zch.ZoneMembersId {
done, e := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", v, map[string]interface{}{
"chatMessage": chatMessage,
"chatId": chatId,
})
go notifyActivity(done, e, v)
}
case PRIVATE:
for _, v := range chatMembers {
done, e := zch.sendDataChannelMessage(NEW_CHAT_MESSAGE, "node", v, map[string]interface{}{
"chatMessage": chatMessage,
"chatId": chatId,
})
go notifyActivity(done, e, v)
}
}
return return
} }
@ -955,7 +1031,7 @@ func (zch *ZoneChatsHandler) SetChatPrivateForUser(chatId string, member string)
}) })
select { select {
case <-done: case <-done:
case err = <-e: case <-e:
} }
} }
} }
@ -984,7 +1060,7 @@ func (zch *ZoneChatsHandler) SetChatPublicForUser(chatId string, member string)
}) })
select { select {
case <-done: case <-done:
case err = <-e: case <-e:
} }
} }
} }
@ -997,15 +1073,22 @@ func (zch *ZoneChatsHandler) SetAllPublicChatForUser(userId string) (err error)
for _, chat := range zch.Chats { for _, chat := range zch.Chats {
logger.Println("--------------- public chat for all : ", chat) logger.Println("--------------- public chat for all : ", chat)
if chat.ChatType == PUBLIC || chat.ChatType == BROADCAST { if chat.ChatType == PUBLIC || chat.ChatType == BROADCAST {
if chat.ChatId == GENERAL { var contains bool
if err = zch.AddChatMembers(chat.ChatId, []interface{}{userId}); err != nil { for _, m := range chat.Members {
logger.Println(err) if m == userId {
contains = true
break
}
}
if !contains {
if addErr := zch.AddChatMembers(chat.ChatId, []any{userId}); addErr != nil {
logger.Println(addErr)
} }
continue continue
} }
if err = zch.SetChatPublicForUser(chat.ChatId, userId); err != nil { // if addErr := zch.SetChatPublicForUser(chat.ChatId, userId); addErr != nil {
continue // continue
} // }
} }
} }
return return
@ -1048,7 +1131,7 @@ func (zch *ZoneChatsHandler) ConnectToChatFSInstance(channelId string, userId st
d, e := zch.ChatFSInstance.HandleOffer(context.Background(), channelId, userId, sdp, zch.HostId, zch.sendDataChannelMessage, zch.signalCandidate) d, e := zch.ChatFSInstance.HandleOffer(context.Background(), channelId, userId, sdp, zch.HostId, zch.sendDataChannelMessage, zch.signalCandidate)
select { select {
case <-d: case <-d:
case err = <-e: case <-e:
} }
return return
}) })
@ -1116,7 +1199,7 @@ func (zch *ZoneChatsHandler) DeleteChatMessage(key uint64, chatId string) (err e
func (zch *ZoneChatsHandler) UpdateChatMessage(key uint64, chatId, newContent string) (err error) { func (zch *ZoneChatsHandler) UpdateChatMessage(key uint64, chatId, newContent string) (err error) {
err = atomicallyExecute(zch.ChatFlag, func() (err error) { err = atomicallyExecute(zch.ChatFlag, func() (err error) {
if _, ok := zch.Chats[chatId]; !ok { if _, ok := zch.Chats[chatId]; !ok {
err = fmt.Errorf("no file corresponding to id %s", chatId) err = fmt.Errorf("no chat corresponding to id %s", chatId)
return return
} }
if err = zch.Chats[chatId].DB.ModifyChatMessage(key, newContent); err != nil { if err = zch.Chats[chatId].DB.ModifyChatMessage(key, newContent); err != nil {
@ -1279,13 +1362,10 @@ func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
} }
err = zch.AddNewChat(req.Payload["chatId"].(string), req.Payload["owner"].(string), req.Payload["chatType"].(string), req.Payload["members"].([]interface{})) err = zch.AddNewChat(req.Payload["chatId"].(string), req.Payload["owner"].(string), req.Payload["chatType"].(string), req.Payload["members"].([]interface{}))
case GET_CHATS: case GET_CHATS:
fmt.Println("got a get chat req")
if err = verifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil { if err = verifyFieldsSliceInterface(req.Payload, "chatsId"); err != nil {
return return
} }
fmt.Println("calling get chat")
err = zch.GetChats(req.From, req.Payload["chatsId"].([]interface{})...) err = zch.GetChats(req.From, req.Payload["chatsId"].([]interface{})...)
fmt.Println("get chat done")
case LIST_LATEST_CHATS: case LIST_LATEST_CHATS:
if err = verifyFieldsString(req.Payload, "chatId"); err != nil { if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
return return
@ -1308,7 +1388,7 @@ func (zch *ZoneChatsHandler) handleZoneRequest(ctx context.Context, req *ZoneReq
if err = verifyFieldsString(req.Payload, "chatId"); err != nil { if err = verifyFieldsString(req.Payload, "chatId"); err != nil {
return return
} }
err = zch.ReadLastMessage(req.From,req.Payload["chatId"].(string)) err = zch.ReadLastMessage(req.From, req.Payload["chatId"].(string))
case ADD_CHAT_MESSAGE: case ADD_CHAT_MESSAGE:
logger.Println("got request in zone chat handler", req) logger.Println("got request in zone chat handler", req)
if err = verifyFieldsString(req.Payload, "chatId", "content"); err != nil { if err = verifyFieldsString(req.Payload, "chatId", "content"); err != nil {

View File

@ -264,7 +264,7 @@ func (fs *FSInstance) SetupFileDownload(path, filename, userId string) (err erro
} }
} }
logger.Println("done") logger.Println("done")
<-time.After(4*time.Second) <-time.After(4 * time.Second)
_ = dc.SendText("done") _ = dc.SendText("done")
<-time.After(time.Second) <-time.After(time.Second)
_ = dc.Close() _ = dc.Close()

View File

@ -24,8 +24,8 @@ const (
NEW_ZONE ReqType = "new_zone" NEW_ZONE ReqType = "new_zone"
NEW_AUTHORIZED_ZONE_MEMBER ReqType = "new_authorized_zone_member" NEW_AUTHORIZED_ZONE_MEMBER ReqType = "new_authorized_zone_member"
REMOVED_ZONE_AUTHORIZED_MEMBER ReqType = "removed_zone_authorized_member" REMOVED_ZONE_AUTHORIZED_MEMBER ReqType = "removed_zone_authorized_member"
DELETE_ZONE = "delete_zone" DELETE_ZONE = "delete_zone"
DISCONNECT_ZONE_MEMBER = "disconnect_zone_member" DISCONNECT_ZONE_MEMBER = "disconnect_zone_member"
) )
type ZoneGrpcMiddleware struct { type ZoneGrpcMiddleware struct {

View File

@ -52,7 +52,7 @@ type Zone struct {
func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, owner string, creationDate string, initialized bool, authorizedMembers []string) (zone *Zone, err error) { func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, owner string, creationDate string, initialized bool, authorizedMembers []string) (zone *Zone, err error) {
dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0) dataChannels, dataChannelFlag := make(map[string]*DataChannel), uint32(0)
zoneChatHandler, err := NewZoneChatsHandler(hostId, zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag) zoneChatHandler, err := NewZoneChatsHandler(hostId, zoneId, zoneName, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -68,11 +68,15 @@ func NewZone(hostId string, zoneId string, zoneName string, imageUrl string, own
if err != nil { if err != nil {
return return
} }
zoneNotificationsHandler, err := NewZoneNotificationsHandler(hostId, zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil {
return
}
zoneFileHandler, err := NewZoneFileHandler(hostId, zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag) zoneFileHandler, err := NewZoneFileHandler(hostId, zoneId, owner, authorizedMembers, dataChannels, &dataChannelFlag)
if err != nil { if err != nil {
return return
} }
zoneScheduler, e := NewZoneRequestScheduler(authorizedMembers, zoneUsersHandler, zoneAudioChannelsHandler, zoneVideoChannelsHandler, zoneFileHandler, zoneChatHandler) zoneScheduler, e := NewZoneRequestScheduler(authorizedMembers, zoneUsersHandler, zoneAudioChannelsHandler, zoneVideoChannelsHandler, zoneFileHandler, zoneChatHandler, zoneNotificationsHandler)
go func() { go func() {
for schedErr := range e { for schedErr := range e {
logger.Println("from scheduler :", schedErr) logger.Println("from scheduler :", schedErr)
@ -111,7 +115,7 @@ func NewZoneManager(id string, token string) (zoneManager *ZoneManager, err erro
} }
zoneMap[zone.ID] = z zoneMap[zone.ID] = z
} }
zonesFolder,err := os.ReadDir(filepath.Join("data", "zones")) zonesFolder, err := os.ReadDir(filepath.Join("data", "zones"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -130,7 +134,7 @@ func NewZoneManager(id string, token string) (zoneManager *ZoneManager, err erro
candidateFlag: &candidateFlag, candidateFlag: &candidateFlag,
} }
for _, z := range zonesFolder { for _, z := range zonesFolder {
if _,ok := zoneMap[z.Name()]; !ok { if _, ok := zoneMap[z.Name()]; !ok {
logger.Println(zoneManager.DeleteZone(z.Name())) logger.Println(zoneManager.DeleteZone(z.Name()))
} }
} }
@ -163,17 +167,17 @@ func (zm *ZoneManager) sendSignalingMessage(messageType, from, to string, payloa
} }
func (zm *ZoneManager) DeleteZone(zoneId string) error { func (zm *ZoneManager) DeleteZone(zoneId string) error {
return os.RemoveAll(filepath.Join("data", "zones",zoneId)) return os.RemoveAll(filepath.Join("data", "zones", zoneId))
} }
func (zm *ZoneManager) fetchZones(nodeId string, token string) (zones []*Zone, err error) { func (zm *ZoneManager) fetchZones(nodeId string, token string) (zones []*Zone, err error) {
em := NewEncryptionManager() em := NewEncryptionManager()
sig := em.SignRequestHMAC(nodeId) sig := em.SignRequestHMAC(nodeId)
body, err := json.Marshal(map[string]interface{}{ body, err := json.Marshal(map[string]interface{}{
"type": LIST_ZONES_BY_HOST, "type": LIST_ZONES_BY_HOST,
"mac": sig, "mac": sig,
"from": nodeId, "from": nodeId,
"peerType":"node", "peerType": "node",
"payload": map[string]string{ "payload": map[string]string{
"host": nodeId, "host": nodeId,
"lastIndex": "0", "lastIndex": "0",
@ -246,11 +250,11 @@ func (zm *ZoneManager) HandleOffer(ctx context.Context, from string, to string,
} }
logger.Println("handling zone offer") logger.Println("handling zone offer")
if _,ok := zm.RTCPeerConnections[from]; ok { if _, ok := zm.RTCPeerConnections[from]; ok {
if e := zm.HandleLeavingMember(from,req["zoneId"]); e != nil { if e := zm.HandleLeavingMember(from, req["zoneId"]); e != nil {
logger.Println(e) logger.Println(e)
}
} }
}
peerConnection, err := zm.createPeerConnection(from, to, req["zoneId"], webrtc.SDPTypeAnswer, cb) peerConnection, err := zm.createPeerConnection(from, to, req["zoneId"], webrtc.SDPTypeAnswer, cb)
if err != nil { if err != nil {
@ -708,8 +712,8 @@ func (zm *ZoneManager) AddCandidate(candidate *webrtc.ICECandidateInit, from str
} }
func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error) { func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error) {
defer func () { defer func() {
logger.Println(zm.notifyLeavingMember(id,zoneId,zm.ID)) logger.Println(zm.notifyLeavingMember(id, zoneId, zm.ID))
}() }()
logger.Println("---------------- handling leaving member", id) logger.Println("---------------- handling leaving member", id)
if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) { if err = atomicallyExecute(zm.peerConnectionFlag, func() (err error) {
@ -771,16 +775,16 @@ func (zm *ZoneManager) HandleLeavingMember(id string, zoneId string) (err error)
return return
} }
func (zm *ZoneManager) notifyLeavingMember(userId,zoneId,hostId string) (err error) { func (zm *ZoneManager) notifyLeavingMember(userId, zoneId, hostId string) (err error) {
em := NewEncryptionManager() em := NewEncryptionManager()
sig := em.SignRequestHMAC(hostId) sig := em.SignRequestHMAC(hostId)
body, err := json.Marshal(map[string]interface{}{ body, err := json.Marshal(map[string]interface{}{
"type": DISCONNECT_ZONE_MEMBER, "type": DISCONNECT_ZONE_MEMBER,
"mac": sig, "mac": sig,
"from": hostId, "from": hostId,
"peerType":"node", "peerType": "node",
"payload": map[string]string{ "payload": map[string]string{
"zoneId": zoneId, "zoneId": zoneId,
"userId": userId, "userId": userId,
}, },
}) })

View File

@ -0,0 +1,41 @@
package localserver
import (
"path/filepath"
sync "sync"
"github.com/dgraph-io/badger/v3"
)
type ZoneNotification struct {
ID string
Type string
Description string
Recipients []string
}
type ZoneNotificationDBHandler struct {
ZoneID string
db func(func(*badger.DB) (err error)) (err error)
lock *sync.RWMutex
}
func NewZoneNotificationDBHandler(zoneId string) (zoneFilesDBHandler *ZoneNotificationDBHandler, err error) {
zoneFilesDBHandler = &ZoneNotificationDBHandler{
db: func(f func(*badger.DB) (err error)) (err error) {
path := filepath.Join("data", "zones", zoneId, "notifications")
db, err := badger.Open(badger.DefaultOptions(path).WithLogger(dbLogger))
if err != nil {
return
}
defer db.Close()
err = f(db)
return
},
ZoneID: zoneId,
lock: new(sync.RWMutex),
}
return
}
//Todo: implement pull notification module for beta only push notification are enabled for simplicity

View File

@ -1,10 +1,179 @@
package localserver package localserver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
)
const (
CREATE_NOTIFICATION = "create_notification"
)
const (
NOTIFY = "notify"
)
type ZoneNotificationsHandler struct { type ZoneNotificationsHandler struct {
ZoneId string ZoneId string
ZoneMembersId []string ZoneMembersId []string
DataChannels map[string]*DataChannel DataChannels map[string]*DataChannel
Flag *uint32 Flag *uint32
DB *ZoneNotificationDBHandler
Publishers []<-chan *ZoneRequest Publishers []<-chan *ZoneRequest
reqChans []chan<- *ZoneRequest reqChans []chan<- *ZoneRequest
} }
func NewZoneNotificationsHandler(_ string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneNotificationsHandler *ZoneNotificationsHandler, err error) {
db, err := NewZoneNotificationDBHandler(zoneId)
if err != nil {
return
}
if _, dirErr := os.ReadDir(filepath.Join("data", "zones", zoneId, "notifications")); os.IsNotExist(dirErr) {
dirErr := os.MkdirAll(filepath.Join("data", "zones", zoneId, "notifications"), 0700)
if dirErr != nil {
return
}
}
zoneNotificationsHandler = &ZoneNotificationsHandler{
ZoneId: zoneId,
ZoneMembersId: authorizedMembers,
DataChannels: dataChannels,
DB: db,
Flag: flag,
}
return
}
func (znh *ZoneNotificationsHandler) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
go func() {
for _, rc := range znh.reqChans {
rc <- &ZoneRequest{
ReqType: reqType,
From: from,
Payload: payload,
}
}
}()
}
func (znh *ZoneNotificationsHandler) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
if err := atomicallyExecute(znh.Flag, func() (err error) {
if _, ok := znh.DataChannels[to]; ok {
bs, jsonErr := json.Marshal(&ZoneResponse{
Type: reqType,
From: from,
To: to,
Payload: payload,
})
if jsonErr != nil {
return jsonErr
}
err = znh.DataChannels[to].DataChannel.SendText(string(bs))
}
return
}); err != nil {
errCh <- err
return
}
done <- struct{}{}
}()
return done, errCh
}
func (znh *ZoneNotificationsHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
//? initialization code here
return
}
func (znh *ZoneNotificationsHandler) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) {
reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error)
znh.reqChans = append(znh.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := znh.handleZoneRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (zng *ZoneNotificationsHandler) ListNotifications(userId string) {}
func (zng *ZoneNotificationsHandler) CreateNotification(notificationType, title, body, payload string, isPushed bool, recipients ...string) (err error) {
if isPushed {
err = zng.PushNotification(notificationType, title, body, payload, recipients...)
}
return
}
func (zng *ZoneNotificationsHandler) DeleteNotification() {}
func (zng *ZoneNotificationsHandler) PushNotification(notificationType, title, body ,payload string, recipients ...string) (err error) {
em := NewEncryptionManager()
sig := em.SignRequestHMAC(NodeID)
b, err := json.Marshal(map[string]interface{}{
"type": NOTIFY,
"mac": sig,
"from": NodeID,
"peerType": "node",
"payload": map[string]interface{}{
"type": notificationType,
"title": title,
"body": body,
"recipients": recipients,
"payload": payload,
},
})
if err != nil {
return
}
_, err = http.Post("https://app.zippytal.com/req", "application/json", bytes.NewBuffer(b))
if err != nil {
logger.Println("error come from there in zone manager")
return
}
return
}
func (zng *ZoneNotificationsHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
switch req.ReqType {
case CREATE_NOTIFICATION:
if err = verifyFieldsString(req.Payload, "type", "title", "body","payload"); err != nil {
return
}
if err = verifyFieldsBool(req.Payload, "isPushed"); err != nil {
return
}
if _, ok := req.Payload["recipients"]; !ok {
err = fmt.Errorf("no field recipient in payload")
return
}
if _, ok := req.Payload["recipients"].([]string); !ok {
err = fmt.Errorf(" field recipient in payload is wrong type")
return
}
// recipients := []string{}
// for _, recipient := range req.Payload["recipients"].([]any) {
// if r, ok := recipient.(string); ok {
// recipients = append(recipients, r)
// }
// }
err = zng.CreateNotification(req.Payload["type"].(string), req.Payload["title"].(string), req.Payload["body"].(string), req.Payload["payload"].(string),req.Payload["isPushed"].(bool),req.Payload["recipients"].([]string)...)
}
return
}

View File

@ -72,7 +72,7 @@ func verifyFieldsSliceInterface(payload map[string]interface{}, fields ...string
if _, ok := payload[field]; !ok { if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field) err = fmt.Errorf("no field %s in payload", field)
return return
} else if _, ok := payload[field].([]interface{}); !ok { } else if _, ok := payload[field].([]any); !ok {
err = fmt.Errorf("field %s in payload is not a []interface{}", field) err = fmt.Errorf("field %s in payload is not a []interface{}", field)
return return
} }

View File

@ -282,7 +282,7 @@ func (zvch *ZoneVideoChannelsHandler) AddNewVideoChannel(channelName string, own
ID: channelName, ID: channelName,
Owner: owner, Owner: owner,
ChannelType: channelType, ChannelType: channelType,
Members: append(m,owner), Members: append(m, owner),
} }
bs, jsonErr := json.Marshal(baseConfig) bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil { if jsonErr != nil {