Home Manual Reference Source

src/client/basic.js

import { ClientHelper } from './helper'
import { API_URL, FORCE_HTTPS } from '../utils/index'
import { ConnectionStatusListener } from '../connection/connection-status'

/**
 * Client config object.
 * @typedef {Object} ClientConfig
 * @property {string} apiUrl - Api Url
 * @property {string} sandboxId - Sandbox id
 * @property {boolean} forceHttps - Force end to end HTTPS connection
 * @property {function():AbstractHandshake} authentication - Return authentication properties
 * @property {string} resource - Client resource id
 * @property {Transports} transports - Client transports implementation
 */

/**
 * ZetaPush Client to connect
 * @access public
 * @example
 * // Securized client with token based connection
 * const client = new ZetaPush.Client({
 *   sandboxId: '<YOUR-SANDBOX-ID>',
 *   authentication() {
 *     return ZetaPush.Authentication.weak({
 *       token: null
 *    })
 *   }
 * })
 * @example
 * // Client with authentication based connection
 * const client = new ZetaPush.Client({
 *   sandboxId: '<YOUR-SANDBOX-ID>',
 *   authentication() {
 *     return ZetaPush.Authentication.simple({
 *       login: '<USER-LOGIN>',
 *       password: '<USER-PASSWORD>'
 *    })
 *   }
 * })
 * @example
 * // Explicit deploymentId
 * const clientSimple = new ZetaPush.Client({
 *   sandboxId: '<YOUR-SANDBOX-ID>',
 *   authentication() {
 *     return ZetaPush.Authentication.simple({
 *       deploymentId: '<YOUR-SIMPLE-AUTHENTICATION-DEPLOYMENT-ID>',
 *       login: '<USER-LOGIN>',
 *       password: '<USER-PASSWORD>'
 *    })
 *   }
 * })
 * const clientWeak = new ZetaPush.Client({
 *   sandboxId: '<YOUR-SANDBOX-ID>',
 *   authentication() {
 *     return ZetaPush.Authentication.weak({
 *       deploymentId: '<YOUR-WEAK-AUTHENTICATION-DEPLOYMENT-ID>',
 *       token: '<SESSION-TOKEN>'
 *    })
 *   }
 * })
 */
