UNPKG

@eclipse-ditto/ditto-javascript-client-dom

Version:

DOM implementation of Eclipse Ditto JavaScript API to be used in browsers.

205 lines 8.37 kB
/*! * Copyright (c) 2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0 * * SPDX-License-Identifier: EPL-2.0 */ import { RequestSender } from './request-sender'; import { StandardSubscription } from './websocket-request-handler'; import { ContentType } from '../constants/content-type'; import { Header } from '../constants/header'; import { HttpVerb } from '../constants/http-verb'; import { DittoAction } from '../constants/ditto-actions'; /** * Handle to send web socket requests. */ export class WebSocketRequestSender extends RequestSender { constructor(requester, group, channel, apiVersion) { super(); this.requester = requester; this.group = group; this.channel = channel; this.apiVersion = apiVersion; } static buildPath(path) { if (path !== undefined) { return path.startsWith('/') ? path : `/${path}`; } return '/'; } /** * Builds the path to use for a Message web socket request. * * @param path - The path to the entity within the basic object. * @param mailbox - The direction the message is sent in (eg. inbox). * @param subject - The subject of the message. * @returns The path for a Message request */ static buildMessagePath(path, mailbox, subject) { return `${path !== undefined ? path : ''}/${mailbox}/messages/${subject}`; } /** * Splits an ID into name and namespace. Element 0 is the namespace and element 1 is the name. * * @param idWithNamespace - The id to separate. * @returns The Array containing namespace and name */ static separateNamespace(idWithNamespace) { if (idWithNamespace !== undefined) { const splitName = idWithNamespace.split(':'); const namespace = splitName[0]; splitName.shift(); const name = splitName.join(''); return [namespace, name]; } return ['', '']; } /** * Translate a verb from HTTP (eg. GET) into web socket form (eg. retrieve). * * @param verb - The verb to translate. * @returns The translated verb */ static translateVerb(verb) { switch (verb) { case HttpVerb.POST: return DittoAction.CREATE; case HttpVerb.GET: return DittoAction.RETRIEVE; case HttpVerb.PUT: return DittoAction.MODIFY; case HttpVerb.PATCH: return DittoAction.MERGE; case HttpVerb.DELETE: return DittoAction.DELETE; default: return verb.toLowerCase(); } } /** * The basic headers needed for every web socket request. * * @returns The headers */ get baseHeaders() { return { version: this.apiVersion }; } fetchRequest(options) { const topic = this.buildTopic(options.id, this.group, 'commands', WebSocketRequestSender.translateVerb(options.verb)); const path = WebSocketRequestSender.buildPath(options.path); const requestOptions = options === null || options === void 0 ? void 0 : options.requestOptions; const headers = this.buildHeaders(requestOptions, (requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.getHeaders().has(Header.CONTENT_TYPE)) === true ? undefined : { [Header.CONTENT_TYPE]: ContentType.JSON }); return this.requester.sendRequest(topic, path, options.payload, headers) .then(response => { if (response.status >= 200 && response.status < 300) { return Promise.resolve(response); } return Promise.reject(response.body); }); } /** * Fetches the specified request and checks if the request was successful. * * @param options - The options to use for the request. * @returns A Promise for the response */ fetchGenericJsonRequest(options) { return this.fetchRequest(options); } /** * Sends a Message and returns the response. * * @param options - The options to use for the Message. * @returns A Promise for the response */ sendMessageWithResponse(options) { const topic = this.buildMessageTopic(options.id, options.messageSubject); const path = WebSocketRequestSender.buildMessagePath(options.path, options.direction, options.messageSubject); const headers = this.buildHeaders(options.options, { [Header.CONTENT_TYPE]: options.contentType }); return this.requester.sendRequest(topic, path, options.message, headers); } /** * Sends a Message. * * @param options - The options to use for the Message. * @returns A Promise that resolves once the Message was sent */ sendMessage(options) { const topic = this.buildMessageTopic(options.id, options.messageSubject); const path = WebSocketRequestSender.buildMessagePath(options.path, options.direction, options.messageSubject); const headers = this.buildHeaders(options.options, { [Header.CONTENT_TYPE]: options.contentType }); return this.requester.sendMessage(topic, path, options.message, headers); } /** * Registers a subscription. * * @param options - The options to use for the subscription. * @returns The id of the subscription. It can be used to delete the subscription. */ subscribe(options) { const topic = this.buildTopic(options.id, 'things', options.type, options.action !== undefined ? options.action : ''); const path = options.path !== undefined ? options.path : ''; const subResources = typeof options.subResources === 'boolean' ? options.subResources : true; return this.requester.subscribe(new StandardSubscription(options.callback, topic, path, subResources)); } /** * Builds headers to use for a web socket request. It combines base headers, options headers and then additional headers * * @param options - The options to provided in the request. * @param additionalHeaders - Additional headers to add. * @returns The combined headers */ buildHeaders(options, additionalHeaders) { let headers = this.baseHeaders; if (options !== undefined) { const headersMap = options.getHeaders(); headersMap.forEach((v, k) => headers[k] = v); headers = Object.assign(headers, additionalHeaders); return headers; } return additionalHeaders === undefined ? this.baseHeaders : Object.assign(headers, additionalHeaders); } /** * Builds the topic to use for a Message web socket request. * * @param id - The id of the basic entity the request is for. * @param messageSubject - The subject of the message. * @returns The topic for a Message request */ buildMessageTopic(id, messageSubject) { return this.buildTopic(id, 'things', 'messages', messageSubject); } /** * Builds the topic to use for a web socket request. * * @param id - The id of the basic entity the request is for. * @param group - The group of the request (eg. things). * @param criterion - The area of the request (eg. commands). * @param action - The action to perform. * @returns The topic for a request */ buildTopic(id, group, criterion, action) { const splitName = WebSocketRequestSender.separateNamespace(id); return `${splitName[0]}/${splitName[1]}/${group}/${this.channel}/${criterion}/${action}`; } } /** * A Factory for a WebSocketRequestSender. */ export class WebSocketRequestSenderFactory { constructor(apiVersion, channel, requester) { this.apiVersion = apiVersion; this.channel = channel; this.requester = requester; } buildInstance(group) { return new WebSocketRequestSender(this.requester, group, this.channel, this.apiVersion); } } //# sourceMappingURL=websocket-request-sender.js.map