具有服务器功能的 WebPack 项目

WebPack project with server functionality

http://wiki.bitplan.com/index.php/Dash describes the Car simulation software https://github.com/mattbradley/dash which I am forking to integrate it with https://github.com/rc-dukes/dukes as asked for in https://github.com/rc-dukes/dukes/issues/37.

目标是将驱动程序图像发送到 rc-dukes 软件,并允许通过 vert.x 总线命令从 rc-dukes 控制模拟器中的运动。

当与 "real" 汽车交谈时 - 此时图像通过 http 作为 mjpeg 流传输。

现在 Dash 是一个基于 webpack 的项目,因此被设计为 运行 作为浏览器中的客户端,甚至来自 file:// 协议。

我现在想创建一个具有 Web 服务器功能并使用 vert.x 与 rc-dukes 项目的其余部分通信的版本。

首先,我误以为简单地添加一个 WebServer 并使用 require http 和 fs,这导致了很多关于如何将节点与 WebServer 集成的问题 - 最后这似乎不是一个好的途径去吧,因为它会打破底层破折号项目的最初想法。

现在我想 "optionally" 在项目中有服务器功能。

将项目拆分为服务器/客户端版本似乎不是一个好主意。

您将在 https://github.com/rc-dukes/dash/commit/ea616a38 找到相关的当前提交 相关行

  // import WebServer from "./remote/WebServer"

  //this.videoServer=new WebServer(8234);
  //this.videoServer.start()

目前已被注释掉

更好的设计是什么?

我的假设是,简单地通过 vert.x 发送图像是最好的选择。

Verticle 方法效果很好。

心跳和发送图片的回调

/**
   * call back when a vert.x heartbeat is received
   * @param self - the true this pointer for class Simulator
   * @param heartBeatCount - the number of heart beats received so far
   */
  onHeartBeat(self,heartBeatCount) {
    var color=heartBeatCount/3%2==0?"white":"purple";
    self.setColorAndTitle("heartbeat-icon",color,heartBeatCount.toString());
    // reply with the current image
    self.onSendImage(self);
  }

  /**
   * call back to send current Three.js canvas over the vert.x wire
   * @param self - the true this pointer for class Simulator
   */
  onSendImage(self) {
    // 
    var strMime = "image/jpeg";
    var imgData = this.renderer.domElement.toDataURL(strMime);
    self.remoteController.sendImage(imgData);
  }

Vert.x javascript 与 Java 服务器端通信的 Verticle

// part of https://github.com/rc-dukes/dash fork of https://github.com/mattbradley/dash

const CALLSIGN_FLASH = "Velvet ears"; // Watchdog
const CALLSIGN_BO = "Lost sheep Bo";  // Car
const CALLSIGN_ROSCO = "Red Dog"; // Debug ImageView server
var simulatorVerticle = null;

/**
 * SimulatorVerticle to be used as remoteController
 */
export default class SimulatorVerticle {

  /**
   * construct me
   * @param busUrl
   * @param self
   * @param onHeartBeat
   */
  constructor(busUrl,self=null,onHeartBeat=null) {
    this.busUrl=busUrl;
    this.self=self;
    this.onHeartBeat=onHeartBeat;
    this.heartBeatCount=0;
    this.debugHeartBeat=true;
    this.remoteControl=new RemoteControl();
    simulatorVerticle=this;
    this.enabled=false;
  }

  /**
   * all publish messages should go thru this function
   *
   * @param address
   * @param message
   * @param headers
   */
  publish(address,message,headers) {
    if (this.eb.state===EventBus.OPEN)
      this.eb.publish(address, message, headers);
  };

  /**
   * send the given image to the debug image server
   * @param imgData
   */
  sendImage(imgData) {
    this.publish(CALLSIGN_ROSCO+":SIMULATOR_IMAGE",imgData);
  }

  /**
   * start the verticle and register the handlers
   */
  start() {
    if (!this.eb) {
      this.eb = new EventBus(this.busUrl);
      this.eb.onopen = function() {
        simulatorVerticle.eb.registerHandler(CALLSIGN_FLASH,simulatorVerticle.heartBeatHandler);
        simulatorVerticle.eb.registerHandler(CALLSIGN_BO,simulatorVerticle.carMessageHandler)
      };
    };
    this.enabled=true;
  }

  stop() {
    if (this.eb)
      this.eb.close();
    this.eb=null;
    this.enabled=false;
  }

  /**
   * handle a car message
   * @param err - potential errors
   * @param msg - the vert.x message
   */
  carMessageHandler(err,msg) {
    var carjo=msg.body;
    console.log(JSON.stringify(carjo));
    var sv=simulatorVerticle;
    switch (carjo.type) {
      case 'servodirect':
        if (carjo.position) {
          // the position can be between -100 and 100
          var pos=parseFloat(carjo.position);
          // we need a value between -1 and +1
          sv.remoteControl.steer=pos/100;
        }
      break;
      case 'servo':
         switch (carjo.position) {
           case 'left':
             sv.remoteControl.steer-=0.01;
           break;
           case 'right':
             sv.remoteControl.steer+=0.01;
           break;
           case 'center':
             sv.remoteControl.steer=0;
           break;
         }
      break;
      case 'motor':
         switch (carjo.speed) {
           case 'up':
             sv.remoteControl.gas+=0.01;
           break;
           case 'down':
             sv.remoteControl.gas-=0.01;
           break;
           case 'brake':
             sv.remoteControl.break+=0.01;
           break;
           case 'stop':
             sv.remoteControl.gas=0;
             sv.remoteControl.break=1;
           break;
         }
      break;
    }
  }

  /**
   * handle a heart beat message
   * @param err - potential errors
   * @param msg - the vert.x message
   */
  heartBeatHandler(err,msg) {
    var jo=msg.body;
    var sv=simulatorVerticle;
    if (sv.debugHeartBeat)
       console.log(JSON.stringify(jo));
    sv.heartBeatCount++;
    if (sv.onHeartBeat && sv.self) {
      sv.onHeartBeat(sv.self,sv.heartBeatCount);
    }
  }

  stateColor() {
    var stateColor = "white";
    if (this.eb) {
      switch (this.eb.state) {
      case EventBus.CONNECTING:
        stateColor = "orange";
        break;
      case EventBus.OPEN:
        stateColor = "green";
        break;
      case EventBus.CLOSING:
        stateColor = "orange";
        break;
      case EventBus.CLOSED:
        stateColor = "red";
        break;
      }
    } else {
      stateColor = "violet";
    }
    return stateColor;
  }
}

export class RemoteControl {
  /**
   * @param gas
   * @param brake
   * @param steer
   */
  constructor(gas=0,brake=0,steer=0) {
    this.gas=0;
    this.brake=0;
    this.steer=0;
  }
}