const { Message } = require("./Message");
const { MessageType } = require("./MessageType");
const { TransactionMessage } = require("./TransactionMessage");
const { Dictionary } = require("./Dictionary");
const { List } = require("./List");
const { HashSet } = require("./HashSet");
const { Out } = require("./Out");
/**
* @class MessageManager
*/
class MessageManager {
constructor(cloud) {
this.lastRequest = new Date(0);
this.lastUnreadMessage = new Date(0);
this.UnreadMessageCountChanged = null;
this.InitialmessagesFetched = new Boolean();
this.UnreadCountByUser = new Dictionary();
this.TotalUnreadCount = 0;
Object.defineProperties(this, {
_messagesLock: {
value: new Object(),
writable: false,
},
Cloud: {
value: cloud,
enumerable: false,
writable: true,
},
_messages: {
value: new Dictionary(),
writable: true,
},
_unreadCountDirty: {
value: false,
writable: true,
},
_waitingForRequest: {
value: false,
writable: true,
},
});
}
static get UPDATE_PERIOD_SECONDS() {
return 1;
}
static get UPDATE_TIMEOUT_SECONDS() {
return 30;
}
static get MAX_READ_HISTORY() {
return 100;
}
static get MAX_UNREAD_HISTORY() {
return 200;
}
MessageManager(cloud) {
Object.defineProperties(this, {
Cloud: {
value: cloud,
enumerable: false,
writable: true,
},
});
}
Update() {
if (this.Cloud.CurrentUser == null) return;
if (this._unreadCountDirty) {
this._unreadCountDirty = false;
this.TotalUnreadCount = this._messages.Reduce((p, m) => {
return p + m.Value.UnreadCount;
}, 0);
for (let m of this._messages) {
if (m.Value.UnreadCount === 0)
this.UnreadCountByUser.TryRemove(m.Key, []);
else
this.UnreadCountByUser.AddOrUpdate(
m.Key,
m.Value.UnreadCount,
() => m.Value.UnreadCount
);
}
let messageCountChanged = this.UnreadMessageCountChanged;
if (messageCountChanged != null)
messageCountChanged(this.TotalUnreadCount);
}
if (
new Date(new Date() - this.lastRequest).getTime() / 1000 <
(this._waitingForRequest
? MessageManager.UPDATE_TIMEOUT_SECONDS
: MessageManager.UPDATE_PERIOD_SECONDS)
)
return;
this.lastRequest = new Date();
this._waitingForRequest = true;
(async () => {
//Async Task
var cloudresult1 = await this.Cloud.GetUnreadMessages(
this.lastUnreadMessage
);
this._waitingForRequest = false; //Async Limiting Tomfoolery
if (cloudresult1.IsError) return; //Bad Request
var hashSet = new HashSet();
for (let message of cloudresult1.Entity) {
this.lastUnreadMessage =
this.lastUnreadMessage != null
? new Date(Math.max(this.lastUnreadMessage, message.LastUpdateTime))
: new Date(message.LastUpdateTime);
if (!this.GetUserMessages(message.SenderId).AddMessage(message)) {
hashSet.Add(message);
}
}
let flag1 = false;
for (let message of cloudresult1.Entity) {
if (!hashSet.Contains(message)) {
if (
this.InitialMessagesFetched &&
message.MessageType == MessageType.CreditTransfer
) {
let content = message.ExtractContent();
let flag2 = content.RecepientId == this.Cloud.CurrentUser.Id;
let currentUser = this.Cloud.CurrentUser;
if (
currentUser.Credits != null &&
currentUser.Credits.ContainsKey(content.Token)
)
currentUser.Credits.AddOrUpdate(
content.Token,
flag2 ? content.Amount : -content.Amount,
(key, value) =>
flag2 ? value + content.Amount : value - content.Amount
);
flag1 = true;
}
let onMessageReceived = this.OnMessageReceived;
if (onMessageReceived != null) {
onMessageReceived(message);
}
let friend = this.Cloud.Friends.GetFriend(message.SenderId);
if (friend != null)
friend.LatestMessageTime = Math.max(new Date(), message.SendTime);
}
}
this.MarkUnreadCountDirty();
this.InitialmessagesFetched = true;
if (!flag1) return;
await setTimeout(async () => {
await this.Cloud.UpdateCurrentUserInfo();
}, 10000);
})();
}
MarkUnreadCountDirty() {
Object.defineProperties(this, {
_unreadCountDirty: {
value: true,
writable: true,
},
});
}
Reset() {
Object.defineProperties(this, {
_messages: {
value: new Dictionary(),
writable: true,
},
});
this.lastUnreadMessage = new Date(0);
this.InitialmessagesFetched = false;
}
GetUserMessages(userId) {
let usermessages1 = new Out();
if (this._messages.TryGetValue(userId, usermessages1)) {
return usermessages1.Out;
}
let usermessages2 = new MessageManager.UserMessages();
usermessages2.UserMessages(userId, this);
this._messages.Add(userId, usermessages2);
return usermessages2;
}
/**.
*
*
* @param {List} list
* @memberof MessageManager
*/
GetAllUserMessages(list) {
for (let message of this._messages) {
list.push(message.Value);
}
}
//event OnMessageReceived
//event UnreadMessageCounrChange
static get UserMessages() {
return UserMessages;
}
}
class UserMessages {
constructor() {
this.UserId = new String();
this.UnreadCount = 0;
this.Messages = new List();
Object.defineProperties(this, {
_messageIds: {
value: new List(),
writable: false,
},
_lock: {
value: "MessageManager.UserMessages._lock",
writable: false,
},
_historyLoadTask: {
value: null,
writable: true,
},
_historyLoaded: {
value: false,
writable: true,
},
});
}
get CloudXInterface() {
return this.Manager.Cloud;
}
UserMessages(userId, manager) {
this.UserId = userId;
Object.defineProperties(this, {
Manager: {
value: manager,
writable: true,
enumerable: false,
},
});
}
MarkAllRead() {
let ids = null;
if (this.UnreadCount === 0) return;
ids = new Array();
for (let message of this.Messages) {
if (!message.IsSent && !(message.ReadTime != null)) {
message.ReadTime = new Date();
ids.push(message.Id);
}
}
this.UnreadCount = 0;
(async () => {
await this.Manager.Cloud.MarkMessagesRead(ids);
})();
this.Manager.MarkUnreadCountDirty();
}
CreateTextMessage(text) {
let message = new Message();
message.MessageType = "Text";
message.Content = text;
return message;
}
CreateInviteMessage(sessionInfo) {
let message = new Message();
message.Id = Message.GenerateId();
message.SendTime = new Date();
message.MessageType = "SessionInvite";
message.SetContent(sessionInfo);
return message;
}
async SendInviteMessage(sessionInfo) {
return await this.SendMessage(this.CreateInviteMessage(sessionInfo));
}
AddSentTransactionMessage(token, amount, comment) {
let message = new Message();
message.Id = Message.GenerateId();
message.OwnerId = this.Manager.Cloud.CurrentUser.Id;
message.RecipientId = this.UserId;
message.SenderId = message.OwnerId;
message.SendTime = new Date();
message.MessageType = "CreditTransfer";
let _transaction = new TransactionMessage();
_transaction.Token = token;
_transaction.Amount = amount;
_transaction.Comment = comment;
_transaction.RecipientId = this.UserId;
_transaction.TransactionType = "User2User";
message.SetContent(_transaction);
this.Messages.push(message);
return message;
}
async SendMessage(message) {
if (message.Id == null) message.Id = Message.GenerateId();
message.RecipientId = this.UserId;
message.SenderId = this.CloudXInterface.CurrentUser.Id;
message.OwnerId = message.SenderId;
message.SendTime = new Date();
this.Messages.push(message);
let friend = this.Manager.Cloud.Friends.GetFriend(message.RecipientId);
if (friend != null) friend.LatestMessageTime = new Date();
return await this.Manager.Cloud.SendMessage(message);
}
async SendTextMessage(text) {
return await this.SendMessage(this.CreateTextMessage(text));
}
async EnsureHistory() {
if (this._historyLoaded) return;
let isFirstRequest = false;
if (this._historyLoaded) return;
if (this._historyLoadTask == null) {
isFirstRequest = true;
this._historyLoadTask = this.Manager.Cloud.GetMessageHistory(
this.UserId,
MessageManager.MAX_READ_HISTORY
);
}
let cloudResult = await this._historyLoadTask;
if (!isFirstRequest) return;
if (cloudResult.IsError) {
this._historyLoadTask = null;
} else {
this.Messages = cloudResult.Entity;
this.Messages.reverse();
this.UnreadCount = this.Messages.filter(
(m) => !(m.ReadTime != null)
).length;
this._historyLoaded = true;
}
}
AddMessage(message) {
if (this._messageIds.includes(message.Id)) {
return false;
}
this.Messages.Add(message);
this._messageIds.Add(message.Id);
if (message.IsReceived && !(message.ReadTime != null)) ++this.UnreadCount;
while (
this.Messages.length > MessageManager.MAX_UNREAD_HISTORY ||
(this.Messages.length > MessageManager.MAX_UNREAD_HISTORY &&
(this.Messages[0].IsSent || this.Messages[0].ReadTime != null))
) {
this._messageIds.Remove(this.Messages[0].Id);
this.Messages.RemoveAt(0);
}
return true;
}
GetMessages(messages) {
messages.AddRange(this.Messages);
}
}
module.exports = {
MessageManager,
};