UNPKG

@pheasantplucker/gc-pubsub

Version:

A failables wrapper around Google Cloud's Pubsub

234 lines (212 loc) 6.09 kB
const { failure, success, isFailure, payload, anyFailed, firstFailure, } = require('@pheasantplucker/failables') const PubSub = require('@google-cloud/pubsub') const { pluck, contains, map } = require('ramda') let project let publisher let subscriber const setProject = projectId => (project = projectId) const createPublisher = () => { try { publisher = new PubSub.v1.PublisherClient() return success(publisher) } catch (e) { return failure(e.toString()) } } const createSubscriber = () => { try { subscriber = new PubSub.v1.SubscriberClient() return success(subscriber) } catch (e) { return failure(e.toString()) } } createPublisher() createSubscriber() const createTopic = async topicName => { const existsResult = await topicExists(topicName) if (isFailure(existsResult)) return existsResult const exists = payload(existsResult) if (exists) return success(topicName) try { const topic = publisher.topicPath(project, topicName) await publisher.createTopic({ name: topic }) return success(topicName) } catch (e) { return failure(e.toString()) } } const getAllTopics = async () => { try { const projectPath = publisher.projectPath(project) const [resources] = await publisher.listTopics({ project: projectPath }) return success(resources) } catch (e) { return failure(e.toString()) } } const topicExists = async topicName => { let topic try { topic = publisher.topicPath(project, topicName) } catch (e) { return failure(e.toString()) } const getAllTopicsResult = await getAllTopics() if (isFailure(getAllTopicsResult)) return getAllTopicsResult const allTopics = payload(getAllTopicsResult) return success(propertyMatches(allTopics, 'name', topic)) } const deleteTopic = async topicName => { try { const topic = publisher.topicPath(project, topicName) await publisher.deleteTopic({ topic }) return success(topicName) } catch (e) { return failure(e.toString()) } } const createSubscription = async ( topicName, subscriptionName, options = {} ) => { const subResult = await subscriptionExists(subscriptionName) if (isFailure(subResult)) return subResult const subExists = payload(subResult) if (subExists) return success(subscriptionName) const topicResult = await createTopic(topicName) if (isFailure(topicResult)) return topicResult try { const request = { name: subscriber.subscriptionPath(project, subscriptionName), topic: publisher.topicPath(project, topicName), } const allOptions = Object.assign({}, request, options) await subscriber.createSubscription(allOptions) return success(subscriptionName) } catch (e) { return failure(e.toString()) } } const deleteSubscription = async subscriptionName => { try { const subscription = subscriber.subscriptionPath(project, subscriptionName) await subscriber.deleteSubscription({ subscription }) return success(subscriptionName) } catch (e) { return failure(e.toString()) } } const getAllSubscriptions = async () => { try { const projectPath = subscriber.projectPath(project) const [resources] = await subscriber.listSubscriptions({ project: projectPath, }) return success(resources) } catch (e) { return failure(e.toString()) } } const subscriptionExists = async subscriptionName => { const subscription = subscriber.subscriptionPath(project, subscriptionName) const getAllSubscriptionsResult = await getAllSubscriptions() if (isFailure(getAllSubscriptionsResult)) return getAllSubscriptionsResult const allSubscriptions = payload(getAllSubscriptionsResult) return success(propertyMatches(allSubscriptions, 'name', subscription)) } const propertyMatches = (list, property, name) => { const justNames = pluck(property, list) return contains(name, justNames) } const publish = async (topicName, message) => { const topic = publisher.topicPath(project, topicName) const { data: messageData } = message const bufferedData = Buffer.from(messageData) const bufferedMessage = Object.assign({}, message, { data: bufferedData, }) const request = { topic, messages: [bufferedMessage], } try { const result = await publisher.publish(request) return success(result) } catch (e) { return failure(e.toString()) } } const publishJson = async (topicName, message) => { const { data: messageData } = message const stringifiedData = JSON.stringify(messageData) const updatedMessage = Object.assign({}, message, { data: stringifiedData }) return publish(topicName, updatedMessage) } const publishMany = async (topicName, messages) => { const promises = map(m => publish(topicName, m), messages) const results = await Promise.all(promises) if (anyFailed(results)) return firstFailure(results) return success(messages.length) } const publishManyJson = async (topicName, messages) => { const updatedMessages = map( m => Object.assign({}, m, { data: JSON.stringify(m.data) }), messages ) return publishMany(topicName, updatedMessages) } const pull = async ( subscriptionName, maxMessages = 1, returnImmediately = true ) => { const request = { subscription: subscriber.subscriptionPath(project, subscriptionName), maxMessages, returnImmediately, } try { const result = await subscriber.pull(request) return success(result) } catch (e) { return failure(e.toString()) } } const acknowledge = async (subscriptionName, ackIds) => { const request = { subscription: subscriber.subscriptionPath(project, subscriptionName), ackIds, } try { const result = await subscriber.acknowledge(request) return success(result) } catch (e) { return failure(e.toString()) } } module.exports = { createPublisher, createSubscriber, createTopic, topicExists, deleteTopic, createSubscription, deleteSubscription, subscriptionExists, publish, publishJson, publishMany, publishManyJson, pull, acknowledge, setProject, }