131 lines
3.7 KiB
TypeScript
131 lines
3.7 KiB
TypeScript
import { ChangeDetectorRef, Component, OnInit, EventEmitter, Output } from '@angular/core';
|
|
import { MessageConfig, MessageData, Message, MessageQueue } from '../message-types/bot-messages';
|
|
import { MarkdownService } from '../services/markdown.service';
|
|
import { WebSocketService } from '../services/websocket.service';
|
|
|
|
import { config } from '../config';
|
|
import { Subject, Observer, BehaviorSubject } from 'rxjs';
|
|
|
|
@Component({
|
|
selector: 'app-messages',
|
|
templateUrl: './messages.component.html',
|
|
styleUrls: ['./messages.component.scss']
|
|
})
|
|
export class MessagesComponent implements OnInit {
|
|
@Output() newMessageEvent: EventEmitter<any> = new EventEmitter();
|
|
newMessage: Subject<MessageData> = new Subject<MessageData>();
|
|
messageInQueue = true;
|
|
|
|
originator = 'avataobot';
|
|
messages: MessageData[] = [];
|
|
messageQueueAttender: MessageQueueAttender;
|
|
|
|
command_handlers = {
|
|
'message.queue': this.handleQueueMessage.bind(this),
|
|
'message.config': this.configureMessages.bind(this),
|
|
'message.send': () => {}
|
|
};
|
|
|
|
constructor(
|
|
private markdownService: MarkdownService,
|
|
private websocketService: WebSocketService,
|
|
private changeDetectorRef: ChangeDetectorRef
|
|
) {
|
|
this.messageQueueAttender = new MessageQueueAttender(this.newMessage);
|
|
}
|
|
|
|
ngOnInit() {
|
|
this.newMessage.subscribe(
|
|
message => {
|
|
this.writeMessage(message);
|
|
this.newMessageEvent.emit();
|
|
});
|
|
this.messageQueueAttender.messageInQueue.subscribe(
|
|
(value) => this.messageInQueue = value
|
|
);
|
|
|
|
this.websocketService.connect();
|
|
this.websocketService.observeKey<Message>('message.send').subscribe(
|
|
message => this.newMessage.next(message)
|
|
);
|
|
this.websocketService.observeKey<MessageQueue>('message').subscribe(
|
|
message => this.command_handlers[message.key](message)
|
|
);
|
|
}
|
|
|
|
writeMessage(message: MessageData) {
|
|
this.transformMessage(message);
|
|
this.messages.push(message);
|
|
this.changeDetectorRef.detectChanges();
|
|
}
|
|
|
|
transformMessage(message: MessageData) {
|
|
message.message = this.convertMarkdownToHTML(message.message);
|
|
if (!message.originator) {
|
|
message.originator = this.originator;
|
|
}
|
|
if (!message.timestamp) {
|
|
message.timestamp = new Date();
|
|
}
|
|
}
|
|
|
|
handleQueueMessage(message: MessageQueue) {
|
|
this.messageQueueAttender.queueMessages(message.value);
|
|
}
|
|
|
|
configureMessages(message: MessageConfig) {
|
|
if (message.originator) {
|
|
this.originator = message.originator;
|
|
}
|
|
}
|
|
|
|
convertMarkdownToHTML(text: string) {
|
|
return this.markdownService.convertToHtml(text);
|
|
}
|
|
}
|
|
|
|
|
|
class MessageQueueAttender {
|
|
public messageInQueue = new BehaviorSubject<boolean>(false);
|
|
|
|
private readonly charPerSecond: number;
|
|
private lastMessageLength = 0;
|
|
private queue: MessageData[] = [];
|
|
|
|
constructor(private messageEmitter: Observer<MessageData>, wordPerMinute: number = config.messages.messageQueueWPM) {
|
|
const charPerMinute = wordPerMinute * 5;
|
|
this.charPerSecond = charPerMinute / 60;
|
|
}
|
|
|
|
queueMessages(messages: Array<MessageData>) {
|
|
this.queue = this.queue.concat(messages);
|
|
this.attendQueue();
|
|
}
|
|
|
|
private processMessage() {
|
|
if (this.queue.length > 0) {
|
|
const lastMessage = this.queue.shift();
|
|
this.lastMessageLength = lastMessage.message.length;
|
|
this.messageEmitter.next(lastMessage);
|
|
}
|
|
if (this.queue.length === 0) {
|
|
this.lastMessageLength = 0;
|
|
this.messageInQueue.next(false);
|
|
}
|
|
}
|
|
|
|
private attendQueue() {
|
|
if (this.queue.length > 0) {
|
|
this.messageInQueue.next(true);
|
|
const timeoutSeconds = this.lastMessageLength / this.charPerSecond;
|
|
setTimeout(
|
|
() => {
|
|
this.processMessage();
|
|
this.attendQueue();
|
|
},
|
|
timeoutSeconds * 1000
|
|
);
|
|
}
|
|
}
|
|
}
|