Merge branch 'release'
This commit is contained in:
commit
9b068a142d
|
|
@ -1308,6 +1308,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|||
if (!option.dontCreateOper && !['oper', 'operEntity', 'modiEntity', 'modi'].includes(entity) && ids.length > 0) {
|
||||
// 按照框架要求生成Oper和OperEntity这两个内置的对象
|
||||
(0, assert_1.default)(operId);
|
||||
const operatorId = context.getCurrentUserId(true);
|
||||
const createOper = {
|
||||
id: 'dummy',
|
||||
action: 'create',
|
||||
|
|
@ -1317,6 +1318,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|||
data,
|
||||
targetEntity: entity,
|
||||
bornAt,
|
||||
operatorId,
|
||||
operEntity$oper: {
|
||||
id: 'dummy',
|
||||
action: 'create',
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ function translateCheckerInSyncContext(checker) {
|
|||
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
|
||||
return;
|
||||
}
|
||||
const e = new Exception_1.OakRowInconsistencyException(undefined, errMsg);
|
||||
const e = new Exception_1.OakRowInconsistencyException(undefined, errMsg || 'row checker condition illegal');
|
||||
throw e;
|
||||
};
|
||||
return {
|
||||
|
|
@ -402,7 +402,7 @@ function checkAttributeLegal(schema, entity, data) {
|
|||
case 'enum': {
|
||||
(0, assert_1.default)(enumeration);
|
||||
if (!enumeration.includes(data[attr])) {
|
||||
throw new Exception_1.OakInputIllegalException(entity, [attr], 'not in enumberation');
|
||||
throw new Exception_1.OakInputIllegalException(entity, [attr], 'not in enumeration');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ export interface Connector<ED extends EntityDict, FrontCxt extends SyncContext<E
|
|||
message?: string | null;
|
||||
}>;
|
||||
getRouter: () => string;
|
||||
parseRequestHeaders: (headers: IncomingHttpHeaders) => {
|
||||
parseRequest: (headers: IncomingHttpHeaders, body?: any, files?: any) => {
|
||||
contextString?: string;
|
||||
aspectName: string;
|
||||
data?: any;
|
||||
};
|
||||
serializeResult: (result: any, opRecords: OpRecord<ED>[], headers: IncomingHttpHeaders, body: any, message?: string) => Promise<{
|
||||
body: any;
|
||||
|
|
|
|||
|
|
@ -32,14 +32,13 @@ export interface PushEntityDef<ED extends EntityDict & BaseEntityDict, T extends
|
|||
recursive?: boolean;
|
||||
relationName?: string;
|
||||
actions?: ED[T]['Action'][];
|
||||
/**
|
||||
* 同步结果回调,根据接口的幂等原理,同步一定要完全成功再回调
|
||||
*/
|
||||
onSynchronized?: (result: {
|
||||
action: ED[T]['Action'];
|
||||
data: ED[T]['Operation']['data'];
|
||||
result: Array<{
|
||||
userId: string;
|
||||
rowIds: string[];
|
||||
error?: Error;
|
||||
}>;
|
||||
}, context: Cxt) => Promise<void>;
|
||||
}
|
||||
export interface SyncRemoteConfigBase<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,22 @@ export declare class SimpleConnector<ED extends EntityDict, FrontCxt extends Syn
|
|||
private option;
|
||||
private makeException;
|
||||
constructor(option: ServerOption, makeException: (exceptionData: any) => OakException<ED>);
|
||||
protected makeHeadersAndBody(name: string, data: any, context?: FrontCxt): Promise<{
|
||||
headers: Record<string, string>;
|
||||
body: FormData;
|
||||
} | {
|
||||
headers: HeadersInit;
|
||||
body: string;
|
||||
}>;
|
||||
protected parseAspectResult(response: Response): Promise<{
|
||||
result: any;
|
||||
opRecords: any;
|
||||
message: string | null;
|
||||
} | {
|
||||
result: ArrayBuffer;
|
||||
message: string | null;
|
||||
opRecords?: undefined;
|
||||
}>;
|
||||
callAspect(name: string, params: any, context?: FrontCxt): Promise<{
|
||||
result: any;
|
||||
opRecords: any;
|
||||
|
|
@ -37,9 +53,10 @@ export declare class SimpleConnector<ED extends EntityDict, FrontCxt extends Syn
|
|||
path: any;
|
||||
}>;
|
||||
getEndpointRouter(): string;
|
||||
parseRequestHeaders(headers: IncomingHttpHeaders): {
|
||||
parseRequest(headers: IncomingHttpHeaders, body?: any, files?: any): {
|
||||
contextString: string | undefined;
|
||||
aspectName: string;
|
||||
data: any;
|
||||
};
|
||||
serializeResult(result: any, opRecords: OpRecord<ED>[], headers: IncomingHttpHeaders, body: any, message?: string): Promise<{
|
||||
body: any;
|
||||
|
|
|
|||
|
|
@ -6,20 +6,6 @@ const assert_1 = tslib_1.__importDefault(require("assert"));
|
|||
const stream_1 = require("stream");
|
||||
const url_1 = tslib_1.__importDefault(require("url"));
|
||||
const types_1 = require("../types");
|
||||
function makeContentTypeAndBody(data) {
|
||||
if (process.env.OAK_PLATFORM !== 'wechatMp') {
|
||||
if (data instanceof FormData) {
|
||||
return {
|
||||
// contentType: 'multipart/form-data',
|
||||
body: data,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
}
|
||||
class SimpleConnector {
|
||||
static ASPECT_ROUTER = '/aspect';
|
||||
static BRIDGE_ROUTER = '/bridge';
|
||||
|
|
@ -47,26 +33,30 @@ class SimpleConnector {
|
|||
this.serverSubscribePointUrl = `${serverUrl}${SimpleConnector.SUBSCRIBE_POINT_ROUTER}`;
|
||||
this.makeException = makeException;
|
||||
}
|
||||
async callAspect(name, params, context) {
|
||||
async makeHeadersAndBody(name, data, context) {
|
||||
const cxtStr = context ? await context.toString() : '{}';
|
||||
const { contentType, body } = makeContentTypeAndBody(params);
|
||||
let response;
|
||||
try {
|
||||
response = await global.fetch(this.serverAspectUrl, {
|
||||
method: 'POST',
|
||||
headers: Object.assign({
|
||||
const headers = {
|
||||
'oak-cxt': cxtStr,
|
||||
'oak-aspect': name,
|
||||
}, contentType && {
|
||||
'Content-Type': contentType,
|
||||
}),
|
||||
body,
|
||||
});
|
||||
};
|
||||
if (process.env.OAK_PLATFORM !== 'wechatMp') {
|
||||
if (data instanceof FormData) {
|
||||
return {
|
||||
headers,
|
||||
body: data,
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
// fetch返回异常一定是网络异常
|
||||
throw new types_1.OakNetworkException(`请求[${this.serverAspectUrl}],发生网络异常`);
|
||||
}
|
||||
return {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers,
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
}
|
||||
;
|
||||
async parseAspectResult(response) {
|
||||
if (response.status > 299) {
|
||||
const err = new types_1.OakServerProxyException(`网络请求返回status是${response.status}`);
|
||||
throw err;
|
||||
|
|
@ -98,6 +88,22 @@ class SimpleConnector {
|
|||
throw new Error(`尚不支持的content-type类型${responseType}`);
|
||||
}
|
||||
}
|
||||
async callAspect(name, params, context) {
|
||||
const { headers, body } = await this.makeHeadersAndBody(name, params, context);
|
||||
let response;
|
||||
try {
|
||||
response = await global.fetch(this.serverAspectUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
// fetch返回异常一定是网络异常
|
||||
throw new types_1.OakNetworkException(`请求[${this.serverAspectUrl}],发生网络异常`);
|
||||
}
|
||||
return this.parseAspectResult(response);
|
||||
}
|
||||
getRouter() {
|
||||
return SimpleConnector.ASPECT_ROUTER;
|
||||
}
|
||||
|
|
@ -142,13 +148,18 @@ class SimpleConnector {
|
|||
getEndpointRouter() {
|
||||
return SimpleConnector.ENDPOINT_ROUTER;
|
||||
}
|
||||
parseRequestHeaders(headers) {
|
||||
parseRequest(headers, body, files) {
|
||||
const { 'oak-cxt': oakCxtStr, 'oak-aspect': aspectName } = headers;
|
||||
(0, assert_1.default)(typeof oakCxtStr === 'string' || oakCxtStr === undefined);
|
||||
(0, assert_1.default)(typeof aspectName === 'string');
|
||||
return {
|
||||
contextString: oakCxtStr,
|
||||
aspectName,
|
||||
/* data: !files ? body : {
|
||||
data: body,
|
||||
files,
|
||||
}, */ // 下个版本再改
|
||||
data: files ? Object.assign({}, body, files) : body,
|
||||
};
|
||||
}
|
||||
async serializeResult(result, opRecords, headers, body, message) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "oak-domain",
|
||||
"version": "4.2.2",
|
||||
"version": "4.2.3",
|
||||
"author": {
|
||||
"name": "XuChang"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1586,6 +1586,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
if (!option.dontCreateOper && !['oper', 'operEntity', 'modiEntity', 'modi'].includes(entity as string) && ids.length > 0) {
|
||||
// 按照框架要求生成Oper和OperEntity这两个内置的对象
|
||||
assert(operId);
|
||||
const operatorId = context.getCurrentUserId(true);
|
||||
const createOper: CreateSingleOperOperation = {
|
||||
id: 'dummy',
|
||||
action: 'create',
|
||||
|
|
@ -1595,6 +1596,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
data,
|
||||
targetEntity: entity as string,
|
||||
bornAt,
|
||||
operatorId,
|
||||
operEntity$oper: {
|
||||
id: 'dummy',
|
||||
action: 'create',
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ export function translateCheckerInSyncContext<
|
|||
if (checkFilterContains<ED, T, Cxt>(entity, context, filter2, operationFilter, true)) {
|
||||
return;
|
||||
}
|
||||
const e = new OakRowInconsistencyException(undefined, errMsg);
|
||||
const e = new OakRowInconsistencyException(undefined, errMsg || 'row checker condition illegal');
|
||||
throw e;
|
||||
};
|
||||
return {
|
||||
|
|
@ -446,7 +446,7 @@ function checkAttributeLegal<ED extends EntityDict & BaseEntityDict>(
|
|||
case 'enum': {
|
||||
assert(enumeration);
|
||||
if (!enumeration.includes((data as ED[keyof ED]['CreateSingle']['data'])[attr])) {
|
||||
throw new OakInputIllegalException(entity, [attr], 'not in enumberation');
|
||||
throw new OakInputIllegalException(entity, [attr], 'not in enumeration');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { IncomingHttpHeaders } from "http";
|
||||
import { RowStore } from ".";
|
||||
import { AsyncContext, AsyncRowStore } from "../store/AsyncRowStore";
|
||||
import { SyncContext } from "../store/SyncRowStore";
|
||||
import { EntityDict, OpRecord } from "./Entity";
|
||||
import { OakException } from "./Exception";
|
||||
|
|
@ -18,9 +16,10 @@ export interface Connector<ED extends EntityDict, FrontCxt extends SyncContext<E
|
|||
|
||||
getRouter: () => string;
|
||||
|
||||
parseRequestHeaders: (headers: IncomingHttpHeaders) => {
|
||||
parseRequest: (headers: IncomingHttpHeaders, body?: any, files?: any) => {
|
||||
contextString?: string;
|
||||
aspectName: string;
|
||||
data?: any;
|
||||
};
|
||||
|
||||
serializeResult: (
|
||||
|
|
|
|||
|
|
@ -41,16 +41,13 @@ export interface PushEntityDef<ED extends EntityDict & BaseEntityDict, T extends
|
|||
relationName?: string; // 要同步的user与根对象的relation名称(为空说明是userId)
|
||||
actions?: ED[T]['Action'][];
|
||||
|
||||
// 同步结果回调,一行可能要向多个syncEntity上去同步,因此返回结果是一个数组(表示向某个userId上同步了rowIds相关的数据,如果有失败则返回error)
|
||||
// 如果不定义,则认为同步一定会成功。若失败则会反复同步直到成功为止
|
||||
/**
|
||||
* 同步结果回调,根据接口的幂等原理,同步一定要完全成功再回调
|
||||
*/
|
||||
onSynchronized?: (result: {
|
||||
action: ED[T]['Action'],
|
||||
data: ED[T]['Operation']['data'];
|
||||
result: Array<{
|
||||
userId: string;
|
||||
rowIds: string[];
|
||||
error?: Error;
|
||||
}>
|
||||
}, context: Cxt) => Promise<void>,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,22 +5,6 @@ import URL from 'url';
|
|||
import { SyncContext } from '../store/SyncRowStore';
|
||||
import { Connector, EntityDict, OakException, OakNetworkException, OakServerProxyException, OpRecord } from "../types";
|
||||
|
||||
function makeContentTypeAndBody(data: any) {
|
||||
if (process.env.OAK_PLATFORM !== 'wechatMp') {
|
||||
if (data instanceof FormData) {
|
||||
return {
|
||||
// contentType: 'multipart/form-data',
|
||||
body: data,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
}
|
||||
|
||||
type ServerOption = {
|
||||
protocol: string;
|
||||
hostname: string;
|
||||
|
|
@ -62,29 +46,31 @@ export class SimpleConnector<ED extends EntityDict, FrontCxt extends SyncContext
|
|||
this.makeException = makeException;
|
||||
}
|
||||
|
||||
async callAspect(name: string, params: any, context?: FrontCxt) {
|
||||
protected async makeHeadersAndBody(name: string, data: any, context?: FrontCxt) {
|
||||
const cxtStr = context ? await context.toString() : '{}';
|
||||
|
||||
const { contentType, body } = makeContentTypeAndBody(params);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await global.fetch(this.serverAspectUrl, {
|
||||
method: 'POST',
|
||||
headers: Object.assign(
|
||||
{
|
||||
const headers: HeadersInit = {
|
||||
'oak-cxt': cxtStr,
|
||||
'oak-aspect': name as string,
|
||||
},
|
||||
contentType && {
|
||||
'Content-Type': contentType as string,
|
||||
'oak-aspect': name,
|
||||
};
|
||||
if (process.env.OAK_PLATFORM !== 'wechatMp') {
|
||||
if (data instanceof FormData) {
|
||||
return {
|
||||
headers,
|
||||
body: data,
|
||||
};
|
||||
}
|
||||
) as RequestInit['headers'],
|
||||
body,
|
||||
});
|
||||
} catch (err) {
|
||||
// fetch返回异常一定是网络异常
|
||||
throw new OakNetworkException(`请求[${this.serverAspectUrl}],发生网络异常`);
|
||||
}
|
||||
|
||||
return {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers,
|
||||
} as HeadersInit,
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
};
|
||||
|
||||
protected async parseAspectResult(response: Response) {
|
||||
if (response.status > 299) {
|
||||
const err = new OakServerProxyException(
|
||||
`网络请求返回status是${response.status}`
|
||||
|
|
@ -120,6 +106,24 @@ export class SimpleConnector<ED extends EntityDict, FrontCxt extends SyncContext
|
|||
} else {
|
||||
throw new Error(`尚不支持的content-type类型${responseType}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async callAspect(name: string, params: any, context?: FrontCxt) {
|
||||
const { headers, body } = await this.makeHeadersAndBody(name, params, context);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await global.fetch(this.serverAspectUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
} catch (err) {
|
||||
// fetch返回异常一定是网络异常
|
||||
throw new OakNetworkException(`请求[${this.serverAspectUrl}],发生网络异常`);
|
||||
}
|
||||
|
||||
return this.parseAspectResult(response);
|
||||
}
|
||||
|
||||
getRouter(): string {
|
||||
|
|
@ -177,13 +181,18 @@ export class SimpleConnector<ED extends EntityDict, FrontCxt extends SyncContext
|
|||
return SimpleConnector.ENDPOINT_ROUTER;
|
||||
}
|
||||
|
||||
parseRequestHeaders(headers: IncomingHttpHeaders) {
|
||||
parseRequest(headers: IncomingHttpHeaders, body?: any, files?: any) {
|
||||
const { 'oak-cxt': oakCxtStr, 'oak-aspect': aspectName } = headers;
|
||||
assert(typeof oakCxtStr === 'string' || oakCxtStr === undefined);
|
||||
assert(typeof aspectName === 'string');
|
||||
return {
|
||||
contextString: oakCxtStr,
|
||||
aspectName,
|
||||
/* data: !files ? body : {
|
||||
data: body,
|
||||
files,
|
||||
}, */ // 下个版本再改
|
||||
data: files ? Object.assign({}, body, files) : body,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue