From 670ef0905d6af6a6637ebcbbc52f220ce8f9631e Mon Sep 17 00:00:00 2001 From: Spencer Lepine Date: Thu, 28 Sep 2023 13:36:33 -0700 Subject: [PATCH] fix: enable message receipts by default https://github.com/amazon-connect/amazon-connect-chatjs/issues/132 --- src/constants.js | 2 + src/core/chatController.spec.js | 8 ++-- src/core/chatSession.js | 15 +++---- src/globalConfig.js | 16 +++++++- src/globalConfig.spec.js | 72 +++++++++++++++++---------------- 5 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/constants.js b/src/constants.js index 6fbfe8f..ae8806c 100644 --- a/src/constants.js +++ b/src/constants.js @@ -6,6 +6,8 @@ export const CHAT_CONFIGURATIONS = { export const PARTICIPANT_TOKEN_HEADER = "x-amzn-connect-participant-token"; export const AUTH_HEADER = "X-Amz-Bearer"; +export const DEFAULT_MESSAGE_RECEIPTS_THROTTLE_MS = 5000; + export const FEATURES = { MESSAGE_RECEIPTS_ENABLED: "MESSAGE_RECEIPTS_ENABLED" }; diff --git a/src/core/chatController.spec.js b/src/core/chatController.spec.js index 653557e..62edab7 100644 --- a/src/core/chatController.spec.js +++ b/src/core/chatController.spec.js @@ -42,10 +42,10 @@ describe("ChatController", () => { let endResponse; function getChatController(shouldSendMessageReceipts = true) { - GlobalConfig.update({ - features: shouldSendMessageReceipts ? [FEATURES.MESSAGE_RECEIPTS_ENABLED] : [], - throttleTime: 1000 - }); + if (!shouldSendMessageReceipts) { + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + } + GlobalConfig.updateThrottleTime(1000); return new ChatController({ sessionType: SESSION_TYPES.AGENT, diff --git a/src/core/chatSession.js b/src/core/chatSession.js index 6f78837..80ce5e8 100644 --- a/src/core/chatSession.js +++ b/src/core/chatSession.js @@ -11,8 +11,6 @@ import { LogManager, LogLevel, Logger } from "../log"; import { csmService } from "../service/csmService"; import WebSocketManager from "../lib/amazon-connect-websocket-manager"; -const logger = LogManager.getLogger({ prefix: "ChatJS-GlobalConfig" }); - class ChatSessionFactory { /*eslint-disable no-unused-vars*/ @@ -192,11 +190,14 @@ var setGlobalConfig = config => { if (csmConfig) { csmService.updateCsmConfig(csmConfig); } - //Message Receipts enabled by default - if (!(config.features?.messageReceipts?.shouldSendMessageReceipts === false)) { - logger.warn("enabling message-receipts by default; to disable set config.features.messageReceipts.shouldSendMessageReceipts = false"); - setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); - GlobalConfig.updateThrottleTime(config.features?.messageReceipts?.throttleTime); + /** + * Handle setting message receipts feature in Global Config. If no values are given will default to: + * - Message receipts enabled + * - Throttle = 5000 ms + */ + GlobalConfig.updateThrottleTime(config.features?.messageReceipts?.throttleTime); + if (config.features?.messageReceipts?.shouldSendMessageReceipts === false) { + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); } }; diff --git a/src/globalConfig.js b/src/globalConfig.js index 9e0d73e..960d0ce 100644 --- a/src/globalConfig.js +++ b/src/globalConfig.js @@ -1,3 +1,4 @@ +import { FEATURES, DEFAULT_MESSAGE_RECEIPTS_THROTTLE_MS } from "./constants"; import { LogManager } from "./log"; class GlobalConfigImpl { @@ -32,6 +33,8 @@ class GlobalConfigImpl { return true; } }); + this.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); // message receipts enabled by default + this.messageReceiptThrottleTime = DEFAULT_MESSAGE_RECEIPTS_THROTTLE_MS; this.featureChangeListeners = []; } update(configInput) { @@ -42,7 +45,8 @@ class GlobalConfigImpl { this.endpointOverride = config.endpoint || this.endpointOverride; this.reconnect = config.reconnect === false ? false : this.reconnect; this.messageReceiptThrottleTime = config.throttleTime ? config.throttleTime : 5000; - this.features["values"] = Array.isArray(config.features) ? [...config.features] : new Array(); + const features = config.features || this.features.values; + this.features["values"] = Array.isArray(features) ? [...features] : new Array(); } updateStageRegionCell(config) { @@ -58,7 +62,7 @@ class GlobalConfigImpl { } updateThrottleTime(throttleTime) { - this.messageReceiptThrottleTime = throttleTime ? throttleTime : this.messageReceiptThrottleTime; + this.messageReceiptThrottleTime = throttleTime || this.messageReceiptThrottleTime; } getMessageReceiptsThrottleTime() { @@ -77,6 +81,14 @@ class GlobalConfigImpl { return this.endpointOverride; } + removeFeatureFlag(feature) { + if (!this.isFeatureEnabled(feature)) { + return; + } + const index = this.features["values"].indexOf(feature); + this.features["values"].splice(index, 1); + } + setFeatureFlag(feature) { if(this.isFeatureEnabled(feature)) { return; diff --git a/src/globalConfig.spec.js b/src/globalConfig.spec.js index 5dc0d01..35113d7 100644 --- a/src/globalConfig.spec.js +++ b/src/globalConfig.spec.js @@ -30,7 +30,6 @@ const configInput = { endpoint: "test-endpoint" }; const logMetaData = {contactId: "abc"}; -const defaultMessageReceiptsError = "WARN [2022-04-12T23:12:36.677Z] ChatJS-GlobalConfig: enabling message-receipts by default; to disable set config.features.messageReceipts.shouldSendMessageReceipts = false "; describe("globalConfig", () => { beforeAll(() => { @@ -59,7 +58,7 @@ describe("globalConfig", () => { expect(GlobalConfig.getRegion()).toEqual(configInput.region); expect(GlobalConfig.getCell()).toEqual(configInput.cell); expect(GlobalConfig.getEndpointOverride()).toEqual(configInput.endpoint); - expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED)).toEqual(false); + expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED)).toEqual(true); }); it("should update stage, region and cell and fetch correct config", () => { GlobalConfig.updateStageRegionCell(stageRegionCell); @@ -128,8 +127,7 @@ describe("globalConfig", () => { setConfig(LogLevel.WARN); var logger = LogManager.getLogger({ prefix: "prefix " }); logger.warn("warn", 3); - expect(messages[0]).toEqual([defaultMessageReceiptsError]); - expect(messages[1]).toEqual(["WARN [2022-04-12T23:12:36.677Z] prefix : warn 3 "]); + expect(messages[0]).toEqual(["WARN [2022-04-12T23:12:36.677Z] prefix : warn 3 "]); }); it("should match log format in error level", () => { console.error = mockFn; @@ -156,21 +154,21 @@ describe("globalConfig", () => { setConfig(LogLevel.INFO); var logger = LogManager.getLogger({ prefix: "prefix ", logMetaData }); logger.info("info", 3); - expect(messages[1]).toEqual(["INFO [2022-04-12T23:12:36.677Z] prefix : info 3 {\"contactId\":\"abc\"}"]); + expect(messages[0]).toEqual(["INFO [2022-04-12T23:12:36.677Z] prefix : info 3 {\"contactId\":\"abc\"}"]); }); it("should match log format when there is no prefix and logMetaData", () => { console.info = mockFn; setConfig(LogLevel.INFO); var logger = LogManager.getLogger({ logMetaData: {contactId: "abc"}}); logger.info("info", 3); - expect(messages[1]).toEqual(["INFO [2022-04-12T23:12:36.677Z] info 3 {\"contactId\":\"abc\"}"]); + expect(messages[0]).toEqual(["INFO [2022-04-12T23:12:36.677Z] info 3 {\"contactId\":\"abc\"}"]); }); it("should match log format when there is no prefix, but logMetaData is included", () => { console.info = mockFn; setConfig(LogLevel.INFO); var logger = LogManager.getLogger({ logMetaData }); logger.info("info", 3); - expect(messages[1]).toEqual(["INFO [2022-04-12T23:12:36.677Z] info 3 {\"contactId\":\"abc\"}"]); + expect(messages[0]).toEqual(["INFO [2022-04-12T23:12:36.677Z] info 3 {\"contactId\":\"abc\"}"]); }); }); @@ -235,7 +233,7 @@ describe("globalConfig", () => { expect(testLogger.debug.mock.calls.length).toEqual(0); expect(testLogger.info.mock.calls.length).toEqual(1); - expect(testLogger.warn.mock.calls.length).toEqual(2); + expect(testLogger.warn.mock.calls.length).toEqual(1); expect(testLogger.error.mock.calls.length).toEqual(2); }); @@ -292,55 +290,61 @@ describe("globalConfig", () => { }); describe("feature flag test", () => { - it("should update feature Flag", () => { + it("Should have message receipts feature enabled by default", () => { GlobalConfig.update({ features: [FEATURES.MESSAGE_RECEIPTS_ENABLED] }); expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED)).toEqual(true); }); - it("should update feature Flag and call the registered listeners only once", () => { - GlobalConfig.update({ - features: [] - }); - const handler = jest.fn(); - expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(false); - GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); - expect(handler).toHaveBeenCalled(); - GlobalConfig.update({ + + it("Should update feature flags according to setGlobalConfig input", () => { + ChatSessionObject.setGlobalConfig({ features: { messageReceipts: { - shouldSendMessageReceipts: false + shouldSendMessageReceipts: false, + throttleTime: 4000, } } }); + expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED)).toEqual(false); + expect(GlobalConfig.getMessageReceiptsThrottleTime()).toEqual(4000); + }); + + it("Should be able to remove feature flag", () => { + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED)).toEqual(false); + }); + + it("Should be able to add feature flag", () => { + GlobalConfig.setFeatureFlag(FEATURES.PARTICIPANT_CONN_ACK); + expect(GlobalConfig.isFeatureEnabled(FEATURES.PARTICIPANT_CONN_ACK)).toEqual(true); + }); + + it("Should update feature flag and call the registered listeners only once", () => { + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + const handler = jest.fn(); + expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(false); + GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + expect(handler).toHaveBeenCalled(); GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); expect(handler).toHaveBeenCalledTimes(1); }); - it("should update feature Flag and call multiple registered listeners only once", () => { - GlobalConfig.update({ - features: { - messageReceipts: { - shouldSendMessageReceipts: true - } - } - }); + it("should update feature flag and call multiple registered listeners only once", () => { const handler = jest.fn().mockReturnValue(true); const handler2 = jest.fn(); - expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(false); - GlobalConfig.update({ - features: [] - }); + expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(true); + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(false); expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler2)).toEqual(false); GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + GlobalConfig.setFeatureFlag(FEATURES.PARTICIPANT_CONN_ACK); expect(GlobalConfig.isFeatureEnabled(FEATURES.MESSAGE_RECEIPTS_ENABLED, handler)).toEqual(true); expect(handler).toHaveBeenCalled(); expect(handler2).toHaveBeenCalled(); - GlobalConfig.update({ - features: [] - }); + GlobalConfig.removeFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); + GlobalConfig.removeFeatureFlag(FEATURES.PARTICIPANT_CONN_ACK); GlobalConfig.setFeatureFlag(FEATURES.MESSAGE_RECEIPTS_ENABLED); expect(handler).toHaveBeenCalledTimes(3); expect(handler2).toHaveBeenCalledTimes(1);