123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /*
- The MIT License (MIT)
- Copyright (c) 2014-2019 Nikolai Suslov and the Krestianstvo.org project contributors. (https://github.com/NikolaySuslov/livecodingspace/blob/master/LICENSE.md)
- Virtual World Framework Apache 2.0 license (https://github.com/NikolaySuslov/livecodingspace/blob/master/licenses/LICENSE_VWF.md)
- */
- import { Helpers } from '/helpers.js';
- class ReflectorClient {
- constructor() {
- console.log("reflector client constructor");
- this.helpers = new Helpers;
- this.socket = undefined;
- }
- connect(component_uri_or_json_or_object, path){
- function isSocketIO07() {
- //return ( parseFloat( io.version ) >= 0.7 );
- return true
- }
- try {
- let objToRef = this.helpers.reduceSaveObject(path);
- var options = {
- // The socket is relative to the application path.
- // resource: window.location.pathname.slice( 1,
- // window.location.pathname.lastIndexOf("/") ),
- query: {
- pathname: window.location.pathname.slice( 1,
- window.location.pathname.lastIndexOf("/") ),
- appRoot: "./public",
- path: JSON.stringify(objToRef)//JSON.stringify(path)
- },
- // query: 'pathname=' + window.location.pathname.slice( 1,
- // window.location.pathname.lastIndexOf("/") ),
- // Use a secure connection when the application comes from https.
-
- secure: window.location.protocol === "https:",
- // Don't attempt to reestablish lost connections. The client reloads after a
- // disconnection to recreate the application from scratch.
- //reconnect: false,
- reconnection: false,
- upgrade: false,
- transports: ['websocket']
- };
- if ( isSocketIO07() ) {
- //window.location.host
- var host = window._app.reflectorHost; //localStorage.getItem('lcs_reflector');
- //if(!host) host = 'http://localhost:3002'; //window.location.origin;
- this.socket = io.connect( host, options );
-
- } else { // Ruby Server -- only supports socket.io 0.6
- io.util.merge( options, {
- // For socket.io 0.6, specify the port since the default isn't correct when
- // using https.
- port: window.location.port ||
- ( window.location.protocol === "https:" ? 443 : 80 ),
- // The ruby socket.io server only supports WebSockets. Don't try the others.
- transports: [
- 'websocket',
- ],
- // Increase the timeout because of starvation while loading the scene. The
- // server timeout must also be increased. (For socket.io 0.7+, the client
- // timeout is controlled by the server.)
- transportOptions: {
- "websocket": { timeout: 90000 },
- },
- } );
- this.socket = io.connect( undefined, options );
- }
- } catch ( e ) {
- // If a connection to the reflector is not available, then run in single-user mode.
- // Messages intended for the reflector will loop directly back to us in this case.
- // Start a timer to monitor the incoming queue and dispatch the messages as though
- // they were received from the server.
- vwf.dispatch();
- setInterval( function() {
- var fields = {
- time: vwf.now + 0.010, // TODO: there will be a slight skew here since the callback intervals won't be exactly 10 ms; increment using the actual delta time; also, support play/pause/stop and different playback rates as with connected mode.
- origin: "reflector",
- };
- vwf.private.queue.insert( fields, true ); // may invoke dispatch(), so call last before returning to the host
- }, 10 );
- }
- if ( this.socket ) {
- this.socket.on('connect_error', function(err) {
- console.log(err);
- var errDiv = document.createElement("div");
- errDiv.innerHTML = "<div class='vwf-err' style='z-index: 10; position: absolute; top: 80px; right: 50px'>Connection error!" + err + "</div>";
- document.querySelector('body').appendChild(errDiv);
-
- });
- this.socket.on( "connect", function() {
- vwf.logger.infox( "-socket", "connected" );
- if ( isSocketIO07() ) {
- vwf.moniker_ = this.id;
- } else { //Ruby Server
- vwf.moniker_ = this.transport.sessionid;
- }
- } );
- // Configure a handler to receive messages from the server.
-
- // Note that this example code doesn't implement a robust parser capable of handling
- // arbitrary text and that the messages should be placed in a dedicated priority
- // queue for best performance rather than resorting the queue as each message
- // arrives. Additionally, overlapping messages may cause actions to be performed out
- // of order in some cases if messages are not processed on a single thread.
- this.socket.on( "message", function( message ) {
- // vwf.logger.debugx( "-socket", "message", message );
- try {
- if ( isSocketIO07() ) {
- var fields = message;
- } else { // Ruby Server - Unpack the arguements
- var fields = JSON.parse( message );
- }
- fields.time = Number( fields.time );
- // TODO: other message validation (check node id, others?)
- fields.origin = "reflector";
- // Update the queue. Messages in the queue are ordered by time, then by order of arrival.
- // Time is only advanced if the message has no action, meaning it is a tick.
- vwf.private.queue.insert( fields, !fields.action ); // may invoke dispatch(), so call last before returning to the host
- // Each message from the server allows us to move time forward. Parse the
- // timestamp from the message and call dispatch() to execute all queued
- // actions through that time, including the message just received.
-
- // The simulation may perform immediate actions at the current time or it
- // may post actions to the queue to be performed in the future. But we only
- // move time forward for items arriving in the queue from the reflector.
- } catch ( e ) {
- vwf.logger.warn( fields.action, fields.node, fields.member, fields.parameters,
- "exception performing action:", require( "vwf/utility" ).exceptionMessage( e ) );
- }
- } );
- this.socket.on( "disconnect", function() {
- vwf.logger.infox( "-socket", "disconnected" );
- // Reload to rejoin the application.
- window.location = window.location.href;
- } );
- this.socket.on( "error", function() {
- //Overcome by compatibility.js websockets check
- document.querySelector('body').innerHTML = "<div class='vwf-err'>WebSockets connections are currently being blocked. Please check your proxy server settings.</div>";
- // jQuery('body').html("<div class='vwf-err'>WebSockets connections are currently being blocked. Please check your proxy server settings.</div>");
- } );
- if ( !isSocketIO07() ) {
- // Start communication with the reflector.
- this.socket.connect(); // TODO: errors can occur here too, particularly if a local client contains the socket.io files but there is no server; do the loopback here instead of earlier in response to new io.Socket.
- }
- } else if ( component_uri_or_json_or_object ) {
- // Load the application. The application is rooted in a single node constructed here
- // as an instance of the component passed to initialize(). That component, its
- // prototype(s), and its children, and their prototypes and children, flesh out the
- // entire application.
- // TODO: add note that this is only for a self-determined application; with socket, wait for reflection server to tell us.
- // TODO: maybe depends on component_uri_or_json_or_object too; when to override and not connect to reflection server?
- this.createNode( component_uri_or_json_or_object, "application" );
- } else { // TODO: also do this if component_uri_or_json_or_object was invalid and createNode() failed
- // TODO: show a selection dialog
- }
- }
- }
- export { ReflectorClient }
|