loopback-connector-remote/lib/remote-connector.js

159 lines
4.2 KiB
JavaScript
Raw Normal View History

2018-01-16 14:55:09 +00:00
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
2016-05-06 19:02:21 +00:00
// Node module: loopback-connector-remote
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
2016-09-01 09:54:34 +00:00
'use strict';
2014-09-25 21:06:06 +00:00
/**
* Dependencies.
*/
const assert = require('assert');
const remoting = require('strong-remoting');
const utils = require('loopback-datasource-juggler/lib/utils');
const jutil = require('loopback-datasource-juggler/lib/jutil');
const RelationMixin = require('./relations');
const InclusionMixin = require('loopback-datasource-juggler/lib/include');
2014-09-25 21:06:06 +00:00
const findMethodNames = ['findById', 'findOne'];
2014-09-25 21:06:06 +00:00
/**
* Export the RemoteConnector class.
*/
module.exports = RemoteConnector;
/**
* Create an instance of the connector with the given `settings`.
*/
function RemoteConnector(settings) {
2014-09-25 21:19:39 +00:00
assert(typeof settings ===
'object',
'cannot initialize RemoteConnector without a settings object');
2014-09-25 21:06:06 +00:00
this.client = settings.client;
this.adapter = settings.adapter || 'rest';
2016-01-07 06:45:29 +00:00
this.protocol = settings.protocol || 'http';
2014-09-25 21:06:06 +00:00
this.root = settings.root || '';
this.host = settings.host || 'localhost';
this.port = settings.port || 3000;
this.remotes = remoting.create(settings.options);
2014-09-25 21:06:06 +00:00
this.name = 'remote-connector';
2014-09-25 21:19:39 +00:00
if (settings.url) {
2014-09-25 21:06:06 +00:00
this.url = settings.url;
} else {
this.url = this.protocol + '://' + this.host + ':' + this.port + this.root;
}
// handle mixins in the define() method
const DAO = this.DataAccessObject = function() {
2014-09-25 21:19:39 +00:00
};
2014-09-25 21:06:06 +00:00
}
RemoteConnector.prototype.connect = function() {
this.remotes.connect(this.url, this.adapter);
};
2014-09-25 21:06:06 +00:00
RemoteConnector.initialize = function(dataSource, callback) {
const connector = dataSource.connector =
2014-09-25 21:19:39 +00:00
new RemoteConnector(dataSource.settings);
2014-09-25 21:06:06 +00:00
connector.connect();
process.nextTick(callback);
};
2014-09-25 21:06:06 +00:00
RemoteConnector.prototype.define = function(definition) {
const Model = definition.model;
const remotes = this.remotes;
2014-09-25 21:06:06 +00:00
2014-09-25 21:19:39 +00:00
assert(Model.sharedClass,
'cannot attach ' +
2014-09-25 21:19:39 +00:00
Model.modelName +
' to a remote connector without a Model.sharedClass');
2014-09-25 21:06:06 +00:00
jutil.mixin(Model, RelationMixin);
2014-12-19 22:30:56 +00:00
jutil.mixin(Model, InclusionMixin);
2014-09-25 21:06:06 +00:00
remotes.addClass(Model.sharedClass);
2014-10-01 21:36:08 +00:00
this.resolve(Model);
this.setupRemotingTypeFor(Model);
};
RemoteConnector.prototype.resolve = function(Model) {
const remotes = this.remotes;
2014-09-25 21:06:06 +00:00
2014-09-25 21:19:39 +00:00
Model.sharedClass.methods().forEach(function(remoteMethod) {
if (remoteMethod.name !== 'Change' && remoteMethod.name !== 'Checkpoint') {
createProxyMethod(Model, remotes, remoteMethod);
}
});
};
RemoteConnector.prototype.setupRemotingTypeFor = function(Model) {
const remotes = this.remotes;
// setup a remoting type converter for this model
remotes.defineObjectType(Model.modelName, function(data) {
const model = new Model(data);
// process cached relations
if (model.__cachedRelations) {
for (const relation in model.__cachedRelations) {
const relatedModel = model.__cachedRelations[relation];
model.__data[relation] = relatedModel;
}
}
return model;
});
};
2014-09-25 21:06:06 +00:00
function createProxyMethod(Model, remotes, remoteMethod) {
const scope = remoteMethod.isStatic ? Model : Model.prototype;
const original = scope[remoteMethod.name];
2014-09-25 21:19:39 +00:00
2015-03-27 00:14:35 +00:00
function remoteMethodProxy() {
const args = Array.prototype.slice.call(arguments);
const lastArgIsFunc = typeof args[args.length - 1] === 'function';
let callback;
2014-09-25 21:19:39 +00:00
if (lastArgIsFunc) {
2014-09-25 21:06:06 +00:00
callback = args.pop();
2016-04-24 22:07:15 +00:00
} else {
callback = utils.createPromiseCallback();
2014-09-25 21:06:06 +00:00
}
const callbackPromise = callback.promise;
if (findMethodNames.includes(remoteMethod.name)) {
callback = proxy404toNull(callback);
}
2014-09-25 21:06:06 +00:00
if (remoteMethod.isStatic) {
2016-04-24 22:07:15 +00:00
remotes.invoke(remoteMethod.stringName, args, callback);
2016-04-24 22:11:05 +00:00
} else {
const ctorArgs = [this.id];
2016-04-24 22:11:05 +00:00
remotes.invoke(remoteMethod.stringName, ctorArgs, args, callback);
}
return callbackPromise;
}
function proxy404toNull(cb) {
return function(err, data) {
if (err && err.code === 'MODEL_NOT_FOUND') {
cb(null, null);
return;
}
cb(err, data);
};
2014-09-25 21:06:06 +00:00
}
2015-03-27 00:14:35 +00:00
scope[remoteMethod.name] = remoteMethodProxy;
remoteMethod.aliases.forEach(function(alias) {
scope[alias] = remoteMethodProxy;
});
2014-09-25 21:06:06 +00:00
}
2014-09-25 21:19:39 +00:00
function noop() {
}