日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

guacamole 源码_guacamole实现上传下载

發布時間:2023/12/20 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 guacamole 源码_guacamole实现上传下载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

看到首先服務端向客戶端發送了filesystem請求,緊接著瀏覽器向服務端發送了get請求,并且后面帶有根目錄標識(“/”)。

1. 源碼解讀

查看指令

/**

* Handlers for all instruction opcodes receivable by a Guacamole protocol

* client.

* @private

*/

var instructionHandlers = {

...其它指令

"filesystem" : function handleFilesystem(parameters) {

var objectIndex = parseInt(parameters[0]);

var name = parameters[1];

// Create object, if supported

if (guac_client.onfilesystem) {

//這里實例化一個object,并且傳遞給客戶端監聽的onfilesystem方法

var object = objects[objectIndex] = new Guacamole.Object(guac_client, objectIndex);

guac_client.onfilesystem(object, name);

}

// If unsupported, simply ignore the availability of the filesystem

},

...其它指令

}

查看實例化的object源碼

/**

* An object used by the Guacamole client to house arbitrarily-many named

* input and output streams.

*

* @constructor

* @param {Guacamole.Client} client

* The client owning this object.

*

* @param {Number} index

* The index of this object.

*/

Guacamole.Object = function guacamoleObject(client, index) {

/**

* Reference to this Guacamole.Object.

*

* @private

* @type {Guacamole.Object}

*/

var guacObject = this;

/**

* Map of stream name to corresponding queue of callbacks. The queue of

* callbacks is guaranteed to be in order of request.

*

* @private

* @type {Object.}

*/

var bodyCallbacks = {};

/**

* Removes and returns the callback at the head of the callback queue for

* the stream having the given name. If no such callbacks exist, null is

* returned.

*

* @private

* @param {String} name

* The name of the stream to retrieve a callback for.

*

* @returns {Function}

* The next callback associated with the stream having the given name,

* or null if no such callback exists.

*/

var dequeueBodyCallback = function dequeueBodyCallback(name) {

// If no callbacks defined, simply return null

var callbacks = bodyCallbacks[name];

if (!callbacks)

return null;

// Otherwise, pull off first callback, deleting the queue if empty

var callback = callbacks.shift();

if (callbacks.length === 0)

delete bodyCallbacks[name];

// Return found callback

return callback;

};

/**

* Adds the given callback to the tail of the callback queue for the stream

* having the given name.

*

* @private

* @param {String} name

* The name of the stream to associate with the given callback.

*

* @param {Function} callback

* The callback to add to the queue of the stream with the given name.

*/

var enqueueBodyCallback = function enqueueBodyCallback(name, callback) {

// Get callback queue by name, creating first if necessary

var callbacks = bodyCallbacks[name];

if (!callbacks) {

callbacks = [];

bodyCallbacks[name] = callbacks;

}

// Add callback to end of queue

callbacks.push(callback);

};

/**

* The index of this object.

*

* @type {Number}

*/

this.index = index;

/**

* Called when this object receives the body of a requested input stream.

* By default, all objects will invoke the callbacks provided to their

* requestInputStream() functions based on the name of the stream

* requested. This behavior can be overridden by specifying a different

* handler here.

*

* @event

* @param {Guacamole.InputStream} inputStream

* The input stream of the received body.

*

* @param {String} mimetype

* The mimetype of the data being received.

*

* @param {String} name

* The name of the stream whose body has been received.

*/

this.onbody = function defaultBodyHandler(inputStream, mimetype, name) {

// Call queued callback for the received body, if any

var callback = dequeueBodyCallback(name);

if (callback)

callback(inputStream, mimetype);

};

/**

* Called when this object is being undefined. Once undefined, no further

* communication involving this object may occur.

*

* @event

*/

this.onundefine = null;

/**

* Requests read access to the input stream having the given name. If

* successful, a new input stream will be created.

*

* @param {String} name

* The name of the input stream to request.

*

* @param {Function} [bodyCallback]

* The callback to invoke when the body of the requested input stream

* is received. This callback will be provided a Guacamole.InputStream

* and its mimetype as its two only arguments. If the onbody handler of

* this object is overridden, this callback will not be invoked.

*/

this.requestInputStream = function requestInputStream(name, bodyCallback) {

// Queue body callback if provided

if (bodyCallback)

enqueueBodyCallback(name, bodyCallback);

// Send request for input stream

client.requestObjectInputStream(guacObject.index, name);

};

/**

* Creates a new output stream associated with this object and having the

* given mimetype and name. The legality of a mimetype and name is dictated

* by the object itself.

*

* @param {String} mimetype

* The mimetype of the data which will be sent to the output stream.

*

* @param {String} name

* The defined name of an output stream within this object.

*

* @returns {Guacamole.OutputStream}

* An output stream which will write blobs to the named output stream

* of this object.

*/

this.createOutputStream = function createOutputStream(mimetype, name) {

return client.createObjectOutputStream(guacObject.index, mimetype, name);

};

};

