mirror of
https://github.com/lone-cloud/prism
synced 2026-06-03 08:43:10 -07:00
more docker compose adventures, better logging, readme clarrifications
This commit is contained in:
parent
136ad038a5
commit
9921c98ffc
5 changed files with 78 additions and 51 deletions
|
|
@ -55,6 +55,8 @@ docker compose up -d
|
|||
|
||||
### 3. ProtonMail Integration (Optional)
|
||||
|
||||
> **Note:** The default ProtonMail Bridge image uses `shenxn/protonmail-bridge:build` which compiles from source and supports multiple architectures. For x86_64 systems, you can use `shenxn/protonmail-bridge:latest` (pre-built binary, smaller and faster). For ARM devices (Raspberry Pi), stick with `:build`.
|
||||
|
||||
To receive ProtonMail notifications via Signal:
|
||||
|
||||
1. **Initialize ProtonMail Bridge** (one-time setup):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import chalk from 'chalk';
|
||||
import { API_KEY, BRIDGE_IMAP_PASSWORD, BRIDGE_IMAP_USERNAME, PORT } from './constants/config';
|
||||
import { ROUTES } from './constants/server';
|
||||
import { checkSignalCli, initSignal, startDaemon } from './modules/signal';
|
||||
|
|
@ -13,6 +12,7 @@ import {
|
|||
handleUnregister,
|
||||
} from './routes/unifiedpush';
|
||||
import { withAuth, withFormAuth } from './utils/auth';
|
||||
import { logError, logInfo, logSuccess, logWarn } from './utils/log';
|
||||
|
||||
let daemon: ReturnType<typeof Bun.spawn> | null = null;
|
||||
|
||||
|
|
@ -22,24 +22,28 @@ try {
|
|||
const hasAccount = isLinked && (await initSignal({}));
|
||||
|
||||
if (hasAccount) {
|
||||
console.log(chalk.green('✓ Signal account linked'));
|
||||
logSuccess('✓ 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`));
|
||||
logWarn('⚠ No Signal account linked');
|
||||
logInfo(` 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)}`));
|
||||
logError(` ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
||||
if (!API_KEY) {
|
||||
console.warn(chalk.yellow('⚠️ Server running without API_KEY'));
|
||||
console.warn(chalk.dim(' Set API_KEY env var for production deployments.'));
|
||||
logWarn('⚠️ Server running without API_KEY');
|
||||
console.warn(' Set API_KEY env var for production deployments.');
|
||||
}
|
||||
|
||||
if (BRIDGE_IMAP_USERNAME && BRIDGE_IMAP_PASSWORD) {
|
||||
try {
|
||||
const { startProtonMonitor } = await import('./modules/protonmail');
|
||||
await startProtonMonitor();
|
||||
} catch (err) {
|
||||
logError('❌ Failed to start ProtonMail monitor:', err);
|
||||
logWarn('⚠️ Continuing without ProtonMail integration');
|
||||
}
|
||||
}
|
||||
|
||||
const server = Bun.serve({
|
||||
|
|
@ -99,4 +103,4 @@ const server = Bun.serve({
|
|||
},
|
||||
});
|
||||
|
||||
console.log(chalk.cyan.bold(`\n🚀 SUP running on http://localhost:${server.port}`));
|
||||
logInfo(`\n🚀 SUP running on http://localhost:${server.port}`);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import chalk from 'chalk';
|
||||
import Imap from 'imap';
|
||||
import {
|
||||
BRIDGE_IMAP_PASSWORD,
|
||||
|
|
@ -9,24 +8,24 @@ import {
|
|||
PROTON_BRIDGE_PORT,
|
||||
SUP_TOPIC,
|
||||
} from '../constants/config';
|
||||
import { log } from '../utils/log';
|
||||
import { logError, logInfo, logSuccess, logVerbose, logWarn } from '../utils/log';
|
||||
import { createGroup, sendGroupMessage } from './signal';
|
||||
import { getGroupId, register } from './store';
|
||||
|
||||
export async function startProtonMonitor() {
|
||||
if (!BRIDGE_IMAP_USERNAME || !BRIDGE_IMAP_PASSWORD) {
|
||||
console.error(
|
||||
chalk.red('Missing required env vars: BRIDGE_IMAP_USERNAME and BRIDGE_IMAP_PASSWORD'),
|
||||
);
|
||||
console.error(chalk.yellow('Run: docker compose run --rm protonmail-bridge init'));
|
||||
console.error(chalk.yellow('Then use `login` and `info` commands to get IMAP credentials'));
|
||||
logError('Missing required env vars: BRIDGE_IMAP_USERNAME and BRIDGE_IMAP_PASSWORD');
|
||||
logWarn('Run: docker compose run --rm protonmail-bridge init');
|
||||
logWarn('Then use `login` and `info` commands to get IMAP credentials');
|
||||
return;
|
||||
}
|
||||
|
||||
log(chalk.blue(`🔗 Connecting to Proton Bridge at ${PROTON_BRIDGE_HOST}:${PROTON_BRIDGE_PORT}`));
|
||||
log(chalk.blue(`📨 Monitoring mailbox: ${BRIDGE_IMAP_USERNAME}`));
|
||||
logInfo(`🔗 Connecting to Proton Bridge at ${PROTON_BRIDGE_HOST}:${PROTON_BRIDGE_PORT}`);
|
||||
logInfo(`📨 Monitoring mailbox: ${BRIDGE_IMAP_USERNAME}`);
|
||||
|
||||
const imap = new Imap({
|
||||
let imap: Imap;
|
||||
try {
|
||||
imap = new Imap({
|
||||
user: BRIDGE_IMAP_USERNAME,
|
||||
password: BRIDGE_IMAP_PASSWORD,
|
||||
host: PROTON_BRIDGE_HOST,
|
||||
|
|
@ -35,6 +34,11 @@ export async function startProtonMonitor() {
|
|||
tlsOptions: { rejectUnauthorized: false },
|
||||
keepalive: true,
|
||||
});
|
||||
} catch (err) {
|
||||
logError('❌ Failed to initialize IMAP client:', err);
|
||||
logWarn('⚠️ ProtonMail integration disabled (bridge not reachable)');
|
||||
return;
|
||||
}
|
||||
|
||||
async function sendNotification(title: string, message: string) {
|
||||
try {
|
||||
|
|
@ -50,23 +54,23 @@ export async function startProtonMonitor() {
|
|||
: '';
|
||||
await sendGroupMessage(groupId, `${prefix}**${title}**\n${message}`);
|
||||
|
||||
console.log(chalk.green(`✅ Notification sent: ${title}`));
|
||||
logSuccess(`✅ Notification sent: ${title}`);
|
||||
} catch (error) {
|
||||
console.error(chalk.red('❌ Failed to send notification:'), error);
|
||||
logError('❌ Failed to send notification:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function openInbox() {
|
||||
imap.openBox('INBOX', false, (err, box) => {
|
||||
if (err) {
|
||||
console.error(chalk.red('Failed to open inbox:'), err);
|
||||
logError('Failed to open inbox:', err);
|
||||
return;
|
||||
}
|
||||
|
||||
log(`✅ Connected to inbox (${box.messages.total} messages)`);
|
||||
logVerbose(`✅ Connected to inbox (${box.messages.total} messages)`);
|
||||
|
||||
imap.on('mail', async (numNewMsgs: number) => {
|
||||
log(`📬 ${numNewMsgs} new message(s) received`);
|
||||
logVerbose(`📬 ${numNewMsgs} new message(s) received`);
|
||||
|
||||
const fetch = imap.seq.fetch(`${box.messages.total}:*`, {
|
||||
bodies: 'HEADER.FIELDS (FROM SUBJECT)',
|
||||
|
|
@ -91,26 +95,38 @@ export async function startProtonMonitor() {
|
|||
});
|
||||
|
||||
imap.on('update', () => {
|
||||
log('📊 Mailbox updated');
|
||||
logVerbose('📊 Mailbox updated');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
imap.once('ready', () => {
|
||||
log('✅ IMAP connection ready');
|
||||
logVerbose('✅ IMAP connection ready');
|
||||
openInbox();
|
||||
});
|
||||
|
||||
imap.once('error', (err: Error) => {
|
||||
console.error(chalk.red('❌ IMAP error:'), err);
|
||||
logError('❌ IMAP error:', err);
|
||||
logWarn('⚠️ ProtonMail integration disabled due to connection error');
|
||||
});
|
||||
|
||||
imap.once('end', () => {
|
||||
log('⚠️ IMAP connection ended, reconnecting...');
|
||||
setTimeout(() => imap.connect(), 5000);
|
||||
logVerbose('⚠️ IMAP connection ended, reconnecting...');
|
||||
setTimeout(() => {
|
||||
try {
|
||||
imap.connect();
|
||||
} catch (err) {
|
||||
logError('❌ Failed to reconnect:', err);
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
try {
|
||||
imap.connect();
|
||||
} catch (err) {
|
||||
logError('❌ Failed to connect to Proton Bridge:', err);
|
||||
logWarn('⚠️ ProtonMail integration disabled');
|
||||
}
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
imap.end();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import { rm } from 'node:fs/promises';
|
||||
import chalk from 'chalk';
|
||||
import { DAEMON_START_MAX_ATTEMPTS, DEVICE_NAME, VERBOSE } from '../constants/config';
|
||||
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 { logError, logInfo, logSuccess, logVerbose, logWarn } from '../utils/log';
|
||||
import { call } from '../utils/rpc';
|
||||
|
||||
log(`Running signal-cli from ${SIGNAL_CLI}`);
|
||||
logVerbose(`Running signal-cli from ${SIGNAL_CLI}`);
|
||||
|
||||
let account: string | null = null;
|
||||
let currentLinkUri: string | null = null;
|
||||
|
|
@ -141,19 +140,19 @@ export async function startDaemon() {
|
|||
|
||||
if (VERBOSE) {
|
||||
if (trimmed.includes('ERROR')) {
|
||||
console.error(chalk.red('[signal-cli]'), trimmed);
|
||||
logError('[signal-cli]', trimmed);
|
||||
} else if (trimmed.includes('WARN')) {
|
||||
console.warn(chalk.yellow('[signal-cli]'), trimmed);
|
||||
logWarn('[signal-cli]', trimmed);
|
||||
} else {
|
||||
console.log(chalk.dim('[signal-cli]'), trimmed);
|
||||
logInfo('[signal-cli]', trimmed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.includes('WARN')) {
|
||||
console.warn(chalk.yellow('[signal-cli]'), trimmed);
|
||||
logWarn('[signal-cli]', trimmed);
|
||||
} else if (trimmed.includes('ERROR') || !trimmed.includes('INFO')) {
|
||||
console.error(chalk.red('[signal-cli]'), trimmed);
|
||||
logError('[signal-cli]', trimmed);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -169,11 +168,11 @@ export async function startDaemon() {
|
|||
},
|
||||
});
|
||||
socket.end();
|
||||
console.log(chalk.green('✓ signal-cli daemon started'));
|
||||
logSuccess('✓ signal-cli daemon started');
|
||||
return proc;
|
||||
} catch (_error) {
|
||||
if (authError && attempts > 5 && !cleaned) {
|
||||
console.log(chalk.yellow('⚠ Detected stale account data, cleaning up and retrying...'));
|
||||
logWarn('⚠ Detected stale account data, cleaning up and retrying...');
|
||||
proc.kill();
|
||||
await unlinkDevice();
|
||||
cleaned = true;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
import chalk from 'chalk';
|
||||
import { VERBOSE } from '../constants/config';
|
||||
|
||||
export const log = (...args: unknown[]) => VERBOSE && console.log(...args);
|
||||
export const logVerbose = (...args: unknown[]) => VERBOSE && console.log(...args);
|
||||
|
||||
export const logError = (...args: unknown[]) => console.error(chalk.red(...args));
|
||||
export const logWarn = (...args: unknown[]) => console.warn(chalk.yellow(...args));
|
||||
export const logInfo = (...args: unknown[]) => console.log(chalk.blue(...args));
|
||||
export const logSuccess = (...args: unknown[]) => console.log(chalk.green(...args));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue