Skip to content

Commit ad00e1c

Browse files
authored
Merge pull request #1406 from Bilb/feat/add-multi-part-support
feat: add multi part libsession config msg support
2 parents 9ec2e31 + 9771a86 commit ad00e1c

File tree

25 files changed

+1071
-341
lines changed

25 files changed

+1071
-341
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "session-desktop",
33
"productName": "Session",
44
"description": "Private messaging from your desktop",
5-
"version": "1.15.2",
5+
"version": "1.16.0",
66
"license": "GPL-3.0",
77
"author": {
88
"name": "Session Foundation",
@@ -79,7 +79,7 @@
7979
"fs-extra": "11.3.0",
8080
"glob": "10.4.5",
8181
"image-type": "^4.1.0",
82-
"libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.33/libsession_util_nodejs-v0.4.33.tar.gz",
82+
"libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.5.3/libsession_util_nodejs-v0.5.3.tar.gz",
8383
"libsodium-wrappers-sumo": "^0.7.15",
8484
"linkify-it": "^5.0.0",
8585
"lodash": "^4.17.21",

ts/components/SessionPasswordPrompt.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const StyledContent = styled.div`
4141
width: 100%;
4242
`;
4343

44-
// We cannot import toastutils from the password window as it is pulling the whole sending
44+
// We cannot import ToastUtils from the password window as it is pulling the whole sending
4545
// pipeline(and causing crashes on Session instances with password)
4646
function pushToastError(id: string, description: string) {
4747
toast.error(<SessionToast description={description} />, {

ts/components/basic/SessionButton.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export type SessionButtonProps = {
127127
dataTestId?: React.SessionDataTestId;
128128
reference?: RefObject<HTMLButtonElement>;
129129
className?: string;
130+
style?: React.CSSProperties;
130131
};
131132

132133
export const SessionButton = (props: SessionButtonProps) => {
@@ -145,6 +146,7 @@ export const SessionButton = (props: SessionButtonProps) => {
145146
onClick = null,
146147
fontWeight,
147148
margin,
149+
style,
148150
} = props;
149151

150152
const clickHandler = (e: any) => {
@@ -175,7 +177,7 @@ export const SessionButton = (props: SessionButtonProps) => {
175177
ref={reference}
176178
data-testid={dataTestId}
177179
$fontWeight={fontWeight}
178-
style={{ margin }}
180+
style={{ ...style, margin }}
179181
>
180182
{props.children || text}
181183
</StyledButton>

ts/components/dialog/debug/components.tsx

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import useAsyncFn from 'react-use/lib/useAsyncFn';
66
import useInterval from 'react-use/lib/useInterval';
77
import { filesize } from 'filesize';
88

9+
import type { PubkeyType } from 'libsession_util_nodejs';
10+
import { chunk } from 'lodash';
911
import { Flex } from '../../basic/Flex';
1012
import { SpacerXS } from '../../basic/Text';
1113
import { localize } from '../../../localization/localeTools';
@@ -15,14 +17,48 @@ import { SessionButton, SessionButtonColor } from '../../basic/SessionButton';
1517
import { ToastUtils, UserUtils } from '../../../session/utils';
1618
import { getLatestReleaseFromFileServer } from '../../../session/apis/file_server_api/FileServerApi';
1719
import { SessionSpinner } from '../../loading';
18-
import { setDebugMode } from '../../../state/ducks/debug';
1920
import { updateDebugMenuModal } from '../../../state/ducks/modalDialog';
21+
import { setDebugMode } from '../../../state/ducks/debug';
2022
import LIBSESSION_CONSTANTS from '../../../session/utils/libsession/libsession_constants';
2123
import { type ReleaseChannels } from '../../../updater/types';
2224
import { fetchLatestRelease } from '../../../session/fetch_latest_release';
2325
import { saveLogToDesktop } from '../../../util/logger/renderer_process_logging';
2426
import { DURATION } from '../../../session/constants';
2527
import { Errors } from '../../../types/Errors';
28+
import { PubKey } from '../../../session/types';
29+
import { ConvoHub } from '../../../session/conversations';
30+
import { ConversationTypeEnum } from '../../../models/types';
31+
import { ContactsWrapperActions } from '../../../webworker/workers/browser/libsession_worker_interface';
32+
import { usePolling } from '../../../hooks/usePolling';
33+
34+
const hexRef = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
35+
36+
function genRandomHexString(length: number) {
37+
const result = [];
38+
39+
for (let n = 0; n < length; n++) {
40+
result.push(hexRef[Math.floor(Math.random() * 16)]);
41+
}
42+
return result.join('');
43+
}
44+
45+
async function generateOneRandomContact() {
46+
const numBytes = PubKey.PUBKEY_LEN - 2;
47+
48+
const hexBuffer = genRandomHexString(numBytes);
49+
const id: PubkeyType = `05${hexBuffer}`;
50+
const created = await ConvoHub.use().getOrCreateAndWait(id, ConversationTypeEnum.PRIVATE);
51+
// now() is not going to be synced on devices, instead createdAt will be used.
52+
// createdAt is set to now in libsession-util itself,
53+
// but we still need to mark that conversation as active
54+
// for it to be inserted in the config
55+
created.setKey('active_at', Date.now());
56+
created.setKey('isApproved', true);
57+
created.setSessionDisplayNameNoCommit(id.slice(2, 8));
58+
59+
await created.commit();
60+
return created;
61+
}
2662

2763
const CheckVersionButton = ({ channelToCheck }: { channelToCheck: ReleaseChannels }) => {
2864
const [loading, setLoading] = useState(false);
@@ -172,12 +208,68 @@ const ClearOldLogsButton = () => {
172208
onClick={() => {
173209
void handleDeleteAllLogs();
174210
}}
211+
style={{ minWidth: '250px' }}
175212
>
176213
Clear old logs {filesize(logSize)}
177214
</SessionButton>
178215
);
179216
};
180217

218+
const dummyContactPerClick = 500;
219+
220+
async function fetchContactsCountAndUpdate() {
221+
const count = (await ContactsWrapperActions.getAll()).length;
222+
if (count && Number.isFinite(count)) {
223+
return count;
224+
}
225+
return 0;
226+
}
227+
228+
function AddDummyContactButton() {
229+
const [loading, setLoading] = useState(false);
230+
const [addedCount, setAddedCount] = useState(0);
231+
232+
const { data: contactsCount } = usePolling(
233+
fetchContactsCountAndUpdate,
234+
1000,
235+
'AddDummyContactButton'
236+
);
237+
238+
return (
239+
<SessionButton
240+
onClick={async () => {
241+
if (loading) {
242+
return;
243+
}
244+
try {
245+
setLoading(true);
246+
setAddedCount(0);
247+
const chunkSize = 10;
248+
const allIndexes = Array.from({ length: dummyContactPerClick }).map((_unused, i) => i);
249+
const chunks = chunk(allIndexes, chunkSize);
250+
for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
251+
// eslint-disable-next-line no-await-in-loop
252+
await Promise.all(chunks[chunkIndex].map(() => generateOneRandomContact()));
253+
setAddedCount(Math.min(chunkIndex * chunkSize, dummyContactPerClick));
254+
}
255+
} finally {
256+
setLoading(false);
257+
setAddedCount(0);
258+
}
259+
}}
260+
disabled={loading}
261+
>
262+
{loading ? (
263+
<>
264+
{addedCount}/{dummyContactPerClick}...
265+
</>
266+
) : (
267+
`Add ${dummyContactPerClick} contacts (${contactsCount})`
268+
)}
269+
</SessionButton>
270+
);
271+
}
272+
181273
export const DebugActions = () => {
182274
const dispatch = useDispatch();
183275

@@ -246,6 +338,7 @@ export const DebugActions = () => {
246338
>
247339
Open storage profile
248340
</SessionButton>
341+
<AddDummyContactButton />
249342
</Flex>
250343
</>
251344
);

ts/hooks/usePolling.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { useEffect, useState } from 'react';
2+
3+
export function usePolling<T>(fn: () => Promise<T>, pollInterval: number, identifier: string) {
4+
const [data, setData] = useState<T | null>(null);
5+
const [error, setError] = useState<Error | null>(null);
6+
7+
useEffect(() => {
8+
let isMounted = true;
9+
10+
const execute = async () => {
11+
if (!isMounted) {
12+
return;
13+
}
14+
15+
try {
16+
const result = await fn();
17+
if (isMounted) {
18+
setData(result);
19+
setError(null);
20+
}
21+
} catch (err) {
22+
window.log.warn(`${identifier} polling error:`, err);
23+
if (isMounted) {
24+
setError(err as Error);
25+
}
26+
}
27+
};
28+
29+
const voidedExecute = () => {
30+
void execute();
31+
};
32+
33+
voidedExecute();
34+
35+
const interval = setInterval(voidedExecute, pollInterval);
36+
37+
return () => {
38+
isMounted = false;
39+
clearInterval(interval);
40+
};
41+
}, [fn, pollInterval, identifier]);
42+
43+
return { data, error };
44+
}

ts/mains/main_renderer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ window.globalOnlineStatus = true; // default to true as we don't get an event on
8787
window.getGlobalOnlineStatus = () => window.globalOnlineStatus;
8888

8989
window.log.info('background page reloaded');
90+
9091
window.log.info('environment:', window.getEnvironment());
9192

9293
let newVersion = false;
@@ -154,6 +155,7 @@ Storage.onready(async () => {
154155
return;
155156
}
156157
first = false;
158+
157159
// Update zoom
158160
window.updateZoomFactor();
159161

ts/models/conversation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ export class ConversationModel extends Model<ConversationAttributes> {
15331533
}
15341534

15351535
if (valueForced !== Boolean(this.isApproved())) {
1536-
window?.log?.info(`Setting ${ed25519Str(this.id)} isApproved to: ${value}`);
1536+
window?.log?.debug(`Setting ${ed25519Str(this.id)} isApproved to: ${value}`);
15371537
this.set({
15381538
isApproved: valueForced,
15391539
});
@@ -1554,7 +1554,7 @@ export class ConversationModel extends Model<ConversationAttributes> {
15541554
}
15551555
const valueForced = Boolean(value);
15561556
if (valueForced !== Boolean(this.didApproveMe())) {
1557-
window?.log?.info(`Setting ${ed25519Str(this.id)} didApproveMe to: ${value}`);
1557+
window?.log?.debug(`Setting ${ed25519Str(this.id)} didApproveMe to: ${value}`);
15581558
this.set({
15591559
didApproveMe: valueForced,
15601560
});

ts/receiver/configMessage.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ import {
3535
ConfigWrapperObjectTypesMeta,
3636
ConfigWrapperUser,
3737
getGroupPubkeyFromWrapperType,
38-
isBlindingWrapperType,
39-
isMultiEncryptWrapperType,
38+
isStaticSessionWrapper,
4039
isUserConfigWrapperType,
4140
} from '../webworker/workers/browser/libsession_worker_functions';
4241
// eslint-disable-next-line import/no-unresolved, import/extensions
@@ -84,13 +83,15 @@ function byUserNamespace(incomingConfigs: Array<RetrieveMessageItemWithNamespace
8483
}
8584

8685
async function printDumpForDebug(prefix: string, variant: ConfigWrapperObjectTypesMeta) {
86+
if (isStaticSessionWrapper(variant)) {
87+
return; // nothing to print for those static wrappers
88+
}
89+
8790
if (isUserConfigWrapperType(variant)) {
8891
window.log.info(prefix, StringUtils.toHex(await UserGenericWrapperActions.makeDump(variant)));
8992
return;
9093
}
91-
if (isMultiEncryptWrapperType(variant) || isBlindingWrapperType(variant)) {
92-
return; // nothing to print for this one
93-
}
94+
9495
const metaGroupDumps = await MetaGroupWrapperActions.metaMakeDump(
9596
getGroupPubkeyFromWrapperType(variant)
9697
);
@@ -128,7 +129,6 @@ async function mergeUserConfigsWithIncomingUpdates(
128129
variant
129130
);
130131
}
131-
132132
const hashesMerged = await UserGenericWrapperActions.merge(variant, toMerge);
133133

134134
const needsDump = await UserGenericWrapperActions.needsDump(variant);

0 commit comments

Comments
 (0)