Skip to content

Commit

Permalink
Add realm limit settings (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
baranga committed Aug 1, 2023
1 parent 73d3668 commit 2428657
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Introduce new administrative channel management endpoints `/admin/v1/realms/{realmId}/channels`.
- Introduce new administrative subscription management endpoints `/admin/v1/realms/{realmId}/subscriptions`.
- Introduce new administrative endpoint for deleting auth tokens `DELETE /admin/v1/realms/{realmId}/tokens/{tokenId}`
- Introduce limit settings on realm level ([#151]).

### Changed
- Add support for upgraded verneMQ broker. This requires the acceptance of their [EULA](https://vernemq.com/end-user-license-agreement/),
Expand All @@ -20,6 +21,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Hide secret `auth.token` from all responses, except token creation, to avoid access right escalation. ([#138])

[#138]: https://github.com/realmq/realmq-platform/issues/138
[#151]: https://github.com/realmq/realmq-platform/issues/151

## [0.2.0] - 2023-03-09

Expand Down
2 changes: 2 additions & 0 deletions src/api/admin/v1/mappers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const authList = require('./auth-list');
const channel = require('./channel');
const channelList = require('./channel-list');
const realm = require('./realm');
const realmDetails = require('./realm-details');
const realmList = require('./realm-list');
const subscription = require('./subscription');
const subscriptionList = require('./subscription-list');
Expand All @@ -18,6 +19,7 @@ module.exports = {
channel,
channelList,
realm,
realmDetails,
realmList,
subscription,
subscriptionList,
Expand Down
30 changes: 30 additions & 0 deletions src/api/admin/v1/mappers/realm-details.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const mapRealm = require('./realm');
const mapGenericEntity = require('../../../../lib/mappers/generic-entity');

/**
* @class RealmViewModel
* @property {string} id
* @property {string} name
* @property {Date} createdAt
* @property {Date} updatedAt
*/
/**
* Map a realm to detail response view model
* @param {object} args
* @param {RealmModel} args.realm The realm entity
* @param {RealmLimitsModel} args.realmLimits The realm limits entity
* @return {RealmViewModel} The realm view model
*/
module.exports = ({realm, realmLimits}) => ({
...mapRealm(realm),
limits: mapGenericEntity({
entity: realmLimits,
propertyMap: {
maxConnections: 'maxConnections',
sessionMaxMessageRate: 'sessionMaxMessageRate',
sessionMaxConnectionLifetime: 'sessionMaxConnectionLifetime',
sessionMaxMessageSize: 'sessionMaxMessageSize',
}
}),
});

2 changes: 1 addition & 1 deletion src/api/admin/v1/mappers/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const mapGenericEntity = require('../../../../lib/mappers/generic-entity');
* @property {Date} updatedAt
*/
/**
* Map an realm to response view model
* Map a realm to response view model
* @param {RealmModel} realm The realm entity
* @return {RealmViewModel} The realm view model
*/
Expand Down
28 changes: 27 additions & 1 deletion src/api/admin/v1/openapi/definitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,39 @@ TimestampsTrait:
Realm:
allOf:
- $ref: '#/definitions/BaseEntity'
- properties:
- type: object
properties:
name:
type: string
required:
- name
- $ref: '#/definitions/TimestampsTrait'

RealmDetails:
allOf:
- $ref: '#/definitions/Realm'
- type: object
properties:
limits:
$ref: '#/definitions/RealmLimits'

RealmLimits:
type: object
properties:
maxConnections:
description: Maximum number of simultaneously online connections
type: integer
sessionMaxMessageRate:
description: Maximum incoming publish rate per session per second
type: integer
sessionMaxConnectionLifetime:
description: Maximum lifetime of a connection in seconds
type: integer
sessionMaxMessageSize:
description: Maximum size of a message payload in bytes
type: integer
additionalProperties: false

RealmList:
allOf:
- $ref: '#/definitions/BaseList'
Expand Down
9 changes: 6 additions & 3 deletions src/api/admin/v1/routes/realms.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ module.exports = (tasks, mappers) => ({
},

async post(request, response) {
const {body: {name}} = request;
const {ok, result: realm, error} = await tasks.admin.createRealm({name});
const {body: {name, limits = {}}} = request;
const {ok, result, error} = await tasks.admin.createRealm({name, limits});

if (!ok) {
throw error;
}

return response.status(201).json(mappers.realm(realm));
return response.status(201).json(mappers.realm({
realm: result.realm,
realmLimits: result.realmLimits
}));
},
});
4 changes: 3 additions & 1 deletion src/api/admin/v1/routes/realms.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@
name:
description: The name of the real, eg. project/org name
type: string
limits:
$ref: '#/definitions/RealmLimits'
responses:
201:
description: Realm was successfully created.
schema:
$ref: '#/definitions/Realm'
$ref: '#/definitions/RealmDetails'
400:
description: Request validation failed.
401:
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/repositories.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = async ({db}) => {
channelCollection,
messageCollection,
realmCollection,
realmLimitsCollection,
realtimeConnectionCollection,
subscriptionCollection,
userCollection,
Expand All @@ -20,6 +21,7 @@ module.exports = async ({db}) => {
db.collection('channels'),
db.collection('messages'),
db.collection('realms'),
db.collection('realm-limits'),
db.collection('realtime-connections'),
db.collection('subscriptions'),
db.collection('users'),
Expand All @@ -29,6 +31,7 @@ module.exports = async ({db}) => {
channelCollection,
messageCollection,
realmCollection,
realmLimitsCollection,
realtimeConnectionCollection,
subscriptionCollection,
userCollection,
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = ({
channel: channelRepository,
message: messageRepository,
realm: realmRepository,
realmLimits: realmLimitsRepository,
realtimeConnection: realtimeConnectionRepository,
subscription: subscriptionRepository,
user: userRepository,
Expand All @@ -44,6 +45,7 @@ module.exports = ({
authRepository,
channelRepository,
realmRepository,
realmLimitsRepository,
subscriptionRepository,
userRepository,
sendSubscriptionSyncMessage,
Expand All @@ -54,6 +56,7 @@ module.exports = ({
authRepository,
channelRepository,
subscriptionRepository,
realmLimitsRepository,
realtimeConnectionRepository,
messageRepository,
userRepository,
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ const createLogger = require('./lib/logger');
process.exit(1);
}
})();

36 changes: 36 additions & 0 deletions src/models/realm-limits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const stripUndefined = require('../lib/strip-undefined');

/**
* @typedef {Object} RealmLimitsModel Specialized set of realm settings focused on connections/sessions
* @param {string} [id]
* @param {string} realmId
* @param {number} maxConnections Max number of simultaneously online connections
* @param {number} sessionMaxMessageRate Max incoming publish rate per session per second
* @param {number} sessionMaxConnectionLifetime Max lifetime of a connection in seconds
* @param {number} sessionMaxMessageSize Max message payload size in bytes
* @param {Date} [createdAt]
* @param {Date} [updatedAt]
*/

/**
* @return {RealmLimitsModel} The generalized realm model
*/
module.exports = ({
id,
realmId,
maxConnections,
sessionMaxMessageRate,
sessionMaxConnectionLifetime,
sessionMaxMessageSize,
createdAt,
updatedAt,
}) => stripUndefined({
id,
realmId,
maxConnections,
sessionMaxMessageRate,
sessionMaxConnectionLifetime,
sessionMaxMessageSize,
createdAt,
updatedAt,
});
13 changes: 11 additions & 2 deletions src/repositories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const createAuthRepository = require('./auth');
const createChannelRepository = require('./channel');
const createMessageRepository = require('./message');
const createRealmRepository = require('./realm');
const createRealmLimitsRepository = require('./realm-limits');
const createRealtimeConnectionRepository = require('./realtime-connection');
const createSubscriptionRepository = require('./subscription');
const createUserRepository = require('./user');
Expand All @@ -13,14 +14,20 @@ const createUserRepository = require('./user');
* @param {Collection} channelCollection Dependency
* @param {Collection} messageCollection Dependency
* @param {Collection} realmCollection Dependency
* @param {Collection} realmLimitsCollection Dependency
* @param {Collection} realtimeConnectionCollection Dependency
* @param {Collection} subscriptionCollection Dependency
* @param {Collection} userCollection Dependency
* @return {Repositories} The repositories
*/
module.exports = ({
authCollection, channelCollection, messageCollection,
realmCollection, subscriptionCollection, userCollection,
authCollection,
channelCollection,
messageCollection,
realmCollection,
realmLimitsCollection,
subscriptionCollection,
userCollection,
realtimeConnectionCollection,
}) =>
/**
Expand All @@ -29,6 +36,7 @@ module.exports = ({
* @property {ChannelRepository} channel
* @property {MessageRepository} message
* @property {RealmRepository} realm
* @property {RealmLimitsRepository} realmLimits
* @property {RealtimeConnectionRepository} realtimeConnection
* @property {SubscriptionRepository} subscription
* @property {UserRepository} user
Expand All @@ -38,6 +46,7 @@ module.exports = ({
channel: createChannelRepository({collection: channelCollection}),
message: createMessageRepository({collection: messageCollection}),
realm: createRealmRepository({collection: realmCollection}),
realmLimits: createRealmLimitsRepository({collection: realmLimitsCollection}),
realtimeConnection: createRealtimeConnectionRepository({collection: realtimeConnectionCollection}),
subscription: createSubscriptionRepository({collection: subscriptionCollection}),
user: createUserRepository({collection: userCollection}),
Expand Down
22 changes: 22 additions & 0 deletions src/repositories/realm-limits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const createRealmLimitsModel = require('../models/realm-limits');
const createMongoRepository = require('./lib/mongo');

/**
* Create realm repository.
*
* @param {Collection} collection Mongodb collection
* @param {function} createModel Model factory
* @return {RealmLimitsRepository} The created realm repository
*/
module.exports = ({collection, createModel = createRealmLimitsModel}) => {
const mongoRepo = createMongoRepository({collection, createModel});

/**
* @class RealmLimitsRepository
* @extends MongoRepository
*/
return {
...mongoRepo,
};
};

14 changes: 10 additions & 4 deletions src/tasks/admin/create-realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ const {success} = require('../../lib/result');

/**
* @param {RealmRepository} realmRepository The realm repository
* @param {RealmLimitsRepository} realmLimitsRepository The realm repository
* @returns {AdminTasks#createRealm} Task
*/
module.exports = ({realmRepository}) =>
module.exports = ({realmRepository, realmLimitsRepository}) =>
/**
* @typedef {Function} AdminTasks#createRealm
* @param {object} args
* @param {string} args.name The name of the realm
* @return {Promise<Result<?RealmModel>>} Realm
* @param {object} [args.limits] The limit settings of the realm
* @param {number} [args.limits] The limit settings of the realm
* @return {Promise<Result<{realm: RealmModel, realmLimits: RealmLimitsModel}>>} Realm
*/
async ({name}) =>
success(await realmRepository.create({name}));
async ({name, limits}) => {
const realm = await realmRepository.create({name});
const realmLimits = await realmLimitsRepository.create({realmId: realm.id, ...limits});
success({realm, realmLimits});
}
4 changes: 3 additions & 1 deletion src/tasks/admin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const initListUsers = require('./list-users');
/**
* @param {AuthTokenRules} authTokenRules The auth token rules
* @param {RealmRepository} realmRepository The realm repository
* @param {RealmLimitsRepository} realmLimitsRepository The realm limits repository
* @param {AuthRepository} authRepository The auth repository
* @param {ChannelRepository} channelRepository The channel repository
* @param {RealtimeConnectionRepository} realtimeConnectionRepository The real-time connection repository
Expand All @@ -28,14 +29,15 @@ module.exports = ({
authRepository,
channelRepository,
realmRepository,
realmLimitsRepository,
realtimeConnectionRepository,
subscriptionRepository,
userRepository,
sendSubscriptionSyncMessage,
}) => ({
fetchRealm: initFetchRealm({realmRepository}),
createChannel: initCreateChannel({realmRepository, channelRepository}),
createRealm: initCreateRealm({realmRepository}),
createRealm: initCreateRealm({realmRepository, realmLimitsRepository}),
createRealmToken: initCreateRealmToken({authTokenRules, realmRepository, userRepository, authRepository}),
createSubscription: initCreateSubscription({
userRepository,
Expand Down

0 comments on commit 2428657

Please sign in to comment.