From 8d3804593c21b301fbc40a212dace2dab4331d29 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 18 Jan 2026 14:29:56 -0800 Subject: [PATCH] more code cleanup --- server/index.ts | 22 +++++---- server/modules/signal.ts | 102 ++++++++++++++------------------------- server/routes/link.ts | 1 + server/utils/rpc.ts | 50 +++++++++++++++++++ 4 files changed, 99 insertions(+), 76 deletions(-) create mode 100644 server/utils/rpc.ts diff --git a/server/index.ts b/server/index.ts index 5282b20..a3026b8 100644 --- a/server/index.ts +++ b/server/index.ts @@ -16,16 +16,20 @@ import { withAuth, withFormAuth } from './utils/auth'; let daemon: ReturnType | null = null; -daemon = await startDaemon(); +try { + daemon = await startDaemon(); + const isLinked = await checkSignalCli(); + const hasAccount = isLinked && (await initSignal({})); -const isLinked = await checkSignalCli(); -const hasAccount = isLinked && (await initSignal({})); - -if (hasAccount) { - console.log(chalk.green('✓ Signal account linked')); -} else { - console.log(chalk.yellow('⚠ No Signal account linked')); - console.log(chalk.dim(` Visit http://localhost:${PORT}/link to link your device`)); + if (hasAccount) { + console.log(chalk.green('✓ Signal account linked')); + } else { + console.log(chalk.yellow('⚠ No Signal account linked')); + console.log(chalk.dim(` Visit http://localhost:${PORT}/link to link your device`)); + } +} catch (error) { + console.error(chalk.red('✗ Failed to start signal-cli daemon')); + console.error(chalk.dim(` ${error instanceof Error ? error.message : String(error)}`)); } if (!API_KEY) { diff --git a/server/modules/signal.ts b/server/modules/signal.ts index 8ccf210..6e3a7fd 100644 --- a/server/modules/signal.ts +++ b/server/modules/signal.ts @@ -4,13 +4,12 @@ import { DAEMON_START_MAX_ATTEMPTS, DEVICE_NAME, VERBOSE } from '../constants/co import { SIGNAL_CLI, SIGNAL_CLI_DATA, SIGNAL_CLI_SOCKET } from '../constants/paths'; import type { ListAccountsResult, StartLinkResult, UpdateGroupResult } from '../types'; import { log } from '../utils/log'; +import { call } from '../utils/rpc'; log(`Running signal-cli from ${SIGNAL_CLI}`); -const MESSAGE_DELIMITER = '\n'; let account: string | null = null; let currentLinkUri: string | null = null; -let rpcId = 1; export async function initSignal({ accountOverride }: { accountOverride?: string }) { if (accountOverride) { @@ -18,7 +17,7 @@ export async function initSignal({ accountOverride }: { accountOverride?: string return true; } - const result = (await rpcCall('listAccounts', {})) as ListAccountsResult; + const result = (await call('listAccounts', {}, account)) as ListAccountsResult; const [firstAccount] = result; if (firstAccount) { account = firstAccount; @@ -28,57 +27,14 @@ export async function initSignal({ accountOverride }: { accountOverride?: string return false; } -async function rpcCall(method: string, params: Record) { - return new Promise((resolve, reject) => { - let response = ''; - - Bun.connect({ - unix: SIGNAL_CLI_SOCKET, - socket: { - data(socket, data) { - response += new TextDecoder().decode(data); - - const isComplete = response.includes(MESSAGE_DELIMITER); - if (isComplete) { - socket.end(); - - const parsed = JSON.parse(response.trim()); - - if (parsed.error) { - reject(new Error(`signal-cli RPC error: ${parsed.error.message}`)); - } else { - resolve(parsed.result); - } - } - }, - error(_socket, error) { - reject(error); - }, - close() { - const isComplete = response.includes(MESSAGE_DELIMITER); - if (!isComplete) { - reject(new Error('Connection closed before response received')); - } - }, - open(socket) { - const request = JSON.stringify({ - jsonrpc: '2.0', - id: rpcId++, - method, - params: account ? { account, ...params } : params, - }); - - socket.write(`${request}${MESSAGE_DELIMITER}`); - }, - }, - }); - }); -} - export async function generateLinkQR() { - const result = (await rpcCall('startLink', { - deviceName: DEVICE_NAME, - })) as StartLinkResult; + const result = (await call( + 'startLink', + { + deviceName: DEVICE_NAME, + }, + account, + )) as StartLinkResult; const uri = result.deviceLinkUri; if (!uri) { @@ -94,10 +50,14 @@ export async function finishLink() { throw new Error('No link in progress'); } - const result = await rpcCall('finishLink', { - deviceLinkUri: currentLinkUri, - deviceName: DEVICE_NAME, - }); + const result = await call( + 'finishLink', + { + deviceLinkUri: currentLinkUri, + deviceName: DEVICE_NAME, + }, + account, + ); currentLinkUri = null; return result; } @@ -112,10 +72,14 @@ export async function unlinkDevice() { } export async function createGroup(name: string, members: string[] = []) { - const result = (await rpcCall('updateGroup', { - name, - member: members, - })) as UpdateGroupResult; + const result = (await call( + 'updateGroup', + { + name, + member: members, + }, + account, + )) as UpdateGroupResult; if (!result?.groupId) { throw new Error('Failed to create group'); @@ -125,15 +89,19 @@ export async function createGroup(name: string, members: string[] = []) { } export async function sendGroupMessage(groupId: string, message: string) { - await rpcCall('send', { - groupId, - message, - }); + await call( + 'send', + { + groupId, + message, + }, + account, + ); } export async function checkSignalCli() { try { - await rpcCall('listAccounts', {}); + await call('listAccounts', {}, account); return true; } catch { return false; @@ -142,7 +110,7 @@ export async function checkSignalCli() { export async function hasValidAccount() { try { - const result = (await rpcCall('listAccounts', {})) as ListAccountsResult; + const result = (await call('listAccounts', {}, account)) as ListAccountsResult; return result.length > 0; } catch { return false; diff --git a/server/routes/link.ts b/server/routes/link.ts index f15366c..c79e4a6 100644 --- a/server/routes/link.ts +++ b/server/routes/link.ts @@ -28,6 +28,7 @@ export const handleLink = async () => { export const handleLinkQR = async () => { const qrDataUrl = await generateLinkQR(); + return new Response(qrDataUrl, { headers: { 'content-type': 'text/plain' }, }); diff --git a/server/utils/rpc.ts b/server/utils/rpc.ts new file mode 100644 index 0000000..7ec85d2 --- /dev/null +++ b/server/utils/rpc.ts @@ -0,0 +1,50 @@ +import { SIGNAL_CLI_SOCKET } from '../constants/paths'; + +const MESSAGE_DELIMITER = '\n'; +let rpcId = 1; + +export const call = (method: string, params: Record, account: string | null) => + new Promise((resolve, reject) => { + let response = ''; + + Bun.connect({ + unix: SIGNAL_CLI_SOCKET, + socket: { + data(socket, data) { + response += new TextDecoder().decode(data); + + const isComplete = response.includes(MESSAGE_DELIMITER); + if (isComplete) { + socket.end(); + + const parsed = JSON.parse(response.trim()); + + if (parsed.error) { + reject(new Error(`signal-cli RPC error: ${parsed.error.message}`)); + } else { + resolve(parsed.result); + } + } + }, + error(_socket, error) { + reject(error); + }, + close() { + const isComplete = response.includes(MESSAGE_DELIMITER); + if (!isComplete) { + reject(new Error('Connection closed before response received')); + } + }, + open(socket) { + const request = JSON.stringify({ + jsonrpc: '2.0', + id: rpcId++, + method, + params: account ? { account, ...params } : params, + }); + + socket.write(`${request}${MESSAGE_DELIMITER}`); + }, + }, + }); + });