mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-html5
synced 2025-12-26 13:25:58 +00:00
Requires a browser with MediaSource extension support, and Opus support for the source buffers. In practice, that is Chrome and Firefox.
180 lines
6.9 KiB
JavaScript
180 lines
6.9 KiB
JavaScript
"use strict";
|
|
/*
|
|
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
|
|
|
This file is part of spice-html5.
|
|
|
|
spice-html5 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
spice-html5 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** SpiceMainConn
|
|
** This is the master Javascript class for establishing and
|
|
** managing a connection to a Spice Server.
|
|
**
|
|
** Invocation: You must pass an object with properties as follows:
|
|
** uri (required) Uri of a WebSocket listener that is
|
|
** connected to a spice server.
|
|
** password (required) Password to send to the spice server
|
|
** message_id (optional) Identifier of an element in the DOM
|
|
** where SpiceConn will write messages.
|
|
** It will use classes spice-messages-x,
|
|
** where x is one of info, warning, or error.
|
|
** screen_id (optional) Identifier of an element in the DOM
|
|
** where SpiceConn will create any new
|
|
** client screens. This is the main UI.
|
|
** dump_id (optional) If given, an element to use for
|
|
** dumping every single image + canvas drawn.
|
|
** Sometimes useful for debugging.
|
|
** onerror (optional) If given, a function to receive async
|
|
** errors. Note that you should also catch
|
|
** errors for ones that occur inline
|
|
**
|
|
** Throws error if there are troubles. Requires a modern (by 2012 standards)
|
|
** browser, including WebSocket and WebSocket.binaryType == arraybuffer
|
|
**
|
|
**--------------------------------------------------------------------------*/
|
|
function SpiceMainConn()
|
|
{
|
|
if (typeof WebSocket === "undefined")
|
|
throw new Error("WebSocket unavailable. You need to use a different browser.");
|
|
|
|
SpiceConn.apply(this, arguments);
|
|
|
|
}
|
|
|
|
SpiceMainConn.prototype = Object.create(SpiceConn.prototype);
|
|
SpiceMainConn.prototype.process_channel_message = function(msg)
|
|
{
|
|
if (msg.type == SPICE_MSG_MAIN_INIT)
|
|
{
|
|
this.log_info("Connected to " + this.ws.url);
|
|
this.report_success("Connected")
|
|
this.main_init = new SpiceMsgMainInit(msg.data);
|
|
this.connection_id = this.main_init.session_id;
|
|
|
|
if (DEBUG > 0)
|
|
{
|
|
// FIXME - there is a lot here we don't handle; mouse modes, agent,
|
|
// ram_hint, multi_media_time
|
|
this.log_info("session id " + this.main_init.session_id +
|
|
" ; display_channels_hint " + this.main_init.display_channels_hint +
|
|
" ; supported_mouse_modes " + this.main_init.supported_mouse_modes +
|
|
" ; current_mouse_mode " + this.main_init.current_mouse_mode +
|
|
" ; agent_connected " + this.main_init.agent_connected +
|
|
" ; agent_tokens " + this.main_init.agent_tokens +
|
|
" ; multi_media_time " + this.main_init.multi_media_time +
|
|
" ; ram_hint " + this.main_init.ram_hint);
|
|
}
|
|
|
|
this.mouse_mode = this.main_init.current_mouse_mode;
|
|
if (this.main_init.current_mouse_mode != SPICE_MOUSE_MODE_CLIENT &&
|
|
(this.main_init.supported_mouse_modes & SPICE_MOUSE_MODE_CLIENT))
|
|
{
|
|
var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT);
|
|
var mr = new SpiceMiniData();
|
|
mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request);
|
|
this.send_msg(mr);
|
|
}
|
|
|
|
var attach = new SpiceMiniData;
|
|
attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS;
|
|
attach.size = attach.buffer_size();
|
|
this.send_msg(attach);
|
|
return true;
|
|
}
|
|
|
|
if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE)
|
|
{
|
|
var mode = new SpiceMsgMainMouseMode(msg.data);
|
|
DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode);
|
|
this.mouse_mode = mode.current_mode;
|
|
if (this.inputs)
|
|
this.inputs.mouse_mode = mode.current_mode;
|
|
return true;
|
|
}
|
|
|
|
if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST)
|
|
{
|
|
var i;
|
|
var chans;
|
|
DEBUG > 0 && console.log("channels");
|
|
chans = new SpiceMsgChannels(msg.data);
|
|
for (i = 0; i < chans.channels.length; i++)
|
|
{
|
|
var conn = {
|
|
uri: this.ws.url,
|
|
parent: this,
|
|
connection_id : this.connection_id,
|
|
type : chans.channels[i].type,
|
|
chan_id : chans.channels[i].id
|
|
};
|
|
if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY)
|
|
this.display = new SpiceDisplayConn(conn);
|
|
else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS)
|
|
{
|
|
this.inputs = new SpiceInputsConn(conn);
|
|
this.inputs.mouse_mode = this.mouse_mode;
|
|
}
|
|
else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR)
|
|
this.cursor = new SpiceCursorConn(conn);
|
|
else if (chans.channels[i].type == SPICE_CHANNEL_PLAYBACK)
|
|
this.cursor = new SpicePlaybackConn(conn);
|
|
else
|
|
{
|
|
this.log_err("Channel type " + chans.channels[i].type + " unknown.");
|
|
if (! ("extra_channels" in this))
|
|
this.extra_channels = [];
|
|
this.extra_channels[i] = new SpiceConn(conn);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
SpiceMainConn.prototype.stop = function(msg)
|
|
{
|
|
this.state = "closing";
|
|
|
|
if (this.inputs)
|
|
{
|
|
this.inputs.cleanup();
|
|
this.inputs = undefined;
|
|
}
|
|
|
|
if (this.cursor)
|
|
{
|
|
this.cursor.cleanup();
|
|
this.cursor = undefined;
|
|
}
|
|
|
|
if (this.display)
|
|
{
|
|
this.display.cleanup();
|
|
this.display.destroy_surfaces();
|
|
this.display = undefined;
|
|
}
|
|
|
|
this.cleanup();
|
|
|
|
if ("extra_channels" in this)
|
|
for (var e in this.extra_channels)
|
|
this.extra_channels[e].cleanup();
|
|
this.extra_channels = undefined;
|
|
}
|