UNPKG

pubnub

Version:

Publish & Subscribe Real-time Messaging with PubNub

260 lines (259 loc) 9.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RetryPolicy = exports.Endpoint = void 0; const categories_1 = __importDefault(require("../constants/categories")); // -------------------------------------------------------- // ------------------------ Types ------------------------- // -------------------------------------------------------- // region Types /** * List of known endpoint groups (by context). */ var Endpoint; (function (Endpoint) { /** * Unknown endpoint. * * @internal */ Endpoint["Unknown"] = "UnknownEndpoint"; /** * The endpoints to send messages. * * This is related to the following functionality: * - `publish` * - `signal` * - `publish file` * - `fire` */ Endpoint["MessageSend"] = "MessageSendEndpoint"; /** * The endpoint for real-time update retrieval. * * This is related to the following functionality: * - `subscribe` */ Endpoint["Subscribe"] = "SubscribeEndpoint"; /** * The endpoint to access and manage `user_id` presence and fetch channel presence information. * * This is related to the following functionality: * - `get presence state` * - `set presence state` * - `here now` * - `where now` * - `heartbeat` */ Endpoint["Presence"] = "PresenceEndpoint"; /** * The endpoint to access and manage files in channel-specific storage. * * This is related to the following functionality: * - `send file` * - `download file` * - `list files` * - `delete file` */ Endpoint["Files"] = "FilesEndpoint"; /** * The endpoint to access and manage messages for a specific channel(s) in the persistent storage. * * This is related to the following functionality: * - `fetch messages / message actions` * - `delete messages` * - `messages count` */ Endpoint["MessageStorage"] = "MessageStorageEndpoint"; /** * The endpoint to access and manage channel groups. * * This is related to the following functionality: * - `add channels to group` * - `list channels in group` * - `remove channels from group` * - `list channel groups` */ Endpoint["ChannelGroups"] = "ChannelGroupsEndpoint"; /** * The endpoint to access and manage device registration for channel push notifications. * * This is related to the following functionality: * - `enable channels for push notifications` * - `list push notification enabled channels` * - `disable push notifications for channels` * - `disable push notifications for all channels` */ Endpoint["DevicePushNotifications"] = "DevicePushNotificationsEndpoint"; /** * The endpoint to access and manage App Context objects. * * This is related to the following functionality: * - `set UUID metadata` * - `get UUID metadata` * - `remove UUID metadata` * - `get all UUID metadata` * - `set Channel metadata` * - `get Channel metadata` * - `remove Channel metadata` * - `get all Channel metadata` * - `manage members` * - `list members` * - `manage memberships` * - `list memberships` */ Endpoint["AppContext"] = "AppContextEndpoint"; /** * The endpoint to access and manage reactions for a specific message. * * This is related to the following functionality: * - `add message action` * - `get message actions` * - `remove message action` */ Endpoint["MessageReactions"] = "MessageReactionsEndpoint"; })(Endpoint || (exports.Endpoint = Endpoint = {})); // endregion /** * Failed request retry policy. */ class RetryPolicy { static None() { return { shouldRetry(_request, _response, _errorCategory, _attempt) { return false; }, getDelay(_attempt, _response) { return -1; }, validate() { return true; }, }; } static LinearRetryPolicy(configuration) { var _a; return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, excluded: (_a = configuration.excluded) !== null && _a !== void 0 ? _a : [], shouldRetry(request, response, error, attempt) { return isRetriableRequest(request, response, error, attempt !== null && attempt !== void 0 ? attempt : 0, this.maximumRetry, this.excluded); }, getDelay(_, response) { let delay = -1; if (response && response.headers['retry-after'] !== undefined) delay = parseInt(response.headers['retry-after'], 10); if (delay === -1) delay = this.delay; return (delay + Math.random()) * 1000; }, validate() { if (this.delay < 2) throw new Error('Delay can not be set less than 2 seconds for retry'); if (this.maximumRetry > 10) throw new Error('Maximum retry for linear retry policy can not be more than 10'); }, }; } static ExponentialRetryPolicy(configuration) { var _a; return { minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, excluded: (_a = configuration.excluded) !== null && _a !== void 0 ? _a : [], shouldRetry(request, response, error, attempt) { return isRetriableRequest(request, response, error, attempt !== null && attempt !== void 0 ? attempt : 0, this.maximumRetry, this.excluded); }, getDelay(attempt, response) { let delay = -1; if (response && response.headers['retry-after'] !== undefined) delay = parseInt(response.headers['retry-after'], 10); if (delay === -1) delay = Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, validate() { if (this.minimumDelay < 2) throw new Error('Minimum delay can not be set less than 2 seconds for retry'); else if (this.maximumDelay > 150) throw new Error('Maximum delay can not be set more than 150 seconds for' + ' retry'); else if (this.maximumRetry > 6) throw new Error('Maximum retry for exponential retry policy can not be more than 6'); }, }; } } exports.RetryPolicy = RetryPolicy; /** * Check whether request can be retried or not. * * @param req - Request for which retry ability is checked. * @param res - Service response which should be taken into consideration. * @param errorCategory - Request processing error category. * @param retryAttempt - Current retry attempt. * @param maximumRetry - Maximum retry attempts count according to the retry policy. * @param excluded - List of endpoints for which retry policy won't be applied. * * @return `true` if request can be retried. * * @internal */ const isRetriableRequest = (req, res, errorCategory, retryAttempt, maximumRetry, excluded) => { if (errorCategory) { if (errorCategory === categories_1.default.PNCancelledCategory || errorCategory === categories_1.default.PNBadRequestCategory || errorCategory === categories_1.default.PNAccessDeniedCategory) return false; } if (isExcludedRequest(req, excluded)) return false; else if (retryAttempt > maximumRetry) return false; return res ? res.status === 429 || res.status >= 500 : true; }; /** * Check whether the provided request is in the list of endpoints for which retry is not allowed or not. * * @param req - Request which will be tested. * @param excluded - List of excluded endpoints configured for retry policy. * * @returns `true` if request has been excluded and shouldn't be retried. * * @internal */ const isExcludedRequest = (req, excluded) => excluded && excluded.length > 0 ? excluded.includes(endpointFromRequest(req)) : false; /** * Identify API group from transport request. * * @param req - Request for which `path` will be analyzed to identify REST API group. * * @returns Endpoint group to which request belongs. * * @internal */ const endpointFromRequest = (req) => { let endpoint = Endpoint.Unknown; if (req.path.startsWith('/v2/subscribe')) endpoint = Endpoint.Subscribe; else if (req.path.startsWith('/publish/') || req.path.startsWith('/signal/')) endpoint = Endpoint.MessageSend; else if (req.path.startsWith('/v2/presence')) endpoint = Endpoint.Presence; else if (req.path.startsWith('/v2/history') || req.path.startsWith('/v3/history')) endpoint = Endpoint.MessageStorage; else if (req.path.startsWith('/v1/message-actions/')) endpoint = Endpoint.MessageReactions; else if (req.path.startsWith('/v1/channel-registration/')) endpoint = Endpoint.ChannelGroups; else if (req.path.startsWith('/v2/objects/')) endpoint = Endpoint.ChannelGroups; else if (req.path.startsWith('/v1/push/') || req.path.startsWith('/v2/push/')) endpoint = Endpoint.DevicePushNotifications; else if (req.path.startsWith('/v1/files/')) endpoint = Endpoint.Files; return endpoint; };