66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
// Bridge to the native PollingPlugin (see
|
|
// android/app/src/main/java/chat/vojo/app/PollingPlugin.java).
|
|
//
|
|
// Drives the WorkManager-based /notifications polling fallback used on
|
|
// networks where FCM (mtalk.google.com:5228) is blocked. JS owns the
|
|
// credential + room-name cache lifecycle; native owns the periodic fetch
|
|
// and notification rendering.
|
|
//
|
|
// Web has no analogue: the Service Worker already wakes for push without
|
|
// needing a periodic poll, and browsers don't expose a 15-minute periodic
|
|
// background API anyway. The web fallback is a no-op.
|
|
|
|
import { registerPlugin } from '@capacitor/core';
|
|
import { isAndroidPlatform } from '../utils/capacitor';
|
|
|
|
export type RoomMetadataMap = Record<string, string | { name: string; isDirect: boolean }>;
|
|
|
|
interface PollingPluginIface {
|
|
saveSession(opts: { accessToken: string; homeserverUrl: string; userId?: string }): Promise<void>;
|
|
clearSession(): Promise<void>;
|
|
// Tolerant of both legacy (`roomId: "Display"`) and new structured shape
|
|
// (`roomId: { name, isDirect }`) — the Java side decides the message
|
|
// channel (DM vs group) based on the structured value when present.
|
|
saveRoomNames(opts: { names: RoomMetadataMap }): Promise<void>;
|
|
schedule(opts: { intervalMinutes: number }): Promise<void>;
|
|
cancel(): Promise<void>;
|
|
dismissRoom(opts: { roomId: string }): Promise<void>;
|
|
}
|
|
|
|
const noopPlugin: PollingPluginIface = {
|
|
saveSession: async () => undefined,
|
|
clearSession: async () => undefined,
|
|
saveRoomNames: async () => undefined,
|
|
schedule: async () => undefined,
|
|
cancel: async () => undefined,
|
|
dismissRoom: async () => undefined,
|
|
};
|
|
|
|
const plugin = registerPlugin<PollingPluginIface>('Polling', {
|
|
web: noopPlugin,
|
|
});
|
|
|
|
const guard = async <T>(fn: () => Promise<T>, fallback: T): Promise<T> => {
|
|
if (!isAndroidPlatform()) return fallback;
|
|
try {
|
|
return await fn();
|
|
} catch (err) {
|
|
// Old APK installed before the plugin shipped, or transient bridge
|
|
// error. Swallow — polling is a best-effort backup channel, not a
|
|
// hard dependency on the foreground push lifecycle.
|
|
// eslint-disable-next-line no-console
|
|
console.warn('[polling] native call failed:', err);
|
|
return fallback;
|
|
}
|
|
};
|
|
|
|
export const polling = {
|
|
saveSession: (opts: { accessToken: string; homeserverUrl: string; userId?: string }) =>
|
|
guard(() => plugin.saveSession(opts), undefined),
|
|
clearSession: () => guard(() => plugin.clearSession(), undefined),
|
|
saveRoomNames: (names: RoomMetadataMap) =>
|
|
guard(() => plugin.saveRoomNames({ names }), undefined),
|
|
schedule: (intervalMinutes = 15) => guard(() => plugin.schedule({ intervalMinutes }), undefined),
|
|
cancel: () => guard(() => plugin.cancel(), undefined),
|
|
dismissRoom: (roomId: string) => guard(() => plugin.dismissRoom({ roomId }), undefined),
|
|
};
|