Skip to content

Commit

Permalink
feat(flat-services): add flat services
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed Aug 22, 2022
1 parent c54b8a4 commit 9e6ed9e
Show file tree
Hide file tree
Showing 21 changed files with 871 additions and 707 deletions.
1 change: 1 addition & 0 deletions .commitlintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ module.exports = {
"flat-rtm",
"flat-server-api",
"flat-stores",
"flat-services",
"pnpm",
"server",
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.loading-page {
position: absolute;
position: fixed;
top: 0;
left: 0;
width: 100%;
Expand Down
4 changes: 4 additions & 0 deletions packages/flat-services/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
public/
*.js
19 changes: 19 additions & 0 deletions packages/flat-services/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@netless/flat-services",
"version": "0.1.0",
"description": "Flat Service Manager",
"main": "src/index.ts",
"private": true,
"license": "MIT",
"scripts": {
"build": "tsc"
},
"dependencies": {
"@netless/flat-rtc": "workspace:*",
"@netless/flat-rtm": "workspace:*"
},
"devDependencies": {
"prettier": "^2.3.0",
"typescript": "^4.6.2"
}
}
83 changes: 83 additions & 0 deletions packages/flat-services/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { FlatRTC } from "@netless/flat-rtc";
import { FlatRTM } from "@netless/flat-rtm";

export interface FlatServicesCatalog {
rtc: FlatRTC;
rtm: FlatRTM;
}

export type FlatServiceID = Extract<keyof FlatServicesCatalog, string>;

export type FlatServicesInstance<T extends FlatServiceID> = FlatServicesCatalog[T];

export interface FlatServicesPendingCatalog {
rtc: Promise<FlatRTC>;
rtm: Promise<FlatRTM>;
}

export type FlatServicesCreator<T extends FlatServiceID> = () => Promise<FlatServicesCatalog[T]>;

export type FlatServicesCreatorCatalog = {
[K in FlatServiceID]: FlatServicesCreator<K>;
};

export class FlatServices {
private registry: Partial<FlatServicesCreatorCatalog> = {};

private services: Partial<FlatServicesPendingCatalog> = {};

public register<T extends FlatServiceID>(
name: T,
serviceCreator: FlatServicesCreatorCatalog[T],
): void {
if (this.isRegistered(name)) {
throw new Error(`${name} is already registered`);
}
this.registry[name] = serviceCreator;
}

public async unregister<T extends FlatServiceID>(name: T): Promise<boolean> {
if (this.isRegistered(name)) {
this.registry[name] = undefined;
await this.shutdownService(name);
return true;
}
return false;
}

public async requestService<T extends FlatServiceID>(
name: T,
): Promise<FlatServicesCatalog[T] | undefined> {
if (this.services[name]) {
return this.services[name] as Promise<FlatServicesCatalog[T]>;
}
const creator = this.registry[name];
if (creator) {
return ((this.services[name] as any) = creator());
}
return;
}

public async shutdownService<T extends FlatServiceID = FlatServiceID>(
name: T,
): Promise<boolean> {
const pService: FlatServicesPendingCatalog[FlatServiceID] | undefined = this.services[name];
if (pService) {
this.services[name] = undefined;
await (await pService).destroy();
return true;
}
return false;
}

public isRegistered(name: FlatServiceID): boolean {
return Boolean(this.registry[name]);
}

public isCreated(name: FlatServiceID): boolean {
return Boolean(this.services[name]);
}
}

export const flatServices: FlatServices =
(window as any).__FlAtSeRvIcEs || ((window as any).__FlAtSeRvIcEs = new FlatServices());
12 changes: 12 additions & 0 deletions packages/flat-services/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"composite": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["./src"]
}
1 change: 1 addition & 0 deletions web/flat-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@netless/flat-rtm": "workspace:*",
"@netless/flat-rtm-agora": "workspace:*",
"@netless/flat-server-api": "workspace:*",
"@netless/flat-services": "workspace:*",
"@netless/flat-stores": "workspace:*",
"@netless/player-controller": "^0.0.9",
"@netless/synced-store": "^1.1.1",
Expand Down
4 changes: 0 additions & 4 deletions web/flat-web/src/components/FlatRTCContext.tsx

This file was deleted.

58 changes: 58 additions & 0 deletions web/flat-web/src/components/FlatServicesContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import { createContext } from "react";
import {
FlatServices,
flatServices,
FlatServiceID,
FlatServicesInstance,
FlatServicesCatalog,
} from "@netless/flat-services";
import { useIsomorphicLayoutEffect } from "react-use";
import { useSafePromise } from "flat-components";

export const FlatServicesContext = createContext<FlatServices>(flatServices);

export const FlatServicesContextProvider: React.FC = props => (
<FlatServicesContext.Provider value={flatServices}>
{props.children}
</FlatServicesContext.Provider>
);

export const useFlatService = <T extends FlatServiceID>(
name: T,
): FlatServicesInstance<T> | undefined => {
const flatServices = React.useContext(FlatServicesContext);
const [service, setService] = React.useState<FlatServicesInstance<T>>();
const sp = useSafePromise();
useIsomorphicLayoutEffect(() => {
sp(flatServices.requestService(name)).then(setService);
}, [flatServices, name]);
return service;
};

export type WithFlatServicesProps<P = {}, S extends FlatServiceID = FlatServiceID> = P &
Pick<FlatServicesCatalog, S>;

export const withFlatServices = <S extends FlatServiceID>(...names: S[]) => {
return <P extends {}>(Component: React.ComponentType<WithFlatServicesProps<P, S>>) => {
const WithFlatServices: React.FC<P> = props => {
const flatServices = React.useContext(FlatServicesContext);
const [services, setServices] = React.useState<Pick<FlatServicesCatalog, S>>();
const sp = useSafePromise();
useIsomorphicLayoutEffect(() => {
sp(Promise.all(names.map(name => flatServices.requestService(name)))).then(
serviceList => {
setServices(
serviceList.reduce((acc, service, i) => {
acc[names[i]] = service;
return acc;
}, {} as any),
);
},
);
}, [flatServices]);
return services ? <Component {...services} {...props} /> : null;
};
return WithFlatServices;
};
};
Loading

0 comments on commit 9e6ed9e

Please sign in to comment.