Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the React-Native Pusher library for iOS and Android #56610

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions __mocks__/@pusher/pusher-websocket-react-native/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type {PusherEvent} from '@pusher/pusher-websocket-react-native';
import CONST from '@src/CONST';

type OnSubscriptionSucceeded = () => void;

type OnEvent = (event: PusherEvent) => void;

type ChannelCallbacks = {
onSubscriptionSucceeded: OnSubscriptionSucceeded;
onEvent: OnEvent;
};

type InitProps = {
onConnectionStateChange: (currentState: string, previousState: string) => void;
};

type SubscribeProps = {
channelName: string;
onEvent: OnEvent;
onSubscriptionSucceeded: OnSubscriptionSucceeded;
};

type UnsubscribeProps = {
channelName: string;
};

class MockedPusher {
static instance: MockedPusher | null = null;

channels = new Map<string, ChannelCallbacks>();

socketId = 'mock-socket-id';

connectionState: string = CONST.PUSHER.STATE.DISCONNECTED;

static getInstance() {
if (!MockedPusher.instance) {
MockedPusher.instance = new MockedPusher();
}
return MockedPusher.instance;
}

init({onConnectionStateChange}: InitProps) {
onConnectionStateChange(CONST.PUSHER.STATE.CONNECTED, CONST.PUSHER.STATE.DISCONNECTED);
return Promise.resolve();
}

connect() {
this.connectionState = CONST.PUSHER.STATE.CONNECTED;
return Promise.resolve();
}

disconnect() {
this.connectionState = CONST.PUSHER.STATE.DISCONNECTED;
this.channels.clear();
return Promise.resolve();
}

subscribe({channelName, onEvent, onSubscriptionSucceeded}: SubscribeProps) {
if (!this.channels.has(channelName)) {
this.channels.set(channelName, {onEvent, onSubscriptionSucceeded});
onSubscriptionSucceeded();
}
return Promise.resolve();
}

unsubscribe({channelName}: UnsubscribeProps) {
this.channels.delete(channelName);
}

trigger({channelName, eventName, data}: PusherEvent) {
this.channels.get(channelName)?.onEvent({channelName, eventName, data: data as Record<string, unknown>});
}

getChannel(channelName: string) {
return this.channels.get(channelName);
}

getSocketId() {
return Promise.resolve(this.socketId);
}
}

// eslint-disable-next-line import/prefer-default-export
export {MockedPusher as Pusher};
9 changes: 0 additions & 9 deletions __mocks__/pusher-js/react-native.ts

This file was deleted.

28 changes: 23 additions & 5 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ PODS:
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- NWWebSocket (0.5.4)
- Onfido (29.7.2)
- onfido-react-native-sdk (10.6.0):
- DoubleConversion
Expand All @@ -335,6 +336,12 @@ PODS:
- Yoga
- Plaid (5.6.0)
- PromisesObjC (2.4.0)
- pusher-websocket-react-native (1.3.1):
- PusherSwift (~> 10.1.5)
- React
- PusherSwift (10.1.5):
- NWWebSocket (~> 0.5.4)
- TweetNacl (~> 1.0.0)
- RCT-Folly (2024.01.01.00):
- boost
- DoubleConversion
Expand Down Expand Up @@ -2842,6 +2849,7 @@ PODS:
- SDWebImage/Core (~> 5.17)
- SocketRocket (0.7.1)
- Turf (2.8.0)
- TweetNacl (1.0.2)
- VisionCamera (4.6.1):
- VisionCamera/Core (= 4.6.1)
- VisionCamera/React (= 4.6.1)
Expand Down Expand Up @@ -2872,6 +2880,7 @@ DEPENDENCIES:
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- lottie-react-native (from `../node_modules/lottie-react-native`)
- "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)"
- "pusher-websocket-react-native (from `../node_modules/@pusher/pusher-websocket-react-native`)"
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
Expand Down Expand Up @@ -3008,15 +3017,18 @@ SPEC REPOS:
- MapboxMaps
- MapboxMobileEvents
- nanopb
- NWWebSocket
- Onfido
- Plaid
- PromisesObjC
- PusherSwift
- SDWebImage
- SDWebImageAVIFCoder
- SDWebImageSVGCoder
- SDWebImageWebPCoder
- SocketRocket
- Turf
- TweetNacl

