Merge branch 'sub' into dev
This commit is contained in:
commit
ba054ad1f8
|
|
@ -1,4 +1,4 @@
|
|||
import { EntityDict, OperateOption, SelectOption, OpRecord, AspectWrapper, CheckerType, Aspect, StorageSchema, Checker, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict, OperateOption, SelectOption, OpRecord, AspectWrapper, CheckerType, Aspect, StorageSchema, Checker } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { Feature } from '../types/Feature';
|
||||
|
|
@ -101,7 +101,5 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
|
|||
commit(): void;
|
||||
rollback(): void;
|
||||
buildContext(): FrontCxt;
|
||||
sub(data: Array<SubDataDef<ED, keyof ED>>, callback: (records: OpRecord<ED>[], ids: string[]) => void): Promise<void>;
|
||||
unsub(ids: string[]): Promise<void>;
|
||||
}
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -636,16 +636,6 @@ var Cache = /** @class */ (function (_super) {
|
|||
Cache.prototype.buildContext = function () {
|
||||
return this.contextBuilder();
|
||||
};
|
||||
Cache.prototype.sub = function (data, callback) {
|
||||
var _this = this;
|
||||
return this.aspectWrapper.sub(data, function (records, ids) {
|
||||
_this.sync(records),
|
||||
callback(records, ids);
|
||||
});
|
||||
};
|
||||
Cache.prototype.unsub = function (ids) {
|
||||
return this.aspectWrapper.unsub(ids);
|
||||
};
|
||||
return Cache;
|
||||
}(Feature_1.Feature));
|
||||
exports.Cache = Cache;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@ import { Navigator } from './navigator';
|
|||
import { Port } from './port';
|
||||
import { RelationAuth } from './relationAuth';
|
||||
import { Style } from './style';
|
||||
import { SubScriber } from './subscriber';
|
||||
import { ContextMenuFactory } from './contextMenuFactory';
|
||||
import { Geo } from './geo';
|
||||
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
export declare function initializeStep2<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(features: Pick<BasicFeatures<ED, Cxt, FrontCxt, AD>, 'localStorage' | 'environment'>, aspectWrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>, storageSchema: StorageSchema<ED>, frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt, checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>, actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], authDeduceRelationMap: AuthDeduceRelationMap<ED>, colorDict: ColorDict<ED>, getFullDataFn: () => any, makeBridgeUrlFn?: (url: string, headers?: Record<string, string>) => string, selectFreeEntities?: (keyof ED)[], createFreeEntities?: (keyof ED)[], updateFreeEntities?: (keyof ED)[], savedEntities?: (keyof ED)[], keepFreshPeriod?: number): {
|
||||
export declare function initializeStep2<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(features: Pick<BasicFeatures<ED, Cxt, FrontCxt, AD>, 'localStorage' | 'environment'>, aspectWrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>, storageSchema: StorageSchema<ED>, frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt, checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>, actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], authDeduceRelationMap: AuthDeduceRelationMap<ED>, colorDict: ColorDict<ED>, getFullDataFn: () => any, getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>, makeBridgeUrlFn?: (url: string, headers?: Record<string, string>) => string, selectFreeEntities?: (keyof ED)[], createFreeEntities?: (keyof ED)[], updateFreeEntities?: (keyof ED)[], savedEntities?: (keyof ED)[], keepFreshPeriod?: number): {
|
||||
cache: Cache<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
relationAuth: RelationAuth<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
runningTree: RunningTree<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
|
|
@ -30,6 +34,7 @@ export declare function initializeStep2<ED extends EntityDict & BaseEntityDict,
|
|||
style: Style<ED>;
|
||||
geo: Geo<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
contextMenuFactory: ContextMenuFactory<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
subscriber: SubScriber<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
};
|
||||
export declare function initializeStep1(): {
|
||||
location: Location;
|
||||
|
|
@ -56,4 +61,5 @@ export declare type BasicFeatures<ED extends EntityDict & BaseEntityDict, Cxt ex
|
|||
style: Style<ED>;
|
||||
geo: Geo<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
contextMenuFactory: ContextMenuFactory<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
subscriber: SubScriber<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ var navigator_1 = require("./navigator");
|
|||
var port_1 = require("./port");
|
||||
var relationAuth_1 = require("./relationAuth");
|
||||
var style_1 = require("./style");
|
||||
var subscriber_1 = require("./subscriber");
|
||||
var contextMenuFactory_1 = require("./contextMenuFactory");
|
||||
var geo_1 = require("./geo");
|
||||
function initializeStep2(features, aspectWrapper, storageSchema, frontendContextBuilder, checkers, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, getFullDataFn, makeBridgeUrlFn, selectFreeEntities, createFreeEntities, updateFreeEntities, savedEntities, keepFreshPeriod) {
|
||||
function initializeStep2(features, aspectWrapper, storageSchema, frontendContextBuilder, checkers, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, getFullDataFn, getSubscribePointFn, makeBridgeUrlFn, selectFreeEntities, createFreeEntities, updateFreeEntities, savedEntities, keepFreshPeriod) {
|
||||
var localStorage = features.localStorage, environment = features.environment;
|
||||
var cache = new cache_1.Cache(storageSchema, aspectWrapper, frontendContextBuilder, checkers, getFullDataFn, localStorage, savedEntities, keepFreshPeriod);
|
||||
var relationAuth = new relationAuth_1.RelationAuth(cache, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, selectFreeEntities, createFreeEntities, updateFreeEntities);
|
||||
|
|
@ -26,6 +27,7 @@ function initializeStep2(features, aspectWrapper, storageSchema, frontendContext
|
|||
var style = new style_1.Style(colorDict);
|
||||
var locales = new locales_1.Locales(cache, localStorage, environment, 'zh-CN', makeBridgeUrlFn); // 临时性代码,应由上层传入
|
||||
var contextMenuFactory = new contextMenuFactory_1.ContextMenuFactory(cache, relationAuth, actionCascadePathGraph);
|
||||
var subscriber = new subscriber_1.SubScriber(cache, getSubscribePointFn);
|
||||
return {
|
||||
cache: cache,
|
||||
relationAuth: relationAuth,
|
||||
|
|
@ -35,6 +37,7 @@ function initializeStep2(features, aspectWrapper, storageSchema, frontendContext
|
|||
style: style,
|
||||
geo: geo,
|
||||
contextMenuFactory: contextMenuFactory,
|
||||
subscriber: subscriber,
|
||||
};
|
||||
}
|
||||
exports.initializeStep2 = initializeStep2;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import { EntityDict, Aspect, OpRecord, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
import { Cache } from './cache';
|
||||
import { SyncContext } from "oak-domain/lib/store/SyncRowStore";
|
||||
import { Feature } from "../types/Feature";
|
||||
declare type SubscribeEvent = 'connect' | 'disconnect';
|
||||
export declare class SubScriber<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends CommonAspectDict<ED, Cxt> & Record<string, Aspect<ED, Cxt>>> extends Feature {
|
||||
private cache;
|
||||
private getSubscribePointFn;
|
||||
private callbackMap;
|
||||
private socket?;
|
||||
private socketState;
|
||||
private eventCallbackMap;
|
||||
constructor(cache: Cache<ED, Cxt, FrontCxt, AD>, getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>);
|
||||
on(event: SubscribeEvent, callback: () => void): void;
|
||||
off(event: SubscribeEvent, callback: () => void): void;
|
||||
private emit;
|
||||
private initSocketOption;
|
||||
private login;
|
||||
private connect;
|
||||
sub(data: SubDataDef<ED, keyof ED>[], callback?: (records: OpRecord<ED>[], ids: string[]) => void): Promise<void>;
|
||||
unsub(ids: string[]): Promise<void>;
|
||||
}
|
||||
export {};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { EntityDict, Aspect, OpRecord, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
import { Cache } from './cache';
|
||||
import { SyncContext } from "oak-domain/lib/store/SyncRowStore";
|
||||
import { Feature } from "../types/Feature";
|
||||
declare type SubscribeEvent = 'connect' | 'disconnect';
|
||||
export declare class SubScriber<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends CommonAspectDict<ED, Cxt> & Record<string, Aspect<ED, Cxt>>> extends Feature {
|
||||
private eventCallbackMap;
|
||||
constructor(cache: Cache<ED, Cxt, FrontCxt, AD>, getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>);
|
||||
on(event: SubscribeEvent, callback: () => void): void;
|
||||
off(event: SubscribeEvent, callback: () => void): void;
|
||||
sub(data: SubDataDef<ED, keyof ED>[], callback: (records: OpRecord<ED>[], ids: string[]) => void): Promise<void>;
|
||||
unsub(ids: string[]): Promise<void>;
|
||||
}
|
||||
export {};
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SubScriber = void 0;
|
||||
var tslib_1 = require("tslib");
|
||||
var lodash_1 = require("oak-domain/lib/utils/lodash");
|
||||
var Feature_1 = require("../types/Feature");
|
||||
var SubScriber = /** @class */ (function (_super) {
|
||||
tslib_1.__extends(SubScriber, _super);
|
||||
function SubScriber(cache, getSubscribePointFn) {
|
||||
var _this = _super.call(this) || this;
|
||||
_this.eventCallbackMap = {
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
};
|
||||
return _this;
|
||||
}
|
||||
SubScriber.prototype.on = function (event, callback) {
|
||||
this.eventCallbackMap[event].push(callback);
|
||||
};
|
||||
SubScriber.prototype.off = function (event, callback) {
|
||||
(0, lodash_1.pull)(this.eventCallbackMap[event], callback);
|
||||
};
|
||||
SubScriber.prototype.sub = function (data, callback) {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
console.log('data subscribe 在dev模式下不起作用');
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SubScriber.prototype.unsub = function (ids) {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
return SubScriber;
|
||||
}(Feature_1.Feature));
|
||||
exports.SubScriber = SubScriber;
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SubScriber = void 0;
|
||||
var tslib_1 = require("tslib");
|
||||
var assert_1 = tslib_1.__importDefault(require("assert"));
|
||||
var lodash_1 = require("oak-domain/lib/utils/lodash");
|
||||
var socket_io_1 = tslib_1.__importDefault(require("../utils/socket.io/socket.io"));
|
||||
var Feature_1 = require("../types/Feature");
|
||||
var SubScriber = /** @class */ (function (_super) {
|
||||
tslib_1.__extends(SubScriber, _super);
|
||||
function SubScriber(cache, getSubscribePointFn) {
|
||||
var _this = _super.call(this) || this;
|
||||
_this.callbackMap = {};
|
||||
_this.socketState = 'unconnected';
|
||||
_this.eventCallbackMap = {
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
};
|
||||
_this.cache = cache;
|
||||
_this.getSubscribePointFn = getSubscribePointFn;
|
||||
return _this;
|
||||
}
|
||||
SubScriber.prototype.on = function (event, callback) {
|
||||
this.eventCallbackMap[event].push(callback);
|
||||
};
|
||||
SubScriber.prototype.off = function (event, callback) {
|
||||
(0, lodash_1.pull)(this.eventCallbackMap[event], callback);
|
||||
};
|
||||
SubScriber.prototype.emit = function (event) {
|
||||
this.eventCallbackMap[event].forEach(function (ele) { return ele(); });
|
||||
};
|
||||
SubScriber.prototype.initSocketOption = function () {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
var _a, url, path, socket;
|
||||
return tslib_1.__generator(this, function (_b) {
|
||||
switch (_b.label) {
|
||||
case 0: return [4 /*yield*/, this.getSubscribePointFn()];
|
||||
case 1:
|
||||
_a = _b.sent(), url = _a.url, path = _a.path;
|
||||
socket = (0, socket_io_1.default)(url, {
|
||||
path: path,
|
||||
});
|
||||
this.socket = socket;
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
SubScriber.prototype.login = function () {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SubScriber.prototype.connect = function () {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
var optionInited, socket;
|
||||
var _this = this;
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
optionInited = false;
|
||||
if (!!this.socket) return [3 /*break*/, 2];
|
||||
return [4 /*yield*/, this.initSocketOption()];
|
||||
case 1:
|
||||
_a.sent();
|
||||
optionInited = true;
|
||||
_a.label = 2;
|
||||
case 2:
|
||||
socket = this.socket;
|
||||
return [2 /*return*/, new Promise(function (resolve, reject) {
|
||||
/**
|
||||
* https://socket.io/zh-CN/docs/v4/client-socket-instance/
|
||||
*/
|
||||
socket.on('connect', function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||
var _this = this;
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
// 验证身份
|
||||
this.socketState = 'connected';
|
||||
this.emit('connect');
|
||||
socket.off('connect');
|
||||
socket.on('disconnect', function () {
|
||||
_this.socketState = 'unconnected';
|
||||
_this.emit('disconnect');
|
||||
socket.removeAllListeners();
|
||||
if (Object.keys(_this.callbackMap).length > 0) {
|
||||
_this.connect();
|
||||
}
|
||||
});
|
||||
return [4 /*yield*/, this.login()];
|
||||
case 1:
|
||||
_a.sent();
|
||||
resolve(undefined);
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
}); });
|
||||
if (!optionInited) {
|
||||
var count_1 = 0;
|
||||
socket.on('connect_error', function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
count_1++;
|
||||
if (!(count_1 > 10)) return [3 /*break*/, 2];
|
||||
// 可能socket地址改变了,刷新重连
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
this.socket = undefined;
|
||||
return [4 /*yield*/, this.connect()];
|
||||
case 1:
|
||||
_a.sent();
|
||||
resolve(undefined);
|
||||
_a.label = 2;
|
||||
case 2: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
}); });
|
||||
}
|
||||
socket.connect();
|
||||
})];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
SubScriber.prototype.sub = function (data, callback) {
|
||||
var _a;
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
var ids;
|
||||
var _this = this;
|
||||
return tslib_1.__generator(this, function (_b) {
|
||||
ids = data.map(function (ele) { return ele.id; });
|
||||
if (callback) {
|
||||
ids.forEach(function (id) {
|
||||
(0, assert_1.default)(!_this.callbackMap[id], "[subscriber]\u6CE8\u518C\u56DE\u8C03\u7684id".concat(id, "\u53D1\u751F\u91CD\u590D"));
|
||||
_this.callbackMap[id] = callback;
|
||||
});
|
||||
}
|
||||
if (this.socketState === 'unconnected') {
|
||||
this.connect();
|
||||
}
|
||||
else if (this.socketState === 'connected') {
|
||||
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.emit('sub', data);
|
||||
}
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SubScriber.prototype.unsub = function (ids) {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
var _this = this;
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
ids.forEach(function (id) { return (0, lodash_1.omit)(_this.callbackMap, id); });
|
||||
if (this.socketState === 'connected') {
|
||||
this.socket.emit('unsub', ids);
|
||||
}
|
||||
if (this.socketState !== 'unconnected') {
|
||||
if (Object.keys(this.callbackMap).length === 0) {
|
||||
this.socket.disconnect();
|
||||
this.socket.removeAllListeners();
|
||||
this.socketState = 'unconnected';
|
||||
}
|
||||
}
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
return SubScriber;
|
||||
}(Feature_1.Feature));
|
||||
exports.SubScriber = SubScriber;
|
||||
|
|
@ -32,6 +32,7 @@ export declare function initialize<ED extends EntityDict & BaseEntityDict, Cxt e
|
|||
style: import("./features/style").Style<ED>;
|
||||
geo: import("./features/geo").Geo<ED, Cxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
contextMenuFactory: import("./features/contextMenuFactory").ContextMenuFactory<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
subscriber: import("./features/subscriber").SubScriber<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
} & {
|
||||
location: import("./features/location").Location;
|
||||
environment: import("./features/environment").Environment;
|
||||
|
|
|
|||
|
|
@ -73,19 +73,10 @@ function initialize(storageSchema, frontendContextBuilder, backendContextBuilder
|
|||
}
|
||||
});
|
||||
}); },
|
||||
/**
|
||||
* dev模式下订阅数据没有意义(单用户模式)
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
sub: function (data, callback) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
unsub: function (ids) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
var features2 = (0, features_1.initializeStep2)(features1, wrapper, storageSchema, frontendContextBuilder, checkers2, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, function () { return debugStore.getCurrentData(); }, undefined, selectFreeEntities, createFreeEntities, updateFreeEntities, cacheSavedEntities, cacheKeepFreshPeriod);
|
||||
var features2 = (0, features_1.initializeStep2)(features1, wrapper, storageSchema, frontendContextBuilder, checkers2, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, function () { return debugStore.getCurrentData(); }, function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
|
||||
return [2 /*return*/, ({ url: '', path: '' })];
|
||||
}); }); }, undefined, selectFreeEntities, createFreeEntities, updateFreeEntities, cacheSavedEntities, cacheKeepFreshPeriod);
|
||||
(0, oak_common_aspect_2.registerPorts)(importations || [], exportations || []);
|
||||
var features = Object.assign(features2, features1);
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { InitializeOptions } from './types/Initialize';
|
|||
* @param actionDict
|
||||
* @returns
|
||||
*/
|
||||
export declare function initialize<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(storageSchema: StorageSchema<ED>, frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt, connector: Connector<ED, Cxt, FrontCxt>, checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>, option: InitializeOptions<ED>): {
|
||||
export declare function initialize<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(storageSchema: StorageSchema<ED>, frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt, connector: Connector<ED, FrontCxt>, checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>, option: InitializeOptions<ED>): {
|
||||
features: {
|
||||
location: import("./features/location").Location;
|
||||
environment: import("./features/environment").Environment;
|
||||
|
|
@ -37,5 +37,6 @@ export declare function initialize<ED extends EntityDict & BaseEntityDict, Cxt e
|
|||
style: import("./features/style").Style<ED>;
|
||||
geo: import("./features/geo").Geo<ED, Cxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
contextMenuFactory: import("./features/contextMenuFactory").ContextMenuFactory<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
subscriber: import("./features/subscriber").SubScriber<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ exports.initialize = void 0;
|
|||
var tslib_1 = require("tslib");
|
||||
var features_1 = require("./features");
|
||||
var actionDef_1 = require("oak-domain/lib/store/actionDef");
|
||||
var subscriber_1 = tslib_1.__importDefault(require("./utils/subscriber"));
|
||||
/**
|
||||
* @param storageSchema
|
||||
* @param createFeatures
|
||||
|
|
@ -24,7 +23,6 @@ function initialize(storageSchema, frontendContextBuilder, connector, checkers,
|
|||
var intCheckers = (0, actionDef_1.makeIntrinsicCTWs)(storageSchema, actionDict).checkers;
|
||||
var checkers2 = checkers.concat(intCheckers);
|
||||
var features1 = (0, features_1.initializeStep1)();
|
||||
var subscriber = new subscriber_1.default(connector.getSubscribeRouter());
|
||||
var wrapper = {
|
||||
exec: function (name, params) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||
var context, _a, result, opRecords, message;
|
||||
|
|
@ -43,14 +41,8 @@ function initialize(storageSchema, frontendContextBuilder, connector, checkers,
|
|||
}
|
||||
});
|
||||
}); },
|
||||
sub: function (data, callback) {
|
||||
return subscriber.sub(data, callback);
|
||||
},
|
||||
unsub: function (ids) {
|
||||
return subscriber.unsub(ids);
|
||||
},
|
||||
};
|
||||
var features2 = (0, features_1.initializeStep2)(features1, wrapper, storageSchema, frontendContextBuilder, checkers2, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, function () { return '请查看数据库中的数据'; }, function (url, headers) { return connector.makeBridgeUrl(url, headers); }, selectFreeEntities, createFreeEntities, updateFreeEntities, cacheSavedEntities, cacheKeepFreshPeriod);
|
||||
var features2 = (0, features_1.initializeStep2)(features1, wrapper, storageSchema, frontendContextBuilder, checkers2, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, colorDict, function () { return '请查看数据库中的数据'; }, function () { return connector.getSubscribePoint(); }, function (url, headers) { return connector.makeBridgeUrl(url, headers); }, selectFreeEntities, createFreeEntities, updateFreeEntities, cacheSavedEntities, cacheKeepFreshPeriod);
|
||||
var features = Object.assign(features1, features2);
|
||||
return {
|
||||
features: features,
|
||||
|
|
|
|||
|
|
@ -144,16 +144,16 @@ var oakBehavior = Behavior({
|
|||
});
|
||||
});
|
||||
},
|
||||
sub: function (type, callback) {
|
||||
subEvent: function (type, callback) {
|
||||
this.features.eventBus.sub(type, callback);
|
||||
},
|
||||
unsub: function (type, callback) {
|
||||
unsubEvent: function (type, callback) {
|
||||
this.features.eventBus.unsub(type, callback);
|
||||
},
|
||||
pub: function (type, option) {
|
||||
pubEvent: function (type, option) {
|
||||
this.features.eventBus.pub(type, option);
|
||||
},
|
||||
unsubAll: function (type) {
|
||||
unsubAllEvents: function (type) {
|
||||
this.features.eventBus.unsubAll(type);
|
||||
},
|
||||
save: function (key, item) {
|
||||
|
|
@ -448,6 +448,12 @@ var oakBehavior = Behavior({
|
|||
},
|
||||
loadMissedLocales: function (key) {
|
||||
this.features.locales.loadMissedLocale(key);
|
||||
},
|
||||
subData: function (data, callback) {
|
||||
return this.features.subscriber.sub(data, callback);
|
||||
},
|
||||
unSubData: function (ids) {
|
||||
return this.features.subscriber.unsub(ids);
|
||||
}
|
||||
},
|
||||
observers: {
|
||||
|
|
|
|||
|
|
@ -23,16 +23,16 @@ var OakComponentBase = /** @class */ (function (_super) {
|
|||
return page_common_1.onPathSet.call(this, this.oakOption);
|
||||
};
|
||||
OakComponentBase.prototype.triggerEvent = function (name, detail, options) { };
|
||||
OakComponentBase.prototype.sub = function (type, callback) {
|
||||
OakComponentBase.prototype.subEvent = function (type, callback) {
|
||||
this.features.eventBus.sub(type, callback);
|
||||
};
|
||||
OakComponentBase.prototype.unsub = function (type, callback) {
|
||||
OakComponentBase.prototype.unsubEvent = function (type, callback) {
|
||||
this.features.eventBus.unsub(type, callback);
|
||||
};
|
||||
OakComponentBase.prototype.pub = function (type, options) {
|
||||
OakComponentBase.prototype.pubEvent = function (type, options) {
|
||||
this.features.eventBus.pub(type, options);
|
||||
};
|
||||
OakComponentBase.prototype.unsubAll = function (type) {
|
||||
OakComponentBase.prototype.unsubAllEvents = function (type) {
|
||||
this.features.eventBus.unsubAll(type);
|
||||
};
|
||||
OakComponentBase.prototype.save = function (key, item) {
|
||||
|
|
@ -389,6 +389,12 @@ var OakComponentBase = /** @class */ (function (_super) {
|
|||
this.features.runningTree.setCurrentPage(path2, currentPage);
|
||||
}
|
||||
};
|
||||
OakComponentBase.prototype.subData = function (data, callback) {
|
||||
return this.features.subscriber.sub(data, callback);
|
||||
};
|
||||
OakComponentBase.prototype.unSubData = function (ids) {
|
||||
return this.features.subscriber.unsub(ids);
|
||||
};
|
||||
return OakComponentBase;
|
||||
}(react_1.default.PureComponent));
|
||||
function translateListeners(listeners) {
|
||||
|
|
|
|||
|
|
@ -3,3 +3,6 @@ export declare class OakEnvInitializedFailure extends OakException<any> {
|
|||
error: Error;
|
||||
constructor(err: Error);
|
||||
}
|
||||
export declare class OakSubscriberConnectError extends OakException<any> {
|
||||
constructor(url: string, path?: string);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OakEnvInitializedFailure = void 0;
|
||||
exports.OakSubscriberConnectError = exports.OakEnvInitializedFailure = void 0;
|
||||
var tslib_1 = require("tslib");
|
||||
var types_1 = require("oak-domain/lib/types");
|
||||
var OakEnvInitializedFailure = /** @class */ (function (_super) {
|
||||
|
|
@ -13,3 +13,12 @@ var OakEnvInitializedFailure = /** @class */ (function (_super) {
|
|||
return OakEnvInitializedFailure;
|
||||
}(types_1.OakException));
|
||||
exports.OakEnvInitializedFailure = OakEnvInitializedFailure;
|
||||
;
|
||||
var OakSubscriberConnectError = /** @class */ (function (_super) {
|
||||
tslib_1.__extends(OakSubscriberConnectError, _super);
|
||||
function OakSubscriberConnectError(url, path) {
|
||||
return _super.call(this, "Subscriber\u65E0\u6CD5\u8FDE\u63A5\u4E0Asocket\uFF0C\u8BF7\u8054\u7CFB\u6280\u672F\u4EBA\u5458\u3002url\u300C".concat(url, "\u300D\uFF0Cpath\u300C").concat(path, "\u300D")) || this;
|
||||
}
|
||||
return OakSubscriberConnectError;
|
||||
}(types_1.OakException));
|
||||
exports.OakSubscriberConnectError = OakSubscriberConnectError;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
import { Aspect, EntityDict, CheckerType, AggregationResult } from "oak-domain/lib/types";
|
||||
import { Aspect, EntityDict, CheckerType, AggregationResult, SubDataDef, OpRecord } from "oak-domain/lib/types";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { Feature } from './Feature';
|
||||
|
|
@ -137,10 +137,10 @@ export declare type OakNavigateToParameters<ED extends EntityDict & BaseEntityDi
|
|||
};
|
||||
export declare type OakCommonComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
|
||||
setDisablePulldownRefresh: (able: boolean) => void;
|
||||
sub: (type: string, callback: Function) => void;
|
||||
unsub: (type: string, callback: Function) => void;
|
||||
pub: (type: string, options?: any) => void;
|
||||
unsubAll: (type: string) => void;
|
||||
subEvent: (type: string, callback: Function) => void;
|
||||
unsubEvent: (type: string, callback: Function) => void;
|
||||
pubEvent: (type: string, options?: any) => void;
|
||||
unsubAllEvents: (type: string) => void;
|
||||
save: (key: string, item: any) => void;
|
||||
load: (key: string) => any;
|
||||
clear: () => void;
|
||||
|
|
@ -174,6 +174,8 @@ export declare type OakCommonComponentMethods<ED extends EntityDict & BaseEntity
|
|||
}[] | undefined;
|
||||
refresh: () => Promise<void>;
|
||||
aggregate: (aggregation: ED[T]['Aggregation']) => Promise<AggregationResult<ED[T]['Schema']>>;
|
||||
subData: (data: SubDataDef<ED, keyof ED>[], callback?: (records: OpRecord<ED>[], ids: string[]) => void) => Promise<void>;
|
||||
unSubData: (ids: string[]) => Promise<void>;
|
||||
};
|
||||
export declare type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
|
||||
setId: (id: string) => void;
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import { io } from "socket.io-client";
|
||||
import { io, Socket } from "socket.io-client";
|
||||
export default io;
|
||||
export { Socket, };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Socket = void 0;
|
||||
var socket_io_client_1 = require("socket.io-client");
|
||||
Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_io_client_1.Socket; } });
|
||||
exports.default = socket_io_client_1.io;
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import { io } from "socket.io-client";
|
||||
import { io, Socket } from "socket.io-client";
|
||||
export default io;
|
||||
export { Socket, };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Socket = void 0;
|
||||
var socket_io_client_1 = require("socket.io-client");
|
||||
Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_io_client_1.Socket; } });
|
||||
exports.default = socket_io_client_1.io;
|
||||
|
|
|
|||
|
|
@ -682,15 +682,4 @@ export class Cache<
|
|||
buildContext() {
|
||||
return this.contextBuilder!();
|
||||
}
|
||||
|
||||
sub(data: Array<SubDataDef<ED, keyof ED>>, callback: (records: OpRecord<ED>[], ids: string[]) => void) {
|
||||
return this.aspectWrapper.sub(data, (records, ids) => {
|
||||
this.sync(records),
|
||||
callback(records, ids);
|
||||
});
|
||||
}
|
||||
|
||||
unsub(ids: string[]) {
|
||||
return this.aspectWrapper.unsub(ids);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,30 +18,38 @@ import { Navigator } from './navigator';
|
|||
import { Port } from './port';
|
||||
import { RelationAuth } from './relationAuth';
|
||||
import { Style } from './style';
|
||||
import { SubScriber } from './subscriber';
|
||||
import { ContextMenuFactory } from './contextMenuFactory';
|
||||
import { Geo } from './geo';
|
||||
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
|
||||
export function initializeStep2<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(
|
||||
features: Pick<BasicFeatures<ED, Cxt, FrontCxt, AD>, 'localStorage' | 'environment'>,
|
||||
aspectWrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>,
|
||||
storageSchema: StorageSchema<ED>,
|
||||
frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt,
|
||||
checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>,
|
||||
actionCascadePathGraph: AuthCascadePath<ED>[],
|
||||
relationCascadePathGraph: AuthCascadePath<ED>[],
|
||||
authDeduceRelationMap: AuthDeduceRelationMap<ED>,
|
||||
colorDict: ColorDict<ED>,
|
||||
getFullDataFn: () => any,
|
||||
makeBridgeUrlFn?: (url: string, headers?: Record<string, string>) => string,
|
||||
selectFreeEntities?: (keyof ED)[],
|
||||
createFreeEntities?: (keyof ED)[],
|
||||
updateFreeEntities?: (keyof ED)[],
|
||||
savedEntities?: (keyof ED)[],
|
||||
keepFreshPeriod?: number) {
|
||||
export function initializeStep2<
|
||||
ED extends EntityDict & BaseEntityDict,
|
||||
Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>,
|
||||
AD extends Record<string, Aspect<ED, Cxt>>>(
|
||||
features: Pick<BasicFeatures<ED, Cxt, FrontCxt, AD>, 'localStorage' | 'environment'>,
|
||||
aspectWrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>,
|
||||
storageSchema: StorageSchema<ED>,
|
||||
frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt,
|
||||
checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>,
|
||||
actionCascadePathGraph: AuthCascadePath<ED>[],
|
||||
relationCascadePathGraph: AuthCascadePath<ED>[],
|
||||
authDeduceRelationMap: AuthDeduceRelationMap<ED>,
|
||||
colorDict: ColorDict<ED>,
|
||||
getFullDataFn: () => any,
|
||||
getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>,
|
||||
makeBridgeUrlFn?: (url: string, headers?: Record<string, string>) => string,
|
||||
selectFreeEntities?: (keyof ED)[],
|
||||
createFreeEntities?: (keyof ED)[],
|
||||
updateFreeEntities?: (keyof ED)[],
|
||||
savedEntities?: (keyof ED)[],
|
||||
keepFreshPeriod?: number) {
|
||||
const { localStorage, environment } = features;
|
||||
const cache = new Cache<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>(storageSchema, aspectWrapper,
|
||||
const cache = new Cache<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>(storageSchema, aspectWrapper,
|
||||
frontendContextBuilder, checkers, getFullDataFn, localStorage, savedEntities, keepFreshPeriod);
|
||||
const relationAuth = new RelationAuth<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>(cache,
|
||||
actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap, selectFreeEntities, createFreeEntities, updateFreeEntities);
|
||||
|
|
@ -51,6 +59,7 @@ export function initializeStep2<ED extends EntityDict & BaseEntityDict, Cxt exte
|
|||
const style = new Style<ED>(colorDict);
|
||||
const locales = new Locales(cache, localStorage, environment, 'zh-CN', makeBridgeUrlFn); // 临时性代码,应由上层传入
|
||||
const contextMenuFactory = new ContextMenuFactory<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>(cache, relationAuth, actionCascadePathGraph);
|
||||
const subscriber = new SubScriber(cache, getSubscribePointFn);
|
||||
return {
|
||||
cache,
|
||||
relationAuth,
|
||||
|
|
@ -60,6 +69,7 @@ export function initializeStep2<ED extends EntityDict & BaseEntityDict, Cxt exte
|
|||
style,
|
||||
geo,
|
||||
contextMenuFactory,
|
||||
subscriber,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -88,20 +98,21 @@ export type BasicFeatures<
|
|||
Cxt extends AsyncContext<ED>,
|
||||
FrontCxt extends SyncContext<ED>,
|
||||
AD extends Record<string, Aspect<ED, Cxt>>
|
||||
> = {
|
||||
cache: Cache<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
location: Location;
|
||||
runningTree: RunningTree<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
locales: Locales<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
eventBus: EventBus;
|
||||
localStorage: LocalStorage;
|
||||
notification: Notification;
|
||||
message: Message;
|
||||
navigator: Navigator;
|
||||
port: Port<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
relationAuth: RelationAuth<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
environment: Environment;
|
||||
style: Style<ED>;
|
||||
geo: Geo<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
contextMenuFactory: ContextMenuFactory<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
};
|
||||
> = {
|
||||
cache: Cache<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
location: Location;
|
||||
runningTree: RunningTree<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
locales: Locales<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
eventBus: EventBus;
|
||||
localStorage: LocalStorage;
|
||||
notification: Notification;
|
||||
message: Message;
|
||||
navigator: Navigator;
|
||||
port: Port<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
relationAuth: RelationAuth<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
environment: Environment;
|
||||
style: Style<ED>;
|
||||
geo: Geo<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
contextMenuFactory: ContextMenuFactory<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
subscriber: SubScriber<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
import assert from "assert";
|
||||
import { EntityDict, Aspect, OpRecord, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
import { pull, omit } from 'oak-domain/lib/utils/lodash';
|
||||
import { Cache } from './cache';
|
||||
import { SyncContext } from "oak-domain/lib/store/SyncRowStore";
|
||||
import io, { Socket } from '../utils/socket.io/socket.io';
|
||||
import { Feature } from "../types/Feature";
|
||||
|
||||
type SubscribeEvent = 'connect' | 'disconnect';
|
||||
|
||||
export class SubScriber<
|
||||
ED extends EntityDict & BaseEntityDict,
|
||||
Cxt extends AsyncContext<ED>,
|
||||
FrontCxt extends SyncContext<ED>,
|
||||
AD extends CommonAspectDict<ED, Cxt> & Record<string, Aspect<ED, Cxt>>
|
||||
> extends Feature {
|
||||
|
||||
private eventCallbackMap: Record<SubscribeEvent, Array<() => void>> = {
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
};
|
||||
|
||||
constructor(cache: Cache<ED, Cxt, FrontCxt, AD>, getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>) {
|
||||
super();
|
||||
}
|
||||
|
||||
on(event: SubscribeEvent, callback: () => void) {
|
||||
this.eventCallbackMap[event].push(callback);
|
||||
}
|
||||
|
||||
off(event: SubscribeEvent, callback: () => void) {
|
||||
pull(this.eventCallbackMap[event], callback);
|
||||
}
|
||||
|
||||
async sub(data: SubDataDef<ED, keyof ED>[], callback: (records: OpRecord<ED>[], ids: string[]) => void) {
|
||||
console.log('data subscribe 在dev模式下不起作用');
|
||||
}
|
||||
|
||||
async unsub(ids: string[]) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
import assert from "assert";
|
||||
import { EntityDict, Aspect, OpRecord, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
import { pull, omit } from 'oak-domain/lib/utils/lodash';
|
||||
import { Cache } from './cache';
|
||||
import { SyncContext } from "oak-domain/lib/store/SyncRowStore";
|
||||
import io, { Socket } from '../utils/socket.io/socket.io';
|
||||
import { Feature } from "../types/Feature";
|
||||
|
||||
type SubscribeEvent = 'connect' | 'disconnect';
|
||||
|
||||
export class SubScriber<
|
||||
ED extends EntityDict & BaseEntityDict,
|
||||
Cxt extends AsyncContext<ED>,
|
||||
FrontCxt extends SyncContext<ED>,
|
||||
AD extends CommonAspectDict<ED, Cxt> & Record<string, Aspect<ED, Cxt>>
|
||||
> extends Feature {
|
||||
private cache: Cache<ED, Cxt, FrontCxt, AD>;
|
||||
private getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>;
|
||||
private callbackMap: Record<string, (records: OpRecord<ED>[], ids: string[]) => void> = {};
|
||||
private socket?: Socket;
|
||||
private socketState: 'connecting' | 'connected' | 'unconnected' = 'unconnected';
|
||||
|
||||
private eventCallbackMap: Record<SubscribeEvent, Array<() => void>> = {
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
};
|
||||
|
||||
constructor(cache: Cache<ED, Cxt, FrontCxt, AD>, getSubscribePointFn: () => Promise<{
|
||||
url: string;
|
||||
path: string;
|
||||
}>) {
|
||||
super();
|
||||
this.cache = cache;
|
||||
this.getSubscribePointFn = getSubscribePointFn;
|
||||
}
|
||||
|
||||
on(event: SubscribeEvent, callback: () => void) {
|
||||
this.eventCallbackMap[event].push(callback);
|
||||
}
|
||||
|
||||
off(event: SubscribeEvent, callback: () => void) {
|
||||
pull(this.eventCallbackMap[event], callback);
|
||||
}
|
||||
|
||||
private emit(event: SubscribeEvent) {
|
||||
this.eventCallbackMap[event].forEach(
|
||||
ele => ele()
|
||||
);
|
||||
}
|
||||
|
||||
private async initSocketOption() {
|
||||
const { url, path } = await this.getSubscribePointFn();
|
||||
|
||||
const socket = io(url, {
|
||||
path,
|
||||
});
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
private async login() {
|
||||
|
||||
}
|
||||
|
||||
private async connect() {
|
||||
let optionInited = false;
|
||||
if (!this.socket) {
|
||||
await this.initSocketOption();
|
||||
optionInited = true;
|
||||
}
|
||||
|
||||
const socket = this.socket!;
|
||||
return new Promise(
|
||||
(resolve, reject) => {
|
||||
/**
|
||||
* https://socket.io/zh-CN/docs/v4/client-socket-instance/
|
||||
*/
|
||||
socket.on('connect', async () => {
|
||||
// 验证身份
|
||||
this.socketState = 'connected';
|
||||
this.emit('connect');
|
||||
socket.off('connect');
|
||||
socket.on('disconnect', () => {
|
||||
this.socketState = 'unconnected';
|
||||
this.emit('disconnect');
|
||||
socket.removeAllListeners();
|
||||
|
||||
if (Object.keys(this.callbackMap).length > 0) {
|
||||
this.connect();
|
||||
}
|
||||
});
|
||||
await this.login();
|
||||
resolve(undefined);
|
||||
});
|
||||
|
||||
if (!optionInited) {
|
||||
let count = 0;
|
||||
socket.on('connect_error', async () => {
|
||||
count ++;
|
||||
if (count > 10) {
|
||||
// 可能socket地址改变了,刷新重连
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
this.socket = undefined;
|
||||
await this.connect();
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
socket.connect();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async sub(data: SubDataDef<ED, keyof ED>[], callback?: (records: OpRecord<ED>[], ids: string[]) => void) {
|
||||
const ids = data.map(ele => ele.id);
|
||||
|
||||
if (callback) {
|
||||
ids.forEach(
|
||||
(id) => {
|
||||
assert(!this.callbackMap[id], `[subscriber]注册回调的id${id}发生重复`);
|
||||
this.callbackMap[id] = callback;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (this.socketState === 'unconnected') {
|
||||
this.connect();
|
||||
}
|
||||
else if (this.socketState === 'connected') {
|
||||
this.socket?.emit('sub', data);
|
||||
}
|
||||
}
|
||||
|
||||
async unsub(ids: string[]) {
|
||||
ids.forEach(
|
||||
(id) => omit(this.callbackMap, id)
|
||||
);
|
||||
|
||||
if (this.socketState === 'connected') {
|
||||
this.socket!.emit('unsub', ids);
|
||||
}
|
||||
|
||||
if (this.socketState !== 'unconnected') {
|
||||
if (Object.keys(this.callbackMap).length === 0) {
|
||||
this.socket!.disconnect();
|
||||
this.socket!.removeAllListeners();
|
||||
this.socketState = 'unconnected';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -114,18 +114,6 @@ export function initialize<
|
|||
message: contextBackend.getMessage(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* dev模式下订阅数据没有意义(单用户模式)
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
sub: function (data: SubDataDef<ED, keyof ED>[], callback: (records: OpRecord<ED>[], ids: string[]) => void): Promise<void> {
|
||||
return Promise.resolve();
|
||||
},
|
||||
unsub: function (ids: string[]): Promise<void> {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
const features2 = initBasicFeaturesStep2<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>(
|
||||
|
|
@ -139,6 +127,7 @@ export function initialize<
|
|||
authDeduceRelationMap,
|
||||
colorDict,
|
||||
() => debugStore.getCurrentData(),
|
||||
async () => ({ url: '', path: '' }),
|
||||
undefined,
|
||||
selectFreeEntities,
|
||||
createFreeEntities,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
|||
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
|
||||
import { InitializeOptions } from './types/Initialize';
|
||||
|
||||
import SubScriber from './utils/subscriber';
|
||||
/**
|
||||
* @param storageSchema
|
||||
* @param createFeatures
|
||||
|
|
@ -38,7 +37,7 @@ export function initialize<
|
|||
>(
|
||||
storageSchema: StorageSchema<ED>,
|
||||
frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt,
|
||||
connector: Connector<ED, Cxt, FrontCxt>,
|
||||
connector: Connector<ED, FrontCxt>,
|
||||
checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>,
|
||||
option: InitializeOptions<ED>
|
||||
) {
|
||||
|
|
@ -51,7 +50,6 @@ export function initialize<
|
|||
|
||||
const features1 = initBasicFeaturesStep1();
|
||||
|
||||
const subscriber = new SubScriber<ED>(connector.getSubscribeRouter());
|
||||
const wrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> = {
|
||||
exec: async (name, params) => {
|
||||
const context = features2.cache.buildContext();
|
||||
|
|
@ -62,12 +60,6 @@ export function initialize<
|
|||
message,
|
||||
};
|
||||
},
|
||||
sub: function (data: SubDataDef<ED, keyof ED>[], callback: (records: OpRecord<ED>[], ids: string[]) => void): Promise<void> {
|
||||
return subscriber.sub(data, callback);
|
||||
},
|
||||
unsub: function (ids: string[]): Promise<void> {
|
||||
return subscriber.unsub(ids);
|
||||
},
|
||||
};
|
||||
|
||||
const features2 = initBasicFeaturesStep2<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt> & AD>(
|
||||
|
|
@ -81,6 +73,7 @@ export function initialize<
|
|||
authDeduceRelationMap,
|
||||
colorDict,
|
||||
() => '请查看数据库中的数据',
|
||||
() => connector.getSubscribePoint(),
|
||||
(url, headers) => connector.makeBridgeUrl(url, headers),
|
||||
selectFreeEntities,
|
||||
createFreeEntities,
|
||||
|
|
|
|||
|
|
@ -227,19 +227,19 @@ const oakBehavior = Behavior<
|
|||
}
|
||||
},
|
||||
|
||||
sub(type: string, callback: Function) {
|
||||
subEvent(type: string, callback: Function) {
|
||||
this.features.eventBus.sub(type, callback);
|
||||
},
|
||||
|
||||
unsub(type: string, callback: Function) {
|
||||
unsubEvent(type: string, callback: Function) {
|
||||
this.features.eventBus.unsub(type, callback);
|
||||
},
|
||||
|
||||
pub(type: string, option?: any) {
|
||||
pubEvent(type: string, option?: any) {
|
||||
this.features.eventBus.pub(type, option);
|
||||
},
|
||||
|
||||
unsubAll(type: string) {
|
||||
unsubAllEvents(type: string) {
|
||||
this.features.eventBus.unsubAll(type);
|
||||
},
|
||||
|
||||
|
|
@ -652,6 +652,14 @@ const oakBehavior = Behavior<
|
|||
|
||||
loadMissedLocales(key: string) {
|
||||
this.features.locales.loadMissedLocale(key);
|
||||
},
|
||||
|
||||
subData(data, callback) {
|
||||
return this.features.subscriber.sub(data, callback);
|
||||
},
|
||||
|
||||
unSubData(ids) {
|
||||
return this.features.subscriber.unsub(ids);
|
||||
}
|
||||
},
|
||||
observers: {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import React from 'react';
|
|||
import { withRouter, PullToRefresh } from './platforms/web';
|
||||
import { get } from 'oak-domain/lib/utils/lodash';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { Action, Aspect, CheckerType, EntityDict } from 'oak-domain/lib/types';
|
||||
import { Action, Aspect, CheckerType, EntityDict, OpRecord, SubDataDef } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { BasicFeatures } from './features';
|
||||
import { NamedFilterItem, NamedSorterItem } from './types/NamedCondition';
|
||||
|
|
@ -79,19 +79,19 @@ abstract class OakComponentBase<
|
|||
options?: WechatMiniprogram.Component.TriggerEventOption
|
||||
) { }
|
||||
|
||||
sub(type: string, callback: Function) {
|
||||
subEvent(type: string, callback: Function) {
|
||||
this.features.eventBus.sub(type, callback);
|
||||
}
|
||||
|
||||
unsub(type: string, callback: Function) {
|
||||
unsubEvent(type: string, callback: Function) {
|
||||
this.features.eventBus.unsub(type, callback);
|
||||
}
|
||||
|
||||
pub(type: string, options?: any) {
|
||||
pubEvent(type: string, options?: any) {
|
||||
this.features.eventBus.pub(type, options);
|
||||
}
|
||||
|
||||
unsubAll(type: string) {
|
||||
unsubAllEvents(type: string) {
|
||||
this.features.eventBus.unsubAll(type);
|
||||
}
|
||||
|
||||
|
|
@ -636,6 +636,14 @@ abstract class OakComponentBase<
|
|||
this.features.runningTree.setCurrentPage(path2, currentPage);
|
||||
}
|
||||
}
|
||||
|
||||
subData(data: SubDataDef<ED, keyof ED>[], callback?: (records: OpRecord<ED>[], ids: string[]) => void) {
|
||||
return this.features.subscriber.sub(data, callback);
|
||||
}
|
||||
|
||||
unSubData(ids: string[]) {
|
||||
return this.features.subscriber.unsub(ids);
|
||||
}
|
||||
}
|
||||
|
||||
function translateListeners(listeners?: Record<string, (prev: Record<string, any>, next: Record<string, any>) => void>): { fn: React.Component['componentDidUpdate'] } & ThisType<React.Component> {
|
||||
|
|
|
|||
|
|
@ -6,4 +6,10 @@ export class OakEnvInitializedFailure extends OakException<any> {
|
|||
super('环境初始化失败,请检查授权情况');
|
||||
this.error = err;
|
||||
}
|
||||
};
|
||||
|
||||
export class OakSubscriberConnectError extends OakException<any> {
|
||||
constructor(url: string, path?: string) {
|
||||
super(`Subscriber无法连接上socket,请联系技术人员。url「${url}」,path「${path}」`);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Aspect, EntityDict, CheckerType, AggregationResult } from "oak-domain/lib/types";
|
||||
import { Aspect, EntityDict, CheckerType, AggregationResult, SubDataDef, OpRecord } from "oak-domain/lib/types";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { Feature } from './Feature';
|
||||
|
|
@ -327,10 +327,11 @@ export type OakCommonComponentMethods<
|
|||
T extends keyof ED
|
||||
> = {
|
||||
setDisablePulldownRefresh: (able: boolean) => void;
|
||||
sub: (type: string, callback: Function) => void;
|
||||
unsub: (type: string, callback: Function) => void;
|
||||
pub: (type: string, options?: any) => void;
|
||||
unsubAll: (type: string) => void;
|
||||
subEvent: (type: string, callback: Function) => void;
|
||||
unsubEvent: (type: string, callback: Function) => void;
|
||||
pubEvent: (type: string, options?: any) => void;
|
||||
unsubAllEvents: (type: string) => void;
|
||||
|
||||
save: (key: string, item: any) => void;
|
||||
load: (key: string) => any;
|
||||
clear: () => void;
|
||||
|
|
@ -394,6 +395,8 @@ export type OakCommonComponentMethods<
|
|||
aggregate: (
|
||||
aggregation: ED[T]['Aggregation']
|
||||
) => Promise<AggregationResult<ED[T]['Schema']>>;
|
||||
subData: (data: SubDataDef<ED, keyof ED>[], callback?: (records: OpRecord<ED>[], ids: string[]) => void) => Promise<void>;
|
||||
unSubData: (ids: string[]) => Promise<void>;
|
||||
};
|
||||
|
||||
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
import { io } from "socket.io-client";
|
||||
export default io;
|
||||
import { io, Socket } from "socket.io-client";
|
||||
export default io;
|
||||
export {
|
||||
Socket,
|
||||
};
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
import { io } from "socket.io-client";
|
||||
export default io;
|
||||
import { io, Socket } from "socket.io-client";
|
||||
export default io;
|
||||
export {
|
||||
Socket,
|
||||
};
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import {
|
||||
Aspect,
|
||||
AspectWrapper,
|
||||
Checker,
|
||||
StorageSchema,
|
||||
Connector,
|
||||
EntityDict,
|
||||
SubDataDef,
|
||||
OpRecord,
|
||||
} from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
|
||||
export default class SubScriber<ED extends BaseEntityDict & EntityDict>{
|
||||
private getSubscribePointUrl: string;
|
||||
constructor(getSubscribePointUrl: string) {
|
||||
this.getSubscribePointUrl = getSubscribePointUrl;
|
||||
}
|
||||
|
||||
async sub(data: SubDataDef<ED, keyof ED>[], callback: (records: OpRecord<ED>[], ids: string[]) => void) {
|
||||
}
|
||||
|
||||
async unsub(ids: string[]) {
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue