Source: openspace.js

/**
* OpenSpace WebSocket related communication method
* @constructor openspace

* @param {object} setting The configuration object

* @property {object} config The configuration object stored from the parameter
* @property {library} robot The robotjs library
* @property {library} ws The WebSocket use to connect OpenSpace backend
*/

class openspace {

  constructor(setting) {

    var port = setting['port']
    this.config = setting['config']

    this.robot = require("robotjs");
    this.init()

    const net = require('net');
    const WebSocket = require('ws');

    this.ws = new WebSocket('ws://' + 'localhost' + ':' + port);

    this.ws.on('open', (connection) => {
      console.log('Connected to local OpenSpace server');
    });

  }

  /**
  * Function to initial mouse control related (robotjs) variable

  * @property {array-number} mouse The user's mouse x and y position
  * @property {array-number} altY How many y pixels should mouse increase/decrease while holding right key (zoom in/zoom out)
  * @property {array-number} latY How many y pixels should mouse increase/decrease while holding left key (rotate up/rotate down)
  * @property {array-number} latX How many x pixels should mouse increase/decrease while holding left key (rotate left/rotate right)
  */
  init() {
    this.mouse = this.robot.getMousePos();
    this.altY = 0;
    this.latY = 0;
    this.latX = 0;
  }

  /**
  * Function to clear mouse control

  * @param {string} type 'alt' / 'lat' / 'all'

  */
  clear(type) {
    var x = this.mouse.x,
    y = this.mouse.y;

    if(type=='alt' || type=='all') {
      this.robot.mouseToggle("up","right");
      this.altY = 0;

      if(this.latY>0)
      y = this.latY + y;
      if(this.latX>0)
      x = this.latX + x;
      this.robot.moveMouse(x, y);
    }

    if(type=='lat' || type=='all') {
      this.robot.mouseToggle("up","left");

      this.latX = 0;
      this.latY = 0;
      if(this.altY>0)
      y = this.altY + y;
      this.robot.moveMouse(x, y);
    }
  }

  /**
  * Function to move altitude (zoom in or zoom out)

  * @param {string} type -1 (zoom out) / 1 (zoom in)
  * @param {string} value How many pixels should be moved

  */
  moveAltitude(type,value) {
    value = value*20
    if(value>200) value = 200;
    if(value<-200) value = -200;

    var x = this.mouse.x,
    y = this.mouse.y;

    this.config.OpenSpaceLog['Altitude'] && console.log(value)

    this.altY = value;
    y = y+value + this.latY;
    x = x + this.latX;

    this.robot.mouseToggle("down","right");


    var mouse = this.robot.getMousePos();

    if(mouse.y !=y)
    this.robot.dragMouse(x, y);


  }

  /**
  * Function to move latitude and longitude (rotation)

  * @param {array-number} msg A array includes {angle,distance}

  * @property {object} msg.angle What is angle triggered on joystick.
  * @property {library} msg.distance What is distance triggered on joystick.

  */
  moveGeo(msg) {

    var speed,type,multi,type2,multi2;

    if(msg.angle>=0 && msg.angle<=90) {
      this.config.OpenSpaceLog['Geography'] && console.log('message: latitude- N:' + msg.angle/90 + '- E:' + (90-msg.angle)/90);
      speed = msg.distance;
      type = 'N';
      multi = msg.angle/90;
      type2 = 'E';
      multi2 = (90-msg.angle)/90;
    } else if (msg.angle>=270) {
      this.config.OpenSpaceLog['Geography'] && console.log('message: latitude- E:' + (msg.angle - 270)/90 + '- S:' + (360 - msg.angle)/90);
      speed = msg.distance;
      type = 'E';
      multi = (msg.angle - 270)/90;
      type2 = 'S';
      multi2 = (360 - msg.angle)/90;
    } else if (msg.angle>=180 && msg.angle<=270) {
      this.config.OpenSpaceLog['Geography'] && console.log('message: latitude- S:' + (msg.angle - 180)/90 + '- W:' + (270 - msg.angle)/90);
      speed = msg.distance;
      type = 'S';
      multi = (msg.angle - 180)/90;
      type2 = 'W';
      multi2 = (270 - msg.angle)/90;

    } else if (msg.angle>=90 && msg.angle<=180) {
      this.config.OpenSpaceLog['Geography'] && console.log('message: latitude- W:' + (msg.angle - 90)/90 + '- N:' + (180 - msg.angle)/90);
      speed = msg.distance;
      type = 'W';
      multi = (msg.angle - 90)/90;
      type2 = 'N';
      multi2 = (180 - msg.angle)/90;
    }

    this.config.OpenSpaceLog['Geography'] && console.log('message: latitude- ' + msg.distance);


    var x = this.mouse.x,
    y = this.mouse.y,
    base = 20;

    multi = multi * 10;
    multi2 = multi2 * 10;

    if(type=='N') {
      y = y + base*multi
    } else if(type=='S')  {
      y = y - base*multi
    } else if(type=='E') {
      x = x - base*multi
    } else if(type=='W')  {
      x = x + base*multi
    }

    if(type2=='N') {
      y = y + base*multi2
    } else if(type2=='S')  {
      y = y - base*multi2
    } else if(type2=='E') {
      x = x - base*multi2
    } else if(type2=='W')  {
      x = x + base*multi2
    }


    this.latY = y - this.mouse.y
    this.latX = x - this.mouse.x

    y = y+this.altY;


    this.robot.mouseToggle("down","left");

    var mouse = this.robot.getMousePos();

    if(mouse.x !=x  || mouse.y !=y)
    this.robot.dragMouse(x, y);

  }

