Chore: Dehydrate share extension from rocketchat.js (#3753)

Co-authored-by: Gleidson Daniel Silva <gleidson10daniel@hotmail.com>
This commit is contained in:
Gerzon Z 2022-03-16 16:40:32 -04:00 committed by GitHub
parent e792f2a49b
commit a754983ac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 152 additions and 102 deletions

View File

@ -37,6 +37,21 @@ class AvatarContainer extends React.Component<IAvatar, any> {
} }
} }
shouldComponentUpdate(nextProps: IAvatar, nextState: { avatarETag: string }) {
const { avatarETag } = this.state;
const { text, type } = this.props;
if (nextState.avatarETag !== avatarETag) {
return true;
}
if (nextProps.text !== text) {
return true;
}
if (nextProps.type !== type) {
return true;
}
return false;
}
componentWillUnmount() { componentWillUnmount() {
if (this.subscription?.unsubscribe) { if (this.subscription?.unsubscribe) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();

View File

@ -1,4 +1,5 @@
export interface ICredentials { export interface ICredentials {
resume?: string;
user?: string; user?: string;
password?: string; password?: string;
username?: string; username?: string;

View File

@ -66,7 +66,7 @@ export const getDatabase = (database = ''): Database => {
}; };
interface IDatabases { interface IDatabases {
shareDB?: TAppDatabase; shareDB?: TAppDatabase | null;
serversDB: TServerDatabase; serversDB: TServerDatabase;
activeDB?: TAppDatabase; activeDB?: TAppDatabase;
} }

View File

@ -2,13 +2,10 @@ import { Q } from '@nozbe/watermelondb';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import { InteractionManager } from 'react-native'; import { InteractionManager } from 'react-native';
import { setActiveUsers } from '../../actions/activeUsers'; import { setActiveUsers } from '../../actions/activeUsers';
import { encryptionInit } from '../../actions/encryption';
import { setUser } from '../../actions/login'; import { setUser } from '../../actions/login';
import { shareSelectServer, shareSetSettings, shareSetUser } from '../../actions/share';
import defaultSettings from '../../constants/settings'; import defaultSettings from '../../constants/settings';
import { getDeviceToken } from '../../notifications/push'; import { getDeviceToken } from '../../notifications/push';
import log from '../../utils/log'; import log from '../../utils/log';
import SSLPinning from '../../utils/sslPinning';
import database from '../database'; import database from '../database';
import triggerBlockAction, { triggerCancel, triggerSubmitView } from '../methods/actions'; import triggerBlockAction, { triggerCancel, triggerSubmitView } from '../methods/actions';
import callJitsi, { callJitsiWithoutServer } from '../methods/callJitsi'; import callJitsi, { callJitsiWithoutServer } from '../methods/callJitsi';
@ -65,7 +62,8 @@ import {
stopListener, stopListener,
connect connect
} from './services/connect'; } from './services/connect';
import * as restAPis from './services/restApi'; import { shareExtensionInit, closeShareExtension } from './services/shareExtension';
import * as restApis from './services/restApi';
const TOKEN_KEY = 'reactnativemeteor_usertoken'; const TOKEN_KEY = 'reactnativemeteor_usertoken';
const CURRENT_SERVER = 'currentServer'; const CURRENT_SERVER = 'currentServer';
@ -81,7 +79,7 @@ const RocketChat = {
TOKEN_KEY, TOKEN_KEY,
CURRENT_SERVER, CURRENT_SERVER,
CERTIFICATE_KEY, CERTIFICATE_KEY,
...restAPis, ...restApis,
...search, ...search,
callJitsi, callJitsi,
callJitsiWithoutServer, callJitsiWithoutServer,
@ -109,81 +107,11 @@ const RocketChat = {
checkAndReopen, checkAndReopen,
disconnect, disconnect,
connect, connect,
async shareExtensionInit(server) { shareExtensionInit,
database.setShareDB(server); closeShareExtension,
try {
const certificate = UserPreferences.getString(`${RocketChat.CERTIFICATE_KEY}-${server}`);
SSLPinning.setCertificate(certificate, server);
} catch {
// Do nothing
}
this.shareSDK = sdk.disconnect();
this.shareSDK = sdk.initialize(server);
// set Server
const currentServer = { server };
const serversDB = database.servers;
const serversCollection = serversDB.get('servers');
try {
const serverRecord = await serversCollection.find(server);
currentServer.version = serverRecord.version;
} catch {
// Record not found
}
reduxStore.dispatch(shareSelectServer(currentServer));
RocketChat.setCustomEmojis();
try {
// set Settings
const settings = ['Accounts_AvatarBlockUnauthenticatedAccess'];
const db = database.active;
const settingsCollection = db.get('settings');
const settingsRecords = await settingsCollection.query(Q.where('id', Q.oneOf(settings))).fetch();
const parsed = Object.values(settingsRecords).map(item => ({
_id: item.id,
valueAsString: item.valueAsString,
valueAsBoolean: item.valueAsBoolean,
valueAsNumber: item.valueAsNumber,
valueAsArray: item.valueAsArray,
_updatedAt: item._updatedAt
}));
reduxStore.dispatch(shareSetSettings(this.parseSettings(parsed)));
// set User info
const userId = UserPreferences.getString(`${RocketChat.TOKEN_KEY}-${server}`);
const userCollections = serversDB.get('users');
let user = null;
if (userId) {
const userRecord = await userCollections.find(userId);
user = {
id: userRecord.id,
token: userRecord.token,
username: userRecord.username,
roles: userRecord.roles
};
}
reduxStore.dispatch(shareSetUser(user));
await RocketChat.login({ resume: user.token });
reduxStore.dispatch(encryptionInit());
} catch (e) {
log(e);
}
},
closeShareExtension() {
this.shareSDK = sdk.disconnect();
database.share = null;
reduxStore.dispatch(shareSelectServer({}));
reduxStore.dispatch(shareSetUser({}));
reduxStore.dispatch(shareSetSettings({}));
},
async e2eFetchMyKeys() { async e2eFetchMyKeys() {
// RC 0.70.0 // RC 0.70.0
const sdk = this.shareSDK || this.sdk;
const result = await sdk.get('e2e.fetchMyKeys'); const result = await sdk.get('e2e.fetchMyKeys');
// snake_case -> camelCase // snake_case -> camelCase
if (result.success) { if (result.success) {

View File

@ -9,19 +9,27 @@ import { Serialized, MatchPathPattern, OperationParams, PathFor, ResultFor } fro
class Sdk { class Sdk {
private sdk: typeof Rocketchat; private sdk: typeof Rocketchat;
private shareSdk?: typeof Rocketchat;
private code: any; private code: any;
private initializeSdk(server: string): typeof Rocketchat {
// The app can't reconnect if reopen interval is 5s while in development
return new Rocketchat({ host: server, protocol: 'ddp', useSsl: useSsl(server), reopen: __DEV__ ? 20000 : 5000 });
}
// TODO: We need to stop returning the SDK after all methods are dehydrated // TODO: We need to stop returning the SDK after all methods are dehydrated
initialize(server: string) { initialize(server: string) {
this.code = null; this.code = null;
this.sdk = this.initializeSdk(server);
// The app can't reconnect if reopen interval is 5s while in development
this.sdk = new Rocketchat({ host: server, protocol: 'ddp', useSsl: useSsl(server), reopen: __DEV__ ? 20000 : 5000 });
return this.sdk; return this.sdk;
} }
initializeShareExtension(server: string) {
this.shareSdk = this.initializeSdk(server);
}
get current() { get current() {
return this.sdk; return this.shareSdk || this.sdk;
} }
/** /**
@ -29,6 +37,11 @@ class Sdk {
* I'm returning "null" because we need to remove both instances of this.sdk here and on rocketchat.js * I'm returning "null" because we need to remove both instances of this.sdk here and on rocketchat.js
*/ */
disconnect() { disconnect() {
if (this.shareSdk) {
this.shareSdk.disconnect();
this.shareSdk = null;
return null;
}
if (this.sdk) { if (this.sdk) {
this.sdk.disconnect(); this.sdk.disconnect();
this.sdk = null; this.sdk = null;
@ -47,7 +60,7 @@ class Sdk {
? void ? void
: Serialized<OperationParams<'GET', MatchPathPattern<TPath>>> : Serialized<OperationParams<'GET', MatchPathPattern<TPath>>>
): Promise<Serialized<ResultFor<'GET', MatchPathPattern<TPath>>>> { ): Promise<Serialized<ResultFor<'GET', MatchPathPattern<TPath>>>> {
return this.sdk.get(endpoint, params); return this.current.get(endpoint, params);
} }
post<TPath extends PathFor<'POST'>>( post<TPath extends PathFor<'POST'>>(
@ -64,7 +77,7 @@ class Sdk {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const isMethodCall = endpoint?.startsWith('method.call/'); const isMethodCall = endpoint?.startsWith('method.call/');
try { try {
const result = await this.sdk.post(endpoint, params); const result = await this.current.post(endpoint, params);
/** /**
* if API_Use_REST_For_DDP_Calls is enabled and it's a method call, * if API_Use_REST_For_DDP_Calls is enabled and it's a method call,
@ -101,7 +114,7 @@ class Sdk {
methodCall(...args: any[]): Promise<any> { methodCall(...args: any[]): Promise<any> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const result = await this.sdk?.methodCall(...args, this.code || ''); const result = await this.current.methodCall(...args, this.code || '');
return resolve(result); return resolve(result);
} catch (e: any) { } catch (e: any) {
if (e.error && (e.error === 'totp-required' || e.error === 'totp-invalid')) { if (e.error && (e.error === 'totp-required' || e.error === 'totp-invalid')) {
@ -140,23 +153,23 @@ class Sdk {
} }
subscribe(...args: any[]) { subscribe(...args: any[]) {
return this.sdk.subscribe(...args); return this.current.subscribe(...args);
} }
subscribeRaw(...args: any[]) { subscribeRaw(...args: any[]) {
return this.sdk.subscribeRaw(...args); return this.current.subscribeRaw(...args);
} }
subscribeRoom(...args: any[]) { subscribeRoom(...args: any[]) {
return this.sdk.subscribeRoom(...args); return this.current.subscribeRoom(...args);
} }
unsubscribe(subscription: any[]) { unsubscribe(subscription: any[]) {
return this.sdk.unsubscribe(subscription); return this.current.unsubscribe(subscription);
} }
onStreamData(...args: any[]) { onStreamData(...args: any[]) {
return this.sdk.onStreamData(...args); return this.current.onStreamData(...args);
} }
} }

View File

@ -0,0 +1,92 @@
import { Q } from '@nozbe/watermelondb';
import { shareSetSettings, shareSelectServer, shareSetUser } from '../../../actions/share';
import SSLPinning from '../../../utils/sslPinning';
import log from '../../../utils/log';
import { IShareServer, IShareUser } from '../../../reducers/share';
import UserPreferences from '../../userPreferences';
import database from '../../database';
import RocketChat from '../rocketchat';
import { encryptionInit } from '../../../actions/encryption';
import { store } from '../../auxStore';
import sdk from './sdk';
export async function shareExtensionInit(server: string) {
database.setShareDB(server);
try {
const certificate = UserPreferences.getString(`${RocketChat.CERTIFICATE_KEY}-${server}`);
if (SSLPinning && certificate) {
await SSLPinning.setCertificate(certificate, server);
}
} catch {
// Do nothing
}
// sdk.current.disconnect();
sdk.initializeShareExtension(server);
// set Server
const currentServer: IShareServer = {
server,
version: ''
};
const serversDB = database.servers;
const serversCollection = serversDB.get('servers');
try {
const serverRecord = await serversCollection.find(server);
currentServer.version = serverRecord.version;
} catch {
// Record not found
}
store.dispatch(shareSelectServer(currentServer));
RocketChat.setCustomEmojis();
try {
// set Settings
const settings = ['Accounts_AvatarBlockUnauthenticatedAccess'];
const db = database.active;
const settingsCollection = db.get('settings');
const settingsRecords = await settingsCollection.query(Q.where('id', Q.oneOf(settings))).fetch();
const parsed = Object.values(settingsRecords).map(item => ({
_id: item.id,
valueAsString: item.valueAsString,
valueAsBoolean: item.valueAsBoolean,
valueAsNumber: item.valueAsNumber,
valueAsArray: item.valueAsArray,
_updatedAt: item._updatedAt
}));
store.dispatch(shareSetSettings(RocketChat.parseSettings(parsed)));
// set User info
const userId = UserPreferences.getString(`${RocketChat.TOKEN_KEY}-${server}`);
const userCollections = serversDB.get('users');
let user = null;
if (userId) {
const userRecord = await userCollections.find(userId);
user = {
id: userRecord.id,
token: userRecord.token,
username: userRecord.username,
roles: userRecord.roles
};
}
store.dispatch(shareSetUser(user as IShareUser));
if (user) {
await RocketChat.login({ resume: user.token });
}
store.dispatch(encryptionInit());
} catch (e) {
log(e);
}
}
export function closeShareExtension() {
sdk.disconnect();
database.share = null;
store.dispatch(shareSelectServer({}));
store.dispatch(shareSetUser({}));
store.dispatch(shareSetSettings({}));
}

View File

@ -2,17 +2,17 @@ import { TActionsShare } from '../actions/share';
import { SHARE } from '../actions/actionsTypes'; import { SHARE } from '../actions/actionsTypes';
export interface IShareServer { export interface IShareServer {
server: string; server?: string;
version: string; version?: string;
} }
export type TShareSettings = Record<string, string | number | boolean>; export type TShareSettings = Record<string, string | number | boolean>;
export interface IShareUser { export interface IShareUser {
id: string; id?: string;
token: string; token?: string;
username: string; username?: string;
roles: string[]; roles?: string[];
} }
export interface IShare { export interface IShare {
@ -22,8 +22,8 @@ export interface IShare {
} }
export const initialState: IShare = { export const initialState: IShare = {
user: {} as IShareUser, user: {},
server: {} as IShareServer, server: {},
settings: {} settings: {}
}; };

View File

@ -10,6 +10,7 @@ import UserPreferences from './lib/userPreferences';
import Navigation from './lib/ShareNavigation'; import Navigation from './lib/ShareNavigation';
import store from './lib/createStore'; import store from './lib/createStore';
import { initStore } from './lib/auxStore'; import { initStore } from './lib/auxStore';
import { closeShareExtension, shareExtensionInit } from './lib/rocketchat/services/shareExtension';
import { defaultHeader, getActiveRouteName, navigationTheme, themedHeader } from './utils/navigation'; import { defaultHeader, getActiveRouteName, navigationTheme, themedHeader } from './utils/navigation';
import RocketChat from './lib/rocketchat'; import RocketChat from './lib/rocketchat';
import { ThemeContext } from './theme'; import { ThemeContext } from './theme';
@ -107,7 +108,7 @@ class Root extends React.Component<{}, IState> {
} }
componentWillUnmount(): void { componentWillUnmount(): void {
RocketChat.closeShareExtension(); closeShareExtension();
unsubscribeTheme(); unsubscribeTheme();
} }
@ -117,7 +118,7 @@ class Root extends React.Component<{}, IState> {
if (currentServer) { if (currentServer) {
await localAuthenticate(currentServer); await localAuthenticate(currentServer);
this.setState({ root: 'inside' }); this.setState({ root: 'inside' });
await RocketChat.shareExtensionInit(currentServer); await shareExtensionInit(currentServer);
} else { } else {
this.setState({ root: 'outside' }); this.setState({ root: 'outside' });
} }

View File

@ -7,7 +7,7 @@ import { Q, Model } from '@nozbe/watermelondb';
import I18n from '../i18n'; import I18n from '../i18n';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import ServerItem, { ROW_HEIGHT } from '../presentation/ServerItem'; import ServerItem, { ROW_HEIGHT } from '../presentation/ServerItem';
import RocketChat from '../lib/rocketchat'; import { shareExtensionInit } from '../lib/rocketchat/services/shareExtension';
import database from '../lib/database'; import database from '../lib/database';
import SafeAreaView from '../containers/SafeAreaView'; import SafeAreaView from '../containers/SafeAreaView';
import * as List from '../containers/List'; import * as List from '../containers/List';
@ -50,7 +50,7 @@ class SelectServerView extends React.Component<ISelectServerViewProps, ISelectSe
navigation.navigate('ShareListView'); navigation.navigate('ShareListView');
if (currentServer !== server) { if (currentServer !== server) {
await RocketChat.shareExtensionInit(server); await shareExtensionInit(server);
} }
}; };