mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
98 lines
2.8 KiB
JavaScript
98 lines
2.8 KiB
JavaScript
import { execFile } from 'node:child_process'
|
|
import { promisify } from 'node:util'
|
|
|
|
const execFileAsync = promisify(execFile)
|
|
const packageName = 'com.stably.orca.mobile'
|
|
const cacheRoot = 'no_backup/OrcaMobileWeb'
|
|
const activationLimit = 16
|
|
const buildIdPattern = /^[a-f0-9]{64}$/
|
|
|
|
export async function readAndroidMobileWebActivations(command, runAdb = runAndroidAdb) {
|
|
const output = await runAdb(command, [
|
|
'shell',
|
|
'run-as',
|
|
packageName,
|
|
'find',
|
|
cacheRoot,
|
|
'-name',
|
|
'activation.json',
|
|
'-type',
|
|
'f'
|
|
])
|
|
const paths = output.split(/\r?\n/u).filter(Boolean)
|
|
if (paths.length > activationLimit) {
|
|
throw new Error('Android cache returned too many activation records')
|
|
}
|
|
return Promise.all(
|
|
paths.map(async (path) => ({
|
|
path,
|
|
...parseAndroidMobileWebActivation(
|
|
await runAdb(command, ['shell', 'run-as', packageName, 'cat', path])
|
|
)
|
|
}))
|
|
)
|
|
}
|
|
|
|
export async function readAndroidRollbackActivation(command, runAdb = runAndroidAdb) {
|
|
const records = await readAndroidMobileWebActivations(command, runAdb)
|
|
const candidates = records.filter((record) => record.previous)
|
|
if (candidates.length !== 1) {
|
|
throw new Error(`Expected one Android rollback candidate, found ${candidates.length}`)
|
|
}
|
|
return candidates[0]
|
|
}
|
|
|
|
export async function readSingleAndroidActivation(command, runAdb = runAndroidAdb) {
|
|
const records = await readAndroidMobileWebActivations(command, runAdb)
|
|
if (records.length !== 1) {
|
|
throw new Error(`Expected one Android activation record, found ${records.length}`)
|
|
}
|
|
return records[0]
|
|
}
|
|
|
|
export async function waitForAndroidActivation(
|
|
command,
|
|
path,
|
|
expectedBuildId,
|
|
timeoutMs,
|
|
runAdb = runAndroidAdb
|
|
) {
|
|
const deadline = Date.now() + timeoutMs
|
|
let last
|
|
while (Date.now() < deadline) {
|
|
last = parseAndroidMobileWebActivation(
|
|
await runAdb(command, ['shell', 'run-as', packageName, 'cat', path])
|
|
)
|
|
if (last.active === expectedBuildId) {
|
|
return last
|
|
}
|
|
await delay(100)
|
|
}
|
|
throw new Error(`Android activation did not change: ${JSON.stringify(last)}`)
|
|
}
|
|
|
|
export function parseAndroidMobileWebActivation(value) {
|
|
const parsed = JSON.parse(value)
|
|
const previous = parsed?.previous ?? null
|
|
if (
|
|
!buildIdPattern.test(parsed?.active) ||
|
|
(previous !== null && !buildIdPattern.test(previous))
|
|
) {
|
|
throw new Error('Android cache returned an invalid activation record')
|
|
}
|
|
return { active: parsed.active, previous }
|
|
}
|
|
|
|
export async function runAndroidAdb(command, args, timeoutMs = 30_000) {
|
|
const result = await execFileAsync(command, args, {
|
|
encoding: 'utf8',
|
|
maxBuffer: 2 * 1024 * 1024,
|
|
timeout: timeoutMs
|
|
})
|
|
return result.stdout.trim()
|
|
}
|
|
|
|
function delay(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
}
|