Skip to content

Implement seekable streams #418

Closed
Closed
@cdmurph32

Description

@cdmurph32

Seekable streams would enable a great deal of functionality for my C2PA SDK work and likely many other use cases. I don't have much of an understanding of how this would be implemented, but I'd like to start a conversation.

The most obvious use case would be file handles. This would allow feature parity with web_sys::FileSystemFileHandle.
For example this JS code uses this wasm-bindgen rust code:

 async signFileSystemHandle(
    signer: AsyncSigner,
    format: string,
    source: FileSystemFileHandle,
    dest: FileSystemFileHandle,
  ): Promise<Uint8Array> {
    const {
      value: { signerPtr, manifestBytes },
      ptr,
    } = await Builder.pool.builder_signFileSystemHandle(
      Builder.workerConfig,
      this.getPtr(),
      signer.getPtr(),
      format,
      source,
      dest,
    );
    this.ptr = ptr;
    signer.setPtr(signerPtr);

    return manifestBytes;
  }

The wasm-bindgen rust code can use FIleSystemFileHandle as a stream using createWritable

    #[wasm_bindgen(js_name = signFileSystemHandle)]
    pub async fn sign_file_system_handle(
        mut self,
        signer_ptr: u32,
        format: &str,
        source_handle: &FileSystemFileHandle,
        dest_handle: &FileSystemFileHandle,
    ) -> Result<JsValue, JsSysError> {
        let signer = JavaScriptAsyncSigner::from_ptr(signer_ptr)?;
        let mut source = HandleStream::new(source_handle).await?;
        let mut dest = HandleStream::new(dest_handle).await?;
        let manifest_bytes = self
            .builder
            .sign_async(&signer, format, &mut source, &mut dest)
            .await
            .unwrap();

Besides file handles, seekable streams would be very useful for other use cases. C2PA manifests must be located in very large asset containers, which must be parsed to understand their structure. This requires the streams to be seekable. As a workaround, my POC of a C2PA component reads the input stream into a cursor before passing it to the c2pa SDK functions. This is obviously far from ideal and will not work with very large containers streams such as video.

fn add_seek_to_read<R: Read>(mut reader: R) -> std::io::Result<Cursor<Vec<u8>>> {
    let mut buffer = Vec::new();
    reader.read_to_end(&mut buffer)?;
    Ok(Cursor::new(buffer))
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions