1 /* 2 * Copyright (C) 2013 Glyptodon LLC 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 * THE SOFTWARE. 21 */ 22 23 var Guacamole = Guacamole || {}; 24 25 /** 26 * An object used by the Guacamole client to house arbitrarily-many named 27 * input and output streams. 28 * 29 * @constructor 30 * @param {Guacamole.Client} client 31 * The client owning this object. 32 * 33 * @param {Number} index 34 * The index of this object. 35 */ 36 Guacamole.Object = function guacamoleObject(client, index) { 37 38 /** 39 * Reference to this Guacamole.Object. 40 * 41 * @private 42 * @type Guacamole.Object 43 */ 44 var guacObject = this; 45 46 /** 47 * The callbacks associated with all pending input stream requests, if the 48 * default onbody handling is in use. 49 * 50 * @private 51 * @type Object.<String, Function[]> 52 * Map of stream name to corresponding queue of callbacks. The queue of 53 * callbacks is guaranteed to be in order of request. 54 */ 55 var bodyCallbacks = {}; 56 57 /** 58 * Removes and returns the callback at the head of the callback queue for 59 * the stream having the given name. If no such callbacks exist, null is 60 * returned. 61 * 62 * @private 63 * @param {String} name 64 * The name of the stream to retrieve a callback for. 65 * 66 * @returns {Function} 67 * The next callback associated with the stream having the given name, 68 * or null if no such callback exists. 69 */ 70 var dequeueBodyCallback = function dequeueBodyCallback(name) { 71 72 // If no callbacks defined, simply return null 73 var callbacks = bodyCallbacks[name]; 74 if (!callbacks) 75 return null; 76 77 // Otherwise, pull off first callback, deleting the queue if empty 78 var callback = callbacks.shift(); 79 if (callbacks.length === 0) 80 delete bodyCallbacks[name]; 81 82 // Return found callback 83 return callback; 84 85 }; 86 87 /** 88 * Adds the given callback to the tail of the callback queue for the stream 89 * having the given name. 90 * 91 * @private 92 * @param {String} name 93 * The name of the stream to associate with the given callback. 94 * 95 * @param {Function} callback 96 * The callback to add to the queue of the stream with the given name. 97 */ 98 var enqueueBodyCallback = function enqueueBodyCallback(name, callback) { 99 100 // Get callback queue by name, creating first if necessary 101 var callbacks = bodyCallbacks[name]; 102 if (!callbacks) { 103 callbacks = []; 104 bodyCallbacks[name] = callbacks; 105 } 106 107 // Add callback to end of queue 108 callbacks.push(callback); 109 110 }; 111 112 /** 113 * The index of this object. 114 * 115 * @type Number 116 */ 117 this.index = index; 118 119 /** 120 * Called when this object receives the body of a requested input stream. 121 * By default, all objects will invoke the callbacks provided to their 122 * requestInputStream() functions based on the name of the stream 123 * requested. This behavior can be overridden by specifying a different 124 * handler here. 125 * 126 * @event 127 * @param {Guacamole.InputStream} inputStream 128 * The input stream of the received body. 129 * 130 * @param {String} mimetype 131 * The mimetype of the data being received. 132 * 133 * @param {String} name 134 * The name of the stream whose body has been received. 135 */ 136 this.onbody = function defaultBodyHandler(inputStream, mimetype, name) { 137 138 // Call queued callback for the received body, if any 139 var callback = dequeueBodyCallback(name); 140 if (callback) 141 callback(inputStream, mimetype); 142 143 }; 144 145 /** 146 * Called when this object is being undefined. Once undefined, no further 147 * communication involving this object may occur. 148 * 149 * @event 150 */ 151 this.onundefine = null; 152 153 /** 154 * Requests read access to the input stream having the given name. If 155 * successful, a new input stream will be created. 156 * 157 * @param {String} name 158 * The name of the input stream to request. 159 * 160 * @param {Function} [bodyCallback] 161 * The callback to invoke when the body of the requested input stream 162 * is received. This callback will be provided a Guacamole.InputStream 163 * and its mimetype as its two only arguments. If the onbody handler of 164 * this object is overridden, this callback will not be invoked. 165 */ 166 this.requestInputStream = function requestInputStream(name, bodyCallback) { 167 168 // Queue body callback if provided 169 if (bodyCallback) 170 enqueueBodyCallback(name, bodyCallback); 171 172 // Send request for input stream 173 client.requestObjectInputStream(guacObject.index, name); 174 175 }; 176 177 /** 178 * Creates a new output stream associated with this object and having the 179 * given mimetype and name. The legality of a mimetype and name is dictated 180 * by the object itself. 181 * 182 * @param {String} mimetype 183 * The mimetype of the data which will be sent to the output stream. 184 * 185 * @param {String} name 186 * The defined name of an output stream within this object. 187 * 188 * @returns {Guacamole.OutputStream} 189 * An output stream which will write blobs to the named output stream 190 * of this object. 191 */ 192 this.createOutputStream = function createOutputStream(mimetype, name) { 193 return client.createObjectOutputStream(guacObject.index, mimetype, name); 194 }; 195 196 }; 197 198 /** 199 * The reserved name denoting the root stream of any object. The contents of 200 * the root stream MUST be a JSON map of stream name to mimetype. 201 * 202 * @constant 203 * @type String 204 */ 205 Guacamole.Object.ROOT_STREAM = '/'; 206 207 /** 208 * The mimetype of a stream containing JSON which maps available stream names 209 * to their corresponding mimetype. The root stream of a Guacamole.Object MUST 210 * have this mimetype. 211 * 212 * @constant 213 * @type String 214 */ 215 Guacamole.Object.STREAM_INDEX_MIMETYPE = 'application/vnd.glyptodon.guacamole.stream-index+json'; 216