refactor: new provider (#4900)

This commit is contained in:
EYHN
2023-11-17 15:50:01 +08:00
committed by GitHub
parent 9baad36e41
commit aa4c7407de
48 changed files with 1783 additions and 1480 deletions
@@ -0,0 +1,101 @@
import { DebugLogger } from '@affine/debug';
import {
applyAwarenessUpdate,
type Awareness,
encodeAwarenessUpdate,
removeAwarenessStates,
} from 'y-protocols/awareness';
import { getIoManager } from '../../utils/affine-io';
import { base64ToUint8Array, uint8ArrayToBase64 } from '../../utils/base64';
import type { AwarenessProvider } from '..';
const logger = new DebugLogger('affine:awareness:socketio');
export type AwarenessChanges = Record<
'added' | 'updated' | 'removed',
number[]
>;
export function createAffineAwarenessProvider(
workspaceId: string,
awareness: Awareness
): AwarenessProvider {
const socket = getIoManager().socket('/');
const awarenessBroadcast = ({
workspaceId,
awarenessUpdate,
}: {
workspaceId: string;
awarenessUpdate: string;
}) => {
if (workspaceId !== workspaceId) {
return;
}
applyAwarenessUpdate(
awareness,
base64ToUint8Array(awarenessUpdate),
'remote'
);
};
const awarenessUpdate = (changes: AwarenessChanges, origin: unknown) => {
if (origin === 'remote') {
return;
}
const changedClients = Object.values(changes).reduce((res, cur) => [
...res,
...cur,
]);
const update = encodeAwarenessUpdate(awareness, changedClients);
uint8ArrayToBase64(update)
.then(encodedUpdate => {
socket.emit('awareness-update', {
workspaceId: workspaceId,
awarenessUpdate: encodedUpdate,
});
})
.catch(err => logger.error(err));
};
const newClientAwarenessInitHandler = () => {
const awarenessUpdate = encodeAwarenessUpdate(awareness, [
awareness.clientID,
]);
uint8ArrayToBase64(awarenessUpdate)
.then(encodedAwarenessUpdate => {
socket.emit('awareness-update', {
guid: workspaceId,
awarenessUpdate: encodedAwarenessUpdate,
});
})
.catch(err => logger.error(err));
};
const windowBeforeUnloadHandler = () => {
removeAwarenessStates(awareness, [awareness.clientID], 'window unload');
};
return {
connect: () => {
socket.on('server-awareness-broadcast', awarenessBroadcast);
socket.on('new-client-awareness-init', newClientAwarenessInitHandler);
awareness.on('update', awarenessUpdate);
window.addEventListener('beforeunload', windowBeforeUnloadHandler);
socket.emit('awareness-init', workspaceId);
socket.connect();
},
disconnect: () => {
awareness.off('update', awarenessUpdate);
socket.off('server-awareness-broadcast', awarenessBroadcast);
socket.off('new-client-awareness-init', newClientAwarenessInitHandler);
window.removeEventListener('unload', windowBeforeUnloadHandler);
socket.disconnect();
},
};
}
@@ -0,0 +1,63 @@
import type { Awareness } from 'y-protocols/awareness.js';
import {
applyAwarenessUpdate,
encodeAwarenessUpdate,
} from 'y-protocols/awareness.js';
import type { AwarenessProvider } from '..';
import type { AwarenessChanges } from '../affine';
type ChannelMessage =
| { type: 'connect' }
| { type: 'update'; update: Uint8Array };
export function createBroadcastChannelAwarenessProvider(
workspaceId: string,
awareness: Awareness
): AwarenessProvider {
const channel = new BroadcastChannel('awareness:' + workspaceId);
function handleAwarenessUpdate(changes: AwarenessChanges, origin: unknown) {
if (origin === 'remote') {
return;
}
const changedClients = Object.values(changes).reduce((res, cur) => [
...res,
...cur,
]);
const update = encodeAwarenessUpdate(awareness, changedClients);
channel.postMessage({
type: 'update',
update: update,
} satisfies ChannelMessage);
}
function handleChannelMessage(event: MessageEvent<ChannelMessage>) {
if (event.data.type === 'update') {
const update = event.data.update;
applyAwarenessUpdate(awareness, update, 'remote');
}
if (event.data.type === 'connect') {
channel.postMessage({
type: 'update',
update: encodeAwarenessUpdate(awareness, [awareness.clientID]),
} satisfies ChannelMessage);
}
}
return {
connect() {
channel.postMessage({
type: 'connect',
} satisfies ChannelMessage);
awareness.on('update', handleAwarenessUpdate);
channel.addEventListener('message', handleChannelMessage);
},
disconnect() {
awareness.off('update', handleAwarenessUpdate);
channel.removeEventListener('message', handleChannelMessage);
},
};
}
@@ -0,0 +1,7 @@
export interface AwarenessProvider {
connect(): void;
disconnect(): void;
}
export * from './affine';
export * from './broadcast-channel';