讀取下官方的注釋,關于此類的定義:

An object used by the Guacamole client to house arbitrarily-many named input and output streams.

我們需要操作的應該就是input 和 output stream,下面我們進行下猜測

1> this.onbody對應的方法應該就是我們需要實際處理inputStream的地方,

2> this.requestInputStream后面調用了client.requestObjectInputStream(guacObject.index, name);方法,源碼如下:

Guacamole.Client = function(tunnel) {

...其它內容

this.requestObjectInputStream = function requestObjectInputStream(index, name) {

// Do not send requests if not connected

if (!isConnected())

return;

tunnel.sendMessage("get", index, name);

};

...其它內容

}

可以看出這個方法就是向服務端方發送get請求。我們上面分析websocket請求的時候,提到過向客戶端發送過這樣一個請求,并且在一直監聽的onbody方法中應該能收到服務器返回的響應。

3> this.createOutputStream應該是創建了一個通往guacamole服務器的stream,我們上傳文件的時候可能會用到這個stream,調用了client.createObjectOutputStream(guacObject.index, mimetype, name);方法,其源碼如下:

Guacamole.Client = function(tunnel) {

...其它內容

/**

* Creates a new output stream associated with the given object and having

* the given mimetype and name. The legality of a mimetype and name is

* dictated by the object itself. The instruction necessary to create this

* stream will automatically be sent.

*

* @param {Number} index

* The index of the object for which the output stream is being

* created.

*

* @param {String} mimetype

* The mimetype of the data which will be sent to the output stream.

*

* @param {String} name

* The defined name of an output stream within the given object.

*

* @returns {Guacamole.OutputStream}

* An output stream which will write blobs to the named output stream

* of the given object.

*/

this.createObjectOutputStream = function createObjectOutputStream(index, mimetype, name) {

// 得到了stream,并向服務端發送了put請求

// Allocate and ssociate stream with object metadata

var stream = guac_client.createOutputStream();

tunnel.sendMessage("put", index, stream.index, mimetype, name);

return stream;

};

...其它內容

}

繼續往下追diamante, 這句var stream = guac_client.createOutputStream(); 源碼如下:

Guacamole.Client = function(tunnel) {

...其它內容

/**

* Allocates an available stream index and creates a new

* Guacamole.OutputStream using that index, associating the resulting

* stream with this Guacamole.Client. Note that this stream will not yet

* exist as far as the other end of the Guacamole connection is concerned.

* Streams exist within the Guacamole protocol only when referenced by an

* instruction which creates the stream, such as a "clipboard", "file", or

* "pipe" instruction.

*

* @returns {Guacamole.OutputStream}

* A new Guacamole.OutputStream with a newly-allocated index and

* associated with this Guacamole.Client.

*/

this.createOutputStream = function createOutputStream() {

// Allocate index

var index = stream_indices.next();

// Return new stream

var stream = output_streams[index] = new Guacamole.OutputStream(guac_client, index);

return stream;

};

...其它內容

}

再繼續,new Guacamole.OutputStream(guac_client, index);源碼:

/**

* Abstract stream which can receive data.

*

* @constructor

* @param {Guacamole.Client} client The client owning this stream.

* @param {Number} index The index of this stream.

*/

