Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Are TypedArray slice() and subarray() implemented? #115

Closed
guest271314 opened this issue May 8, 2022 · 3 comments
Closed

Are TypedArray slice() and subarray() implemented? #115

guest271314 opened this issue May 8, 2022 · 3 comments

Comments

@guest271314
Copy link

I am implementing a Native Messaging (https://developer.chrome.com/docs/apps/nativeMessaging/#native-messaging-host-protocol) host in QuickJS and txiki.js.

During testing I noticed when slice() and subarray() are executed a) QuickJS exits; 2) txiki.js does not exit, yet does not slice or get subarray of Uint8Array.

The actual use case beyong echoing simple messages is using popen() to stream content, potentially indefinely, as implemented in C++ (https://github.com/guest271314/captureSystemAudio/blob/master/native_messaging/capture_system_audio/capture_system_audio.cpp) and Python (https://github.com/guest271314/captureSystemAudio/blob/master/native_messaging/capture_system_audio/capture_system_audio.py).

Without the use of slice() and subarray() I also noticed that popen() appears to block. This issue is specifically to address the question of whether or not TypedArray slice() and subarray() methods are implemented by the engine?

Code

#!/usr/bin/env -S /path/to/qjs -m --std
// QuickJS Native Messaging host
// guest271314, 5-6-2022
import * as std from 'std';
import * as os from 'os';

async function getMessage() {
  const header = new Uint8Array(4);
  std.in.read(header.buffer, 0, header.length);
  // https://stackoverflow.com/a/26140545
  const length = new Uint32Array(header.buffer).reduce(
    (a, b, index) => (a = a | (b << (index * 8))),
    0
  );
  const output = new Uint8Array(length);
  std.in.read(output.buffer, 0, length);

  /*
  const stream = std.popen("pwd", "r");
  while (true) {
    const data = new Uint8Array(1024);
    stream.read(data.buffer, 0, 1024);
    sendMessage(data);
    stream.flush();
    stream.close();
  }
  */  
  // for (let i = 0; i < 10; i++) {
  //   await sendMessage(await encodeMessage(new Uint8Array([i])));
  // }
  return output;

}

async function encodeMessage(message) {
  // https://stackoverflow.com/a/24777120
  const header = Uint32Array.from(
    {
      length: 4,
    },
    (_, index) => (message.length >> (index * 8)) & 0xff
  );
  const output = new Uint8Array(header.length + message.length);
  output.set(header, 0, true);
  output.set(message, 4, true);
  return output;

}

async function sendMessage(message) {
  std.out.write(message.buffer, 0, message.length);
  std.out.flush();
  return true;
}

async function main() {
  while (true) {
    const message = await getMessage();
    await sendMessage(await encodeMessage(message));
    await sendMessage(await encodeMessage(message.reverse()));
    await sendMessage(message.slice(1)); // exits
    await sendMessage(message.subarray(1)); // exits
    for (let i = 0; i < message.length; i++) {
      await sendMessage(message.subarray(i)); // does not send message to client
    }
    // doesn't work
    /*
    const stream = std.popen(String.fromCharCode.apply(null, message) "r");
    while (true) {
      const data = new Uint8Array(1024);
      stream.read(data.buffer, 0, 1024);
      await sendMessage(await encodeMessage(data));
      stream.flush();
    }
    */
  }
}

main();
@guest271314
Copy link
Author

It appears that the issue is std.open() which blocks when called inside of a Native Messaging host.

This code outputs the expected result when run in a standalone file

test1.js

#!/usr/bin/env -S /path/to/qjs -m --std
import * as std from 'std';
import * as os from 'os';
const stream = std.popen("ls -l", "r");
const data = new Uint8Array(1024);
stream.read(data.buffer, 0, 1024);
console.log(String.fromCharCode.apply(null, data));

when run inside of a Native Messaging host the process does not pipe data.

@guest271314
Copy link
Author

When read() is executed with 1 passed as third parameter I can read for a fraction of a second, with CPU rising to 99-100%.

async function main() {
  while (true) {
    const message = await getMessage();
    const data = new Uint8Array(1);
    const stream = std.popen("parec -d @DEFAULT_MONITOR@", "r");
    while (true) {     
        stream.read(data.buffer, 0, 1);
        await sendMessage(await encodeMessage(data));
        stream.flush();
    }    
  }
}

@guest271314
Copy link
Author

I tried with exec() with block set the false. Only 1 number streams per line to the client, memory usage increased from 3.3MB to 28MB, CPU is consistently over 95%, initially freezing the OS.

    let fds = os.pipe();
    let pid = os.exec(["sh", "-c", "parec -d @DEFAULT_MONITOR@"], {
        stdout: fds[1],
        block: false
    } );

   let f = std.fdopen(fds[0], "r");
    while (true) {     
      let d = new Uint8Array([...f.getline()].map(s => s.codePointAt(0) & 0xff));
      await sendMessage(await encodeMessage(d));
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant