Skip to content

Commit

Permalink
ring ring
Browse files Browse the repository at this point in the history
  • Loading branch information
furudean committed Aug 7, 2024
1 parent 06fa6a7 commit a8554f0
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 62 deletions.
7 changes: 2 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function activate(context: vscode.ExtensionContext) {
if (most_recent) {
follow_cursor.set(most_recent)
status_bar.notify(
`$(debug-line-by-line) Now following pid ${most_recent.process.pid}`
`$(debug-line-by-line) Now following pid ${most_recent.pid}`
)
}
}
Expand Down Expand Up @@ -255,10 +255,7 @@ export function activate(context: vscode.ExtensionContext) {
for (const process of pm) {
if (!process.socket) return

logger.info(
'reloading process on save',
process.process.pid
)
logger.info('reloading process on save', process.pid)
await process.set_autoreload()
}
} catch (error: any) {
Expand Down
11 changes: 7 additions & 4 deletions src/lib/launch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from 'vscode'
import path from 'upath'
import { sh } from 'puka'
import child_process from 'child_process'

import { focus_window, ProcessManager, RenpyProcess } from './process'
import { FollowCursor, sync_editor_with_renpy } from './follow_cursor'
Expand Down Expand Up @@ -196,10 +197,13 @@ export async function launch_renpy({
cancellable: true,
},
async (_, cancel) => {
logger.info('executing subshell:', cmd)
const process = child_process.exec(cmd)
logger.info('created process', process.pid)

const rpp = new RenpyProcess({
cmd,
process,
game_root,
socket_port,
async message_handler(process, message) {
if (message.type === 'current_line') {
logger.debug(
Expand All @@ -216,7 +220,6 @@ export async function launch_renpy({
logger.warn('unhandled message:', message)
}
},
context,
})
pm.add(running_nonce, rpp)

Expand All @@ -234,7 +237,7 @@ export async function launch_renpy({

if (pm.length > 1) {
status_bar.notify(
`$(debug-line-by-line) Now following pid ${rpp.process.pid}`
`$(debug-line-by-line) Now following pid ${rpp.pid}`
)
}
}
Expand Down
102 changes: 55 additions & 47 deletions src/lib/process.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from 'vscode'
import child_process from 'node:child_process'
import child_process, { ChildProcess } from 'node:child_process'
import { WebSocket } from 'ws'
import { get_logger } from './logger'
import pidtree from 'pidtree'
Expand Down Expand Up @@ -45,63 +45,63 @@ export async function focus_window(pid: number) {
}
}

export class RenpyProcess {
cmd: string
interface RenpyProcessOptions {
process?: ChildProcess
pid?: number
message_handler: (
process: RenpyProcess,
data: SocketMessage
) => MaybePromise<void>
game_root: string
socket_port: number | undefined
process: child_process.ChildProcess
}

export class RenpyProcess {
process?: child_process.ChildProcess
pid: number
game_root: string
message_handler: (
process: RenpyProcess,
data: SocketMessage
) => MaybePromise<void>
socket?: WebSocket = undefined
dead: boolean = false
output_channel: vscode.OutputChannel
output_channel?: vscode.OutputChannel

constructor({
cmd,
process,
pid,
message_handler,
game_root,
socket_port,
context,
}: {
cmd: string
message_handler: typeof RenpyProcess.prototype.message_handler
game_root: string
socket_port: number | undefined
context: vscode.ExtensionContext
}) {
this.cmd = cmd
}: RenpyProcessOptions) {
this.process = process
this.pid = (process?.pid ?? pid) as number
this.message_handler = message_handler
this.game_root = game_root
this.socket_port = socket_port

logger.info('executing subshell:', cmd)
this.process = child_process.exec(cmd)

this.output_channel = vscode.window.createOutputChannel(
`Ren'Py Launch and Sync - Process Output (${this.process.pid})`
)
context.subscriptions.push(this.output_channel)

this.process.stdout!.on('data', (data: string) =>
this.output_channel!.append(data)
)
this.process.stderr!.on('data', (data: string) =>
this.output_channel!.append(data)
)
if (this.process) {
this.output_channel = vscode.window.createOutputChannel(
`Ren'Py Launch and Sync - Process Output (${this.process.pid})`
)

this.output_channel.appendLine(`process ${this.process.pid} started`)
this.process.stdout!.on('data', (data: string) =>
this.output_channel!.append(data)
)
this.process.stderr!.on('data', (data: string) =>
this.output_channel!.append(data)
)

this.process.on('exit', (code) => {
this.dead = true
logger.info(`process ${this.process.pid} exited with code ${code}`)
this.output_channel!.appendLine(
`process ${this.process.pid} exited with code ${code}`
this.output_channel.appendLine(
`process ${this.process.pid} started`
)
})

logger.info('created process', this.process.pid)
this.process.on('exit', (code) => {
this.dead = true
logger.info(`process ${this.pid} exited with code ${code}`)
this.output_channel!.appendLine(
`process ${this.pid} exited with code ${code}`
)
})
}
}

async wait_for_socket(timeout_ms: number): Promise<void> {
Expand Down Expand Up @@ -133,7 +133,11 @@ export class RenpyProcess {
}

kill() {
this.process.kill()
process.kill(this.pid, 9) // SIGKILL, bypasses "are you sure" dialog
}

dispose() {
this.output_channel?.dispose()
}

async ipc(message: SocketMessage): Promise<void> {
Expand Down Expand Up @@ -202,12 +206,12 @@ export class ProcessManager {
}

async add(id: number, process: RenpyProcess) {
if (!process.process.pid) throw new Error('no pid in process')
if (!process.pid) throw new Error('no pid in process')

this.processes.set(id, process)

process.process.on('exit', (code) => {
if (!process.process.pid) throw new Error('no pid in process')
process.process!.on('exit', (code) => {
if (!process.pid) throw new Error('no pid in process')

this.processes.delete(id)

Expand All @@ -219,7 +223,7 @@ export class ProcessManager {
'Logs'
)
.then((selected) => {
if (selected === 'Logs') process.output_channel.show()
if (selected === 'Logs') process.output_channel?.show()
})
}

Expand All @@ -236,13 +240,17 @@ export class ProcessManager {
}

kill_all() {
for (const { process } of this) {
process.kill(9) // SIGKILL, bypasses "are you sure" dialog
for (const { kill } of this) {
kill()
}
}

dispose() {
this.kill_all()

for (const { dispose } of this) {
dispose()
}
}

get length() {
Expand Down
10 changes: 4 additions & 6 deletions src/lib/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,8 @@ export async function start_websocket_server({
return
}

const ppid = rpp.process.pid

logger.info(
`found new socket connection from process ${ppid}, with nonce ${nonce}`
`found new socket connection from process ${rpp.pid}, with nonce ${nonce}`
)

if (rpp.socket) {
Expand All @@ -88,19 +86,19 @@ export async function start_websocket_server({
rpp.socket = socket

socket.on('message', async (data) => {
logger.debug(`websocket (${ppid}) <`, data.toString())
logger.debug(`websocket (${rpp.pid}) <`, data.toString())
const message = JSON.parse(data.toString())

await rpp.message_handler(rpp, message)
})

socket.on('close', () => {
logger.info(`websocket connection closed (pid ${ppid})`)
logger.info(`websocket connection closed (pid ${rpp.pid})`)
rpp.socket = undefined
})

socket.on('error', (error) => {
logger.error(`websocket error (pid ${ppid})`, error)
logger.error(`websocket error (pid ${rpp.pid})`, error)
})

rpp.process.off('exit', process_exit_handler)

Check failure on line 104 in src/lib/socket.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

'rpp.process' is possibly 'undefined'.

Check failure on line 104 in src/lib/socket.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest)

'rpp.process' is possibly 'undefined'.
Expand Down

0 comments on commit a8554f0

Please sign in to comment.