mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 01:26:37 +08:00
refactor(workspace): split workspace interface and implementation (#5463)
@affine/workspace -> (@affine/workspace, @affine/workspace-impl)
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { isSvgBuffer } from '../buffer-to-blob';
|
||||
|
||||
describe('isSvgBuffer', () => {
|
||||
test('basic', async () => {
|
||||
expect(isSvgBuffer(Buffer.from('<svg></svg>'))).toBe(true);
|
||||
expect(isSvgBuffer(Buffer.from(' \n\r\t<svg></svg>'))).toBe(true);
|
||||
expect(isSvgBuffer(Buffer.from('<123>'))).toBe(false);
|
||||
expect(
|
||||
isSvgBuffer(
|
||||
Buffer.from('<?xml version="1.0" encoding="UTF-8"?><svg></svg>')
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Manager } from 'socket.io-client';
|
||||
|
||||
let ioManager: Manager | null = null;
|
||||
|
||||
function getBaseUrl(): string {
|
||||
if (environment.isDesktop) {
|
||||
return runtimeConfig.serverUrlPrefix;
|
||||
}
|
||||
const { protocol, hostname, port } = window.location;
|
||||
return `${protocol === 'https:' ? 'wss' : 'ws'}://${hostname}${
|
||||
port ? `:${port}` : ''
|
||||
}`;
|
||||
}
|
||||
|
||||
// use lazy initialization socket.io io manager
|
||||
export function getIoManager(): Manager {
|
||||
if (ioManager) {
|
||||
return ioManager;
|
||||
}
|
||||
ioManager = new Manager(`${getBaseUrl()}/`, {
|
||||
autoConnect: false,
|
||||
transports: ['websocket'],
|
||||
secure: location.protocol === 'https:',
|
||||
});
|
||||
return ioManager;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export function uint8ArrayToBase64(array: Uint8Array): Promise<string> {
|
||||
return new Promise<string>(resolve => {
|
||||
// Create a blob from the Uint8Array
|
||||
const blob = new Blob([array]);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
const dataUrl = reader.result as string | null;
|
||||
if (!dataUrl) {
|
||||
resolve('');
|
||||
return;
|
||||
}
|
||||
// The result includes the `data:` URL prefix and the MIME type. We only want the Base64 data
|
||||
const base64 = dataUrl.split(',')[1];
|
||||
resolve(base64);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export function base64ToUint8Array(base64: string) {
|
||||
const binaryString = atob(base64);
|
||||
const binaryArray = binaryString.split('').map(function (char) {
|
||||
return char.charCodeAt(0);
|
||||
});
|
||||
return new Uint8Array(binaryArray);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import isSvg from 'is-svg';
|
||||
|
||||
function fastCheckIsNotSvg(buffer: Uint8Array) {
|
||||
// check first non-whitespace character is not '<svg' or '<?xml'
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
const ch = buffer[i];
|
||||
|
||||
// skip whitespace
|
||||
if (
|
||||
ch === 0x20 /* \s */ ||
|
||||
ch === 0x09 /* \t */ ||
|
||||
ch === 0x0b /* \v */ ||
|
||||
ch === 0x0c /* \f */ ||
|
||||
ch === 0x0a /* \n */ ||
|
||||
ch === 0x0d /* \r */ ||
|
||||
ch === 0xa0
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return (
|
||||
!(
|
||||
buffer[i] === /* '<' */ 0x3c &&
|
||||
buffer[i + 1] === /* 's' */ 0x73 &&
|
||||
buffer[i + 2] === /* 'v' */ 0x76 &&
|
||||
buffer[i + 3] === /* 'g' */ 0x67
|
||||
) &&
|
||||
!(
|
||||
buffer[i] === /* '<' */ 0x3c &&
|
||||
buffer[i + 1] === /* '?' */ 0x3f &&
|
||||
buffer[i + 2] === /* 'x' */ 0x78 &&
|
||||
buffer[i + 3] === /* 'm' */ 0x6d &&
|
||||
buffer[i + 4] === /* 'l' */ 0x6c
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this has a overhead of converting to string for testing if it is svg.
|
||||
export function isSvgBuffer(buffer: Uint8Array) {
|
||||
if (fastCheckIsNotSvg(buffer)) {
|
||||
return false;
|
||||
}
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const str = decoder.decode(buffer);
|
||||
return isSvg(str);
|
||||
}
|
||||
|
||||
export function bufferToBlob(buffer: Uint8Array | ArrayBuffer) {
|
||||
const isSVG = isSvgBuffer(
|
||||
buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer
|
||||
);
|
||||
// for svg blob, we need to explicitly set the type to image/svg+xml
|
||||
return isSVG
|
||||
? new Blob([buffer], { type: 'image/svg+xml' })
|
||||
: new Blob([buffer]);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
export function mergeUpdates(updates: Uint8Array[]) {
|
||||
if (updates.length === 0) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
if (updates.length === 1) {
|
||||
return updates[0];
|
||||
}
|
||||
const doc = new Doc();
|
||||
doc.transact(() => {
|
||||
updates.forEach(update => {
|
||||
applyUpdate(doc, update);
|
||||
});
|
||||
});
|
||||
return encodeStateAsUpdate(doc);
|
||||
}
|
||||
Reference in New Issue
Block a user