export class Client {
  /**
   * Create a new ZetaPush Client
   * @param {ClientConfig} config
   */
  constructor({ apiUrl = API_URL, sandboxId, forceHttps = FORCE_HTTPS, authentication, resource, transports }) {
    /**
     * @access private
     * @type {ClientHelper}
     */
    this.helper = new ClientHelper({
      apiUrl,
      sandboxId,
      forceHttps,
      authentication,
      resource,
      transports
    })
  }
  /**
   * Add a connection listener to handle life cycle connection events
   * @param {ConnectionStatusListener} listener
   * @return {number} handler
   */
  addConnectionStatusListener(listener) {
    return this.helper.addConnectionStatusListener(listener)
  }
  /**
   * Safely connect client to ZetaPush
   */
  connect() {
    if (this.isConnected()) {
      const handler = this.addConnectionStatusListener({
        onConnectionClosed: () => {
          this.removeConnectionStatusListener(handler)
          this.helper.connect()
        }
      })
      this.disconnect()
    } else {
      this.helper.connect()
    }
  }
  /**
   * Create a promise based service instance
   * @param {{listener: Object, Type: class, deploymentId: string}} parameters
   * @return {Object} service
   * @example
   * const api = client.createAsyncMacroService({
   *   Type: WelcomeMacro
   * })
   * api.welcome({
   *   message: Hello'
   * }).then(({ message }) => {
   *   console.log(message)
   * })
   */
  createAsyncMacroService({ deploymentId, listener, Type }) {
    return this.helper.createAsyncMacroService({ deploymentId, listener, Type })
  }
  /**
   * Create a publish/subscribe for a service type
   * @param {{listener: Object, Type: class, deploymentId: string}} parameters
   * @return {Object} service
   * @example
   * const service = client.createService({
   *   listener: {
   *     list(message) {
   *       console.log('Stack list callback', message)
   *     },
   *     push(message) {
   *       console.log('Stack push callback', message)
   *     }
   *   },
   *   Type: ZetaPush.services.Stack
   * })
   * service.list({
   *   stack: '<STACK-ID>'
   * })
   * @example
   * // Explicit deploymentId
   * // Authentication provide optional deployment id, according to the following convention `${ServiceType.toLowerCase()_0}`
   * const service = client.createService({
   *   deploymentId: 'stack_0'
   *   listener: {
   *     list(message) {
   *       console.log('Stack list callback', message)
   *     },
   *     push(message) {
   *       console.log('Stack push callback', message)
   *     }
   *   },
   *   Type: ZetaPush.services.Stack
   * })
   * service.list({
   *   stack: '<STACK-ID>'
   * })
   */
  createService({ deploymentId, listener, Type }) {
    return this.helper.createService({ deploymentId, listener, Type })
  }
  /**
   * Disonnect client from ZetaPush
   */
  disconnect() {
    if (this.isConnected()) {
      this.helper.disconnect()
    }
  }
  /**
   * Is client connected to ZetaPush
   * @return {boolean}
   */
  isConnected() {
    return this.helper.isConnected()
  }
  /**
   * Get the client sandbox id
   * @return {string}
   */
  getSandboxId() {
    return this.helper.getSandboxId()
  }
  /**
   * Get the client resource
   * @return {string}
   */
  getResource() {
    return this.helper.getResource()
  }
  /**
   * Get server urls list
   * @return {Promise} servers
   */
  getServers() {
    return this.helper.getServers()
  }
  /**
   * Get the client user id
   * @return {string}
   */
  getUserId() {
    return this.helper.getUserId()
  }
  /*
   * Get the client user info
   * @return {Object}
   * @example
   * // Create new ZetaPush Client
   * const client = new Client({
   *   sandboxId: '<YOUR-SANDBOX-ID>',
   *   authentication: () => Authentication.simple({
   *     login: '<YOUR-USER-LOGIN>',
   *     password: '<YOUR-USER-PASSWORD>'
   *   })
   * })
   * // Add connection establised listener
   * client.onConnectionEstablished(() => {
   *   console.log('onConnectionEstablished')
   *   const profile = client.getUserInfo()
   *   console.log('Your profile', profile)
   * })
   * client.connect()
   */
  getUserInfo() {
    return this.helper.getUserInfo()
  }
  /**
   * Remove a connection status listener
   * @param {number} handler
   */
  removeConnectionStatusListener(handler) {
    return this.helper.removeConnectionStatusListener(handler)
  }
  /**
   * Set a new authentication methods
   * @param {function():AbstractHandshake} authentication
   */
  setAuthentication(authentication) {
    this.helper.setAuthentication(authentication)
  }
  /**
   * Set logging level
   * Valid values are the strings 'error', 'warn', 'info' and 'debug', from
   * less verbose to more verbose.
   * @param {string} level
   */
  setLogLevel(level) {
    this.helper.setLogLevel(level)
  }
  /**
   * Set new client resource value
   * @param {string} resource
   */
  setResource(resource) {
    this.helper.setResource(resource)
  }
  /**
   * Remove all subscriptions
   * @param {Object} service
   */
  unsubscribe(service) {
    if (!service.$subscriptions) {
      throw new TypeError('Missing $subscriptions property in service')
    }
    return this.helper.unsubscribe(service.$subscriptions)
  }
}

/**
 * Add shorthand connection status method
 */
Object.getOwnPropertyNames(ConnectionStatusListener.prototype).forEach((method) => {
  // Only implements unsupported methods
  if (!Client.prototype.hasOwnProperty(method)) {
    Client.prototype[method] = function addListener(listener) {
      return this.addConnectionStatusListener({
        [method]: listener
      })
    }
  }
})