Merge remote-tracking branch 'origin/feat/cloud-sync-saika' into feat/cloud-sync-saika

This commit is contained in:
alt0 2023-01-11 23:18:23 +08:00
commit c7f974ed77
5 changed files with 109 additions and 29 deletions

View File

@ -411,6 +411,18 @@ export class DataCenter {
return []; return [];
} }
/**
* accept invitation
* @param {string} inviteCode
*/
async acceptInvitation(inviteCode: string, providerStr = 'affine') {
const provider = this.providerMap.get(providerStr);
if (provider) {
return await provider.acceptInvitation(inviteCode);
}
return [];
}
onMessage(cb: (message: Message) => void) { onMessage(cb: (message: Message) => void) {
return this._messageCenter.onMessage(cb); return this._messageCenter.onMessage(cb);
} }

View File

@ -10,7 +10,7 @@ import { storage } from './storage.js';
import assert from 'assert'; import assert from 'assert';
import { WebsocketProvider } from './sync.js'; import { WebsocketProvider } from './sync.js';
// import { IndexedDBProvider } from '../local/indexeddb'; // import { IndexedDBProvider } from '../local/indexeddb';
import { getApis } from './apis/index.js'; import { getApis, Workspace } from './apis/index.js';
import type { Apis, WorkspaceDetail, Callback } from './apis'; import type { Apis, WorkspaceDetail, Callback } from './apis';
import { setDefaultAvatar } from '../utils.js'; import { setDefaultAvatar } from '../utils.js';
import { MessageCode } from '../../message/index.js'; import { MessageCode } from '../../message/index.js';
@ -23,6 +23,13 @@ import {
} from './utils.js'; } from './utils.js';
import { WorkspaceUnit } from '../../workspace-unit.js'; import { WorkspaceUnit } from '../../workspace-unit.js';
import { createBlocksuiteWorkspace } from '../../utils/index.js'; import { createBlocksuiteWorkspace } from '../../utils/index.js';
import type { SyncMode } from '../../workspace-unit';
type ChannelMessage = {
ws_list: Workspace[];
ws_details: Record<string, WorkspaceDetail>;
metadata: Record<string, { avatar: string; name: string }>;
};
export interface AffineProviderConstructorParams export interface AffineProviderConstructorParams
extends ProviderConstructorParams { extends ProviderConstructorParams {
@ -39,21 +46,12 @@ export class AffineProvider extends BaseProvider {
private _onTokenRefresh?: Callback = undefined; private _onTokenRefresh?: Callback = undefined;
private _wsMap: Map<string, WebsocketProvider> = new Map(); private _wsMap: Map<string, WebsocketProvider> = new Map();
private _apis: Apis; private _apis: Apis;
private _channel: WebsocketClient; private _channel?: WebsocketClient;
// private _idbMap: Map<string, IndexedDBProvider> = new Map(); // private _idbMap: Map<string, IndexedDBProvider> = new Map();
constructor({ apis, ...params }: AffineProviderConstructorParams) { constructor({ apis, ...params }: AffineProviderConstructorParams) {
super(params); super(params);
this._apis = apis || getApis(); this._apis = apis || getApis();
this._channel = new WebsocketClient(
`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${
window.location.host
}/global/sync/`,
this._logger
);
if (token.isLogin) {
this._connectChannel();
}
} }
override async init() { override async init() {
@ -82,14 +80,59 @@ export class AffineProvider extends BaseProvider {
} else { } else {
storage.setItem('token', this._apis.token.refresh); storage.setItem('token', this._apis.token.refresh);
} }
if (token.isLogin) {
this._connectChannel();
}
} }
private _connectChannel() { private _connectChannel() {
this._channel.connect(); if (!this._channel) {
this._channel = new WebsocketClient(
`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${
window.location.host
}/api/global/sync/`,
this._logger,
{
params: {
token: this._apis.token.refresh,
},
}
);
}
this._channel.on('message', (msg: ChannelMessage) => {
this._handlerAffineListMessage(msg);
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any private _handlerAffineListMessage({ ws_details, metadata }: ChannelMessage) {
this._channel.on('message', (message: any) => { this._logger('receive server message');
console.log('message', message); Object.entries(ws_details).forEach(async ([id, detail]) => {
const { name, avatar } = metadata[id];
assert(name);
const workspace = {
name: name,
avatar,
owner: {
name: detail.owner.name,
id: detail.owner.id,
email: detail.owner.email,
avatar: detail.owner.avatar_url,
},
published: detail.public,
memberCount: detail.member_count,
provider: 'affine',
syncMode: 'core' as SyncMode,
};
if (this._workspaces.get(id)) {
this._workspaces.update(id, workspace);
} else {
const workspaceUnit = await loadWorkspaceUnit(
{ id, ...workspace },
this._apis
);
this._workspaces.add(workspaceUnit);
}
}); });
} }
@ -190,7 +233,7 @@ export class AffineProvider extends BaseProvider {
} }
} }
const user = await this._apis.signInWithGoogle?.(); const user = await this._apis.signInWithGoogle?.();
if (!this._channel.connected) { if (!this._channel?.connected) {
this._connectChannel(); this._connectChannel();
} }
if (!user) { if (!user) {
@ -296,13 +339,13 @@ export class AffineProvider extends BaseProvider {
workspace_id: string, workspace_id: string,
email: string email: string
): Promise<User | null> { ): Promise<User | null> {
const user = await this._apis.getUserByEmail({ workspace_id, email }); const users = await this._apis.getUserByEmail({ workspace_id, email });
return user return users?.length
? { ? {
id: user.id, id: users[0].id,
name: user.name, name: users[0].name,
avatar: user.avatar_url, avatar: users[0].avatar_url,
email: user.email, email: users[0].email,
} }
: null; : null;
} }
@ -346,7 +389,7 @@ export class AffineProvider extends BaseProvider {
public override async logout(): Promise<void> { public override async logout(): Promise<void> {
token.clear(); token.clear();
this._channel.disconnect(); this._channel?.disconnect();
this._wsMap.forEach(ws => ws.disconnect()); this._wsMap.forEach(ws => ws.disconnect());
storage.removeItem('token'); storage.removeItem('token');
} }
@ -354,4 +397,8 @@ export class AffineProvider extends BaseProvider {
public override async getWorkspaceMembers(id: string) { public override async getWorkspaceMembers(id: string) {
return this._apis.getWorkspaceMembers({ id }); return this._apis.getWorkspaceMembers({ id });
} }
public override async acceptInvitation(invitingCode: string): Promise<void> {
await this._apis.acceptInviting({ invitingCode });
}
} }

View File

@ -15,7 +15,7 @@ export interface User {
export async function getUserByEmail( export async function getUserByEmail(
params: GetUserByEmailParams params: GetUserByEmailParams
): Promise<User | null> { ): Promise<User[] | null> {
const searchParams = new URLSearchParams({ ...params }); const searchParams = new URLSearchParams({ ...params });
return client.get('api/user', { searchParams }).json<User | null>(); return client.get('api/user', { searchParams }).json<User[] | null>();
} }

View File

@ -1,6 +1,7 @@
import websocket from 'lib0/websocket'; import * as websocket from 'lib0/websocket';
import { Logger } from 'src/types'; import { Logger } from 'src/types';
import { token } from './apis/token'; import { token } from './apis/token';
import * as url from 'lib0/url';
const RECONNECT_INTERVAL_TIME = 5000; const RECONNECT_INTERVAL_TIME = 5000;
const MAX_RECONNECT_TIMES = 50; const MAX_RECONNECT_TIMES = 50;
@ -10,11 +11,21 @@ export class WebsocketClient extends websocket.WebsocketClient {
private _reconnectInterval: number | null = null; private _reconnectInterval: number | null = null;
private _logger: Logger; private _logger: Logger;
constructor( constructor(
url: string, serverUrl: string,
logger: Logger, logger: Logger,
options?: { binaryType: 'arraybuffer' | 'blob' | null } options?: ConstructorParameters<typeof websocket.WebsocketClient>[1] & {
params: Record<string, string>;
}
) { ) {
super(url, options); const params = options?.params || {};
// ensure that url is always ends with /
while (serverUrl[serverUrl.length - 1] === '/') {
serverUrl = serverUrl.slice(0, serverUrl.length - 1);
}
const encodedParams = url.encodeQueryParams(params);
const newUrl =
serverUrl + '/' + (encodedParams.length === 0 ? '' : '?' + encodedParams);
super(newUrl, options);
this._logger = logger; this._logger = logger;
this._setupChannel(); this._setupChannel();
} }

View File

@ -222,4 +222,14 @@ export class BaseProvider {
workspaceId; workspaceId;
return Promise.resolve([]); return Promise.resolve([]);
} }
/**
* accept invitation
* @param {string} inviteCode
* @returns
*/
public async acceptInvitation(inviteCode: string): Promise<void> {
inviteCode;
return;
}
} }