仅在readFile()Node js Electron之后杀死子进程



我在Electron React应用程序(在Windows Pro 10上(中使用导入的ffmpeg二进制ffmpeg-static-electron,希望删除保存的裁剪视频,然后从我的Main process中终止子进程。

总体目标是在捕获后裁剪整个屏幕的视频,然后将裁剪后的视频发送到渲染器。

const fsPromises = require('fs').promises
const ffmpeg = require('ffmpeg-static-electron')
const { execFile } = require("child_process")

ipcMain.on("windoze_capture_screen:video_buffer", async (event, buffer) => {
const temp_directory =  await fsPromises.mkdtemp(await fsPromises.realpath(os.tmpdir()) + path.sep)
const capture_screen_video_path = path.join(temp_directory, "screen_capture_video.mp4")
child_object = execFile(`${ffmpeg.path}`, 
['-i', `${capture_screen_video_path}`, '-vf', `crop=${width}:${height}:${x_pos}:${y_pos}`, `${path.join(temp_directory,'cropped_video.mp4')}`])

child_object.on("exit", async () => {
// child_object.kill()
console.log("?Killed -1", child_object.killed)

try { 
databasePayload.video_buffer = await fsPromises.readFile(path.join(temp_directory, "cropped_video.mp4"), {encoding: 'base64'})
mainWindow.webContents.send("main_process:video_buffer", databasePayload.video_buffer)
} catch (error) {
console.log(error)
} finally {
// child_object.kill()
console.log("?Killed - 2", child_object.killed)

// noASAR required to be set to 'true' in order to remove temp directory in build
process.noAsar = true 
fs.rmdir(temp_directory, {recursive: true}, (error) => {if (error) {log(error)}})
process.noASAR = false
}
// 3rd scenario
// child_object.kill()
console.log("?Killed -3", child_object.killed)   
})
// 4th scenario
console.log("?Killed-4", child_object.killed)   
})

当运行这些场景中的每一个时,我都会得到以下输出。

场景1、2和3-成功地将裁剪后的视频发送到渲染器,但不会终止进程。

输出:

?Killed-4 false
?Killed -1 false
[ffmpeg version 3.0.1 Copyright (c) 2000-2016 the FFmpeg developers built with gcc 5.3.0 (GCC).... etc. ]
?Killed-2 false
?Killed -3 false

场景4-不裁剪视频

?Killed-4 true
?Killed -1 true
Command failed: C:UsersXXXDesktopwindows-electron-forgenode_modulesffmpeg-static-electronbinwinx64ffmpeg.exe -i C:UsersXXXAppDataLocalTemp4WgnUwscreen_capture_video.mp4 -vf crop=796:763:462:509 C:UsersXXXAppDataLocalTemp4WgnUwcropped_video.mp4
[Error: ENOENT: no such file or directory, open 'C:UsersXXXAppDataLocalTemp4WgnUwcropped_video.mp4'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\Users\XXX\AppData\Local\Temp\4WgnUw\cropped_video.mp4'
}
?Killed - 2 true
?Killed -3 true

最后一种情况是出于绝望而尝试的。

问题:我哪里出问题了?我怀疑这与子进程和父进程之间的ipc有关,但不确定将代码放在哪里。

任何帮助都将不胜感激!!!

一旦在.on ("exit", () => { ... });函数中接收到exit事件,就不需要终止子进程——它已经自行退出,这意味着它已经完成运行,并且将"模具;因为没有什么可做的了。只有当它们应该被迫中止当前正在做的事情时,或者如果它们行为不端,什么都没做就一直呆着(这可以在操作系统的任务管理器中观察到(,才需要终止进程。

正如exit上的Node.js文档所述,只有当进程终止时才会触发此事件。因此,您不再可以在处理程序函数中杀死它,而且实际上也不需要这样做,因为它不会像所谓的"僵尸;(见上文(,因为它已经完成了执行。

因此,以下功能应该足够:

child_object.on("exit", async () => {
try {
databasePayload.video_buffer = await fsPromises.readFile(path.join(temp_directory, "cropped_video.mp4"), {encoding: 'base64'})
mainWindow.webContents.send("main_process:video_buffer", databasePayload.video_buffer)
} catch (error) {
console.log(error)
}

// ... your file removal code ...
});

还有三件事我想解决:

  • 当要求在继续执行以下代码之前实际解决承诺时,最好不要使用await,而是使用函数的同步版本(如果可用(。然后,您的fs函数调用将变为:
const fs = require ("fs");
const temp_directory = fs.mkdtempSync (fs.realpathSync (os.tmpdir()) + path.sep)
// ...
databasePayload.video_buffer = fs.readFileSync (path.join (temp_directory, "cropped_video.mp4"), { encoding: 'base64' })
// ...
try { fs.rmdirSync (temp_directory, { recursive: true }) } catch (e) { console.log (e); }
  • process.noAsar = true不应该被需要,除非你的临时目录实际上是在你的应用程序的ASAR档案中创建的,除非Electron Forge做了一些我不知道的魔法,否则这是不可能的。考虑一下为什么设置此标志可以解决问题(可能是通过转储临时目录的路径(
  • 单个文件不应该需要临时目录。除非您计划将此目录用作更多文件的存储空间,否则请考虑重写函数以创建一个临时文件,然后删除此单个文件(这在磁盘硬件上也会更容易,因为只需要执行一次删除,而不需要执行两次,但除非执行数百次,否则这实际上可以忽略不计(

最新更新