Guacamole.OutputStream = function(client, index) {

/**

* Reference to this stream.

* @private

*/

var guac_stream = this;

/**

* The index of this stream.

* @type {Number}

*/

this.index = index;

/**

* Fired whenever an acknowledgement is received from the server, indicating

* that a stream operation has completed, or an error has occurred.

*

* @event

* @param {Guacamole.Status} status The status of the operation.

*/

this.onack = null;

/**

* Writes the given base64-encoded data to this stream as a blob.

*

* @param {String} data The base64-encoded data to send.

*/

this.sendBlob = function(data) {

//發送數據到服務端,并且數據格式應該為該base64-encoded data格式,分塊傳輸過去的

client.sendBlob(guac_stream.index, data);

};

/**

* Closes this stream.

*/

this.sendEnd = function() {

client.endStream(guac_stream.index);

};

};

到此,我們可以知道this.createOutputStream是做的是事情就是建立了一個通往服務器的stream通道,并且,我們可以操作這個通道發送分塊數據(stream.sendBlob方法)。

2. 上傳下載的核心代碼

關于文件系統和下載的代碼

var fileSystem;

//初始化文件系統

client.onfilesystem = function(object){

fileSystem=object;

//監聽onbody事件,對返回值進行處理,返回內容可能有兩種,一種是文件夾,一種是文件。

object.onbody = function(stream, mimetype, filename){

stream.sendAck('OK', Guacamole.Status.Code.SUCCESS);

downloadFile(stream, mimetype, filename);

}

}

//連接有滯后,初始化文件系統給個延遲

setTimeout(function(){

//從根目錄開始,想服務端發送get請求

let path = '/';

fileSystem.requestInputStream(path);

}, 5000);

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});

};

})();

// 收到blob的處理,因為收到的可能是一塊一塊的數據,需要把他們整合,這里用到了blob_builder

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

bufferView[i] = binary.charCodeAt(i);

blob_builder.append(arrayBuffer);

length += arrayBuffer.byteLength;

// Send success response

stream.sendAck("OK", 0x0000);

};

// 結束后的操作

stream.onend = function(){

//獲取整合后的數據

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)

//這里加入自己代碼,實現文件目錄的ui,重新組織當前文件目錄

});

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);

}

}

}

感受下console.log(blob_data)和 console.log(folder_data)的內容如下

關于上傳的代碼

const input = document.getElementById('file-input');

input.onchange = function() {

const file = input.files[0];

//上傳開始

uploadFile(fileSystem, file);

};

uploadFile = (object, file) => {

const _this = this;

const fileUpload = {};

//需要讀取文件內容,使用filereader

const reader = new FileReader();

var current_path = $("#header_title").text(); //上傳到堡壘機的目錄,可以自己動態獲取

var STREAM_BLOB_SIZE = 4096;

reader.onloadend = function fileContentsLoaded() {

//上面源碼分析過,這里先創建一個連接服務端的數據通道

const stream = object.createOutputStream(file.type, current_path + '/' + file.name);

const bytes = new Uint8Array(reader.result);

let offset = 0;

let progress = 0;

fileUpload.name = file.name;

fileUpload.mimetype = file.type;

fileUpload.length = bytes.length;

stream.onack = function ackReceived(status) {

if (status.isError()) {

//提示錯誤信息

//layer.msg(status.message);

return false;

}

const slice = bytes.subarray(offset, offset + STREAM_BLOB_SIZE);

const base64 = bufferToBase64(slice);

// Write packet

stream.sendBlob(base64);

// Advance to next packet

offset += STREAM_BLOB_SIZE;

if (offset >= bytes.length) {

stream.sendEnd();

}

}

};

reader.readAsArrayBuffer(file);

return fileUpload;

};

function bufferToBase64(buf) {

var binstr = Array.prototype.map.call(buf, function (ch) {

return String.fromCharCode(ch);

}).join('');

return btoa(binstr);

}

總結

以上是生活随笔為你收集整理的guacamole 源码_guacamole实现上传下载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。