Skip to content

Commit

Permalink
sync
Browse files Browse the repository at this point in the history
  • Loading branch information
AtomicSponge committed May 20, 2024
1 parent ed62f5a commit 00409c6
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 3 deletions.
15 changes: 15 additions & 0 deletions electron/electron-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ export interface IinputAPI {
onReceiveData: (callback:Function) => void
}

export interface IjobMgrAPI {
termProcess: (data:number) => void
onReceiveData: (callback:Function) => void
}

declare global {
/** Preload APIs */
interface Window {
bufferAPI:IbufferAPI
settingsAPI:IsettingsAPI
inputAPI:IinputAPI
jobMgrAPI:IjobMgrAPI
}

/** Settings data format */
Expand All @@ -51,6 +57,7 @@ declare global {
startup:boolean
}

/** Script Buffer data format */
interface ScriptBufferData {
command:string
start:string
Expand All @@ -60,6 +67,14 @@ declare global {
err:string
}

/** Process manager data format */
interface ProcessManagerData {
label:string
command:string
start:string
pid:number
}

/** Settings data format for Electron Ipc */
interface SettingsIpc {
launchMenu:string
Expand Down
56 changes: 56 additions & 0 deletions electron/lib/ProcessManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
*
* @author Matthew Evans
* @module script-tray
* @see README.md
* @copyright MIT see LICENSE.md
*
*/

import { EventEmitter } from 'node:events'

import type { ChildProcess } from 'node:child_process'

export class ProcessManager extends EventEmitter {
#dataBuffer:Array<ProcessManagerData>
#processBuffer:Array<ChildProcess>

/** Create a new ProcessManager object */
constructor() {
super()
this.#dataBuffer = []
this.#processBuffer = []

// Listen for write events
this.on('process-manager-add', (data, proc) => {
this.#dataBuffer.push(data)
this.#processBuffer.push(proc)
this.emit('process-manager-updated')
})

// Listen for remove events
this.on('process-manager-remove', (pid) => {
this.#dataBuffer = this.#dataBuffer.filter(proc => { proc.pid !== pid })
this.#processBuffer = this.#processBuffer.filter(proc => { proc.pid !== pid })
this.emit('process-manager-updated')
})
}

/**
* Read the ProcessManager buffer
* @returns The list of running processes
*/
read():Array<ProcessManagerData> {
return this.#dataBuffer
}

/**
* Terminate a running process by its Process ID
* @param pid Process ID to terminate
*/
term(pid:number):void {
this.#processBuffer.forEach(proc => {
if (proc.pid === pid) proc.kill()
})
}
}
72 changes: 69 additions & 3 deletions electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { AsyncResolver } from '@spongex/async-resolver'
import { appInfo } from './appInfo'
import { AppSettings } from './lib/AppSettings'
import { ScriptBuffer } from './lib/ScriptBuffer'
import { ProcessManager } from './lib/ProcessManager'

let loadTrayData:boolean = true
process.argv.forEach(arg => {
Expand All @@ -29,12 +30,14 @@ const __locale = Intl.DateTimeFormat().resolvedOptions().locale
const autoLauncher:AutoLaunch = new AutoLaunch({ name: 'script_tray' })
const appSettings:AppSettings = new AppSettings(loadTrayData)
const resBuff:ScriptBuffer = new ScriptBuffer(appSettings.bufferSize)
const runningJobs:ProcessManager = new ProcessManager()
let resolveInputWin:AsyncResolver = new AsyncResolver()

// Windows & tray objects
let bufferWin:BrowserWindow | null
let settingsWin:BrowserWindow | null
let inputWin:BrowserWindow | null
let jobMgrWin:BrowserWindow | null
let appTray:Tray | null

/** Window for output buffer */
Expand Down Expand Up @@ -172,6 +175,57 @@ ipcMain.on('recieve-input-data', (_event, data) => {
inputWin?.destroy()
})

/** Window for Job Manager */
const jobManagerWindow = ():void => {
jobMgrWin = new BrowserWindow({
icon: appInfo.icon,
title: `${appInfo.name} - Job Manager`,
width: 840,
height: 500,
fullscreen: false,
fullscreenable: false,
resizable: true,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
spellcheck: false,
preload: path.join(__dirname, '../dist-electron/preload.js'),
}
})
jobMgrWin.webContents.on('did-finish-load', () => {
jobMgrWin?.webContents.send('send-job-data', runningJobs.read())
})

// Send when the buffer updates
runningJobs.on('process-manager-updated', () => {
jobMgrWin?.webContents.send('send-job-data', runningJobs.read())
})
runningJobs.on('error', (error:any) => {
dialog.showErrorBox(`${appInfo.name}`, `Job Manager Event Error: ${error.message}`)
})

jobMgrWin.on('close', (_event) => {
jobMgrWin?.destroy()
})
{(process.env.VITE_DEV_SERVER_URL) ?
jobMgrWin.loadURL('http://localhost:5176/html/jobmgr.html') :
jobMgrWin.loadFile(path.join(__dirname, '../dist/html/jobmgr.html'))}
}

/* Event handler for process termination */
ipcMain.on('send-term-process', (_event, data) => {
if (dialog.showMessageBoxSync(<BrowserWindow>jobMgrWin, {
type: 'question',
title: `${appInfo.name} - Confirm`,
buttons: [ 'Yes', 'No' ],
message: `Are you sure you want to terminate running process ${data}?`
}) === 0) {
runningJobs.term(data)
jobMgrWin?.webContents.send('send-job-data', runningJobs.read())
}
})

/** About message box */
const aboutMessageBox = ():void => {
dialog.showMessageBox({
Expand All @@ -198,10 +252,13 @@ const buildMenu = ():Menu => {
const buildMain = (menu:Menu):void => {
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({
label: `Show Output Buffer`,
label: `Output Buffer`,
click: () => { bufferWindow() }
}))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({
label: `Job Manager`,
click: () => { jobManagerWindow() }
}))
menu.append(new MenuItem({ label: 'Settings',
click: () => { settingsEditorWindow() }
}))
Expand All @@ -227,7 +284,7 @@ const buildMenu = ():Menu => {
const CommandRunner = (cmd:string, item:TrayCommand):void => {
const startDate = new Date().toLocaleString(__locale, { timeZoneName: 'short' })
const startTime = performance.now()
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
const job = exec(cmd, { encoding: 'utf8', windowsHide: true }, (error, stdout, stderr) => {
const endTime = performance.now()
const endDate = new Date().toLocaleString(__locale, { timeZoneName: 'short' })
if(error) {
Expand All @@ -243,6 +300,15 @@ const buildMenu = ():Menu => {
err: stderr
})
})
runningJobs.emit('process-manager-add', {
label: item.label,
command: cmd,
start: startDate,
pid: job.pid
}, job)
job.on('close', () => {
runningJobs.emit('process-manager-remove', job.pid)
})
}

collection.forEach((item:any) => {
Expand Down
9 changes: 9 additions & 0 deletions electron/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ contextBridge.exposeInMainWorld('inputAPI', {
ipcRenderer.on('send-input-data', (_event, value) => callback(value))
}
})

contextBridge.exposeInMainWorld('jobMgrAPI', {
termProcess: (data:number):void => {
ipcRenderer.send('send-term-process', data)
},
onReceiveData: (callback:Function):void => {
ipcRenderer.on('send-job-data', (_event, value) => callback(value))
}
})
11 changes: 11 additions & 0 deletions html/jobmgr.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/renderer/jobmgr.ts"></script>
</body>
</html>
80 changes: 80 additions & 0 deletions renderer/JobMgr.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!--
script-tray
By: Matthew Evans
See LICENSE.md
-->

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const _runningJobs = ref()

/**
* Terminate running job button
* @param pid Process ID to terminate
*/
const termJob = (pid:number) => {
window.jobMgrAPI.termProcess(pid)
}

onMounted(() => {
window.jobMgrAPI.onReceiveData((runningJobs:ProcessManagerData) => {
_runningJobs.value = runningJobs
})
})
</script>

<template>
<section>
<table>
<tr>
<th class="pid">PID</th>
<th class="label">Label</th>
<th>Command</th>
<th class="time">Start time</th>
<th class="term">&nbsp;</th>
</tr>
<tr v-for="item in _runningJobs">
<td>{{ item.pid }}</td>
<td>{{ item.label }}</td>
<td>{{ item.command }}</td>
<td>{{ item.start }}</td>
<td>
<button @click="termJob(item.pid)">TERM</button>
</td>
</tr>
</table>
</section>
</template>

<style lang="stylus" scoped>
section
overflow auto
padding-top 4px
padding-left 4px
padding-right 4px
padding-bottom 4px
table
width 100%
border-collapse collapse
border 1px solid rgb(100, 100, 100, 0.1)
th
padding 4px
background-color rgb(80, 80, 80, 0.1)
text-align left
.pid
width 60px
.label
width 160px
.time
width 220px
.term
width 50px
tr:nth-child(odd)
background-color rgb(60, 60, 60, 0.1)
td
padding 4px
button
vertical-align top
font-size 0.6em
</style>
14 changes: 14 additions & 0 deletions renderer/jobmgr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
*
* @author Matthew Evans
* @module script-tray
* @see README.md
* @copyright MIT see LICENSE.md
*
*/

import { createApp } from 'vue'
import JobMgrApp from './JobMgr.vue'
import './style.styl'

createApp(JobMgrApp).mount('#app')
4 changes: 4 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default defineConfig(() => {
{
name: 'settings',
config: 'vite.settings.config.ts',
},
{
name: 'jobmgr',
config: 'vite.jobmgr.config.ts',
}
])
],
Expand Down
17 changes: 17 additions & 0 deletions vite.jobmgr.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import path from 'node:path'
import { defineConfig } from 'vite'
import renderer from 'vite-plugin-electron-renderer'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [ renderer(), vue() ],
build: {
outDir: 'dist',
emptyOutDir: false,
minify: false,
rollupOptions: { input: path.join(__dirname, 'html/jobmgr.html') }
},
esbuild: {
target: 'esnext'
}
})

0 comments on commit 00409c6

Please sign in to comment.