From d772a0d9df4fa284fd71009df1537e6efb04b2eb Mon Sep 17 00:00:00 2001
From: ziajka <dominik@gns3.net>
Date: Mon, 11 Feb 2019 14:53:45 +0100
Subject: [PATCH] Basic starting and stopping servers on UI

---
 local-server.js                               | 46 ++++++++++++++++++
 main.js                                       | 48 -------------------
 .../components/servers/add-server-dialog.html |  4 ++
 .../components/servers/servers.component.html |  8 ++++
 .../components/servers/servers.component.ts   | 33 ++++++++++++-
 src/app/models/server.ts                      |  2 +
 src/app/services/server.database.ts           |  8 ++++
 7 files changed, 100 insertions(+), 49 deletions(-)

diff --git a/local-server.js b/local-server.js
index d3abe038..2cc5a639 100644
--- a/local-server.js
+++ b/local-server.js
@@ -1,8 +1,50 @@
 const { spawn } = require('child_process');
 const kill = require('tree-kill');
+const path = require('path');
+const fs = require('fs');
+const { ipcMain } = require('electron')
+
+const isWin = /^win/.test(process.platform);
 
 let runningServers = {};
 
+
+exports.getLocalServerPath = async () => {
+  const distDirectory = path.join(__dirname, 'dist');
+  if (!fs.existsSync(distDirectory)) {
+    return;
+  }
+
+  const files = fs.readdirSync(distDirectory);
+  
+  let serverPath = null;
+
+  files.forEach((directory) => {
+    if(directory.startsWith('exe.')) {
+      if (isWin) {
+        serverPath = path.join(__dirname, 'dist', directory, 'gns3server.exe');
+      }
+      else {
+        serverPath = path.join(__dirname, 'dist', directory, 'gns3server');
+      }
+    }
+  });
+
+  if(serverPath !== null && fs.existsSync(serverPath)) {
+    return serverPath;
+  }
+
+  return;
+}
+
+exports.startLocalServer = async (server) => {
+  return await run(server);
+}
+
+exports.stopLocalServer = async (server) => {
+  return await stop(server);
+}
+
 function getServerArguments(server, overrides) {
     let serverArguments = [];
     return serverArguments;
@@ -41,6 +83,10 @@ async function stop(serverName) {
 }
 
 async function run(server, options) {
+    if(!options) {
+      options = {};
+    }
+
     const logStdout = options.logStdout || false;
 
     console.log(`Running '${server.path}'`);
diff --git a/main.js b/main.js
index 74f42f20..776cee3a 100644
--- a/main.js
+++ b/main.js
@@ -1,18 +1,13 @@
 const electron = require('electron');
-const fs = require('fs');
 const app = electron.app;
 const BrowserWindow = electron.BrowserWindow;
 const path = require('path');
 const url = require('url');
 const yargs = require('yargs');
 
-const { ipcMain } = require('electron')
-
 // Keep a global reference of the window object, if you don't, the window will
 // be closed automatically when the JavaScript object is garbage collected.
 let mainWindow;
-let serverProc = null;
-let isWin = /^win/.test(process.platform);
 let isDev = false;
 
 const argv = yargs
@@ -29,49 +24,6 @@ if (argv.e == 'dev') {
 }
 
 
-const createServerProc = () => {
-  const directory = path.join(__dirname, 'dist');
-
-  if (!fs.existsSync(directory)) {
-    return;
-  }
-
-  fs.readdir(path.join(__dirname, 'dist'), (err, files) => {
-    var serverPath = null;
-
-    files.forEach((filename) => {
-      if(filename.startsWith('exe.')) {
-        if (isWin) {
-          serverPath = path.join(__dirname, 'dist', filename, 'gns3server.exe');
-        }
-        else {
-          serverPath = path.join(__dirname, 'dist', filename, 'gns3server');
-        }
-      }
-    });
-
-    if (serverPath == null) {
-      console.error('gns3server cannot be found');
-    }
-
-    if (serverPath != null) {
-      serverProc = require('child_process').execFile(serverPath, []);
-
-      if (serverProc != null) {
-        console.log('gns3server started from path: ' + serverPath);
-      }
-    }
-  });
-}
-
-const exitServerProc = () => {
-  if(serverProc) {
-    serverProc.kill();
-    serverProc = null;
-  }
-}
-
-
 function createWindow () {
   // Create the browser window.
   mainWindow = new BrowserWindow({
diff --git a/src/app/components/servers/add-server-dialog.html b/src/app/components/servers/add-server-dialog.html
index a4999abb..489531be 100644
--- a/src/app/components/servers/add-server-dialog.html
+++ b/src/app/components/servers/add-server-dialog.html
@@ -8,6 +8,10 @@
     </mat-select>
   </mat-form-field>
 
+  <mat-form-field *ngIf="server.location === 'local'">
+    <input matInput tabindex="1" [(ngModel)]="server.path" placeholder="Local server path" />
+  </mat-form-field>
+
   <mat-form-field> <input matInput tabindex="1" [(ngModel)]="server.host" placeholder="Host" /> </mat-form-field>
   <mat-form-field> <input matInput tabindex="1" [(ngModel)]="server.port" placeholder="Port" /> </mat-form-field>
 
diff --git a/src/app/components/servers/servers.component.html b/src/app/components/servers/servers.component.html
index 806475a5..8f4ea9f9 100644
--- a/src/app/components/servers/servers.component.html
+++ b/src/app/components/servers/servers.component.html
@@ -35,6 +35,14 @@
         <ng-container matColumnDef="actions">
           <mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
           <mat-cell *matCellDef="let row" style="text-align: right">
+            <button mat-icon-button (click)="startServer(row)" *ngIf="row.location === 'local' && getServerStatus(row) === 'stopped'">
+              <mat-icon aria-label="Start server">play_arrow</mat-icon>
+            </button>
+
+            <button mat-icon-button (click)="stopServer(row)" *ngIf="row.location === 'local' && getServerStatus(row) === 'running'">
+              <mat-icon aria-label="Stop server">stop</mat-icon>
+            </button>
+            
             <button mat-icon-button (click)="deleteServer(row)">
               <mat-icon aria-label="Remove server">delete</mat-icon>
             </button>
diff --git a/src/app/components/servers/servers.component.ts b/src/app/components/servers/servers.component.ts
index 681ded09..f88cc52c 100644
--- a/src/app/components/servers/servers.component.ts
+++ b/src/app/components/servers/servers.component.ts
@@ -22,7 +22,8 @@ export class ServersComponent implements OnInit {
   constructor(
     private dialog: MatDialog,
     private serverService: ServerService,
-    private serverDatabase: ServerDatabase
+    private serverDatabase: ServerDatabase,
+    private electronService: ElectronService,
   ) {}
 
   ngOnInit() {
@@ -47,11 +48,32 @@ export class ServersComponent implements OnInit {
     });
   }
 
+  getServerStatus(server: Server) {
+    if(server.location === 'local') {
+      if(server.status === undefined) {
+        return 'stopped';
+      }
+      return server.status;
+    }
+  }
+
   deleteServer(server: Server) {
     this.serverService.delete(server).then(() => {
       this.serverDatabase.remove(server);
     });
   }
+
+  async startServer(server: Server) {
+    await this.electronService.remote.require('./local-server.js').startLocalServer(server);
+    server.status = 'running';
+    this.serverDatabase.update(server);
+  }
+
+  async stopServer(server: Server) {
+    await this.electronService.remote.require('./local-server.js').stopLocalServer(server);
+    server.status = 'stopped';
+    this.serverDatabase.update(server);
+  }
 }
 
 @Component({
@@ -86,13 +108,22 @@ export class AddServerDialogComponent implements OnInit {
     return 'remote';
   }
 
+  getDefaultLocalServerPath() {
+    return this.electronService.remote.require('./local-server.js').getLocalServerPath();
+  }
+
   ngOnInit() {
     this.locations = this.getLocations();
     this.server.authorization = 'none';
     this.server.location = this.getDefaultLocation();
+    this.server.path = this.getDefaultLocalServerPath();
   }
 
   onAddClick(): void {
+    // clear path if not local server
+    if(this.server.location !== 'local') {
+      this.server.path = null;
+    }
     this.dialogRef.close(this.server);
   }
 
diff --git a/src/app/models/server.ts b/src/app/models/server.ts
index 93894147..2ad4ccd1 100644
--- a/src/app/models/server.ts
+++ b/src/app/models/server.ts
@@ -1,5 +1,6 @@
 export type ServerAuthorization = 'basic' | 'none';
 export type ServerLocation = 'local' | 'remote';
+export type ServerStatus = 'stopped' | 'starting' | 'running';
 
 export class Server {
   id: number;
@@ -12,4 +13,5 @@ export class Server {
   login: string;
   password: string;
   is_local: boolean;
+  status: ServerStatus;
 }
diff --git a/src/app/services/server.database.ts b/src/app/services/server.database.ts
index 4d8af007..fea41c42 100644
--- a/src/app/services/server.database.ts
+++ b/src/app/services/server.database.ts
@@ -29,4 +29,12 @@ export class ServerDatabase {
       this.dataChange.next(this.data.slice());
     }
   }
+
+  public update(server: Server) {
+    const index = this.data.indexOf(server);
+    if (index >= 0) {
+      this.data[index] = server;
+      this.dataChange.next(this.data.slice());
+    }
+  }
 }