mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-30 17:42:12 +03:00
feat(electron): add offline mode (#8086)
fix AF-1334 It seems `session.enableNetworkEmulation({ offline: true });` does not work - https://github.com/electron/electron/issues/21250 implemented using an in-house solution. When turned on: ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/6805735b-1006-4e51-be46-c047b0f1a82c.png)
This commit is contained in:
parent
51bc40d2a8
commit
0ae5673aaa
@ -96,6 +96,13 @@ export const AFFINE_FLAGS = {
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: isCanaryBuild,
|
||||
},
|
||||
enable_offline_mode: {
|
||||
category: 'affine',
|
||||
displayName: 'Offline Mode',
|
||||
description: 'Enables offline mode.',
|
||||
configurable: isDesktopEnvironment,
|
||||
defaultState: false,
|
||||
},
|
||||
} satisfies { [key in string]: FlagInfo };
|
||||
|
||||
export type AFFINE_FLAGS = typeof AFFINE_FLAGS;
|
||||
|
@ -3,6 +3,7 @@ import { join } from 'node:path';
|
||||
import { net, protocol, session } from 'electron';
|
||||
|
||||
import { CLOUD_BASE_URL } from './config';
|
||||
import { isOfflineModeEnabled } from './utils';
|
||||
import { getCookies } from './windows-manager';
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
@ -105,9 +106,21 @@ export function registerProtocol() {
|
||||
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
const url = new URL(details.url);
|
||||
const pathname = url.pathname;
|
||||
const protocol = url.protocol;
|
||||
const origin = url.origin;
|
||||
|
||||
const sameOrigin = origin === CLOUD_BASE_URL || protocol === 'file:';
|
||||
|
||||
if (isOfflineModeEnabled() && (sameOrigin || 'devtools:' !== protocol)) {
|
||||
callback({
|
||||
cancel: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// session cookies are set to file:// on production
|
||||
// if sending request to the cloud, attach the session cookie (to affine cloud server)
|
||||
if (isNetworkResource(pathname)) {
|
||||
if (isNetworkResource(pathname) && sameOrigin) {
|
||||
const cookie = getCookies();
|
||||
if (cookie) {
|
||||
const cookieString = cookie.map(c => `${c.name}=${c.value}`).join('; ');
|
||||
|
@ -3,6 +3,7 @@ import { autoUpdater as defaultAutoUpdater } from 'electron-updater';
|
||||
|
||||
import { buildType } from '../config';
|
||||
import { logger } from '../logger';
|
||||
import { isOfflineModeEnabled } from '../utils';
|
||||
import { AFFiNEUpdateProvider } from './affine-update-provider';
|
||||
import { updaterSubjects } from './event';
|
||||
import { WindowsUpdater } from './windows-updater';
|
||||
@ -54,7 +55,7 @@ export const setConfig = (newConfig: Partial<UpdaterConfig> = {}): void => {
|
||||
};
|
||||
|
||||
export const checkForUpdates = async () => {
|
||||
if (disabled || checkingUpdate) {
|
||||
if (disabled || checkingUpdate || isOfflineModeEnabled()) {
|
||||
return;
|
||||
}
|
||||
checkingUpdate = true;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import http from 'node:http';
|
||||
import https from 'node:https';
|
||||
|
||||
import type { CookiesSetDetails } from 'electron';
|
||||
|
||||
import { logger } from './logger';
|
||||
import { globalStateStorage } from './shared-storage/storage';
|
||||
|
||||
export function parseCookie(
|
||||
cookieString: string,
|
||||
url: string
|
||||
@ -56,55 +56,15 @@ export function parseCookie(
|
||||
return details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a GET request to a specified URL.
|
||||
* This function uses native http/https modules instead of fetch to
|
||||
* bypassing set-cookies headers
|
||||
*/
|
||||
export async function simpleGet(requestUrl: string): Promise<{
|
||||
body: string;
|
||||
headers: [string, string][];
|
||||
statusCode: number;
|
||||
}> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const parsedUrl = new URL(requestUrl);
|
||||
const protocol = parsedUrl.protocol === 'https:' ? https : http;
|
||||
const options = {
|
||||
hostname: parsedUrl.hostname,
|
||||
port: parsedUrl.port,
|
||||
path: parsedUrl.pathname + parsedUrl.search,
|
||||
method: 'GET',
|
||||
};
|
||||
const req = protocol.request(options, res => {
|
||||
let data = '';
|
||||
res.on('data', chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
resolve({
|
||||
body: data,
|
||||
headers: toStandardHeaders(res.headers),
|
||||
statusCode: res.statusCode || 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', error => {
|
||||
reject(error);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
|
||||
function toStandardHeaders(headers: http.IncomingHttpHeaders) {
|
||||
const result: [string, string][] = [];
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(v => {
|
||||
result.push([key, v]);
|
||||
});
|
||||
} else {
|
||||
result.push([key, value || '']);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
export const isOfflineModeEnabled = () => {
|
||||
try {
|
||||
return (
|
||||
// todo(pengx17): better abstraction for syncing flags with electron
|
||||
// packages/common/infra/src/modules/feature-flag/entities/flags.ts
|
||||
globalStateStorage.get('affine-flag:enable_offline_mode') ?? false
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error('Failed to get offline mode flag', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user