parityStore.js 2.49 KiB
Newer Older
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
Amaury Martiny's avatar
Amaury Martiny committed
// This file is part of Parity.
//
Amaury Martiny's avatar
Amaury Martiny committed
// SPDX-License-Identifier: BSD-3-Clause
Amaury Martiny's avatar
Amaury Martiny committed

import { action, observable } from 'mobx';
import Api from '@parity/api';
import { distinctUntilChanged, map, take, tap } from 'rxjs/operators';
Amaury Martiny's avatar
Amaury Martiny committed
import light from '@parity/light.js';
import { of, timer, zip } from 'rxjs';
Amaury Martiny's avatar
Amaury Martiny committed
import store from 'store';

import Debug from '../utils/debug';
Amaury Martiny's avatar
Amaury Martiny committed
import LS_PREFIX from './utils/lsPrefix';
import * as postMessage from '../utils/postMessage';
Amaury Martiny's avatar
Amaury Martiny committed
const debug = Debug('parityStore');
Amaury Martiny's avatar
Amaury Martiny committed
const LS_KEY = `${LS_PREFIX}::secureToken`;
Amaury Martiny's avatar
Amaury Martiny committed

Amaury Martiny's avatar
Amaury Martiny committed
export class ParityStore {
Axel Chalon's avatar
Axel Chalon committed
  // TODO This is not working
  // api.on('connected', () => ...);
  // api.on('disconnected', () => ...);
  // So instead, we poll every 1s
Axel Chalon's avatar
Axel Chalon committed
  isApiConnected$ = timer(0, 1000).pipe(
    map(_ => Boolean(this.api && this.api.isConnected)),
Axel Chalon's avatar
Axel Chalon committed
    distinctUntilChanged()
Axel Chalon's avatar
Axel Chalon committed
  );
Axel Chalon's avatar
Axel Chalon committed

  @observable
  api = undefined;

Amaury Martiny's avatar
Amaury Martiny committed
  constructor () {
    // Request WS port and interface from electron
    postMessage.send('WS_INTERFACE_REQUEST');
    postMessage.send('WS_PORT_REQUEST');

    const lsToken = store.get(LS_KEY);
    const token$ = lsToken
      ? of(lsToken).pipe(tap(() => debug('Got token from localStorage.')))
      : this.requestNewToken$();

    zip(
      token$,
      postMessage.listen$('WS_INTERFACE_RESPONSE'),
      postMessage.listen$('WS_PORT_RESPONSE')
    )
      .pipe(take(1))
      .subscribe(([token, wsInterface, wsPort]) =>
        this.connectToApi(token, wsInterface, wsPort)
  connectToApi (token, wsInterface, wsPort) {
Amaury Martiny's avatar
Amaury Martiny committed
    // Get the provider, optionally from --ws-interface and --ws-port flags
    let provider = `ws://${wsInterface}:${wsPort}`;
Amaury Martiny's avatar
Amaury Martiny committed

Amaury Martiny's avatar
Amaury Martiny committed
    debug(`Connecting to ${provider}.`);
Amaury Martiny's avatar
Amaury Martiny committed
    const api = new Api(
      // FIXME - change to WsSecure when implement `wss` and security certificates
Amaury Martiny's avatar
Amaury Martiny committed
      new Api.Provider.Ws(
        provider,
        token.replace(/[^a-zA-Z0-9]/g, '') // Sanitize token
Amaury Martiny's avatar
Amaury Martiny committed
      )
    );

    // Initialize the light.js lib
    light.setApi(api);

    // Also set api as member for React Components to use it if needed
    this.api = api;
Amaury Martiny's avatar
Amaury Martiny committed

Amaury Martiny's avatar
Amaury Martiny committed
    // Request new token from Electron
Amaury Martiny's avatar
Amaury Martiny committed
    debug('Requesting new token.');
    postMessage.send('SIGNER_NEW_TOKEN_REQUEST');
    return postMessage.listen$('SIGNER_NEW_TOKEN_RESPONSE').pipe(
      tap(() => debug('Successfully received new token.')),
      tap(this.updateLS)
    );
  }
Amaury Martiny's avatar
Amaury Martiny committed

  @action
  updateLS = token => {
    store.set(LS_KEY, token);
Amaury Martiny's avatar
Amaury Martiny committed
  };
}

export default new ParityStore();