@v4fire/core
Version:
V4Fire core library
395 lines (394 loc) • 13.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
var _exportNames = {
$$: true
};
exports.default = exports.$$ = void 0;
var _eventemitter = require("eventemitter2");
var _symbol = _interopRequireDefault(require("../../../core/symbol"));
var _proxyReadonly = require("../../../core/object/proxy-readonly");
var _implementation = require("../../../core/functools/implementation");
var _functools = require("../../../core/functools");
var _url = require("../../../core/url");
var _async = _interopRequireDefault(require("../../../core/async"));
var _socket = _interopRequireDefault(require("../../../core/socket"));
var _request = require("../../../core/request");
var _const = require("../../../core/data/const");
var _params = _interopRequireWildcard(require("../../../core/data/modules/params"));
Object.keys(_params).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _params[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _params[key];
}
});
});
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const $$ = (0, _symbol.default)();
exports.$$ = $$;
class Provider extends _params.default {
get providerName() {
return this.constructor[_const.namespace];
}
get event() {
(0, _functools.deprecate)({
name: 'event',
type: 'accessor',
renamedTo: 'emitter'
});
return this.emitter;
}
constructor(opts = {}) {
super();
const id = this.getCacheKey(opts),
cacheVal = _const.instanceCache[id];
if (cacheVal != null) {
return cacheVal;
}
_const.instanceCache[id] = this;
_const.requestCache[id] = Object.createDict();
this.cacheId = id;
this.params = opts;
this.async = new _async.default(this);
this.emitter = new _eventemitter.EventEmitter2({
maxListeners: 1e3,
newListener: false
});
if (opts.socket || this.socketURL != null) {
this.connect().then(this.initSocketBehaviour.bind(this), stderr);
}
}
getCacheKey(paramsForCache = {}) {
return `${this.providerName}:${Object.fastHash(paramsForCache)}`;
}
getAuthParams(params) {
return Promise.resolve({});
}
resolver(url, params) {
return undefined;
}
async connect(opts) {
await this.async.wait(() => this.socketURL);
const {
socketURL: url
} = this,
key = Object.fastHash(opts);
if (_const.connectCache[key] == null) {
_const.connectCache[key] = new Promise((resolve, reject) => {
const socket = (0, _socket.default)(url);
if (!socket) {
return;
}
function onClear(err) {
reject(err);
delete _const.connectCache[key];
}
const asyncParams = {
group: 'connection',
label: $$.connect,
join: true,
onClear
};
this.async.worker(socket, asyncParams);
this.async.once(socket, 'connect', () => resolve(socket), asyncParams);
});
}
return _const.connectCache[key];
}
name(value) {
if (value == null) {
return this.eventName;
}
const obj = Object.create(this);
obj.eventName = value;
return obj;
}
method(value) {
if (value == null) {
return this.customMethod;
}
const obj = Object.create(this);
obj.customMethod = value;
return obj;
}
base(value) {
if (value == null) {
return this.baseURL;
}
const obj = Object.create(this);
obj.baseURL = value;
obj.baseGetURL = undefined;
obj.basePeekURL = undefined;
obj.baseAddURL = undefined;
obj.baseUpdURL = undefined;
obj.baseDelURL = undefined;
return obj;
}
url(value) {
if (value == null) {
return (0, _url.concatURLs)(this.baseURL, this.advURL);
}
const obj = Object.create(this);
obj.advURL = value;
return obj;
}
dropCache() {
const cache = _const.requestCache[this.cacheId];
if (cache) {
for (let keys = Object.keys(cache), i = 0; i < keys.length; i++) {
const obj = cache[keys[i]];
if (obj) {
obj.dropCache();
}
}
}
_const.requestCache[this.cacheId] = Object.createDict();
this.emitter.emit('dropCache');
}
get(query, opts) {
const url = this.resolveURL(this.baseGetURL),
alias = this.alias ?? this.providerName;
const eventName = this.name(),
method = this.method() ?? this.getMethod;
const mergedOpts = this.getRequestOptions('get', {
...opts,
[_const.queryMethods[method] != null ? 'query' : 'body']: query,
method
});
const req = this.request(url, this.resolver.bind(this), mergedOpts),
res = eventName != null ? this.updateRequest(url, eventName, req) : this.updateRequest(url, req);
const extraProviders = Object.isFunction(this.extraProviders) ? this.extraProviders({
opts: Object.cast(mergedOpts),
globalOpts: _request.globalOpts
}) : this.extraProviders;
if (extraProviders) {
const composition = {},
tasks = [],
cloneTasks = [];
for (let keys = Object.keys(extraProviders), i = 0; i < keys.length; i++) {
const key = keys[i],
el = extraProviders[key] ?? {};
const ProviderLink = el.provider ?? key,
alias = el.alias ?? key;
let ProviderConstructor, providerInstance;
if (Object.isString(ProviderLink)) {
ProviderConstructor = _const.providers[ProviderLink];
if (ProviderConstructor == null) {
throw new Error(`Provider "${ProviderLink}" is not defined`);
}
providerInstance = new ProviderConstructor(el.providerOptions);
} else if (Object.isSimpleFunction(ProviderLink)) {
providerInstance = new ProviderLink(el.providerOptions);
} else {
providerInstance = ProviderLink;
}
const req = providerInstance.get(el.query ?? query, el.request);
tasks.push(req.then(async res => {
const data = await res.data;
Object.set(composition, alias, data);
cloneTasks.push(composition => Object.set(composition, alias, data?.valueOf()));
return res;
}));
}
const compositionRes = res.then(res => Promise.all(tasks).then(async () => {
const data = await res.data;
Object.set(composition, alias, data);
cloneTasks.push(composition => Object.set(composition, alias, data?.valueOf()));
Object.defineProperty(composition, 'valueOf', {
writable: true,
configurable: true,
value: () => {
const clone = {};
for (let i = 0; i < cloneTasks.length; i++) {
cloneTasks[i](clone);
}
return clone;
}
});
res.data = Promise.resolve((0, _proxyReadonly.readonly)(composition));
return res;
}), null, () => {
for (let i = 0; i < tasks.length; i++) {
tasks[i].abort();
}
});
compositionRes['emitter'] = new _eventemitter.EventEmitter2();
void Object.defineProperty(compositionRes, 'data', {
configurable: true,
enumerable: true,
get: () => compositionRes.then(res => res.data)
});
const unimplementedStream = _implementation.unimplement.bind(null, {
name: 'Symbol.asyncIterator',
type: 'property',
notice: "Requests with extra providers can't be streamed"
});
void Object.defineProperty(compositionRes, 'stream', {
configurable: true,
enumerable: true,
get: unimplementedStream
});
compositionRes[Symbol.asyncIterator] = unimplementedStream;
return Object.cast(compositionRes);
}
return res;
}
peek(query, opts) {
const url = this.resolveURL(this.basePeekURL),
eventName = this.name(),
method = this.method() ?? this.peekMethod;
const req = this.request(url, this.resolver.bind(this), this.getRequestOptions('peek', {
...opts,
[_const.queryMethods[method] != null ? 'query' : 'body']: query,
method
}));
if (eventName != null) {
return this.updateRequest(url, eventName, req);
}
return this.updateRequest(url, req);
}
post(body, opts) {
const url = this.resolveURL(),
eventName = this.name(),
method = this.method() ?? 'POST';
const req = this.request(url, this.resolver.bind(this), this.getRequestOptions(eventName ?? 'post', {
...opts,
body,
method
}));
if (eventName != null) {
return this.updateRequest(url, eventName, req);
}
return this.updateRequest(url, req);
}
add(body, opts) {
const url = this.resolveURL(this.baseAddURL),
eventName = this.name() ?? 'add',
method = this.method() ?? this.addMethod;
const req = this.request(url, this.resolver.bind(this), this.getRequestOptions('add', {
...opts,
body,
method
}));
return this.updateRequest(url, eventName, req);
}
update(body, opts) {
return this.upd(body, opts);
}
upd(body, opts) {
const url = this.resolveURL(this.baseUpdURL),
eventName = this.name() ?? 'upd',
method = this.method() ?? this.updMethod;
const req = this.request(url, this.resolver.bind(this), this.getRequestOptions('upd', {
...opts,
body,
method
}));
return this.updateRequest(url, eventName, req);
}
delete(body, opts) {
return this.del(body, opts);
}
del(body, opts) {
const url = this.resolveURL(this.baseDelURL),
eventName = this.name() ?? 'del',
method = this.method() ?? this.delMethod;
const req = this.request(url, this.resolver.bind(this), this.getRequestOptions('del', {
...opts,
body,
method
}));
return this.updateRequest(url, eventName, req);
}
resolveURL(baseURL, advURL) {
return (0, _url.concatURLs)(baseURL == null ? this.baseURL : baseURL, advURL == null ? this.advURL : advURL);
}
setReadonlyParam(key, val) {
Object.defineProperty(this, key, {
configurable: true,
get: () => val,
set: () => {}
});
}
getEventKey(event, data) {
if (Object.isArray(data) || Object.isDictionary(data)) {
return `${event}::${Object.fastHash(data)}`;
}
return {};
}
getRequestOptions(method, params) {
const {
middlewares,
encoders,
decoders
} = this.constructor;
const merge = (a, b) => {
a = Object.isFunction(a) ? [a] : a;
b = Object.isFunction(b) ? [b] : b;
return {
...a,
...b
};
};
const mappedMiddlewares = merge(middlewares, params?.middlewares);
for (let keys = Object.keys(mappedMiddlewares), i = 0; i < keys.length; i++) {
const key = keys[i];
mappedMiddlewares[key] = mappedMiddlewares[key].bind(this);
}
return {
...params,
cacheId: this.cacheId,
middlewares: mappedMiddlewares,
encoder: merge(encoders[method] ?? encoders['def'], params?.encoder),
decoder: merge(decoders[method] ?? decoders['def'], params?.decoder),
meta: {
provider: this,
providerMethod: method,
providerParams: params
}
};
}
updateRequest(url, eventOrFactory, factory) {
let event;
if (Object.isFunction(eventOrFactory)) {
factory = eventOrFactory;
} else {
event = eventOrFactory;
}
if (factory == null) {
throw new ReferenceError('A factory function to create the requests is not specified');
}
const req = factory();
req.then(res => {
try {
const cache = _const.requestCache[this.cacheId];
const {
ctx: {
canCache,
cacheKey
}
} = res;
if (canCache && cacheKey != null && cache != null) {
cache[cacheKey] = Object.cast(res);
}
} catch (err) {
stderr(err);
}
if (event != null) {
this.emitter.emit(event, () => res.data);
}
}).catch(() => {});
return req;
}
initSocketBehaviour() {
return Promise.resolve();
}
}
exports.default = Provider;