Zippytal-Node/zoneUsersHandler.go
2021-12-08 15:58:40 +01:00

535 lines
14 KiB
Go

package localserver
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
)
const (
LIST_ZONE_MEMBERS = "list_zone_members"
LIST_ZONE_MEMBERS_RESPONSE = "list_zone_members_response"
GET_USER = "get_user"
MODIFY_USER_CHAT_RIGHTS = "modify_user_chat_rights"
ADD_KNOWN_CHAT = "add_known_chat"
REMOVE_KNOWN_CHAT = "remove_known_chat"
ADD_KNOWN_AUDIO_CHANNEL = "add_known_audio_channel"
REMOVE_KNOWN_AUDIO_CHANNEL = "remove_known_audio_channel"
ADD_KNOWN_VIDEO_CHANNEL = "add_known_video_channel"
REMOVE_KNOWN_VIDEO_CHANNEL = "remove_known_video_channel"
ADD_USER = "add_user"
REMOVE_USER = "remove_user"
)
const (
NEW_ZONE_USER = "new_zone_user"
REMOVED_ZONE_USER = "removed_zone_user"
)
type ZoneUsersHandler struct {
ZoneId string
ZoneMembersId []string
DataChannels map[string]*DataChannel
Flag *uint32
Publishers []<-chan *ZoneRequest
DB *ZoneUsersDBHandler
reqChans []chan<- *ZoneRequest
}
type ZoneUserConfig struct {
DefaultChatsRights string `json:"defaultChatsRights"`
DefaultAudioChannelsRights string `json:"defaultAudioChannelsRights"`
DefaultVideoChannelsRights string `json:"defaultVideoChannelsRights"`
DefaultMediaRights string `json:"defaultMediaRights"`
DefaultFileRights string `json:"defaultFileRights"`
AdminRights string `json:"adminRights"`
}
func NewZoneUsersHandler(zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneUsersHandler *ZoneUsersHandler, err error) {
_, err = os.ReadDir(filepath.Join("data", "zones", zoneId, "users"))
var zoneUsersDBHandler *ZoneUsersDBHandler
if err != nil {
if os.IsNotExist(err) {
logger.Printf("creating chat directory for zone %s...\n", zoneId)
mkdirErr := os.MkdirAll(filepath.Join("data", "zones", zoneId, "users"), 0700)
if mkdirErr != nil {
return nil, mkdirErr
}
zoneUsersDBHandler, err = NewZoneUsersDBHandler(zoneId, owner, authorizedMembers, true)
if err != nil {
return
}
file, ferr := os.Create(filepath.Join("data", "zones", zoneId, "users", "usersConfig.json"))
if ferr != nil {
return nil, ferr
}
baseConfig := ZoneUserConfig{
DefaultChatsRights: "",
DefaultAudioChannelsRights: "",
DefaultVideoChannelsRights: "",
DefaultMediaRights: "",
DefaultFileRights: "",
AdminRights: "",
}
bs, jsonErr := json.Marshal(baseConfig)
if jsonErr != nil {
return nil, jsonErr
}
if _, writeErr := file.WriteString(string(bs)); writeErr != nil {
return nil, writeErr
}
_ = file.Close()
if err != nil {
return
}
} else {
return
}
} else {
zoneUsersDBHandler, err = NewZoneUsersDBHandler(zoneId, owner, authorizedMembers, false)
}
if err != nil {
return
}
zoneUsersHandler = &ZoneUsersHandler{
ZoneId: zoneId,
DataChannels: dataChannels,
ZoneMembersId: authorizedMembers,
Flag: flag,
DB: zoneUsersDBHandler,
}
return
}
func (zuh *ZoneUsersHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
users, err := zuh.DB.ListUsers(0, 1000)
if err != nil {
return
}
logger.Println(authorizedMembers)
for _, user := range users {
var contain bool
for _, member := range authorizedMembers {
if user.ID == member {
contain = true
break
}
}
if !contain {
logger.Println("userId", user.ID)
if rerr := zuh.RemoveUser(user.ID); rerr != nil {
logger.Println(rerr)
}
go func(userId string) {
for _, rc := range zuh.reqChans {
logger.Println("------------------------ sending to req chan ------------------------")
rc <- &ZoneRequest{
ReqType: string(REMOVED_ZONE_AUTHORIZED_MEMBER),
From: "node",
Payload: map[string]interface{}{
"userId": userId,
},
}
}
}(user.ID)
}
}
return
}
func (zuh *ZoneUsersHandler) 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)
zuh.reqChans = append(zuh.reqChans, reqChan)
go func() {
for {
select {
case <-ctx.Done():
done <- struct{}{}
return
case req := <-publisher:
if err := zuh.handleZoneRequest(ctx, req); err != nil {
errCh <- err
}
}
}
}()
return
}
func (zuh *ZoneUsersHandler) AddUser(userId string) (err error) {
newUser := &User{
ID: userId,
Name: userId,
ChatRights: "",
AudioChannelRights: "",
VideoChannelRights: "",
MediaRights: "",
FileRights: "",
KnownChatsId: []string{},
KnownAudioChannelsId: []string{},
KnownVideoChannelsId: make([]string, 0),
KnownMediaFolderId: make([]string, 0),
KnownFileFolderId: make([]string, 0),
}
if err = zuh.DB.AddNewUser(newUser); err != nil {
return
}
err = atomicallyExecute(zuh.Flag, func() (err error) {
users, err := zuh.DB.ListUsers(0, 10000)
if err != nil {
return
}
bs, jsonErr := json.Marshal(&ZoneResponse{
Type: NEW_ZONE_USER,
From: "node",
To: "user",
Payload: map[string]interface{}{
"user": newUser,
},
})
if jsonErr != nil {
return jsonErr
}
for _, user := range users {
if _, ok := zuh.DataChannels[user.ID]; ok {
_ = zuh.DataChannels[user.ID].DataChannel.SendText(string(bs))
}
}
return
})
return
}
func (zuh *ZoneUsersHandler) RemoveUser(userId string) (err error) {
if err = zuh.DB.DeleteUser(userId); err != nil {
return
}
err = atomicallyExecute(zuh.Flag, func() (err error) {
users, err := zuh.DB.ListUsers(0, 10000)
if err != nil {
return
}
bs, jsonErr := json.Marshal(&ZoneResponse{
Type: REMOVED_ZONE_USER,
From: "node",
To: "user",
Payload: map[string]interface{}{
"userId": userId,
},
})
if jsonErr != nil {
return jsonErr
}
if _, ok := zuh.DataChannels[userId]; ok {
_ = zuh.DataChannels[userId].DataChannel.SendText(string(bs))
}
for _, user := range users {
if _, ok := zuh.DataChannels[user.ID]; ok {
_ = zuh.DataChannels[user.ID].DataChannel.SendText(string(bs))
}
}
return
})
return
}
func (zuh *ZoneUsersHandler) AddKnownChat(chatId string, userId string) (err error) {
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
for _, id := range user.KnownChatsId {
if id == chatId {
err = fmt.Errorf("user already know channel %s", chatId)
return
}
}
user.KnownChatsId = append(user.KnownChatsId, chatId)
if err = zuh.DB.ModifyUser(userId, user); err != nil {
return
}
return
}
func (zuh *ZoneUsersHandler) RemoveKnownChat(chatId string, userId string) (err error) {
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
var index int
var contain bool
for i, id := range user.KnownChatsId {
if id == chatId {
index = i
contain = true
break
}
}
if !contain {
err = fmt.Errorf("does not know this chat")
return
}
if len(user.KnownChatsId) < 2 {
user.KnownChatsId = make([]string, 0)
} else {
user.KnownChatsId = append(user.KnownChatsId[:index], user.KnownChatsId[index+1:]...)
}
err = zuh.DB.ModifyUser(userId, user)
return
}
func (zuh *ZoneUsersHandler) AddKnownAudioChannel(channelId string, userId string) (err error) {
logger.Println("added new audio channel", channelId, userId)
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
for _, id := range user.KnownAudioChannelsId {
if id == channelId {
err = fmt.Errorf("user already know channel %s", channelId)
return
}
}
user.KnownAudioChannelsId = append(user.KnownAudioChannelsId, channelId)
if err = zuh.DB.ModifyUser(userId, user); err != nil {
return
}
return
}
func (zuh *ZoneUsersHandler) RemoveKnownAudioChannel(channelId string, userId string) (err error) {
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
var index int
var contain bool
for i, id := range user.KnownAudioChannelsId {
if id == channelId {
index = i
contain = true
break
}
}
if !contain {
err = fmt.Errorf("does not know this chat")
return
}
if len(user.KnownAudioChannelsId) < 2 {
user.KnownAudioChannelsId = make([]string, 0)
} else {
user.KnownAudioChannelsId = append(user.KnownAudioChannelsId[:index], user.KnownAudioChannelsId[index+1:]...)
}
err = zuh.DB.ModifyUser(userId, user)
return
}
func (zuh *ZoneUsersHandler) AddKnownVideoChannel(channelId string, userId string) (err error) {
logger.Println("added new audio channel", channelId, userId)
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
for _, id := range user.KnownVideoChannelsId {
if id == channelId {
err = fmt.Errorf("user already know channel %s", channelId)
return
}
}
user.KnownVideoChannelsId = append(user.KnownVideoChannelsId, channelId)
if err = zuh.DB.ModifyUser(userId, user); err != nil {
return
}
return
}
func (zuh *ZoneUsersHandler) RemoveKnownVideoChannel(channelId string, userId string) (err error) {
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
var index int
var contain bool
for i, id := range user.KnownVideoChannelsId {
if id == channelId {
index = i
contain = true
break
}
}
if !contain {
err = fmt.Errorf("does not know this chat")
return
}
if len(user.KnownVideoChannelsId) < 2 {
user.KnownVideoChannelsId = make([]string, 0)
} else {
user.KnownVideoChannelsId = append(user.KnownVideoChannelsId[:index], user.KnownVideoChannelsId[index+1:]...)
}
err = zuh.DB.ModifyUser(userId, user)
return
}
func (zuh *ZoneUsersHandler) AddKnownFolder(folderId string, userId string) (err error) {
logger.Println("added new known folder", folderId, userId)
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
for _, id := range user.KnownFileFolderId {
if id == folderId {
err = fmt.Errorf("user already know channel %s", folderId)
return
}
}
user.KnownVideoChannelsId = append(user.KnownVideoChannelsId, folderId)
if err = zuh.DB.ModifyUser(userId, user); err != nil {
return
}
return
}
func (zuh *ZoneUsersHandler) RemoveKnownFolder(folderId string, userId string) (err error) {
user, err := zuh.DB.GetUser(userId)
if err != nil {
return
}
var index int
var contain bool
for i, id := range user.KnownFileFolderId {
if id == folderId {
index = i
contain = true
break
}
}
if !contain {
err = fmt.Errorf("does not know this chat")
return
}
if len(user.KnownFileFolderId) < 2 {
user.KnownFileFolderId = make([]string, 0)
} else {
user.KnownFileFolderId = append(user.KnownFileFolderId[:index], user.KnownFileFolderId[index+1:]...)
}
err = zuh.DB.ModifyUser(userId, user)
return
}
func (zuh *ZoneUsersHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
logger.Println("got request in zone users handler", req)
switch req.ReqType {
case REMOVE_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
return
}
err = zuh.RemoveUser(req.Payload["userId"].(string))
case ADD_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
return
}
err = zuh.AddUser(req.Payload["userId"].(string))
case REMOVE_KNOWN_CHAT:
if err = verifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownChat(req.Payload["chatId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_CHAT:
if err = verifyFieldsString(req.Payload, "chatId", "userId"); err != nil {
return
}
err = zuh.AddKnownChat(req.Payload["chatId"].(string), req.Payload["userId"].(string))
case REMOVE_KNOWN_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_AUDIO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.AddKnownAudioChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case REMOVE_KNOWN_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.RemoveKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case ADD_KNOWN_VIDEO_CHANNEL:
if err = verifyFieldsString(req.Payload, "channelId", "userId"); err != nil {
return
}
err = zuh.AddKnownVideoChannel(req.Payload["channelId"].(string), req.Payload["userId"].(string))
case GET_USER:
if err = verifyFieldsString(req.Payload, "userId"); err != nil {
return
}
if _, ok := req.Payload["init"]; !ok {
err = fmt.Errorf("no field init in req payload for get user")
return
}
if _, ok := req.Payload["init"].(bool); !ok {
err = fmt.Errorf("field init is of wrong type")
return
}
user, err := zuh.DB.GetUser(req.Payload["userId"].(string))
if err != nil {
return err
}
var answer *ZoneResponse
if req.Payload["init"].(bool) {
answer = &ZoneResponse{
Type: "get_current_user_response",
To: "",
From: "",
Payload: map[string]interface{}{
"user": user,
},
}
} else {
answer = &ZoneResponse{
Type: "get_user_response",
To: "",
From: "",
Payload: map[string]interface{}{
"user": user,
},
}
}
bs, err := json.Marshal(answer)
if err != nil {
return err
}
logger.Println(string(bs))
if _, ok := zuh.DataChannels[req.From]; ok {
if err = zuh.DataChannels[req.From].DataChannel.SendText(string(bs)); err != nil {
return err
}
}
case LIST_ZONE_MEMBERS:
users, err := zuh.DB.ListUsers(0, 0)
if err != nil {
return err
}
bs, err := json.Marshal(&ZoneResponse{
Type: LIST_ZONE_MEMBERS_RESPONSE,
To: "",
From: "",
Payload: map[string]interface{}{
"users": users,
},
})
if err != nil {
return err
}
if _, ok := zuh.DataChannels[req.From]; ok {
if err = zuh.DataChannels[req.From].DataChannel.SendText(string(bs)); err != nil {
return err
}
}
case MODIFY_USER_CHAT_RIGHTS:
}
return
}