-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Require Replay browser to exit before starting a new recording #496
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"replayio": minor | ||
--- | ||
|
||
Require Replay browser to exit before creating a new recording. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,13 @@ import { writeFileSync } from "fs-extra"; | |
import { v4 as uuid } from "uuid"; | ||
import { ProcessError } from "../utils/ProcessError"; | ||
import { logAsyncOperation } from "../utils/async/logAsyncOperation"; | ||
import { getRunningProcess } from "../utils/browser/getRunningProcess"; | ||
import { launchBrowser } from "../utils/browser/launchBrowser"; | ||
import { registerCommand } from "../utils/commander/registerCommand"; | ||
import { confirm } from "../utils/confirm"; | ||
import { exitProcess } from "../utils/exitProcess"; | ||
import { getReplayPath } from "../utils/getReplayPath"; | ||
import { killProcess } from "../utils/killProcess"; | ||
import { trackEvent } from "../utils/mixpanel/trackEvent"; | ||
import { canUpload } from "../utils/recordings/canUpload"; | ||
import { getRecordings } from "../utils/recordings/getRecordings"; | ||
|
@@ -34,6 +36,23 @@ async function record(url: string = "about:blank") { | |
const processGroupId = uuid(); | ||
|
||
try { | ||
const process = await getRunningProcess(); | ||
if (process) { | ||
const confirmed = await confirm( | ||
"The replay browser is already running. You'll need to close it before starting a new recording.\n\nWould you like to close it now?", | ||
true | ||
); | ||
Comment on lines
+41
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little bit conflicted on this proposed behavior but when thinking about it logically... yee, why wouldn't we want to help the user and do it for them if we can? It definitely sounds reasonable. So you have my 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I felt the same. I didn't intend to do it, but then I thought I probably should |
||
if (confirmed) { | ||
const killResult = await killProcess(process.pid); | ||
if (!killResult) { | ||
console.log("Something went wrong trying to close the replay browser. Please try again."); | ||
await exitProcess(1); | ||
} | ||
} else { | ||
await exitProcess(0); | ||
} | ||
} | ||
|
||
await launchBrowser(url, { processGroupId, verbose }); | ||
} catch (error) { | ||
if (error instanceof ProcessError) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import findProcess from "find-process"; | ||
import { highlight } from "../theme"; | ||
import { debug } from "./debug"; | ||
import { getBrowserPath } from "./getBrowserPath"; | ||
|
||
export async function getRunningProcess() { | ||
const browserExecutablePath = getBrowserPath(); | ||
|
||
const processes = await findProcess("name", browserExecutablePath); | ||
if (processes.length > 0) { | ||
const match = processes[0]; | ||
|
||
debug(`Browser process already running at ${highlight(match.pid)}`); | ||
|
||
return match; | ||
} | ||
|
||
return null; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import findProcess from "find-process"; | ||
import { kill } from "process"; | ||
import { createDeferred } from "./async/createDeferred"; | ||
import { timeoutAfter } from "./async/timeoutAfter"; | ||
|
||
export async function killProcess( | ||
pid: number, | ||
signal?: string | number | undefined, | ||
options: { retryIntervalMs?: number; timeoutMs?: number } = {} | ||
): Promise<boolean> { | ||
const { retryIntervalMs = 100, timeoutMs = 1_000 } = options; | ||
|
||
const deferred = createDeferred<boolean>(); | ||
|
||
let timeout: NodeJS.Timeout | undefined; | ||
|
||
const tryToKill = async () => { | ||
timeout = undefined; | ||
|
||
const process = await findProcess("pid", pid); | ||
if (process.length === 0) { | ||
deferred.resolve(true); | ||
} else { | ||
kill(pid, signal); | ||
|
||
timeout = setTimeout(tryToKill, retryIntervalMs); | ||
} | ||
}; | ||
|
||
tryToKill(); | ||
|
||
return Promise.race([ | ||
deferred.promise.then(() => { | ||
clearTimeout(timeout); | ||
|
||
return true; | ||
}), | ||
timeoutAfter(timeoutMs).then(() => false), | ||
]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is debatable I guess.