import { ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core'; import { WebSocketService } from '../services/websocket.service'; import { WebSocketMessage } from '../message-types/websocket-message'; import { IDEMessage } from '../message-types/ide-message'; import { ProcessManagerService } from '../services/processmanager.service'; import { DeploymentNotificationService } from '../services/deployment-notification.service'; import { config } from '../config'; import { LanguageMap } from './language-map'; import { filter, first } from 'rxjs/operators'; enum DeployButtonState { DEPLOYED, DEPLOYING, FAILED, TODEPLOY } enum CodeState { SAVED, DIRTY } @Component({ selector: 'app-ide', templateUrl: './ide.component.html', styleUrls: ['./ide.component.scss'] }) export class IdeComponent implements OnInit { CodeState = CodeState; DeployButtonState = DeployButtonState; files: string[]; filename = ''; code: string = config.ide.defaultCode; codeState = CodeState.SAVED; deployButtonState = DeployButtonState.DEPLOYED; deployButtonText = config.ide.deployButtonText; showDeployButton: boolean = config.ide.showDeployButton; autosave = null; editorOptions = { theme: 'vs-dark', language: config.ide.defaultLanguage, glyphMargin: false, minimap: {enabled: config.ide.showMiniMap} }; @Output() newLogs = new EventEmitter(); command_handlers = { 'ide.reload': this.reloadHandler.bind(this), 'ide.read': this.readHandler.bind(this), 'ide.write': this.writeHandler.bind(this), }; constructor(private webSocketService: WebSocketService, private changeDetectorRef: ChangeDetectorRef, private processManagerService: ProcessManagerService, private deploymentNotificationService: DeploymentNotificationService) { } ngOnInit() { this.webSocketService.connect(); this.subscribeWS(); this.subscribeFirstLanguageDetection(); this.requestCode(); this.initProcessManagerService(); this.resetAutoSaveCountdown(); } subscribeWS() { this.webSocketService.observeKey('ide').subscribe(message => { this.command_handlers[message.key](message); this.changeDetectorRef.detectChanges(); }); } subscribeFirstLanguageDetection() { this.webSocketService.observeKey('ide.read').pipe(first()).subscribe( () => this.autoDetectEditorLanguageIfEnabled(this.filename) ); } initProcessManagerService() { this.processManagerService.init(); this.processManagerService.subscribeCallback( config.ide.deployProcessName, message => { this.deploymentNotificationService.deploying.next(false); this.newLogs.emit({ stdout: message.stdout, stderr: message.stderr }); } ); this.processManagerService.subscribeSuccessCallback( config.ide.deployProcessName, message => this.setDeployButtonState(DeployButtonState.DEPLOYED) ); this.processManagerService.subscribeErrorCallback( config.ide.deployProcessName, () => this.setDeployButtonState(DeployButtonState.FAILED) ); } reloadHandler(message: WebSocketMessage) { this.requestCode(); } readHandler(message: IDEMessage) { if (this.codeState === CodeState.SAVED) { if (this.filename !== message.filename) { this.filename = message.filename; } this.code = (message.content != null) ? message.content : this.code; this.files = message.files; } } writeHandler(message: IDEMessage) { this.setCodeState(CodeState.SAVED); } autoDetectEditorLanguageIfEnabled(filename: string) { if (!config.ide.autoDetectFileLanguage) { return; } const extension = filename.substr(filename.lastIndexOf('.') + 1); let language = LanguageMap[extension]; language = (language === undefined) ? 'text' : language; this.setEditorLanguage(language); } setEditorLanguage(lang: string) { this.editorOptions = Object.assign( {}, this.editorOptions, { language: lang } ); } resetAutoSaveCountdown() { if (this.autosave) { clearInterval(this.autosave); } this.autosave = setInterval( () => { this.sendCodeIfDirty(); }, config.ide.autoSaveInterval ); } tabSwitchButtonHandler(file: string) { if (this.codeState === CodeState.DIRTY) { this.sendCodeContents(); } this.filename = file; this.requestCode(); this.autoDetectEditorLanguageIfEnabled(this.filename); } editorWriteHandler() { this.setCodeState(CodeState.DIRTY); this.setDeployButtonState(DeployButtonState.TODEPLOY); this.resetAutoSaveCountdown(); } setCodeState(state: CodeState) { this.codeState = state; } setDeployButtonState(state: DeployButtonState) { this.deployButtonState = state; } deployCode() { this.processManagerService.restartProcess(config.ide.deployProcessName); this.setDeployButtonState(DeployButtonState.DEPLOYING); this.deploymentNotificationService.deploying.next(true); } sendCodeIfDirty() { if (this.codeState === CodeState.DIRTY) { this.sendCodeContents(); } } pathBasename(path: string) { return path.split('/').reverse()[0]; } sendCodeContents() { this.webSocketService.sendJSON({ 'key': 'ide.write', 'filename': this.filename, 'content': this.code }); } requestCode() { this.webSocketService.sendJSON({ 'key': 'ide.read', 'filename': this.filename }); } }