customerio-gist-web
Version:
Build beautiful in-app flows with no code and deliver them instantly to your app. http://customer.io
109 lines (102 loc) • 4.29 kB
JavaScript
import Gist from '../gist';
import { log } from "../utilities/log";
import { getUserToken } from "./user-manager";
import { getUserQueue, userQueueNextPullCheckLocalStoreName } from "../services/queue-service";
import { showMessage, embedMessage } from "./message-manager";
import { resolveMessageProperties } from "./gist-properties-manager";
import { preloadRenderer } from "./message-component-manager";
import { getKeyFromLocalStore } from '../utilities/local-storage';
import { updateBroadcastsLocalStore, getEligibleBroadcasts, isShowAlwaysBroadcast } from './message-broadcast-manager';
import { updateQueueLocalStore, getMessagesFromLocalStore, isMessageLoading, setMessageLoading } from './message-user-queue-manager';
var sleep = time => new Promise(resolve => setTimeout(resolve, time))
var poll = (promiseFn, time) => promiseFn().then(sleep(time).then(() => poll(promiseFn, time)));
var pollingSetup = false;
export async function startQueueListener() {
if (!pollingSetup) {
preloadRenderer();
if (getUserToken()) {
log("Queue watcher started");
pollingSetup = true;
poll(() => new Promise(() => pullMessagesFromQueue()), 1000);
} else {
log("User token not setup, queue not started.");
}
} else {
checkMessageQueue();
}
}
export async function checkMessageQueue() {
var broadcastMessages = await getEligibleBroadcasts();
var userMessages = await getMessagesFromLocalStore();
var allMessages = broadcastMessages.concat(userMessages);
log(`Messages in local queue: ${allMessages.length}`);
var orderedMessages = allMessages.sort((a, b) => a.priority - b.priority);
for (const message of orderedMessages) {
await handleMessage(message);
}
}
//TODO: Move this to a utility and only return valid messages (from: getEligibleBroadcasts getMessagesFromLocalStore) & to handleMessage
async function handleMessage(message) {
var messageProperties = resolveMessageProperties(message);
if (messageProperties.hasRouteRule) {
var currentUrl = Gist.currentRoute
if (currentUrl == null) {
currentUrl = new URL(window.location.href).pathname;
}
var routeRule = messageProperties.routeRule;
log(`Verifying route against rule: ${routeRule}`);
var urlTester = new RegExp(routeRule);
if (!urlTester.test(currentUrl)) {
log(`Route ${currentUrl} does not match rule.`);
return false;
}
}
if (messageProperties.hasPosition) {
message.position = messageProperties.position;
}
// If the message is not persistant, is not a show always broadcast, and is already loading, we skip it.
if (!messageProperties.persistent && !isShowAlwaysBroadcast(message) && await isMessageLoading(message.queueId)) {
log(`Not showing message with queueId ${message.queueId} because its already loading.`);
return false;
} else {
var loading = false;
if (messageProperties.isEmbedded) {
loading = await embedMessage(message, messageProperties.elementId);
} else {
loading = await showMessage(message);
}
if (loading) setMessageLoading(message.queueId);
return loading;
}
}
export async function pullMessagesFromQueue() {
if (getUserToken()) {
if (Gist.isDocumentVisible) {
// We're using the TTL as a way to determine if we should check the queue, so if the key is not there, we check the queue.
if (getKeyFromLocalStore(userQueueNextPullCheckLocalStoreName) === null) {
var response = await getUserQueue();
var responseData = [];
if (response) {
if (response.status === 200 || response.status === 204) {
log("200 response, updating local store.");
responseData = response.data;
updateQueueLocalStore(responseData);
updateBroadcastsLocalStore(responseData);
}
else if (response.status === 304) {
log("304 response, using local store.");
}
await checkMessageQueue();
} else {
log(`There was an error while checking message queue.`);
}
} else {
log(`Next queue pull scheduled for later.`);
}
} else {
log(`Document not visible, skipping queue check.`);
}
} else {
log(`User token reset, skipping queue check.`);
}
}