|
|
@@ -1,191 +1,281 @@
|
|
|
-import {App} from "./App";
|
|
|
-import {Client} from "./Client";
|
|
|
-
|
|
|
-export class Conversation {
|
|
|
- private app: App;
|
|
|
- private interval = null;
|
|
|
- private syncInterval = null;
|
|
|
-
|
|
|
- id: string;
|
|
|
- initiator: Client;
|
|
|
- recipient: Client;
|
|
|
-
|
|
|
- duration: number = 0;
|
|
|
-
|
|
|
- conversationState: (value?: number) => number;
|
|
|
-
|
|
|
- static readonly STATE_INIT = 0;
|
|
|
- static readonly STATE_RUNNING = 1;
|
|
|
- static readonly STATE_STOPPED = 2;
|
|
|
- static readonly STATE_PAUSED = 3;
|
|
|
-
|
|
|
- constructor(app: App) {
|
|
|
- let state;
|
|
|
- this.app = app;
|
|
|
- this.conversationState = (value?: number) => {
|
|
|
- if (value !== undefined)
|
|
|
- state = value;
|
|
|
- return state;
|
|
|
- };
|
|
|
+import {Interfaces} from "./Interfaces";
|
|
|
+
|
|
|
+export module Conversations {
|
|
|
+
|
|
|
+ export class NullManager implements Interfaces.ConversationsManagerInterface {
|
|
|
+ get(id: string): Promise<Interfaces.ConversationInterface> {
|
|
|
+ return undefined;
|
|
|
+ }
|
|
|
+
|
|
|
+ add(conversation: Interfaces.ConversationInterface) {
|
|
|
+ }
|
|
|
+
|
|
|
+ remove(id: string) {
|
|
|
+ }
|
|
|
+
|
|
|
+ create(initiator: Interfaces.ClientInterface, recipient: Interfaces.ClientInterface): Promise<Interfaces.ConversationInterface> {
|
|
|
+ return undefined;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- init(): Promise<string> {
|
|
|
- return this.app.apiCall('/conversations', {action: 'create'}).then(response => {
|
|
|
- let data = JSON.parse(response);
|
|
|
- return this.app.apiCall('/conversations', {
|
|
|
- action: 'init',
|
|
|
- id: data.id,
|
|
|
- peers: [this.initiator.id, this.recipient.id]
|
|
|
+ export class DefaultManager implements Interfaces.ConversationsManagerInterface {
|
|
|
+ private apiConnector: Interfaces.ApiConnectorInterface;
|
|
|
+ private logger: Interfaces.LoggerInterface;
|
|
|
+ private clientsManager: Interfaces.ClientsManagerInterface;
|
|
|
+ private conversations: { [id: string]: Interfaces.ConversationInterface } = {};
|
|
|
+
|
|
|
+ constructor(apiConnector: Interfaces.ApiConnectorInterface, clientsManager: Interfaces.ClientsManagerInterface, logger: Interfaces.LoggerInterface) {
|
|
|
+ this.apiConnector = apiConnector;
|
|
|
+ this.clientsManager = clientsManager;
|
|
|
+ this.logger = logger;
|
|
|
+ }
|
|
|
+
|
|
|
+ get(id: string): Promise<Conversation> {
|
|
|
+ this.logger.debug(`Get conversation with ID=${id}`);
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (this.conversations.hasOwnProperty(id)) {
|
|
|
+ this.logger.debug(`Conversation with ID=${id} is already in list`);
|
|
|
+ resolve(this.conversations[id]);
|
|
|
+ } else {
|
|
|
+ this.logger.debug(`Load conversation with ID=${id} by API call`);
|
|
|
+ this.apiConnector.execute('/conversations', {action: 'get', id: id})
|
|
|
+ .then((response: string) => {
|
|
|
+ let data = JSON.parse(response);
|
|
|
+ this.clientsManager.get(data.initiatorId).then(initiator => {
|
|
|
+ this.clientsManager.get(data.recipientId).then(recipient => {
|
|
|
+ let conversation = new Conversation(this.apiConnector, initiator, recipient, this.logger, data.id);
|
|
|
+ conversation.duration = parseInt(data.duration);
|
|
|
+ if (data.isStarted == 1 && data.isFinished == 0) {
|
|
|
+ conversation.state = Interfaces.ConversationState.RUNNING();
|
|
|
+ }
|
|
|
+ this.add(conversation);
|
|
|
+ resolve(this.conversations[id]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }).catch(reject);
|
|
|
+ }
|
|
|
});
|
|
|
- });
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- set state(value: number) {
|
|
|
- if ([Conversation.STATE_INIT, Conversation.STATE_RUNNING, Conversation.STATE_PAUSED, Conversation.STATE_STOPPED].indexOf(value) === -1) {
|
|
|
- throw new Error(`State ${value} not in list of possible values.`);
|
|
|
+ create(initiator: Interfaces.ClientInterface, recipient: Interfaces.ClientInterface): Promise<Interfaces.ConversationInterface> {
|
|
|
+ this.logger.debug(`Create new conversation`);
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ this.apiConnector.execute('/conversations', {action: 'create'})
|
|
|
+ .then(response => {
|
|
|
+ let data = JSON.parse(response);
|
|
|
+ this.apiConnector.execute('/conversations', {
|
|
|
+ action: 'init',
|
|
|
+ id: data.id,
|
|
|
+ peers: [initiator.id, recipient.id]
|
|
|
+ }).then(response => {
|
|
|
+ let data = JSON.parse(response);
|
|
|
+ let conversation = new Conversation(this.apiConnector, initiator, recipient, this.logger, data.id);
|
|
|
+ this.add(conversation);
|
|
|
+ resolve(conversation);
|
|
|
+ }).catch(reject);
|
|
|
+ })
|
|
|
+ .catch(reject);
|
|
|
+ });
|
|
|
}
|
|
|
- if (value !== this.state) {
|
|
|
- this.conversationState(value);
|
|
|
- if (value === Conversation.STATE_INIT) {
|
|
|
- this.app.conversations[this.id] = this;
|
|
|
- this.initiator.conversations[this.id] = this;
|
|
|
- this.recipient.conversations[this.id] = this;
|
|
|
- }
|
|
|
- if (value === Conversation.STATE_RUNNING) {
|
|
|
- this.setRunning();
|
|
|
- }
|
|
|
- if (value === Conversation.STATE_STOPPED || value === Conversation.STATE_PAUSED) {
|
|
|
- this.setPaused();
|
|
|
- }
|
|
|
- if (value === Conversation.STATE_STOPPED) {
|
|
|
- this.setStopped();
|
|
|
- }
|
|
|
+
|
|
|
+ add(conversation: Interfaces.ConversationInterface) {
|
|
|
+ this.logger.debug(`Add conversation with ID=${conversation.id}`);
|
|
|
+ this.conversations[conversation.id] = conversation;
|
|
|
+ }
|
|
|
+
|
|
|
+ remove(id: string) {
|
|
|
+ this.logger.debug(`Delete conversation with ID=${id}`);
|
|
|
+ delete this.conversations[id];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private setRunning()
|
|
|
- {
|
|
|
- if (this.interval === null) {
|
|
|
- let lastIntervalTick = Date.now();
|
|
|
- this.interval = setInterval(() => {
|
|
|
- let now = Date.now();
|
|
|
- let interval = (now - lastIntervalTick) / 1000;
|
|
|
- this.duration += interval;
|
|
|
- lastIntervalTick = now;
|
|
|
- this.initiator.payedTime -= Math.ceil(interval * this.recipient.coeficient);
|
|
|
- this.recipient.payedTime += Math.ceil(interval * this.recipient.coeficient);
|
|
|
- if (this.initiator.payedTime < 0) {
|
|
|
- this.state = Conversation.STATE_STOPPED;
|
|
|
+ export class Conversation implements Interfaces.ConversationInterface {
|
|
|
+ private interval = null;
|
|
|
+ private syncInterval = null;
|
|
|
+
|
|
|
+ private _id: string;
|
|
|
+
|
|
|
+ duration: number = 0;
|
|
|
+
|
|
|
+ private conversationState: (value?: Interfaces.ConversationState) => Interfaces.ConversationState;
|
|
|
+
|
|
|
+ private apiConnector: Interfaces.ApiConnectorInterface;
|
|
|
+ private initiator: Interfaces.ClientInterface;
|
|
|
+ private recipient: Interfaces.ClientInterface;
|
|
|
+ private logger: Interfaces.LoggerInterface;
|
|
|
+
|
|
|
+ constructor(apiConnector: Interfaces.ApiConnectorInterface, initiator: Interfaces.ClientInterface, recipient: Interfaces.ClientInterface, logger: Interfaces.LoggerInterface, id: string) {
|
|
|
+ this.apiConnector = apiConnector;
|
|
|
+ this.initiator = initiator;
|
|
|
+ this.recipient = recipient;
|
|
|
+ this.logger = logger;
|
|
|
+ this._id = id;
|
|
|
+ let state = Interfaces.ConversationState.INIT();
|
|
|
+ this.conversationState = (value?: Interfaces.ConversationState) => {
|
|
|
+ if (value !== undefined)
|
|
|
+ state = value;
|
|
|
+ return state;
|
|
|
+ };
|
|
|
+
|
|
|
+ this.state = Interfaces.ConversationState.INIT();
|
|
|
+ }
|
|
|
+
|
|
|
+ getInitiator(): Interfaces.ClientInterface {
|
|
|
+ return this.initiator;
|
|
|
+ }
|
|
|
+
|
|
|
+ getRecipient(): Interfaces.ClientInterface {
|
|
|
+ return this.recipient;
|
|
|
+ }
|
|
|
+
|
|
|
+ get id(): string {
|
|
|
+ return this._id;
|
|
|
+ }
|
|
|
+
|
|
|
+ get state() {
|
|
|
+ return this.conversationState();
|
|
|
+ }
|
|
|
+
|
|
|
+ set state(state: Interfaces.ConversationState) {
|
|
|
+ if (!this.state.isEqualsTo(state)) {
|
|
|
+ this.conversationState(state);
|
|
|
+ if (state.isEqualsTo(Interfaces.ConversationState.INIT())) {
|
|
|
+ }
|
|
|
+ if (state.isEqualsTo(Interfaces.ConversationState.RUNNING())) {
|
|
|
+ this.setRunning();
|
|
|
}
|
|
|
- }, 1000);
|
|
|
+ if (state.isEqualsTo(Interfaces.ConversationState.STOPPED()) || state.isEqualsTo(Interfaces.ConversationState.PAUSED())) {
|
|
|
+ this.setPaused();
|
|
|
+ }
|
|
|
+ if (state.isEqualsTo(Interfaces.ConversationState.STOPPED())) {
|
|
|
+ this.setStopped();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- if (this.syncInterval === null) {
|
|
|
- this.syncInterval = setInterval(() => {
|
|
|
- this.sync();
|
|
|
- }, 5000);
|
|
|
+
|
|
|
+ private setRunning() {
|
|
|
+ this.logger.debug(`Set conversation with ID=${this.id} running`);
|
|
|
+ if (this.interval === null) {
|
|
|
+ let lastIntervalTick = Date.now();
|
|
|
+ this.interval = setInterval(() => {
|
|
|
+ let now = Date.now();
|
|
|
+ let interval = (now - lastIntervalTick) / 1000;
|
|
|
+ this.duration += interval;
|
|
|
+ lastIntervalTick = now;
|
|
|
+ this.initiator.payedTime -= Math.ceil(interval * this.recipient.coefficient);
|
|
|
+ this.recipient.payedTime += Math.ceil(interval * this.recipient.coefficient);
|
|
|
+ if (this.initiator.payedTime < 0) {
|
|
|
+ this.state = Interfaces.ConversationState.STOPPED();
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ if (this.syncInterval === null) {
|
|
|
+ this.syncInterval = setInterval(() => {
|
|
|
+ this.sync();
|
|
|
+ }, 5000);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.apiConnector.execute('/conversations', {id: this.id, action: 'start'});
|
|
|
}
|
|
|
|
|
|
- this.app.apiCall('/conversations', {id: this.id, action: 'start'});
|
|
|
- }
|
|
|
+ private sync() {
|
|
|
+ this.initiator.send('chat-sync-timer', {
|
|
|
+ conversationId: this.id,
|
|
|
+ duration: this.duration
|
|
|
+ });
|
|
|
|
|
|
- private sync() {
|
|
|
- this.initiator.send('chat-sync-timer', {
|
|
|
- conversationId: this.id,
|
|
|
- duration: this.duration
|
|
|
- });
|
|
|
-
|
|
|
- this.recipient.send('chat-sync-timer', {
|
|
|
- conversationId: this.id,
|
|
|
- duration: this.duration
|
|
|
- });
|
|
|
-
|
|
|
- this.app.apiCall('/conversations', {
|
|
|
- id: this.id,
|
|
|
- action: 'duration',
|
|
|
- duration: this.duration
|
|
|
- });
|
|
|
-
|
|
|
- this.app.apiCall('/user', {
|
|
|
- action: 'updatetime',
|
|
|
- id: this.initiator.id,
|
|
|
- value: this.initiator.payedTime
|
|
|
- });
|
|
|
-
|
|
|
- this.app.apiCall('/user', {
|
|
|
- action: 'updatetime',
|
|
|
- id: this.recipient.id,
|
|
|
- value: this.recipient.payedTime
|
|
|
- });
|
|
|
- }
|
|
|
+ this.recipient.send('chat-sync-timer', {
|
|
|
+ conversationId: this.id,
|
|
|
+ duration: this.duration
|
|
|
+ });
|
|
|
|
|
|
- private setPaused()
|
|
|
- {
|
|
|
- clearInterval(this.interval);
|
|
|
- this.interval = null;
|
|
|
- clearInterval(this.syncInterval);
|
|
|
- this.syncInterval = null;
|
|
|
- this.initiator.send('chat-conversation-stop', {id: this.id});
|
|
|
- this.recipient.send('chat-conversation-stop', {id: this.id});
|
|
|
- }
|
|
|
+ this.apiConnector.execute('/conversations', {
|
|
|
+ id: this.id,
|
|
|
+ action: 'duration',
|
|
|
+ duration: this.duration
|
|
|
+ });
|
|
|
|
|
|
- private setStopped()
|
|
|
- {
|
|
|
- delete this.initiator.conversations[this.id];
|
|
|
- delete this.recipient.conversations[this.id];
|
|
|
- delete this.app.conversations[this.id];
|
|
|
- this.app.apiCall('/conversations', {id: this.id, action: 'stop', duration: this.duration});
|
|
|
- this.app.apiCall('/user', {
|
|
|
- action: 'updatetime',
|
|
|
- id: this.initiator.id,
|
|
|
- value: this.initiator.payedTime
|
|
|
- });
|
|
|
- this.app.apiCall('/user', {
|
|
|
- action: 'updatetime', id: this.recipient.id,
|
|
|
- value: this.recipient.payedTime
|
|
|
- });
|
|
|
- }
|
|
|
+ this.apiConnector.execute('/user', {
|
|
|
+ action: 'updatetime',
|
|
|
+ id: this.initiator.id,
|
|
|
+ value: this.initiator.payedTime
|
|
|
+ });
|
|
|
|
|
|
- get state() {
|
|
|
- return this.conversationState();
|
|
|
- }
|
|
|
+ this.apiConnector.execute('/user', {
|
|
|
+ action: 'updatetime',
|
|
|
+ id: this.recipient.id,
|
|
|
+ value: this.recipient.payedTime
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private setPaused() {
|
|
|
+ this.logger.debug(`Set conversation with ID=${this.id} paused`);
|
|
|
+ clearInterval(this.interval);
|
|
|
+ this.interval = null;
|
|
|
+ clearInterval(this.syncInterval);
|
|
|
+ this.syncInterval = null;
|
|
|
+ this.initiator.send('chat-conversation-stop', {id: this.id});
|
|
|
+ this.recipient.send('chat-conversation-stop', {id: this.id});
|
|
|
+ }
|
|
|
|
|
|
- private getPeer(id): Client {
|
|
|
- let peers = [this.initiator, this.recipient];
|
|
|
- for (let i in peers) {
|
|
|
- if (peers.hasOwnProperty(i) && parseInt(peers[i].id) === parseInt(id)) {
|
|
|
- return peers[i];
|
|
|
+ private setStopped() {
|
|
|
+ this.logger.debug(`Set conversation with ID=${this.id} stopped`);
|
|
|
+ delete this.initiator.conversations[this.id];
|
|
|
+ delete this.recipient.conversations[this.id];
|
|
|
+ this.apiConnector.execute('/conversations', {id: this.id, action: 'stop', duration: this.duration});
|
|
|
+ this.apiConnector.execute('/user', {
|
|
|
+ action: 'updatetime',
|
|
|
+ id: this.initiator.id,
|
|
|
+ value: this.initiator.payedTime
|
|
|
+ });
|
|
|
+ this.apiConnector.execute('/user', {
|
|
|
+ action: 'updatetime', id: this.recipient.id,
|
|
|
+ value: this.recipient.payedTime
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private getPeer(id): Interfaces.ClientInterface {
|
|
|
+ let peers = [this.initiator, this.recipient];
|
|
|
+ for (let i in peers) {
|
|
|
+ if (peers.hasOwnProperty(i) && parseInt(peers[i].id) === parseInt(id)) {
|
|
|
+ return peers[i];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- newMessage(message, from, to) {
|
|
|
- this.app.apiCall('/messages', {
|
|
|
- action: 'send',
|
|
|
- conversationId: this.id,
|
|
|
- senderId: from,
|
|
|
- recipientId: to,
|
|
|
- text: message
|
|
|
- }).then(response => {
|
|
|
- let data = JSON.parse(response);
|
|
|
- if (data.isSent) {
|
|
|
- let sender = this.getPeer(data.senderId);
|
|
|
- let recipient = this.getPeer(data.recipientId);
|
|
|
- let messageData = {
|
|
|
- message: data.text,
|
|
|
+ newMessage(message, from, to) {
|
|
|
+ this.logger.debug(`New message to conversation with ID=${this.id}`);
|
|
|
+ if (this.state.isEqualsTo(Interfaces.ConversationState.RUNNING())) {
|
|
|
+ this.apiConnector.execute('/messages', {
|
|
|
+ action: 'send',
|
|
|
conversationId: this.id,
|
|
|
- sender: {
|
|
|
- name: sender.name,
|
|
|
- photo: sender.photo
|
|
|
- },
|
|
|
- recipient: {
|
|
|
- name: recipient.name,
|
|
|
- photo: recipient.photo
|
|
|
+ senderId: from,
|
|
|
+ recipientId: to,
|
|
|
+ text: message
|
|
|
+ }).then(response => {
|
|
|
+ let data = JSON.parse(response);
|
|
|
+ if (data.isSent) {
|
|
|
+ let sender = this.getPeer(data.senderId);
|
|
|
+ let recipient = this.getPeer(data.recipientId);
|
|
|
+ let messageData = {
|
|
|
+ message: data.text,
|
|
|
+ conversationId: this.id,
|
|
|
+ sender: {
|
|
|
+ name: sender.name,
|
|
|
+ photo: sender.photo
|
|
|
+ },
|
|
|
+ recipient: {
|
|
|
+ name: recipient.name,
|
|
|
+ photo: recipient.photo
|
|
|
+ }
|
|
|
+ };
|
|
|
+ this.initiator.sendMessage(messageData);
|
|
|
+ this.recipient.sendMessage(messageData);
|
|
|
}
|
|
|
- };
|
|
|
- this.initiator.sendMessage(messageData);
|
|
|
- this.recipient.sendMessage(messageData);
|
|
|
+ }).catch(this.logger.error);
|
|
|
}
|
|
|
- }).catch(err => console.log(err));
|
|
|
-
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
+}
|
|
|
+
|