oak-general-business/src/context/FrontendRuntimeContext.ts

168 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { assert } from 'oak-domain/lib/utils/assert';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { FrontendRuntimeContext as Frc, SerializedData as Fsd } from 'oak-frontend-base';
import { BasicFeatures } from 'oak-frontend-base'
import { EntityDict } from '../oak-app-domain';
import { RuntimeContext } from './RuntimeContext';
import { Application } from '../features/application';
import { Token } from '../features/token';
import GeneralAspectDict from '../aspects/AspectDict';
import { CommonAspectDict } from 'oak-common-aspect';
import { SyncRowStore } from 'oak-domain/lib/store/SyncRowStore';
import { GeneralFeatures } from '../features';
import { BackendRuntimeContext } from './BackendRuntimeContext';
import {
OakApplicationLoadingException,
OakTokenExpiredException,
OakUserDisabledException,
OakUserInfoLoadingException,
} from '../types/Exception';
import { OakUnloggedInException } from 'oak-domain/lib/types';
export type AspectDict<
ED extends EntityDict & BaseEntityDict,
Cxt extends BackendRuntimeContext<ED>
> = GeneralAspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>;
// 上下文被serialize后的数据内容
export interface SerializedData extends Fsd {
a?: string;
t?: string;
rm?: boolean;
};
export abstract class FrontendRuntimeContext<
ED extends EntityDict & BaseEntityDict,
Cxt extends BackendRuntimeContext<ED>,
AD extends AspectDict<ED, Cxt>
>
extends Frc<ED, Cxt, AD>
implements RuntimeContext {
private application: Application<ED, Cxt, FrontendRuntimeContext<ED, Cxt, AD>, AD>;
private token: Token<ED, Cxt, FrontendRuntimeContext<ED, Cxt, AD>, AD>;
constructor(
store: SyncRowStore<ED, FrontendRuntimeContext<ED, Cxt, AD>>,
features: GeneralFeatures<ED, Cxt, FrontendRuntimeContext<ED, Cxt, AD>, AD> & BasicFeatures<ED, Cxt, FrontendRuntimeContext<ED, Cxt, AD>, AD>,
) {
super(store, features);
this.application = features.application;
this.token = features.token;
}
protected async getSerializedData(): Promise<SerializedData> {
const data = await super.getSerializedData();
const setAppId = async () => {
// appId必须要取到不能失败
const setInner = (resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
try {
const appId = this.application.getApplicationId();
assert(appId);
Object.assign(data, {
a: appId,
});
resolve(undefined);
}
catch (err: any) {
if (err instanceof OakApplicationLoadingException) {
const fn = this.application.subscribe(() => {
fn();
setInner(resolve, reject);
});
}
else {
reject(err);
}
}
};
return new Promise(
(resolve, reject) => setInner(resolve, reject)
);
};
await setAppId();
const setTokenValue = async() => {
const setInner = (resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
try {
const tokenValue = this.token.getTokenValue();
if (tokenValue) {
Object.assign(data, {
t: tokenValue,
});
}
resolve(undefined);
}
catch (err: any) {
if (err instanceof OakUserInfoLoadingException) {
const fn = this.token.subscribe(() => {
fn();
setInner(resolve, reject);
});
}
else {
reject(err);
}
}
};
return new Promise(
(resolve, reject) => setInner(resolve, reject)
);
};
await setTokenValue();
return data;
}
getApplicationId() {
return this.application?.getApplicationId();
}
getSystemId() {
const app = this.application?.getApplication();
return app?.systemId;
}
getApplication() {
return this.application?.getApplication();
}
getTokenValue() {
return this.token?.getTokenValue();
}
getToken(allowUnloggedIn?: boolean) {
return this.token?.getToken(allowUnloggedIn);
}
getCurrentUserId(allowUnloggedIn?: boolean): string | undefined {
return this.token?.getUserId(allowUnloggedIn);
}
isRoot() {
return this.token?.isRoot() || false;
}
isReallyRoot(): boolean {
return this.token?.isReallyRoot() || false;
}
allowUserUpdate(): boolean {
const userInfo = this.token?.getUserInfo();
if (userInfo) {
const { userState } = userInfo!;
if (userState === 'disabled') {
throw new OakUserDisabledException(
'您的帐号已经被禁用,请联系客服'
);
} else if (['merged'].includes(userState!)) {
throw new OakTokenExpiredException(
'您的登录状态有异常,请重新登录 '
);
} else {
assert(userState === 'normal' || userState === 'shadow');
}
return true;
}
throw new OakUnloggedInException('您尚未登录');
}
}