UNPKG

globular-mvc

Version:

Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)

662 lines (563 loc) 24.9 kB
import { Conversation, ConnectRequest, Conversations, CreateConversationRequest, Message, CreateConversationResponse, DeleteConversationRequest, DeleteConversationResponse, FindConversationsRequest, FindConversationsResponse, JoinConversationRequest, JoinConversationResponse, ConnectResponse, SendMessageRequest, SendMessageResponse, SendInvitationRequest, Invitation, Invitations, GetReceivedInvitationsRequest, GetReceivedInvitationsResponse, AcceptInvitationRequest, DeclineInvitationRequest, GetSentInvitationsRequest, GetSentInvitationsResponse, RevokeInvitationRequest, RevokeInvitationResponse, LeaveConversationRequest, LeaveConversationResponse, KickoutFromConversationRequest, LikeMessageRqst, DisconnectRequest, DislikeMessageRqst, LikeMessageResponse, DislikeMessageResponse, DeleteMessageRequest, DeleteMessageResponse } from "globular-web-client/conversation/conversation_pb"; import { GetConversationsRequest, GetConversationsResponse } from "globular-web-client/conversation/conversation_pb"; import { Account } from "./Account"; import { generatePeerToken, Model } from "./Model"; import { v4 as uuidv4 } from "uuid"; import { encode } from 'uint8-to-base64'; import { Application } from "./Application"; import { Globular } from "globular-web-client"; export class ConversationManager { public static uuid: string; private static conversations: Map<string, Conversation> = new Map<string, Conversation>() constructor() { } // Open conversation channels with each globule. static connect(errorCallback: (err: any) => void) { let __connect__ = (globule:Globular)=>{ generatePeerToken(globule, token => { // This will open the connection with the conversation manager. let rqst = new ConnectRequest rqst.setUuid(ConversationManager.uuid) let stream = globule.conversationService.connect(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }) stream.on("data", (rsp: ConnectResponse) => { /** Local event... */ Model.globular.eventHub.publish(`__received_message_${rsp.getMsg().getConversation()}_evt__`, rsp.getMsg(), true) }); stream.on("status", (status) => { if (status.code != 0) { errorCallback(status.details) } }); }, errorCallback) } ConversationManager.uuid = uuidv4(); Model.getGlobules().forEach(globule => { __connect__(globule) }) // connect / reconnect to globule that get online. Model.eventHub.subscribe("start_peer_evt_", uuid => { }, evt => { let globule = Model.getGlobule(evt.getDomain()) __connect__(globule) }, false) } /** * Create a new conversation. * @param name * @param keywords * @param language * @param succesCallback * @param errorCallback */ static createConversation(name: string, keywords: Array<string>, language: any, succesCallback: (conversation: Conversation) => void, errorCallback: (err: any) => void) { let rqst = new CreateConversationRequest rqst.setName(name) rqst.setKeywordsList(keywords) rqst.setLanguage("en") Model.globular.conversationService.createConversation(rqst, { token: localStorage.getItem("user_token"), application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: CreateConversationResponse) => { succesCallback(rsp.getConversation()) }).catch(errorCallback) } /** * Load conversations of a given account. * @param account Must by the logged account. * @param succesCallback Return the list of conversation owned by the account. * @param errorCallback Error if any. */ private static loadConversations_(globule: Globular, account: Account, succesCallback: (conversations: Conversations) => void, errorCallback: (err: any) => void) { let rqst = new GetConversationsRequest rqst.setCreator(account.id + "@" + account.domain); globule.conversationService.getConversations(rqst, { token: localStorage.getItem("user_token"), application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: GetConversationsResponse) => { // Keep conversation in the map... rsp.getConversations().getConversationsList().forEach((conversation: Conversation) => { ConversationManager.conversations.set(conversation.getUuid(), conversation) }); succesCallback(rsp.getConversations()) }).catch((err: any) => { // return an empty conversation array... succesCallback(new Conversations) }) } static loadConversations(account: Account, succesCallback: (conversations: Array<Conversation>) => void, errorCallback: (err: any) => void) { let globules = Model.getGlobules() let conversations = new Array<Conversation>() let loadConversations = () => { let globule = globules.pop() ConversationManager.loadConversations_(globule, account, (converstions_) => { conversations = conversations.concat(converstions_.getConversationsList()) if (globules.length > 0) { loadConversations() } else { succesCallback(conversations) } }, err => { if (globules.length > 0) { console.log(err) loadConversations() } else { succesCallback(conversations) } }) } // call once loadConversations() } static deleteConversation(conversation: Conversation, succesCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) let conversationUuid = conversation.getUuid() let rqst = new DeleteConversationRequest rqst.setConversationUuid(conversationUuid) globule.conversationService.deleteConversation(rqst, { token: localStorage.getItem("user_token"), application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: DeleteConversationResponse) => { succesCallback() // remove it from the map... ConversationManager.conversations.delete(conversation.getUuid()) // Here the conversation has been deleted... // Model.eventHub.publish(`delete_conversation_${conversationUuid}_evt`, conversationUuid, false) Model.eventHub.publish(`__delete_conversation_${conversationUuid}_evt__`, conversationUuid, true) }).catch((err: any) => { succesCallback() Model.eventHub.publish(`__leave_conversation_evt__`, conversationUuid, true) Model.eventHub.publish(`__delete_conversation_${conversationUuid}_evt__`, conversationUuid, true) }) } static kickoutFromConversation(conversation: Conversation, account: string, succesCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let conversationUuid = conversation.getUuid() let rqst = new KickoutFromConversationRequest rqst.setConversationUuid(conversationUuid) rqst.setAccount(account) globule.conversationService.kickoutFromConversation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: DeleteConversationResponse) => { succesCallback() Model.publish(`kickout_conversation_${conversationUuid}_evt`, { accountId: account, conversationUuid: conversationUuid }, false) }).catch(errorCallback) }, errorCallback) } private static findConversations_(globule: Globular, query: string, succesCallback: (conversations: Conversation[]) => void, errorCallback: (err: any) => void) { generatePeerToken(globule, token => { let rqst = new FindConversationsRequest rqst.setQuery(query) rqst.setOffset(0) rqst.setLanguage(window.navigator.language.split("-")[0]) rqst.setPagesize(500); rqst.setSnippetsize(500); // not realy necessary here... globule.conversationService.findConversations(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: FindConversationsResponse) => { succesCallback(rsp.getConversationsList()) }).catch((err: any) => { errorCallback(err) }) }, errorCallback) } static findConversations(query: string, successCallback: (conversations: Conversation[]) => void, errorCallback: (err: any) => void) { let globules = Model.getGlobules() let conversations = new Array<Conversation>() let findConversations = () => { let globule = globules.pop() ConversationManager.findConversations_(globule, query, conversations_ => { conversations = conversations.concat(conversations_) if (globules.length > 0) { findConversations() } else { successCallback(conversations) } }, err => { if (globules.length > 0) { findConversations() } else { if (conversations.length > 0) { successCallback(conversations) } else { errorCallback(err) } } }) } findConversations() } /** * Join a conversation * @param conversation The conversation with given uuid * @param succesCallback On success callback * @param errorCallback On error callback */ static joinConversation(conversation: Conversation, succesCallback: (conversation: Conversation, messages: Message[]) => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let conversationUuid = conversation.getUuid() let rqst = new JoinConversationRequest rqst.setConnectionUuid(ConversationManager.uuid) rqst.setConversationUuid(conversationUuid) let stream = globule.conversationService.joinConversation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }) // Now I will get existing message from the conversation. var messages = new Array<Message>(); stream.on("data", (rsp: JoinConversationResponse) => { if (rsp.getConversation() != undefined) { conversation = rsp.getConversation(); } if (rsp.getMsg() != undefined) { messages.push(rsp.getMsg()) } }); stream.on("status", (status) => { if (status.code == 0) { succesCallback(conversation, messages) let participants = conversation.getParticipantsList() // network event. Model.getGlobule(conversation.getMac()).eventHub.publish(`ready_conversation_${conversationUuid}_evt`, JSON.stringify({ "participants": participants, "participant": Application.account.id + "@" + Application.account.domain }), false) } else { // No message found... if (status.details == "EOF") { succesCallback(conversation, messages) let participants = conversation.getParticipantsList() // network event. Model.getGlobule(conversation.getMac()).eventHub.publish(`leave_conversation_${conversationUuid}_evt`, JSON.stringify({ "conversationUuid": conversation.getUuid(), "participants": participants, "participant": Application.account.id + "@" + Application.account.domain }), false) return } // An error happen errorCallback(status.details) } }) }, errorCallback) } // leave the conversation. static leaveConversation(conversation: Conversation, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let conversationUuid = conversation.getUuid() let rqst = new LeaveConversationRequest rqst.setConversationUuid(conversationUuid) rqst.setConnectionUuid(ConversationManager.uuid) globule.conversationService.leaveConversation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: LeaveConversationResponse) => { successCallback(); let participants = rsp.getConversation().getParticipantsList() // network event. Model.getGlobule(conversation.getMac()).eventHub.publish(`leave_conversation_${conversationUuid}_evt`, JSON.stringify({ "conversationUuid": conversation.getUuid(), "participants": participants, "participant": Application.account.id + "@" + Application.account.domain }), false) }).catch(errorCallback) }, errorCallback) } // Send a conversation invitation to a given user. static sendConversationInvitation(conversation: Conversation, from: string, to: string, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let rqst = new SendInvitationRequest let invitation = new Invitation invitation.setFrom(from) invitation.setTo(to) invitation.setConversation(conversation.getUuid()) invitation.setName(conversation.getName()) invitation.setMac(conversation.getMac()) rqst.setInvitation(invitation) globule.conversationService.sendInvitation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: SendMessageResponse) => { /** Nothing to do here... */ successCallback() const encoded = encode(invitation.serializeBinary()); // publish network event. Model.publish(`send_conversation_invitation_${from}_evt`, encoded, false) Model.publish(`receive_conversation_invitation_${to}_evt`, encoded, false) }).catch(errorCallback) }, errorCallback) } /** * Get the list of received invitations. * @param accountId The account id * @param successCallback * @param errorCallback */ private static getReceivedInvitations_(globule: Globular, accountId: string, successCallback: (invitations: Array<Invitation>) => void, errorCallback: (err: any) => void) { generatePeerToken(globule, token => { let rqst = new GetReceivedInvitationsRequest rqst.setAccount(accountId); globule.conversationService.getReceivedInvitations(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: GetReceivedInvitationsResponse) => { /** Nothing to do here... */ successCallback(rsp.getInvitations().getInvitationsList()) }).catch((err: any) => { successCallback([]) }) }, errorCallback) } static getReceivedInvitations(accountId: string, successCallback: (invitations: Array<Invitation>) => void, errorCallback: (err: any) => void) { let globules = Model.getGlobules() let invitations = new Array<Invitation>() let getReceivedInvitations = () => { let globule = globules.pop() ConversationManager.getReceivedInvitations_(globule, accountId, invitations_ => { invitations = invitations.concat(invitations_) if (globules.length > 0) { getReceivedInvitations() } else { successCallback(invitations) } }, err => { console.log(err) if (globules.length > 0) { getReceivedInvitations() } else { successCallback(invitations) } }) } getReceivedInvitations() } /** * Get the list of sent invitations. * @param accountId The account id * @param successCallback * @param errorCallback */ private static getSentInvitations_(globule: Globular, accountId: string, successCallback: (invitation: Array<Invitation>) => void, errorCallback: (err: any) => void) { generatePeerToken(globule, token => { let rqst = new GetSentInvitationsRequest rqst.setAccount(accountId); globule.conversationService.getSentInvitations(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: GetSentInvitationsResponse) => { /** Nothing to do here... */ successCallback(rsp.getInvitations().getInvitationsList()) }).catch((err: any) => { successCallback([]) }) }, errorCallback) } static getSentInvitations(accountId: string, successCallback: (invitation: Array<Invitation>) => void, errorCallback: (err: any) => void) { let globules = Model.getGlobules() let invitations = new Array<Invitation>() let getSentInvitations = () => { let globule = globules.pop() ConversationManager.getSentInvitations_(globule, accountId, invitations_ => { invitations = invitations.concat(invitations_) if (globules.length > 0) { getSentInvitations() } else { successCallback(invitations) } }, err => { console.log(err) if (globules.length > 0) { getSentInvitations() } else { successCallback(invitations) } }) } getSentInvitations() } /** * Conversation invitation is accepted! * @param invitation The invitation * @param successCallback The success callback. * @param errorCallback The error callback. */ static acceptConversationInvitation(invitation: Invitation, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(invitation.getMac()) generatePeerToken(globule, token => { let rqst = new AcceptInvitationRequest rqst.setInvitation(invitation); globule.conversationService.acceptInvitation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: AcceptInvitationRequest) => { /** Nothing to do here... */ successCallback() }).catch(errorCallback) }, errorCallback) } /** * The conversation invitation was declined! * @param invitation The invitation. * @param successCallback The success callback * @param errorCallback The error callback */ static declineConversationInvitation(invitation: Invitation, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(invitation.getMac()) generatePeerToken(globule, token => { let rqst = new DeclineInvitationRequest rqst.setInvitation(invitation); globule.conversationService.declineInvitation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: AcceptInvitationRequest) => { /** Nothing to do here... */ successCallback() }).catch(errorCallback) }, errorCallback) } static revokeConversationInvitation(invitation: Invitation, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(invitation.getMac()) generatePeerToken(globule, token => { let rqst = new RevokeInvitationRequest rqst.setInvitation(invitation); globule.conversationService.revokeInvitation(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: RevokeInvitationResponse) => { /** Nothing to do here... */ successCallback() }).catch(errorCallback) }, errorCallback) } static likeIt(conversationUuid: string, message: string, account: string, successCallback: () => void, errorCallback: (err: any) => void) { let conversation = ConversationManager.conversations.get(conversationUuid) let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let rqst = new LikeMessageRqst rqst.setMessage(message) rqst.setConversation(conversation.getUuid()) rqst.setAccount(account) globule.conversationService.likeMessage(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: LikeMessageResponse) => { if (successCallback != undefined) { successCallback() } }).catch(errorCallback) }, errorCallback) } static dislikeIt(conversationUuid: string, message: string, account: string, successCallback: () => void, errorCallback: (err: any) => void) { let conversation = ConversationManager.conversations.get(conversationUuid) let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let rqst = new DislikeMessageRqst rqst.setMessage(message) rqst.setConversation(conversation.getUuid()) rqst.setAccount(account) globule.conversationService.dislikeMessage(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: DislikeMessageResponse) => { if (successCallback != undefined) { successCallback() } }).catch(errorCallback) }, errorCallback) } static deleteMessage(msg: Message, successCallback: () => void, errorCallback: (err: any) => void) { // Retreive the conversation from the map let conversation = ConversationManager.conversations.get(msg.getConversation()) // Retreive the conversation host... let globule = Model.getGlobule(conversation.getMac()) generatePeerToken(globule, token => { let rqst = new DeleteMessageRequest rqst.setUuid(msg.getUuid()) rqst.setConversation(msg.getConversation()) globule.conversationService.deleteMessage(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: DeleteMessageResponse) => { if (successCallback != undefined) { successCallback() } // Simply send event on the network... Model.publish(`delete_message_${msg.getUuid()}_evt`, null, false) }).catch(errorCallback) }, errorCallback) } static sendMessage(conversation: Conversation, author: Account, text: string, replyTo: string, successCallback: () => void, errorCallback: (err: any) => void) { let globule = Model.getGlobule(conversation.getMac()) let conversationUuid = conversation.getUuid() generatePeerToken(globule, token => { let rqst = new SendMessageRequest let message = new Message let uuid = uuidv4(); if (replyTo.length > 0) { uuid = replyTo + "/" + uuid } message.setUuid(uuid) message.setConversation(conversationUuid) message.setText(text) message.setInReplyTo(replyTo) message.setCreationTime(Math.round(Date.now() / 1000)); message.setAuthor(author.id + "@" + author.domain); message.setLanguage(window.navigator.language.split("-")[0]); message.setDislikesList(new Array<string>()); message.setLikesList(new Array<string>()); message.setReadersList([author.id + "@" + author.domain]); rqst.setMsg(message) globule.conversationService.sendMessage(rqst, { token: token, application: Model.application, domain: Model.domain, address: Model.address }).then((rsp: SendMessageResponse) => { /** Nothing to do here... */ }).catch(errorCallback) }, errorCallback) } } /** * Here I will create the signaling server use in conjunction with each other. */ export class SignalingServer { constructor() { } }