  /**
  * Function to screenshot OpenSpace, then send the screenshot to client's device

  * @param {object} setting The configuration object

  */
  screenshot(setting) {

    var path = setting['OpenSpacePath']
    var socket = setting['socketObj']


    this.trigger('RenderEngine.TakeScreenshot')

    const fs = require('fs');

    var screenshotPath = path,
    dir,
    imgName,
    imgTime = 500;
    let latestStats = false,
    latestIndex;

    // Finding the latest folder
    fs.readdir(screenshotPath,function(err, list){
      list.forEach(function(file,index){
        var stats = new Date(fs.statSync(screenshotPath+"/"+file).mtime);
        this.config.OpenSpaceLog['Screenshot'] && console.log(index);

        if(!latestStats) {
          latestStats = stats;
          latestIndex = index;
        } else if(latestStats < stats) {
          latestStats = stats;
          latestIndex = index;
        }
      })
    })

    // Generating the image
    setTimeout(
      function() {

        fs.readdir(screenshotPath,function(err, list){
          // console.log(latestIndex)
          // dir = list[list.length-1]
          dir = list[latestIndex]

          this.config.OpenSpaceLog['Screenshot'] && console.log(screenshotPath+"/"+dir);

          fs.readdir(screenshotPath+"/"+dir,function(err, list){
            imgName = list[list.length-1]
            this.config.OpenSpaceLog['Screenshot'] && console.log(list[list.length-1]);


            // https://stackoverflow.com/questions/26331787/socket-io-node-js-simple-example-to-send-image-files-from-server-to-client
            fs.readFile(screenshotPath+"/"+dir+"/"+imgName , function(err, buf){
              // it's possible to embed binary data
              // within arbitrarily-complex objects
              socket.emit('image', { image: true, buffer: buf.toString('base64') });
            });

          })

        })

      },imgTime)

    }

    /**
    * Function to change OpenSpace current focus planet

    * @param {string} planet The number of planet

    */
    changePlanet(planet) {

      this.set('NavigationHandler.OrbitalNavigator.Anchor',planet)
      this.trigger('NavigationHandler.OrbitalNavigator.RetargetAnchor')
    }

    /**
    * Function to trigger the api script

    * @param {object} event The api event

    */
    trigger(event) {
      this.ws.send(JSON.stringify(
        {
          topic: 0,
          type: 'trigger',
          payload: {
            property: event
          }
        }
      ));
    }

    /**
    * Function to set the api value

    * @param {object} event The api event

    */
    set(event,result) {
      this.ws.send(JSON.stringify(
        {
          topic: 0,
          type: 'set',
          payload: {
            property: event, value: result
          }
        }
      ));
    }

    /**
    * Function to run lua script

    * @param {object} script The lua script

    */
    lua(script) {
      this.ws.send(JSON.stringify(
        {
          topic: 0,
          type: 'luascript',
          payload: {
            script
          }
        }
      ));
    }

  }

  module.exports = function(setting) {
    return new openspace(setting);
  }