[BREAKING] Allow possibility of disabling Scalar upstream
This is a breaking change because of the structure change for upstreams. Instead of being an object, it is now a list. Existing configurations are not guaranteed to work. Adds #108 and starts work on #22 (upstream config).
This commit is contained in:
parent
1138dc3c0a
commit
02c981b070
|
@ -22,4 +22,5 @@ demobot:
|
|||
|
||||
# Upstream configuration. This should almost never change.
|
||||
upstreams:
|
||||
vector: "https://scalar.vector.im/api"
|
||||
- name: vector
|
||||
url: "https://scalar.vector.im/api"
|
|
@ -32,7 +32,11 @@ class DimensionApi {
|
|||
var factory = IntegrationImpl.getFactory(integrationConfig);
|
||||
if (!factory) throw new Error("Missing config factory for " + integrationConfig.name);
|
||||
|
||||
try {
|
||||
return factory(this._db, integrationConfig, roomId, scalarToken);
|
||||
} catch (err) {
|
||||
throw new Error("Error using factory for " + integrationConfig.name + ". Please either fix the integration settings or disable the integration.", err);
|
||||
}
|
||||
}
|
||||
|
||||
_getIntegrations(req, res) {
|
||||
|
@ -49,7 +53,9 @@ class DimensionApi {
|
|||
var integrations = _.map(Integrations.all, i => JSON.parse(JSON.stringify(i))); // clone
|
||||
|
||||
var promises = [];
|
||||
var remove = [];
|
||||
_.forEach(integrations, integration => {
|
||||
try {
|
||||
promises.push(this._getIntegration(integration, roomId, scalarToken).then(builtIntegration => {
|
||||
return builtIntegration.getState().then(state => {
|
||||
var keys = _.keys(state);
|
||||
|
@ -62,8 +68,19 @@ class DimensionApi {
|
|||
integration.userId = userId;
|
||||
});
|
||||
}));
|
||||
} catch (err) {
|
||||
remove.push(integration);
|
||||
log.error("DimensionApi", err);
|
||||
}
|
||||
});
|
||||
|
||||
for (var toRemove of remove) {
|
||||
var idx = integrations.indexOf(toRemove);
|
||||
if (idx === -1) continue;
|
||||
log.warn("DimensionApi", "Disabling integration " + toRemove.name +" due to an error encountered in setup");
|
||||
integrations.splice(idx, 1);
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => res.send(_.map(integrations, integration => {
|
||||
// Remove sensitive material
|
||||
integration.upstream = undefined;
|
||||
|
|
|
@ -4,6 +4,7 @@ var ScalarClient = require("./scalar/ScalarClient.js");
|
|||
var _ = require("lodash");
|
||||
var log = require("./util/LogService");
|
||||
var Promise = require("bluebird");
|
||||
var UpstreamConfiguration = require("./UpstreamConfiguration");
|
||||
|
||||
/**
|
||||
* API handler for the Scalar API, as required by Riot
|
||||
|
@ -33,7 +34,11 @@ class ScalarApi {
|
|||
if (!token) res.sendStatus(400);
|
||||
else this._db.checkToken(token).then(() => {
|
||||
res.sendStatus(200);
|
||||
}).catch(() => res.sendStatus(401));
|
||||
}).catch(e => {
|
||||
res.sendStatus(401);
|
||||
log.warn("ScalarApi", "Failed to authenticate token");
|
||||
log.verbose("ScalarApi", e);
|
||||
});
|
||||
}
|
||||
|
||||
_scalarRegister(req, res) {
|
||||
|
@ -51,6 +56,9 @@ class ScalarApi {
|
|||
client.getSelfMxid().then(mxid => {
|
||||
userId = mxid;
|
||||
if (!mxid) throw new Error("Token does not resolve to a matrix user");
|
||||
|
||||
// TODO: Make this part more generic for other upstreams (#22)
|
||||
if (!UpstreamConfiguration.hasUpstream("vector")) return Promise.resolve(null);
|
||||
return ScalarClient.register(tokenInfo);
|
||||
}).then(upstreamToken => {
|
||||
return this._db.createToken(userId, tokenInfo, scalarToken, upstreamToken);
|
||||
|
|
50
src/UpstreamConfiguration.js
Normal file
50
src/UpstreamConfiguration.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
var LogService = require("./util/LogService");
|
||||
var _ = require("lodash");
|
||||
var config = require("config");
|
||||
|
||||
/**
|
||||
* Handles all upstream configuration information, such as URLs, tokens, and whether or not they are enabled.
|
||||
*/
|
||||
class UpstreamConfiguration {
|
||||
/**
|
||||
* Creates a new upstream configuration handler
|
||||
*/
|
||||
constructor() {
|
||||
this._upstreams = {};
|
||||
this._loadUpstreams();
|
||||
}
|
||||
|
||||
_loadUpstreams() {
|
||||
for (var upstream of config.upstreams) {
|
||||
var upstreamConfig = upstream;
|
||||
|
||||
if (this._upstreams[upstream.name]) {
|
||||
LogService.warn("UpstreamConfiguration", "Duplicate upstream " + upstream.name +" - skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
this._upstreams[upstream.name] = upstreamConfig;
|
||||
LogService.info("UpstreamConfiguration", "Loaded upstream '" + upstream.name + "' as: " + JSON.stringify(upstreamConfig));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a particular upstream exists
|
||||
* @param {string} name the name of the upstream
|
||||
* @returns {boolean} true if it is enabled and exists
|
||||
*/
|
||||
hasUpstream(name) {
|
||||
return !!this._upstreams[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an upstream's configuration
|
||||
* @param {string} name the upstream name
|
||||
* @returns {{url:string}} the upstream configuration
|
||||
*/
|
||||
getUpstream(name) {
|
||||
return _.clone(this._upstreams[name]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UpstreamConfiguration();
|
|
@ -8,6 +8,13 @@ var IntegrationStub = require("../generic_types/IntegrationStub");
|
|||
* @param {string} scalarToken the scalar token
|
||||
* @returns {Promise<*>} resolves to the configured integration
|
||||
*/
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
return Promise.resolve(new IntegrationStub(integrationConfig));
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
// Nothing to do
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -19,7 +19,7 @@ class IRCApi {
|
|||
* @param {DimensionStore} db the store to use
|
||||
*/
|
||||
bootstrap(app, db) {
|
||||
if (!Integrations.byType["bridge"]["irc"]) {
|
||||
if (!Integrations.byType["bridge"] || !Integrations.byType["bridge"]["irc"]) {
|
||||
log.info("IRCApi", "IRC Bridge not enabled - not setting up the API");
|
||||
return;
|
||||
} else log.info("IRCApi", "Setting up IRC API");
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
var IRCBridge = require("./IRCBridge");
|
||||
var VectorIrcBackbone = require("./VectorIrcBackbone");
|
||||
var UpstreamConfiguration = require("../../../UpstreamConfiguration");
|
||||
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
if (integrationConfig.upstream) {
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
return db.getUpstreamToken(scalarToken).then(upstreamToken => {
|
||||
var backbone = new VectorIrcBackbone(roomId, upstreamToken);
|
||||
return new IRCBridge(integrationConfig, backbone);
|
||||
});
|
||||
} else throw new Error("Unsupported config");
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
if (!integrationConfig.upstream) throw new Error("Unsupported configuration");
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified");
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -1,12 +1,20 @@
|
|||
var RSSBot = require("./RSSBot");
|
||||
var VectorRssBackbone = require("./VectorRssBackbone");
|
||||
var UpstreamConfiguration = require("../../../UpstreamConfiguration");
|
||||
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
if (integrationConfig.upstream) {
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
return db.getUpstreamToken(scalarToken).then(upstreamToken => {
|
||||
var backbone = new VectorRssBackbone(roomId, upstreamToken);
|
||||
return new RSSBot(integrationConfig, backbone);
|
||||
});
|
||||
} else throw new Error("Unsupported config");
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
if (!integrationConfig.upstream) throw new Error("Unsupported configuration");
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified");
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -1,10 +1,12 @@
|
|||
var SimpleBot = require("./SimpleBot");
|
||||
var VectorSimpleBackbone = require("./VectorSimpleBackbone");
|
||||
var HostedSimpleBackbone = require("./HostedSimpleBackbone");
|
||||
var UpstreamConfiguration = require("../../../UpstreamConfiguration");
|
||||
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
if (integrationConfig.upstream) {
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
return db.getUpstreamToken(scalarToken).then(upstreamToken => {
|
||||
var backbone = new VectorSimpleBackbone(integrationConfig, upstreamToken);
|
||||
return new SimpleBot(integrationConfig, backbone);
|
||||
|
@ -12,5 +14,14 @@ module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
|||
} else if (integrationConfig.hosted) {
|
||||
var backbone = new HostedSimpleBackbone(integrationConfig);
|
||||
return Promise.resolve(new SimpleBot(integrationConfig, backbone));
|
||||
} else throw new Error("Unsupported config");
|
||||
}
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
if (integrationConfig.upstream) {
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified");
|
||||
} else if (!integrationConfig.hosted) throw new Error("Unsupported configuration");
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -1,6 +1,13 @@
|
|||
var SimpleWidget = require("./SimpleWidget");
|
||||
var Promise = require("bluebird");
|
||||
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
return Promise.resolve(new SimpleWidget(integrationConfig, roomId));
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
// Nothing to do
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -1,12 +1,20 @@
|
|||
var TravisCiBot = require("./TravisCiBot");
|
||||
var VectorTravisCiBackbone = require("./VectorTravisCiBackbone");
|
||||
var UpstreamConfiguration = require("../../../UpstreamConfiguration");
|
||||
|
||||
var factory = (db, integrationConfig, roomId, scalarToken) => {
|
||||
factory.validateConfig(integrationConfig);
|
||||
|
||||
module.exports = (db, integrationConfig, roomId, scalarToken) => {
|
||||
if (integrationConfig.upstream) {
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
return db.getUpstreamToken(scalarToken).then(upstreamToken => {
|
||||
var backbone = new VectorTravisCiBackbone(roomId, upstreamToken);
|
||||
return new TravisCiBot(integrationConfig, backbone);
|
||||
});
|
||||
} else throw new Error("Unsupported config");
|
||||
};
|
||||
|
||||
factory.validateConfig = (integrationConfig) => {
|
||||
if (!integrationConfig.upstream) throw new Error("Unsupported configuration");
|
||||
if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream");
|
||||
if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified");
|
||||
};
|
||||
|
||||
module.exports = factory;
|
|
@ -3,6 +3,7 @@ var log = require("../util/LogService");
|
|||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var _ = require("lodash");
|
||||
var IntegrationImpl = require("./impl");
|
||||
|
||||
log.info("Integrations", "Discovering integrations");
|
||||
|
||||
|
@ -43,6 +44,19 @@ for (var key of keys) {
|
|||
continue;
|
||||
}
|
||||
|
||||
var factory = IntegrationImpl.getFactory(merged);
|
||||
if (!factory) {
|
||||
log.warn("Integrations", "Integration " + key + " does not have an associated factory - skipping");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
factory.validateConfig(merged);
|
||||
} catch (err) {
|
||||
log.error("Integrations", "Error while validating integration " + key + " - skipping");
|
||||
log.error("Integrations", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
linear.push(merged);
|
||||
if (merged['userId'])
|
||||
byUserId[merged['userId']] = merged;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var request = require('request');
|
||||
var log = require("../util/LogService");
|
||||
var config = require("config");
|
||||
var UpstreamConfiguration = require("../UpstreamConfiguration");
|
||||
|
||||
/**
|
||||
* Represents a scalar client
|
||||
|
@ -32,7 +33,7 @@ class ScalarClient {
|
|||
// TODO: Merge this, VectorScalarClient, and MatrixLiteClient into a base class
|
||||
_do(method, endpoint, qs = null, body = null) {
|
||||
// TODO: Generify URL
|
||||
var url = config.get("upstreams.vector") + endpoint;
|
||||
var url = UpstreamConfiguration.getUpstream("vector").url + endpoint;
|
||||
|
||||
log.verbose("ScalarClient", "Performing request: " + url);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var request = require('request');
|
||||
var log = require("../util/LogService");
|
||||
var config = require("config");
|
||||
var UpstreamConfiguration = require("../UpstreamConfiguration");
|
||||
|
||||
/**
|
||||
* Represents a scalar client for vector.im
|
||||
|
@ -234,7 +235,7 @@ class VectorScalarClient {
|
|||
}
|
||||
|
||||
_do(method, endpoint, qs = null, body = null) {
|
||||
var url = config.get("upstreams.vector") + endpoint;
|
||||
var url = UpstreamConfiguration.getUpstream("vector").url + endpoint;
|
||||
|
||||
log.verbose("VectorScalarClient", "Performing request: " + url);
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class DimensionStore {
|
|||
* @param {string} mxid the matrix user id
|
||||
* @param {OpenID} openId the open ID
|
||||
* @param {string} scalarToken the token associated with the user
|
||||
* @param {string} upstreamToken the upstream scalar token
|
||||
* @param {String?} upstreamToken the upstream scalar token (optional)
|
||||
* @returns {Promise<>} resolves when complete
|
||||
*/
|
||||
createToken(mxid, openId, scalarToken, upstreamToken) {
|
||||
|
|
|
@ -29,7 +29,7 @@ module.exports = function (sequelize, DataTypes) {
|
|||
},
|
||||
upstreamToken: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
allowNull: true,
|
||||
field: 'upstreamToken'
|
||||
},
|
||||
expires: {
|
||||
|
|
Loading…
Reference in a new issue