Files
JRedisDesktop/electron/redis/format.ts
T
Jokul 157af4399f fix: 修复文件层级重构后的架构问题
- 恢复 IPC 类型声明 (src/electron-api.d.ts),修复 31 个 TS2339 错误
- 修复构建断裂:vite.config.ts 改回 electron.vite.config.ts
- 修复 2 个 verbatimModuleSyntax type-import 报错
- 修正 .gitignore 构建产物路径 (electron-dist/ -> dist-electron/ + release/)
- 清理 55+ 处过时路径注释
- 更新 AGENTS.md 架构文档与 IPC 通道表
- 修正 docs/ROADMAP.md 过时引用
2026-07-10 23:22:53 +08:00

80 lines
2.7 KiB
TypeScript

// 值格式转换(解压/编码/自定义)
import { gunzipSync, inflateSync, brotliDecompressSync } from 'zlib'
import { execFile } from 'child_process'
import { writeFile, unlink, mkdtemp } from 'fs/promises'
import { tmpdir } from 'os'
import { join } from 'path'
export type FormatType = 'text' | 'hex' | 'json' | 'binary' | 'gzip' | 'deflate' | 'brotli' | 'deflateRaw'
export function decodeValue(value: string, format: FormatType): string {
const buf = Buffer.from(value, 'utf-8')
switch (format) {
case 'hex':
return buf.toString('hex').match(/.{1,2}/g)?.join(' ') ?? ''
case 'binary':
return buf.toString('binary')
case 'json':
try {
return JSON.stringify(JSON.parse(value), null, 2)
} catch {
return value
}
case 'gzip':
try { return gunzipSync(buf).toString('utf-8') } catch { return '[Gzip decode failed]' }
case 'deflate':
try { return inflateSync(buf).toString('utf-8') } catch { return '[Deflate decode failed]' }
case 'brotli':
try { return brotliDecompressSync(buf).toString('utf-8') } catch { return '[Brotli decode failed]' }
case 'deflateRaw':
try { return inflateSync(buf).toString('utf-8') } catch { return '[DeflateRaw decode failed]' }
default:
return value
}
}
export function detectFormat(value: string): FormatType {
if (!value) return 'text'
// JSON
try { JSON.parse(value); return 'json' } catch { /* not json */ }
// Gzip magic: 1f 8b
if (value.charCodeAt(0) === 0x1f && value.charCodeAt(1) === 0x8b) return 'gzip'
// Brotli magic (less reliable, check common patterns)
// Deflate (zlib) magic: 78 01/9c/da
if (value.charCodeAt(0) === 0x78 && [0x01, 0x9c, 0xda, 0x5e].includes(value.charCodeAt(1))) return 'deflate'
// Check for non-printable characters → binary/hex
const hasNonPrintable = /[\x00-\x08\x0e-\x1f]/.test(value.substring(0, 100))
if (hasNonPrintable) return 'hex'
return 'text'
}
export async function customFormat(
value: string,
command: string,
key?: string
): Promise<string> {
const tmpDir = await mkdtemp(join(tmpdir(), 'jrdm-fmt-'))
const tmpFile = join(tmpDir, 'value.bin')
await writeFile(tmpFile, value, 'utf-8')
return new Promise((resolve) => {
const cmd = command
.replace(/\{KEY\}/g, key || '')
.replace(/\{VALUE\}/g, value)
.replace(/\{HEX_FILE\}/g, tmpFile)
const parts = cmd.split(/\s+/)
const exe = parts[0]
const args = parts.slice(1)
execFile(exe, args, { timeout: 10000, maxBuffer: 10 * 1024 * 1024 }, async (err, stdout) => {
await unlink(tmpFile).catch(() => {})
if (err) {
resolve(`[Custom formatter error: ${err.message}]`)
} else {
resolve(stdout)
}
})
})
}