moleculer
Version:
Fast & powerful microservices framework for Node.JS
246 lines (208 loc) • 5.47 kB
JavaScript
/*
* moleculer
* Copyright (c) 2023 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/
;
const _ = require("lodash");
const ServiceItem = require("./service-item");
const { removeFromArray } = require("../utils");
/**
* Import types
*
* @typedef {import("./service-catalog")} ServiceCatalogClass
* @typedef {import("./service-catalog").ServiceCatalogListOptions} ServiceCatalogListOptions
* @typedef {import("./service-catalog").ServiceCatalogListResult} ServiceCatalogListResult
* @typedef {import("./service-catalog").ServiceCatalogLocalNodeServicesResult} ServiceCatalogLocalNodeServicesResult
* @typedef {import("./registry")} Registry
* @typedef {import("./node")} Node
* @typedef {import("../service-broker")} ServiceBroker
*/
/**
* Catalog for services
*
* @class ServiceCatalog
* @implements {ServiceCatalogClass}
*/
class ServiceCatalog {
/**
* Creates an instance of ServiceCatalog.
*
* @param {Registry} registry
* @param {ServiceBroker} broker
* @memberof ServiceCatalog
*/
constructor(registry, broker) {
this.registry = registry;
this.broker = broker;
this.logger = registry.logger;
this.services = [];
}
/**
* Add a new service
*
* @param {Node} node
* @param {Object} service
* @param {Boolean} local
*
* @returns {ServiceItem}
*
* @memberof ServiceCatalog
*/
add(node, service, local) {
const item = new ServiceItem(node, service, local);
this.services.push(item);
return item;
}
/**
* Check the service is exist
*
* @param {String} fullName
* @param {String} nodeID
* @returns {Boolean}
* @memberof ServiceCatalog
*/
has(fullName, nodeID) {
return this.services.find(svc => svc.equals(fullName, nodeID)) != null;
}
/**
* Get a service by fullName & nodeID
*
* @param {String} fullName
* @param {String} nodeID
* @returns {ServiceItem}
* @memberof ServiceCatalog
*/
get(fullName, nodeID) {
return this.services.find(svc => svc.equals(fullName, nodeID));
}
/**
* Get a filtered list of services with actions
*
* @param {ServiceCatalogListOptions} opts
* @returns {ServiceCatalogListResult[]}
*
* @memberof Registry
*/
list({
onlyLocal = false,
onlyAvailable = false,
skipInternal = false,
withActions = false,
withEvents = false,
grouping = false
} = {}) {
let res = [];
this.services.forEach(service => {
if (skipInternal && /^\$/.test(service.name)) return;
if (onlyLocal && !service.local) return;
if (onlyAvailable && !service.node.available) return;
let item;
if (grouping) item = res.find(svc => svc.fullName == service.fullName);
if (!item) {
let item = {
name: service.name,
version: service.version,
fullName: service.fullName,
settings: service.settings,
metadata: service.metadata,
local: service.local,
available: service.node.available
};
if (grouping) item.nodes = [service.node.id];
else item.nodeID = service.node.id;
if (withActions) {
item.actions = {};
_.forIn(service.actions, action => {
if (action.protected) return;
item.actions[action.name] = _.omit(action, [
"handler",
"remoteHandler",
"service"
]);
});
}
if (withEvents) {
item.events = {};
_.forIn(service.events, event => {
// Skip internal event handlers
if (/^\$/.test(event.name)) return;
item.events[event.name] = _.omit(event, [
"handler",
"remoteHandler",
"service"
]);
});
}
res.push(item);
} else {
if (item.nodes.indexOf(service.node.id) === -1) item.nodes.push(service.node.id);
}
});
return res;
}
/**
* Get local service list for INFO packet
*
* @returns {ServiceCatalogLocalNodeServicesResult[]}
* @memberof ServiceCatalog
*/
getLocalNodeServices() {
let res = [];
this.services.forEach(service => {
if (!service.local) return;
let item = {
name: service.name,
version: service.version,
fullName: service.fullName,
settings: service.settings,
metadata: service.metadata,
dependencies: service.dependencies
};
item.actions = {};
_.forIn(service.actions, action => {
if (action.protected) return;
item.actions[action.name] = _.omit(action, ["handler", "remoteHandler", "service"]);
});
item.events = {};
_.forIn(service.events, event => {
// Leave internal event handlers, because it can be used for internal events.
//if (/^\$/.test(event.name)) return;
item.events[event.name] = _.omit(event, ["handler", "remoteHandler", "service"]);
});
res.push(item);
});
return res;
}
/**
* Remove all endpoints by nodeID
*
* @param {String} nodeID
* @memberof ServiceCatalog
*/
removeAllByNodeID(nodeID) {
_.remove(this.services, service => {
if (service.node.id == nodeID) {
this.registry.actions.removeByService(service);
this.registry.events.removeByService(service);
return true;
}
});
}
/**
* Remove endpoint by fullName & nodeID
*
* @param {String} fullName
* @param {String} nodeID
* @memberof ServiceCatalog
*/
remove(fullName, nodeID) {
let service = this.get(fullName, nodeID);
if (service) {
this.registry.actions.removeByService(service);
this.registry.events.removeByService(service);
removeFromArray(this.services, service);
}
}
}
module.exports = ServiceCatalog;