GuacLite
view release on metacpan or search on metacpan
share/public/guaclite.js view on Meta::CPAN
* space to copy data from.
* @param {Number} srcw The width of the rectangle within the source Layer's
* coordinate space to copy data from.
* @param {Number} srch The height of the rectangle within the source
* Layer's coordinate space to copy data from.
* @param {Guacamole.Layer} dstLayer The layer to draw upon.
* @param {Number} x The destination X coordinate.
* @param {Number} y The destination Y coordinate.
*/
this.put = function(srcLayer, srcx, srcy, srcw, srch, dstLayer, x, y) {
scheduleTask(function __display_put() {
dstLayer.put(srcLayer, srcx, srcy, srcw, srch, x, y);
});
};
/**
* Copy a rectangle of image data from one Layer to this Layer. This
* operation will copy exactly the image data that will be drawn once all
* operations of the source Layer that were pending at the time this
* function was called are complete. This operation will not alter the
* size of the source Layer even if its autosize property is set to true.
*
* @param {Guacamole.Layer} srcLayer The Layer to copy image data from.
* @param {Number} srcx The X coordinate of the upper-left corner of the
* rectangle within the source Layer's coordinate
* space to copy data from.
* @param {Number} srcy The Y coordinate of the upper-left corner of the
* rectangle within the source Layer's coordinate
* space to copy data from.
* @param {Number} srcw The width of the rectangle within the source Layer's
* coordinate space to copy data from.
* @param {Number} srch The height of the rectangle within the source
* Layer's coordinate space to copy data from.
* @param {Guacamole.Layer} dstLayer The layer to draw upon.
* @param {Number} x The destination X coordinate.
* @param {Number} y The destination Y coordinate.
*/
this.copy = function(srcLayer, srcx, srcy, srcw, srch, dstLayer, x, y) {
scheduleTask(function __display_copy() {
dstLayer.copy(srcLayer, srcx, srcy, srcw, srch, x, y);
});
};
/**
* Starts a new path at the specified point.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {Number} x The X coordinate of the point to draw.
* @param {Number} y The Y coordinate of the point to draw.
*/
this.moveTo = function(layer, x, y) {
scheduleTask(function __display_moveTo() {
layer.moveTo(x, y);
});
};
/**
* Add the specified line to the current path.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {Number} x The X coordinate of the endpoint of the line to draw.
* @param {Number} y The Y coordinate of the endpoint of the line to draw.
*/
this.lineTo = function(layer, x, y) {
scheduleTask(function __display_lineTo() {
layer.lineTo(x, y);
});
};
/**
* Add the specified arc to the current path.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {Number} x The X coordinate of the center of the circle which
* will contain the arc.
* @param {Number} y The Y coordinate of the center of the circle which
* will contain the arc.
* @param {Number} radius The radius of the circle.
* @param {Number} startAngle The starting angle of the arc, in radians.
* @param {Number} endAngle The ending angle of the arc, in radians.
* @param {Boolean} negative Whether the arc should be drawn in order of
* decreasing angle.
*/
this.arc = function(layer, x, y, radius, startAngle, endAngle, negative) {
scheduleTask(function __display_arc() {
layer.arc(x, y, radius, startAngle, endAngle, negative);
});
};
/**
* Starts a new path at the specified point.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {Number} cp1x The X coordinate of the first control point.
* @param {Number} cp1y The Y coordinate of the first control point.
* @param {Number} cp2x The X coordinate of the second control point.
* @param {Number} cp2y The Y coordinate of the second control point.
* @param {Number} x The X coordinate of the endpoint of the curve.
* @param {Number} y The Y coordinate of the endpoint of the curve.
*/
this.curveTo = function(layer, cp1x, cp1y, cp2x, cp2y, x, y) {
scheduleTask(function __display_curveTo() {
layer.curveTo(cp1x, cp1y, cp2x, cp2y, x, y);
});
};
/**
* Closes the current path by connecting the end point with the start
* point (if any) with a straight line.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
*/
this.close = function(layer) {
scheduleTask(function __display_close() {
layer.close();
});
};
/**
* Add the specified rectangle to the current path.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {Number} x The X coordinate of the upper-left corner of the
* rectangle to draw.
* @param {Number} y The Y coordinate of the upper-left corner of the
* rectangle to draw.
* @param {Number} w The width of the rectangle to draw.
* @param {Number} h The height of the rectangle to draw.
*/
this.rect = function(layer, x, y, w, h) {
scheduleTask(function __display_rect() {
layer.rect(x, y, w, h);
});
};
/**
* Clip all future drawing operations by the current path. The current path
* is implicitly closed. The current path can continue to be reused
* for other operations (such as fillColor()) but a new path will be started
* once a path drawing operation (path() or rect()) is used.
*
* @param {Guacamole.Layer} layer The layer to affect.
*/
this.clip = function(layer) {
scheduleTask(function __display_clip() {
layer.clip();
});
};
/**
* Stroke the current path with the specified color. The current path
* is implicitly closed. The current path can continue to be reused
* for other operations (such as clip()) but a new path will be started
* once a path drawing operation (path() or rect()) is used.
*
* @param {Guacamole.Layer} layer The layer to draw upon.
* @param {String} cap The line cap style. Can be "round", "square",
* or "butt".
* @param {String} join The line join style. Can be "round", "bevel",
share/public/guaclite.js view on Meta::CPAN
*
* @param {Guacamole.Layer} srcLayer The Layer to copy image data from.
* @param {Number} srcx The X coordinate of the upper-left corner of the
* rectangle within the source Layer's coordinate
* space to copy data from.
* @param {Number} srcy The Y coordinate of the upper-left corner of the
* rectangle within the source Layer's coordinate
* space to copy data from.
* @param {Number} srcw The width of the rectangle within the source Layer's
* coordinate space to copy data from.
* @param {Number} srch The height of the rectangle within the source
* Layer's coordinate space to copy data from.
* @param {Number} x The destination X coordinate.
* @param {Number} y The destination Y coordinate.
*/
this.copy = function(srcLayer, srcx, srcy, srcw, srch, x, y) {
var srcCanvas = srcLayer.getCanvas();
// If entire rectangle outside source canvas, stop
if (srcx >= srcCanvas.width || srcy >= srcCanvas.height) return;
// Otherwise, clip rectangle to area
if (srcx + srcw > srcCanvas.width)
srcw = srcCanvas.width - srcx;
if (srcy + srch > srcCanvas.height)
srch = srcCanvas.height - srcy;
// Stop if nothing to draw.
if (srcw === 0 || srch === 0) return;
if (layer.autosize) fitRect(x, y, srcw, srch);
context.drawImage(srcCanvas, srcx, srcy, srcw, srch, x, y, srcw, srch);
empty = false;
};
/**
* Starts a new path at the specified point.
*
* @param {Number} x The X coordinate of the point to draw.
* @param {Number} y The Y coordinate of the point to draw.
*/
this.moveTo = function(x, y) {
// Start a new path if current path is closed
if (pathClosed) {
context.beginPath();
pathClosed = false;
}
if (layer.autosize) fitRect(x, y, 0, 0);
context.moveTo(x, y);
};
/**
* Add the specified line to the current path.
*
* @param {Number} x The X coordinate of the endpoint of the line to draw.
* @param {Number} y The Y coordinate of the endpoint of the line to draw.
*/
this.lineTo = function(x, y) {
// Start a new path if current path is closed
if (pathClosed) {
context.beginPath();
pathClosed = false;
}
if (layer.autosize) fitRect(x, y, 0, 0);
context.lineTo(x, y);
};
/**
* Add the specified arc to the current path.
*
* @param {Number} x The X coordinate of the center of the circle which
* will contain the arc.
* @param {Number} y The Y coordinate of the center of the circle which
* will contain the arc.
* @param {Number} radius The radius of the circle.
* @param {Number} startAngle The starting angle of the arc, in radians.
* @param {Number} endAngle The ending angle of the arc, in radians.
* @param {Boolean} negative Whether the arc should be drawn in order of
* decreasing angle.
*/
this.arc = function(x, y, radius, startAngle, endAngle, negative) {
// Start a new path if current path is closed
if (pathClosed) {
context.beginPath();
pathClosed = false;
}
if (layer.autosize) fitRect(x, y, 0, 0);
context.arc(x, y, radius, startAngle, endAngle, negative);
};
/**
* Starts a new path at the specified point.
*
* @param {Number} cp1x The X coordinate of the first control point.
* @param {Number} cp1y The Y coordinate of the first control point.
* @param {Number} cp2x The X coordinate of the second control point.
* @param {Number} cp2y The Y coordinate of the second control point.
* @param {Number} x The X coordinate of the endpoint of the curve.
* @param {Number} y The Y coordinate of the endpoint of the curve.
*/
this.curveTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
// Start a new path if current path is closed
if (pathClosed) {
context.beginPath();
pathClosed = false;
}
if (layer.autosize) fitRect(x, y, 0, 0);
context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
};
/**
* Closes the current path by connecting the end point with the start
* point (if any) with a straight line.
*/
this.close = function() {
context.closePath();
pathClosed = true;
};
/**
* Add the specified rectangle to the current path.
*
* @param {Number} x The X coordinate of the upper-left corner of the
* rectangle to draw.
* @param {Number} y The Y coordinate of the upper-left corner of the
* rectangle to draw.
* @param {Number} w The width of the rectangle to draw.
* @param {Number} h The height of the rectangle to draw.
*/
this.rect = function(x, y, w, h) {
// Start a new path if current path is closed
if (pathClosed) {
context.beginPath();
pathClosed = false;
}
if (layer.autosize) fitRect(x, y, w, h);
context.rect(x, y, w, h);
};
/**
* Clip all future drawing operations by the current path. The current path
* is implicitly closed. The current path can continue to be reused
* for other operations (such as fillColor()) but a new path will be started
* once a path drawing operation (path() or rect()) is used.
*/
this.clip = function() {
// Set new clipping region
context.clip();
// Path now implicitly closed
pathClosed = true;
share/public/guaclite.js view on Meta::CPAN
parseResponse();
};
}
// Otherwise, just parse
else
xmlhttprequest.onreadystatechange = parseResponse;
parseResponse();
}
/**
* Arbitrary integer, unique for each tunnel read request.
* @private
*/
var request_id = 0;
function makeRequest() {
// Make request, increment request ID
var xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.open("GET", TUNNEL_READ + tunnel.uuid + ":" + (request_id++));
xmlhttprequest.withCredentials = withCredentials;
addExtraHeaders(xmlhttprequest, extraHeaders);
xmlhttprequest.send(null);
return xmlhttprequest;
}
this.connect = function(data) {
// Start waiting for connect
reset_timeout();
// Mark the tunnel as connecting
tunnel.setState(Guacamole.Tunnel.State.CONNECTING);
// Start tunnel and connect
var connect_xmlhttprequest = new XMLHttpRequest();
connect_xmlhttprequest.onreadystatechange = function() {
if (connect_xmlhttprequest.readyState !== 4)
return;
// If failure, throw error
if (connect_xmlhttprequest.status !== 200) {
handleHTTPTunnelError(connect_xmlhttprequest);
return;
}
reset_timeout();
// Get UUID from response
tunnel.setUUID(connect_xmlhttprequest.responseText);
// Mark as open
tunnel.setState(Guacamole.Tunnel.State.OPEN);
// Ping tunnel endpoint regularly to test connection stability
pingInterval = setInterval(function sendPing() {
tunnel.sendMessage("nop");
}, PING_FREQUENCY);
// Start reading data
handleResponse(makeRequest());
};
connect_xmlhttprequest.open("POST", TUNNEL_CONNECT, true);
connect_xmlhttprequest.withCredentials = withCredentials;
addExtraHeaders(connect_xmlhttprequest, extraHeaders);
connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
connect_xmlhttprequest.send(data);
};
this.disconnect = function() {
close_tunnel(new Guacamole.Status(Guacamole.Status.Code.SUCCESS, "Manually closed."));
};
};
Guacamole.HTTPTunnel.prototype = new Guacamole.Tunnel();
/**
* Guacamole Tunnel implemented over WebSocket via XMLHttpRequest.
*
* @constructor
* @augments Guacamole.Tunnel
* @param {String} tunnelURL The URL of the WebSocket tunneling service.
*/
Guacamole.WebSocketTunnel = function(tunnelURL) {
/**
* Reference to this WebSocket tunnel.
* @private
*/
var tunnel = this;
/**
* The WebSocket used by this tunnel.
* @private
*/
var socket = null;
/**
* The current receive timeout ID, if any.
* @private
*/
var receive_timeout = null;
/**
* The current connection stability timeout ID, if any.
*
* @private
* @type {Number}
*/
var unstableTimeout = null;
share/public/guaclite.js view on Meta::CPAN
if (status.code !== Guacamole.Status.Code.SUCCESS && tunnel.onerror)
tunnel.onerror(status);
// Mark as closed
tunnel.setState(Guacamole.Tunnel.State.CLOSED);
socket.close();
}
this.sendMessage = function(elements) {
// Do not attempt to send messages if not connected
if (!tunnel.isConnected())
return;
// Do not attempt to send empty messages
if (arguments.length === 0)
return;
/**
* Converts the given value to a length/string pair for use as an
* element in a Guacamole instruction.
*
* @private
* @param value The value to convert.
* @return {string} The converted value.
*/
function getElement(value) {
var string = new String(value);
return string.length + "." + string;
}
// Initialized message with first element
var message = getElement(arguments[0]);
// Append remaining elements
for (var i=1; i<arguments.length; i++)
message += "," + getElement(arguments[i]);
// Final terminator
message += ";";
socket.send(message);
};
this.connect = function(data) {
reset_timeout();
// Mark the tunnel as connecting
tunnel.setState(Guacamole.Tunnel.State.CONNECTING);
// Connect socket
socket = new WebSocket(tunnelURL + "?" + data, "guacamole");
socket.onopen = function(event) {
reset_timeout();
// Ping tunnel endpoint regularly to test connection stability
pingInterval = setInterval(function sendPing() {
tunnel.sendMessage(Guacamole.Tunnel.INTERNAL_DATA_OPCODE,
"ping", new Date().getTime());
}, PING_FREQUENCY);
};
socket.onclose = function(event) {
// Pull status code directly from closure reason provided by Guacamole
if (event.reason)
close_tunnel(new Guacamole.Status(parseInt(event.reason), event.reason));
// Failing that, derive a Guacamole status code from the WebSocket
// status code provided by the browser
else if (event.code)
close_tunnel(new Guacamole.Status(Guacamole.Status.Code.fromWebSocketCode(event.code)));
// Otherwise, assume server is unreachable
else
close_tunnel(new Guacamole.Status(Guacamole.Status.Code.UPSTREAM_NOT_FOUND));
};
socket.onmessage = function(event) {
reset_timeout();
var message = event.data;
var startIndex = 0;
var elementEnd;
var elements = [];
do {
// Search for end of length
var lengthEnd = message.indexOf(".", startIndex);
if (lengthEnd !== -1) {
// Parse length
var length = parseInt(message.substring(elementEnd+1, lengthEnd));
// Calculate start of element
startIndex = lengthEnd + 1;
// Calculate location of element terminator
elementEnd = startIndex + length;
}
// If no period, incomplete instruction.
else
close_tunnel(new Guacamole.Status(Guacamole.Status.Code.SERVER_ERROR, "Incomplete instruction."));
// We now have enough data for the element. Parse.
var element = message.substring(startIndex, elementEnd);
var terminator = message.substring(elementEnd, elementEnd+1);
// Add element to array
( run in 0.518 second using v1.01-cache-2.11-cpan-5a3173703d6 )