EXTERNAL SOURCES:
AppLogs:
Expand Down Expand Up @@ -3060,6 +3072,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/lottie-react-native"
onfido-react-native-sdk:
:path: "../node_modules/@onfido/react-native-sdk"
pusher-websocket-react-native:
:path: "../node_modules/@pusher/pusher-websocket-react-native"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTDeprecation:
Expand Down Expand Up @@ -3275,8 +3289,8 @@ SPEC CHECKSUMS:
AirshipServiceExtension: 9c73369f426396d9fb9ff222d86d842fac76ba46
AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
AppLogs: 3bc4e9b141dbf265b9464409caaa40416a9ee0e0
boost: d7090b1a93a9798c029277a8288114f2948f471c
DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
boost: 26992d1adf73c1c7676360643e687aee6dda994b
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
EXAV: 9773c9799767c9925547b05e41a26a0240bb8ef2
EXImageLoader: 759063a65ab016b836f73972d3bb25404888713d
expensify-react-native-background-task: 6f797cf470b627912c246514b1631a205794775d
Expand All @@ -3296,11 +3310,11 @@ SPEC CHECKSUMS:
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c
FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
ForkInputMask: 55e3fbab504b22da98483e9f9a6514b98fdd2f3c
FullStory: c8a10b2358c0d33c57be84d16e4c440b0434b33d
fullstory_react-native: 63a803cca04b0447a71daa73e4df3f7b56e1919d
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db
Expand All @@ -3318,11 +3332,14 @@ SPEC CHECKSUMS:
MapboxMaps: 05822ab0ee74f7d626e6471572439afe35c1c116
MapboxMobileEvents: d044b9edbe0ec7df60f6c2c9634fe9a7f449266b
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
NWWebSocket: 040d22f23438cc09aaeabf537beff67699c3c76d
Onfido: f3af62ea1c9a419589c133e3e511e5d2c4f3f8af
onfido-react-native-sdk: 4ccfdeb10f9ccb4a5799d2555cdbc2a068a42c0d
Plaid: c32f22ffce5ec67c9e6147eaf6c4d7d5f8086d89
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
pusher-websocket-react-native: e40c49a1e4ec96d4157375aebcf44943f0f8f62f
PusherSwift: cad631bad86cfff4b8458dce1310a7774e469b1f
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
RCTDeprecation: 2c5e1000b04ab70b53956aa498bf7442c3c6e497
RCTRequired: 5f785a001cf68a551c5f5040fb4c415672dbb481
RCTTypeSafety: 6b98db8965005d32449605c0d005ecb4fee8a0f7
Expand Down Expand Up @@ -3428,6 +3445,7 @@ SPEC CHECKSUMS:
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e
TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6
VisionCamera: c95a8ad535f527562be1fb05fb2fd324578e769c
Yoga: 3deb2471faa9916c8a82dda2a22d3fba2620ad37

Expand Down
20 changes: 11 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"@gorhom/portal": "^1.0.14",
"@invertase/react-native-apple-authentication": "^2.2.2",
"@onfido/react-native-sdk": "10.6.0",
"@pusher/pusher-websocket-react-native": "^1.3.1",
"@react-native-camera-roll/camera-roll": "7.4.0",
"@react-native-clipboard/clipboard": "^1.15.0",
"@react-native-community/geolocation": "3.3.0",
Expand Down Expand Up @@ -321,7 +322,6 @@
"peggy": "^4.0.3",
"portfinder": "^1.0.28",
"prettier": "^2.8.8",
"pusher-js-mock": "^0.3.3",
"react-compiler-healthcheck": "^19.0.0-beta-8a03594-20241020",
"react-compiler-runtime": "^19.0.0-beta-8a03594-20241020",
"react-is": "^18.3.1",
Expand Down
11 changes: 11 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,17 @@ const CONST = {
PRIVATE_USER_CHANNEL_PREFIX: 'private-encrypted-user-accountID-',
PRIVATE_REPORT_CHANNEL_PREFIX: 'private-report-reportID-',
PRESENCE_ACTIVE_GUIDES: 'presence-activeGuides',
STATE: {
CONNECTING: 'CONNECTING',
CONNECTED: 'CONNECTED',
DISCONNECTING: 'DISCONNECTING',
DISCONNECTED: 'DISCONNECTED',
RECONNECTING: 'RECONNECTING',
},
CHANNEL_STATUS: {
SUBSCRIBING: 'SUBSCRIBING',
SUBSCRIBED: 'SUBSCRIBED',
},
},

EMOJI_SPACER: 'SPACER',
Expand Down
4 changes: 2 additions & 2 deletions src/libs/API/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Log from '@libs/Log';
import {HandleUnusedOptimisticID, Logging, Pagination, Reauthentication, RecheckConnection, SaveResponseInOnyx} from '@libs/Middleware';
import {isOffline} from '@libs/Network/NetworkStore';
import {push as pushToSequentialQueue, waitForIdle as waitForSequentialQueueIdle} from '@libs/Network/SequentialQueue';
import {getPusherSocketID} from '@libs/Pusher/pusher';
import Pusher from '@libs/Pusher';
import {processWithMiddleware, use} from '@libs/Request';
import {getLength as getPersistedRequestsLength} from '@userActions/PersistedRequests';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -70,7 +70,7 @@ function prepareRequest<TCommand extends ApiCommand>(

// We send the pusherSocketID with all write requests so that the api can include it in push events to prevent Pusher from sending the events to the requesting client. The push event
// is sent back to the requesting client in the response data instead, which prevents a replay effect in the UI. See https://github.com/Expensify/App/issues/12775.
pusherSocketID: isWriteRequest ? getPusherSocketID() : undefined,
pusherSocketID: isWriteRequest ? Pusher.getPusherSocketID() : undefined,
};

// Assemble all request metadata (used by middlewares, and for persisted requests stored in Onyx)
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOpt
import type {AuthScreensParamList} from '@libs/Navigation/types';
import NetworkConnection from '@libs/NetworkConnection';
import onyxSubscribe from '@libs/onyxSubscribe';
import * as Pusher from '@libs/Pusher/pusher';
import Pusher from '@libs/Pusher';
import PusherConnectionManager from '@libs/PusherConnectionManager';
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
import * as SessionUtils from '@libs/SessionUtils';
Expand Down
Loading
Loading