enable-drivegit
默认状况下禁用文件传输,但启用文件传输后,RDP用户能够将文件传输到持久存在于Guacamole服务器上的虚拟驱动器。经过将此参数设置为“true”来启用文件传输支持。文件将存储在由“ drive-path”参数指定的目录中,若是启用了文件传输,则该参数是必需的。github
drive-path|Guacamolejson
服务器上应存储传输文件的目录。该目录必须对guacd可访问,而且对运行guacd的用户可读写。此参数不指RDP服务器上的目录。若是文件传输未启用,则此参数将被忽略。浏览器
create-drive-path服务器
若是设置为“true”,而且启用了文件传输,drive-path指定的目录将自动建立。将只建立路径中的最终目录 - 若是路径以前的其余目录不存在,则自动建立将失败,并会记录错误。默认状况下,该drive-path参数指定的目录 将不会自动建立,而且尝试将文件传输到不存在的目录将被记录为错误。
若是文件传输未启用,则此参数将被忽略。app
enable-drive = true drive-path = '/yourpath' create-drive-path = true
在浏览器登陆到堡垒机,能够看到设备和驱动里面多了一个guacamole RDP驱动源码分析
如下是截图ui
进入驱动下this
理解:3d
实际上在使用RDP协议的时候,有下面的关系。
浏览器<->guacamole服务器<->真实服务器
咱们看到的guacamole RDP,指向的是guacamole服务器的 /yourpath文件夹,你把文件拖动到这个驱动下,就把文件上传到guacamole服务器的 /yourpath目录下了,接下来咱们能够经过浏览器下载guacamole服务器的文件,这个须要本身去实现。特别注意,发现有个download文件夹,默认存在而且不能删除掉,做用就是你在堡垒机上操做把文件拖进去,会向浏览器发送file命令(以下图所示),而后咱们能够在cilent端进行监听,而后实现拖动自动下载。
/** * Handlers for all instruction opcodes receivable by a Guacamole protocol * client. * @private */ var instructionHandlers = { ...其它指令 "file": function(parameters) { //处理参数 var stream_index = parseInt(parameters[0]); var mimetype = parameters[1]; var filename = parameters[2]; // Create stream if (guac_client.onfile) { //这里根据index获得了输入流的抽象,注意下InputStream方法 var stream = streams[stream_index] = new Guacamole.InputStream(guac_client, stream_index); //建立完流以后,调用了client的onfile方法,而且把参数传递过去,咱们须要在client的onfile方法里面处理输入的流。 guac_client.onfile(stream, mimetype, filename); } // Otherwise, unsupported else guac_client.sendAck(stream_index, "File transfer unsupported", 0x0100); }, ...其它指令 }
如下是InputStream的代码,其实是进行了一些属性的初始化工做
/** * An input stream abstraction used by the Guacamole client to facilitate * transfer of files or other binary data. * * @constructor * @param {Guacamole.Client} client The client owning this stream. * @param {Number} index The index of this stream. */ Guacamole.InputStream = function(client, index) { /** * Reference to this stream. * @private */ var guac_stream = this; /** * The index of this stream. * @type {Number} */ this.index = index; /** * Called when a blob of data is received. * * @event * @param {String} data The received base64 data. */ this.onblob = null; /** * Called when this stream is closed. * * @event */ this.onend = null; /** * Acknowledges the receipt of a blob. * * @param {String} message A human-readable message describing the error * or status. * @param {Number} code The error code, if any, or 0 for success. */ this.sendAck = function(message, code) { client.sendAck(guac_stream.index, message, code); }; };
这个本身实现,做用就是监听上面的onfile事件,并进一步处理
client.onfile = function(stream, mimetype, filename){ //通知服务端,已经收到了stream stream.sendAck('OK', Guacamole.Status.Code.SUCCESS); //开始处理输入流,这里封装了一个downloadFile方法 downloadFile(stream, mimetype, filename); }
downloadFile = (stream, mimetype, filename) => { //拿到的流不能直接使用,先实例化一个处理器,使用blob reader处理数据 var blob_builder; if (window.BlobBuilder) blob_builder = new BlobBuilder(); else if (window.WebKitBlobBuilder) blob_builder = new WebKitBlobBuilder(); else if (window.MozBlobBuilder) blob_builder = new MozBlobBuilder(); else blob_builder = new (function() { var blobs = []; /** @ignore */ this.append = function(data) { blobs.push(new Blob([data], {"type": mimetype})); }; /** @ignore */ this.getBlob = function() { return new Blob(blobs, {"type": mimetype}); }; })(); // Append received blobs stream.onblob = function(data) { // Convert to ArrayBuffer var binary = window.atob(data); var arrayBuffer = new ArrayBuffer(binary.length); var bufferView = new Uint8Array(arrayBuffer); for (var i=0; i<binary.length; i++) bufferView[i] = binary.charCodeAt(i); //收到后就交给blob_builder blob_builder.append(arrayBuffer); length += arrayBuffer.byteLength; // Send success response stream.sendAck("OK", 0x0000); }; stream.onend = function(){ //结束的时候,获取blob_builder里面的可用数据 var blob_data = blob_builder.getBlob(); //数据传输完成后进行下载等处理 if(mimetype.indexOf('stream-index+json') != -1){ //若是是文件夹,使用filereader读取blob数据,能够得到该文件夹下的文件和目录的名称和类型,是一个json形式 var blob_reader = new FileReader(); blob_reader.addEventListener("loadend", function() { let folder_content = JSON.parse(blob_reader.result) //从新组织当前文件目录,appendFileItem是本身封装的文件系统动态展现 appendFileItem(folder_content) $("#header_title").text(filename); }); blob_reader.readAsBinaryString(blob_data); } else { //若是是文件,直接下载,可是须要解决个问题,就是如何下载blob数据 //借鉴了https://github.com/eligrey/FileSaver.js这个库 var file_arr = filename.split("/"); var download_file_name = file_arr[file_arr.length - 1]; saveAs(blob_data, download_file_name); } } }