vadimpronin / guacamole-lite

Node.js library for creating Guacamole-compatible servers. Guacamole is a RDP/VNC/SSH/Telnet client for HTML5 browsers.
Apache License 2.0
250 stars 78 forks source link

Is file uploading provided in this lite client? #9

Closed 0000sir closed 7 years ago

0000sir commented 7 years ago

It's great to find this project, I'm implementing my own guacamole client, but stuck in file uploading.

I have no idea about how to upload files as described in guacamole-client docs, is it provided in guacamole-common-js or I have to write every thing myself?

Do you get file uploading works? How? Thanks very much.

vadimpronin commented 7 years ago

We do have working file uploads, but we use guacamole-common-js version 0.9.9. My colleague told me that versions up to 0.9.9 used websockets for file uploads, while versions 0.9.10 and above use HTTP uploads. I didn't check/confirm it myself though.

So I suggest that you try guacamole-common-js 0.9.9 in the first place. And probably some time later I'll take a look on versions 0.9.10+ and see if the new upload method can be implemented in guacamole-lite.

vadimpronin commented 7 years ago

As a quick note: downgrading guacamole-common-js to 0.9.9 doesn't mean you have to downgrade guacd as well. We have guacamole-common-js v0.9.9 working very well with guacd v0.9.11. So if you need any features of the latest release you can still have them

0000sir commented 7 years ago

Thanks for that, I checked the js api, but still don't know how to do it, may be the BlobWriter ? I'm trying to include the whole guacamole-client to my project, with a nginx for proxy, but have more problem to deal with -_-!..

vadimpronin commented 7 years ago

This is the function we use for uploading files with guacamole-common-js 0.9.9:

  uploadFile = file => {
    const _this      = this;
    const fileUpload = {};
    const reader     = new FileReader();

    reader.onloadend = function fileContentsLoaded() {
      const stream = _this.client.createFileStream(file.type, 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()) {
          console.log('Error uploading file');

          return false;
        }

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

        // Write packet
        stream.sendBlob(base64);

        // Advance to next packet
        offset += STREAM_BLOB_SIZE;

        if (offset >= bytes.length) {
          progress = 100;
          stream.sendEnd();
        } else {
          progress = Math.floor(offset / bytes.length * 100);
        }

        // Send progress to file upload's popup
        _this.uploadProgress.setProgress({
          name: file.name,
          progress: progress
        });
      }
    };

    reader.readAsArrayBuffer(file);

    return fileUpload;
  };

Hope that helps

0000sir commented 7 years ago

Seems enough for me. That's very nice of you, I'll try this later because I'm meeting the deadline of glue the huge guac-client to my project, it's really ugly and slow, but it works at least, someone is going to use it online tomorrow... After tomorrow, I will refactor these based on your codes.

Really really thank you.

0000sir commented 7 years ago

Hey vadimpronin, I did it, much easier than gluing the original guac-client, that's great!

Thanks for your help, I should try this earlier.

And your codes work in guacamole-common-js 0.9.13, no need for changing anything

I think we can close this topic now. Thank you again.

deg0nz commented 3 years ago

For future readers:

As described in #27, file upload still works via websocket on guacd and guacamole-common-js 1.2.0 with guacamole-lite

mfarkan commented 3 years ago

@deg0nz @vadimpronin hello, how this feature works ? Should i use input file element to pick a file but how does guacd understand which folder it will put into ?Am i missing something ? Is it possible to use just guacmole-common.js for sending file ?

I use 1.3.0 version of gua-common-js

Regards,

IlyassElarbaouti commented 2 months ago

Hello @vadimpronin,

When I try to upload I get an error with code 771 and a message 'FAIL (CANNOT OPEN)', is there anything I am missing?

Screenshot 2024-09-20 154336

This is my code: ` // Define STREAM_BLOB_SIZE (adjust as necessary) const STREAM_BLOB_SIZE = 1024 * 64; // 64KB for example

function getBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result.split(',')[1]); // Get Base64 string reader.onerror = () => reject('Error reading blob'); reader.readAsDataURL(blob); }); }

// File upload function const uploadFile = async (file, client) => { const fileUpload = {}; const reader = new FileReader();

return new Promise((resolve, reject) => { reader.onloadend = async () => { const stream = client.createFileStream(file.type, file.name); const bytes = new Uint8Array(reader.result); let offset = 0;

  fileUpload.name = file.name;
  fileUpload.mimetype = file.type;
  fileUpload.length = bytes.length;

  stream.onack = async (status) => {
    console.log('Upload status received:', status);
    if (status.isError()) {
      console.log('Error uploading file');
      reject('Error uploading file');
      return;
    }

    const slice = bytes.subarray(offset, offset + STREAM_BLOB_SIZE);
    const base64 = await getBase64(new Blob([slice])); // Convert to Blob for Base64
    stream.sendBlob(base64);
    offset += STREAM_BLOB_SIZE;
    if (offset >= bytes.length) {
      stream.sendEnd();
      resolve(fileUpload);
    }
  };
};

reader.onerror = () => {
  console.error('File reading error:', reader.error);
  reject('File reading error');
};

reader.readAsArrayBuffer(file);

}); };

function drop(ev) { ev.preventDefault(); if (ev.dataTransfer.items) { for (let i = 0; i < ev.dataTransfer.items.length; i++) { if (ev.dataTransfer.items[i].kind === 'file') { const file = ev.dataTransfer.items[i].getAsFile(); console.log(file); uploadFile(file, clientRef.current) .then((fileUpload) => { console.log('Upload complete:', fileUpload); }) .catch((error) => { console.error('Upload error:', error); }); } } } } `