jimmywarting / StreamSaver.js

StreamSaver writes stream to the filesystem directly asynchronous
https://jimmywarting.github.io/StreamSaver.js/example.html
MIT License
3.97k stars 413 forks source link

websocket download large file #262

Closed GREATwo closed 2 years ago

GREATwo commented 2 years ago

use websocket download large file in browser,can use StreamSaver?

jimmywarting commented 2 years ago

Sure you can use websockets

GREATwo commented 2 years ago

Do you have an example, I don't know how to use it?

jimmywarting commented 2 years ago
// streamSaver.createWriteStream() returns a writable byte stream
// The WritableStream only accepts Uint8Array chunks
// (no other typed arrays, arrayBuffers or strings are allowed)
const fileStream = streamSaver.createWriteStream('filename.txt')

const writer = fileStream.getWriter()

// Let us open a web socket
const ws = new WebSocket('ws://localhost:9998/echo')

ws.binaryType = 'arraybuffer'

ws.onopen = function() {
    // Web Socket is connected, send data using send()
    ws.send('Message to send')
}

ws.onmessage = function (evt) { 
    // Message is received...
    writer.write(new Uint8Array(evt.data))
}

ws.onclose = function() { 
    // websocket is closed.
    writer.close()
}
GREATwo commented 2 years ago

I did as you wrote and it doesn't work, can't download the file, I have to use readablestream

jimmywarting commented 2 years ago

not exactly... you only need a ReadableStream if you wish to pipe data to a writable stream. in my example i'm using the WriteableStream's writer method to manually write data into it.

anyhow... if you wish to convert a websocket into a ReadableStream then the spec have a example for it also

...Just made a small adjustment to it... it enqueues Uint8Array instead of ArrayBuffers

/**
 * Create a ReadableStream from a websocket read-only connection.
 * 
 * @param {string} url 
 * @returns {ReadableStream<Uint8Array>}
 */
function makeReadableWebSocketStream(url) {
  const ws = new WebSocket(url)
  ws.binaryType = 'arraybuffer'

  return new ReadableStream({
    start(controller) {
      ws.onmessage = event => controller.enqueue(new Uint8Array(event.data))
      ws.onclose = () => controller.close()
      ws.onerror = () => controller.error(new Error('The WebSocket errored!'))
    },

    cancel() {
      ws.close()
    }
  })
}

const webSocketStream = makeReadableWebSocketStream('wss://example.com:443/')

webSocketStream.pipeTo(fileStream)
  .then(() => console.log('All data successfully written!'))
  .catch(e => console.error('Something went wrong!', e))
GREATwo commented 2 years ago

in Firefox ,not pipeTo,how to do

jimmywarting commented 2 years ago

then you have to resort to using something like https://github.com/MattiasBuelens/web-streams-polyfill

(note that a native stream can't communicate with a polyfilled stream - ref)

GREATwo commented 2 years ago
                window.writer = writable.getWriter();
                const reader = readable.getReader();
                const pump = () => reader.read()
                    .then(res => {
                        if (res.done) {
                            writer.close(); 
                        } else {
                            writer.write(res.value).then(pump)
                        }

                    });
                pump();

in Firefox,i write so,but cpu 100%