123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /* Import core modules. */
- // const _ = require('lodash')
- const debug = require('debug')('fusion:comm')
- const EventEmitter = require('events').EventEmitter
- const moment = require('moment')
- const WebSocket = require('ws')
- /* Import local modules. */
- const serverMessages = require('./serverMessages.js')
- /**
- * Communications Channel (Class)
- */
- class CommChannel extends EventEmitter {
- constructor (connectionOptions, shuffleRoundInstance) {
- super()
- /* Set instance properties. */
- for (let oneOption in connectionOptions) {
- this[oneOption] = connectionOptions[oneOption]
- }
- /* Set server URI. */
- this.serverUri = connectionOptions.serverUri
- /* Validate server URI. */
- if (!this.serverUri) {
- /* Set connection error. */
- const connectionError = new Error('BAD_SERVER_URI')
- /* Emit connection error. */
- this.emit('connectionError', connectionError)
- }
- /* Initialize Websocket client. */
- this._wsClient = undefined
- /* Initialize server messages. */
- this.msg = serverMessages
- /* Initialize shuffle round. */
- this.round = shuffleRoundInstance
- /* Initialize outbox. */
- // NOTE: Our internal records for sent and received server messages.
- // Used for debugging bad rounds.
- this.outbox = {
- sent: {}
- }
- /* Initialize inbox. */
- this.inbox = {}
- return this
- }
- /**
- * Connect
- *
- * Establish websockets connection with shuffle server.
- */
- async connect () {
- debug('Server Connection', this.serverUri)
- // TODO: This and all communication functionality will be moved to
- // a separate class. The `Round` should only touch messages
- // after they have been parsed, validated, and classified.
- this._wsClient = new WebSocket(this.serverUri, {
- origin: 'http://localhost'
- })
- /* Handle incoming message from CashShuffle server. */
- this._wsClient.on('message', (_buffer) => {
- debug('Websocket (buffer)', _buffer)
- })
- /* Handle a NEW Websockets connection with the CashShuffle server. */
- this._wsClient.on('open', () => {
- this._wsConnected = true
- debug('We are now connected to the CashFusion server', this.serverUri)
- this.emit('connected', this._wsClient)
- })
- /* Handle closing the Websockets connection. */
- this._wsClient.on('close', (details) => {
- if (!this.round.roundComplete) {
- // FIXME: Should we attempt to automatically reconnect
- // and restart the process??
- debug('Socket connection closed:', details)
- this.emit('disconnected', details)
- }
- })
- /* Handle Websockets errors. */
- this._wsClient.on('error', (someError) => {
- debug('THERE WAS A SOCKET ERROR!', someError)
- this.emit('connectionError', someError)
- })
- }
- /**
- * Send Message
- */
- sendMessage () {
- debug('Now sending message:', arguments)
- /* Set message type. */
- // const messageType = arguments[0]
- /* Set message parameters. */
- // const messageParams = [].slice.call(arguments, 1) // FIXME: Why this trailing space??
- // debug('Now sending message:', arguments,
- // 'type:', messageType,
- // 'params:', messageParams)
- /* Initialize packet message. */
- let packedMessage = null
- /* Validate message type. */
- // if (messageType && typeof this.msg[messageType] === 'function') {
- // try {
- // packedMessage = this.msg[messageType].apply(this, messageParams)
- // } catch (nope) {
- // debug('Couldnt create', messageType, 'message using params',
- // messageParams, '\n', nope)
- // // TODO: Throw exception?
- // }
- // } else {
- // // TODO: Should we throw an exception now?
- // }
- /* Add the message to our outbox, in case we need it later. */
- // const outboxEntry = {
- // messageType: messageType,
- // time: new Date().getTime(),
- // protobuffMessage: {
- // // packed: packedMessage.packed.toString('base64'),
- // unpacked: packedMessage.unpacked.toJSON(),
- // components: packedMessage.components
- // }
- // }
- /* Validate outbox. */
- // if (!this.outbox[messageType]) {
- // /* Initialize object. */
- // const obj = {}
- //
- // /* Initialize object's message type. */
- // obj[messageType] = []
- //
- // /* Update outbox. */
- // _.extend(this.outbox, obj)
- // }
- /* Set outbox sent message flag. */
- // this.outbox.sent[messageType] = true
- /* Add entry to outbox. */
- // this.outbox[messageType].push(outboxEntry)
- /* Send packed message. */
- this._wsClient.send(packedMessage.packed)
- }
- /**
- * Write Debug File
- */
- writeDebugFile () {
- /* Loop through inbox. */
- // for (let oneKey in this.inbox) {
- // if (_.isArray(this.inbox[oneKey])) {
- // this.inbox[oneKey] = _.sortBy(this.inbox[oneKey], ['time'], ['desc'])
- // }
- // }
- /* Loop through outbox. */
- // for (let oneKey in this.outbox) {
- // if (_.isArray(this.outbox[oneKey])) {
- // this.outbox[oneKey] = _.sortBy(this.outbox[oneKey], ['time'], ['desc'])
- // }
- // }
- /* Build data package (for disk). */
- const writeThisToDisk = {
- phase: this.round.phase,
- coin: this.round.coin,
- ephemeralKeypair: this.round.ephemeralKeypair,
- encryptionKeypair: this.round.encryptionKeypair,
- shuffled: this.round.shuffled,
- change: this.round.change,
- players: this.round.players,
- equivHashPlaintext: this.round.equivHashPlaintext,
- equivHash: this.round.equivHash,
- shuffleTx: {
- signatures: this.round.shuffleTx.signatures,
- hex: this.round.shuffleTx.hex,
- serialized: this.round.shuffleTx.tx ? this.round.shuffleTx.tx.toObject() : {},
- results: this.round.shuffleTx.results
- },
- inbox: this.inbox,
- outbox: this.outbox
- }
- /* Set data. */
- const data = JSON.stringify(writeThisToDisk, null, 2)
- /* Write data to disk. */
- require('fs').writeFileSync(`_failedFusion-${moment().unix()}.js`, 'module.exports = ' + data)
- /* Quit application. */
- process.exit(0)
- }
- }
- /* Export module. */
- module.exports = CommChannel
|