Added multiple adapters capability to adapter manager

refs https://linear.app/tryghost/issue/CORE-1/multiple-adapters-per-type

- There's a need to support multiple adapter variations per given adapter type (storage, sso, etc.)
- With the introduced changes we can specify a version of an adapter that should be fetched based on `:feature` postfix. For example:

`adapterManager.getAdapter('storage')` -  would return the default adapter listed under "active" configuration
`adapterManager.getAdapter('storage:videos') - would return an adapter configured for videos *feature*

- Here's an example configuration for a custom video storage:
```
"storage": {
    "active": "LocalFileStorage",
    "videos": "ghost-storage-custom-video",
    "ghost-storage-custom-video": {
        "custom": "configHere"
    }
}
```
This commit is contained in:
Naz 2021-10-20 19:03:58 +04:00 committed by naz
parent 84507e181e
commit 98c27b5555
3 changed files with 101 additions and 5 deletions

View File

@ -1,5 +1,6 @@
const AdapterManager = require('@tryghost/adapter-manager');
const getAdapterServiceConfig = require('./config');
const resolveAdapterOptions = require('./options-resolver');
const config = require('../../../shared/config');
const adapterManager = new AdapterManager({
@ -16,13 +17,16 @@ adapterManager.registerAdapter('scheduling', require('../../adapters/scheduling/
adapterManager.registerAdapter('sso', require('../../adapters/sso/Base'));
module.exports = {
getAdapter(adapterType) {
/**
*
* @param {String} name - one of 'storage', 'scheduling', 'sso' etc. Or can contain a "resource" extension like "storage:image"
* @returns {Object} instance of an adapter
*/
getAdapter(name) {
const adapterServiceConfig = getAdapterServiceConfig(config);
const adapterSettings = adapterServiceConfig[adapterType];
const activeAdapter = adapterSettings.active;
const activeAdapterConfig = adapterSettings[activeAdapter];
const {adapterType, adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
return adapterManager.getAdapter(adapterType, activeAdapter, activeAdapterConfig);
return adapterManager.getAdapter(adapterType, adapterName, adapterConfig);
}
};

View File

@ -0,0 +1,18 @@
module.exports = function resolveAdapterOptions(name, adapterServiceConfig) {
const [adapterType, feature] = name.split(':');
const adapterSettings = adapterServiceConfig[adapterType];
let adapterName;
let adapterConfig;
// CASE: load resource-specific adapter when there is an adapter feature name specified as well as custom feature config
if (feature && adapterSettings[feature] && adapterSettings[adapterSettings[feature]]) {
adapterName = adapterSettings[feature];
adapterConfig = adapterSettings[adapterName];
} else {
adapterName = adapterSettings.active;
adapterConfig = adapterSettings[adapterName];
}
return {adapterType, adapterName, adapterConfig};
};

View File

@ -0,0 +1,74 @@
const should = require('should');
const resolveAdapterOptions = require('../../../../../core/server/services/adapter-manager/options-resolver');
describe('Adapter Manager: options resolver', function () {
it('returns default adapter configuration', function () {
const name = 'storage';
const adapterServiceConfig = {
storage: {
active: 'cloud-storage',
'cloud-storage': {
custom: 'configValue'
}
}
};
const {adapterType, adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
adapterType.should.equal('storage');
adapterName.should.equal('cloud-storage');
adapterConfig.should.deepEqual({
custom: 'configValue'
});
});
it('returns adapter configuration based on specified feature', function () {
const name = 'storage:videos';
const adapterServiceConfig = {
storage: {
active: 'cloud-storage',
videos: 'local-storage',
'cloud-storage': {
custom: 'configValue'
},
'local-storage': {
custom: 'localStorageConfig'
}
}
};
const {adapterType, adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
adapterType.should.equal('storage');
adapterName.should.equal('local-storage');
adapterConfig.should.deepEqual({
custom: 'localStorageConfig'
});
});
it('returns active configuration if piece of feature adapter is missing', function () {
const name = 'storage:videos';
const adapterServiceConfig = {
storage: {
active: 'cloud-storage',
videos: 'local-storage',
'cloud-storage': {
custom: 'configValue'
}
// when you forget to configure local-storage!
// 'local-storage': {
// custom: 'localStorageConfig'
// }
}
};
const {adapterType, adapterName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
adapterType.should.equal('storage');
adapterName.should.equal('cloud-storage');
adapterConfig.should.deepEqual({
custom: 'configValue'
});
});
});