(fix): connections (again)
(qol): update todo
This commit is contained in:
parent
676dea2aa4
commit
3666902ac9
6 changed files with 88 additions and 57 deletions
1
TODO
1
TODO
|
|
@ -2,5 +2,6 @@
|
||||||
- Add packages/hotkeys/
|
- Add packages/hotkeys/
|
||||||
- Full accessability
|
- Full accessability
|
||||||
- Add settings saving & update onboarding to use it
|
- Add settings saving & update onboarding to use it
|
||||||
|
- Add onboarding page to load one profile during onboarding
|
||||||
|
|
||||||
-> Most folders in packages/ have specific todos
|
-> Most folders in packages/ have specific todos
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ export function Basic({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
render={<div />}
|
render={<div />}
|
||||||
|
nativeButton={false}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="animate-in fade-in duration-300 h-auto w-full justify-start gap-2.5 rounded-xl min-h-12.5!"
|
className="animate-in fade-in duration-300 h-auto w-full justify-start gap-2.5 rounded-xl min-h-12.5!"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit fee0a8fa9994b6a2d04e0966387c713c47c39b7c
|
Subproject commit 11a1d79409857b734e948dd8c3e28e6ba721d15f
|
||||||
|
|
@ -237,6 +237,7 @@ export function Provider(props: {
|
||||||
let reconnectScheduled = false;
|
let reconnectScheduled = false;
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
let resumeListenerRegistered = false;
|
let resumeListenerRegistered = false;
|
||||||
|
let connectionGeneration = 0;
|
||||||
|
|
||||||
const clearReconnectTimer = () => {
|
const clearReconnectTimer = () => {
|
||||||
if (!reconnectTimer) return;
|
if (!reconnectTimer) return;
|
||||||
|
|
@ -251,16 +252,52 @@ export function Provider(props: {
|
||||||
reconnectResetTimer = null;
|
reconnectResetTimer = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scheduleReconnect = (error: unknown) => {
|
||||||
|
if (disposed || reconnectScheduled) return;
|
||||||
|
if (attempts >= RECONNECT_TRIES) {
|
||||||
|
log(0, "mtp", "red", "Reconnection attempts exhausted", error);
|
||||||
|
sonnerToast.error("Connection failed", {
|
||||||
|
id: "mtp-connection-toast",
|
||||||
|
description:
|
||||||
|
error instanceof Error ? error.message.split(":")[0] : "Connection lost",
|
||||||
|
icon: null,
|
||||||
|
duration: Infinity,
|
||||||
|
closeButton: true,
|
||||||
|
promise: null,
|
||||||
|
} as unknown as Parameters<typeof sonnerToast.error>[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attempts += 1;
|
||||||
|
sonnerToast.loading(
|
||||||
|
`Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`,
|
||||||
|
{ id: "mtp-connection-toast" },
|
||||||
|
);
|
||||||
|
reconnectScheduled = true;
|
||||||
|
reconnectTimer = setTimeout(() => {
|
||||||
|
reconnectScheduled = false;
|
||||||
|
reconnectTimer = null;
|
||||||
|
void connect();
|
||||||
|
}, RETRY_INTERVAL);
|
||||||
|
};
|
||||||
|
|
||||||
async function connect() {
|
async function connect() {
|
||||||
if (disposed || props.blockConnection) return;
|
if (disposed || props.blockConnection) return;
|
||||||
|
|
||||||
|
const generation = ++connectionGeneration;
|
||||||
|
let client: Awaited<ReturnType<typeof MTPClient.create>> | null = null;
|
||||||
|
let failed = false;
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
clientRef.current?.disconnect();
|
client?.disconnect();
|
||||||
|
if (clientRef.current === client) {
|
||||||
clientRef.current = null;
|
clientRef.current = null;
|
||||||
|
}
|
||||||
clearReconnectResetTimer();
|
clearReconnectResetTimer();
|
||||||
|
if (generation === connectionGeneration) {
|
||||||
setReadyState(ConnectionState.Disconnected);
|
setReadyState(ConnectionState.Disconnected);
|
||||||
setIdentified(false);
|
setIdentified(false);
|
||||||
setIdentifying(false);
|
setIdentifying(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
setIdentified(false);
|
setIdentified(false);
|
||||||
|
|
@ -324,7 +361,7 @@ export function Provider(props: {
|
||||||
|
|
||||||
log(2, "mtp", "green", "Connecting to: " + url);
|
log(2, "mtp", "green", "Connecting to: " + url);
|
||||||
|
|
||||||
const client = await MTPClient.create({
|
client = await MTPClient.create({
|
||||||
url,
|
url,
|
||||||
credentials: {
|
credentials: {
|
||||||
clientId: userId,
|
clientId: userId,
|
||||||
|
|
@ -335,9 +372,20 @@ export function Provider(props: {
|
||||||
pings: true,
|
pings: true,
|
||||||
logger: (event) => {
|
logger: (event) => {
|
||||||
if (event.type === "state") {
|
if (event.type === "state") {
|
||||||
setReadyState(
|
if (generation !== connectionGeneration) return;
|
||||||
clientRef.current?.state ?? ConnectionState.Disconnected,
|
const state = client?.state ?? ConnectionState.Disconnected;
|
||||||
);
|
setReadyState(state);
|
||||||
|
if (
|
||||||
|
state === ConnectionState.Disconnected &&
|
||||||
|
clientRef.current === client &&
|
||||||
|
!failed
|
||||||
|
) {
|
||||||
|
failed = true;
|
||||||
|
clientRef.current = null;
|
||||||
|
setIdentified(false);
|
||||||
|
setIdentifying(false);
|
||||||
|
scheduleReconnect(new Error("MTP connection lost"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type !== "Pong" && event.type !== "Ping") {
|
if (event.type !== "Pong" && event.type !== "Ping") {
|
||||||
|
|
@ -364,13 +412,14 @@ export function Provider(props: {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (disposed) {
|
if (disposed || generation !== connectionGeneration) {
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const activeClient = client;
|
||||||
|
|
||||||
clientRef.current = client;
|
clientRef.current = activeClient;
|
||||||
setReadyState(client.state);
|
setReadyState(activeClient.state);
|
||||||
|
|
||||||
clearReconnectTimer();
|
clearReconnectTimer();
|
||||||
|
|
||||||
|
|
@ -381,7 +430,7 @@ export function Provider(props: {
|
||||||
reconnectResetTimer = null;
|
reconnectResetTimer = null;
|
||||||
}, RECONNECT_RESET * 1_000);
|
}, RECONNECT_RESET * 1_000);
|
||||||
|
|
||||||
setReadyState(client.state);
|
setReadyState(activeClient.state);
|
||||||
setIdentifying(true);
|
setIdentifying(true);
|
||||||
|
|
||||||
const stateSync = new Promise<ProtocolMessage<"ClientStateSync">>(
|
const stateSync = new Promise<ProtocolMessage<"ClientStateSync">>(
|
||||||
|
|
@ -390,7 +439,7 @@ export function Provider(props: {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
reject(new Error("Initial state synchronization timed out"));
|
reject(new Error("Initial state synchronization timed out"));
|
||||||
}, 120_000);
|
}, 120_000);
|
||||||
const unsubscribe = client.subscribe(
|
const unsubscribe = activeClient.subscribe(
|
||||||
"ClientStateSync",
|
"ClientStateSync",
|
||||||
(message) => {
|
(message) => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|
@ -404,7 +453,10 @@ export function Provider(props: {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const [, finalResponse] = await Promise.all([client.auth(), stateSync]);
|
const [, finalResponse] = await Promise.all([
|
||||||
|
activeClient.auth(),
|
||||||
|
stateSync,
|
||||||
|
]);
|
||||||
|
|
||||||
if (finalResponse.type.startsWith("Error")) {
|
if (finalResponse.type.startsWith("Error")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
@ -412,7 +464,7 @@ export function Provider(props: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const acknowledgement = await client.request("ClientStateAck", {
|
const acknowledgement = await activeClient.request("ClientStateAck", {
|
||||||
SessionId: finalResponse.data.SessionId,
|
SessionId: finalResponse.data.SessionId,
|
||||||
VersionNumber: finalResponse.data.VersionNumber,
|
VersionNumber: finalResponse.data.VersionNumber,
|
||||||
});
|
});
|
||||||
|
|
@ -422,7 +474,7 @@ export function Provider(props: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disposed || clientRef.current !== client) return;
|
if (disposed || clientRef.current !== activeClient) return;
|
||||||
|
|
||||||
setFreshContacts(finalResponse.data.Contacts);
|
setFreshContacts(finalResponse.data.Contacts);
|
||||||
setFreshCommunities(finalResponse.data.Communities);
|
setFreshCommunities(finalResponse.data.Communities);
|
||||||
|
|
@ -431,7 +483,11 @@ export function Provider(props: {
|
||||||
setIdentified(true);
|
setIdentified(true);
|
||||||
resolveConnectionRef.current?.();
|
resolveConnectionRef.current?.();
|
||||||
} catch (connectError) {
|
} catch (connectError) {
|
||||||
if (disposed) return;
|
if (disposed || generation !== connectionGeneration) {
|
||||||
|
client?.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
failed = true;
|
||||||
cleanup();
|
cleanup();
|
||||||
const connectErrorMessage =
|
const connectErrorMessage =
|
||||||
connectError instanceof Error
|
connectError instanceof Error
|
||||||
|
|
@ -445,41 +501,14 @@ export function Provider(props: {
|
||||||
getProtocolErrorDetails(connectError) ?? connectError,
|
getProtocolErrorDetails(connectError) ?? connectError,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Schedule reconnect
|
scheduleReconnect(connectError);
|
||||||
if (disposed || reconnectScheduled) return;
|
|
||||||
if (attempts >= RECONNECT_TRIES) {
|
|
||||||
log(0, "mtp", "red", "Reconnection attempts exhausted", connectError);
|
|
||||||
sonnerToast.error("Connection failed", {
|
|
||||||
id: "mtp-connection-toast",
|
|
||||||
description: connectErrorMessage.split(":")[0],
|
|
||||||
icon: null,
|
|
||||||
duration: Infinity,
|
|
||||||
closeButton: true,
|
|
||||||
promise: null,
|
|
||||||
} as unknown as Parameters<typeof sonnerToast.error>[1]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts += 1;
|
|
||||||
|
|
||||||
// Show loading toast
|
|
||||||
sonnerToast.loading(
|
|
||||||
`Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`,
|
|
||||||
{ id: "mtp-connection-toast" },
|
|
||||||
);
|
|
||||||
|
|
||||||
reconnectScheduled = true;
|
|
||||||
reconnectTimer = setTimeout(() => {
|
|
||||||
reconnectScheduled = false;
|
|
||||||
reconnectTimer = null;
|
|
||||||
void connect();
|
|
||||||
}, RETRY_INTERVAL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reconnectAfterResume() {
|
async function reconnectAfterResume() {
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
|
|
||||||
|
connectionGeneration += 1;
|
||||||
clientRef.current?.disconnect();
|
clientRef.current?.disconnect();
|
||||||
clientRef.current = null;
|
clientRef.current = null;
|
||||||
clearReconnectTimer();
|
clearReconnectTimer();
|
||||||
|
|
|
||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
|
|
@ -6,7 +6,7 @@ settings:
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
'@methanium/ui': https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz
|
'@methanium/ui': https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz
|
||||||
mtp: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz
|
mtp: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
|
|
@ -16,8 +16,8 @@ importers:
|
||||||
specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz
|
specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz
|
||||||
version: https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3)
|
version: https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3)
|
||||||
mtp:
|
mtp:
|
||||||
specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz
|
specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz
|
||||||
version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz
|
version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^2.0.7
|
specifier: ^2.0.7
|
||||||
version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
|
@ -700,8 +700,8 @@ importers:
|
||||||
specifier: ^1.14.0
|
specifier: ^1.14.0
|
||||||
version: 1.23.0(react@19.2.7)
|
version: 1.23.0(react@19.2.7)
|
||||||
mtp:
|
mtp:
|
||||||
specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz
|
specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz
|
||||||
version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz
|
version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz
|
||||||
react:
|
react:
|
||||||
specifier: ^19.2.0
|
specifier: ^19.2.0
|
||||||
version: 19.2.7
|
version: 19.2.7
|
||||||
|
|
@ -4006,8 +4006,8 @@ packages:
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz:
|
mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz:
|
||||||
resolution: {integrity: sha512-kvJ98CMrr/ZCQr1oVhys9D3c+/OZAl6Oar3DjI6bvnYLelpjnXbrtq/8A31ktbipgMsaRInQuFBKRYMBm/f8OQ==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz}
|
resolution: {integrity: sha512-WcXHd53aDM0zQfO8eaUnK5tpnRP73GlWjwAMMcstcVAIWrvyFGuINkCRNEkb2RsNk9h57UMhxElCZeBkFrVmCg==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz}
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
|
|
||||||
nanoid@3.3.15:
|
nanoid@3.3.15:
|
||||||
|
|
@ -8254,7 +8254,7 @@ snapshots:
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz:
|
mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz:
|
||||||
dependencies:
|
dependencies:
|
||||||
yaml: 2.9.0
|
yaml: 2.9.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ allowBuilds:
|
||||||
esbuild: true
|
esbuild: true
|
||||||
overrides:
|
overrides:
|
||||||
"@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz"
|
"@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.10/methanium-ui.tgz"
|
||||||
mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-fa271e6/mtp-0.2.0.tgz"
|
mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-6f673ba/mtp-0.2.0.tgz"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue