Passing callbacks into JS object constructor with embind in C++ - javascript

I am looking for a way to instantiate and use VideoDecoder in C++ code of webassembly app. Here is an example of the setup:
const decoder = new VideoDecoder({
output(frame)
{
renderFrame(frame);
},
error(e)
{
setStatus("decode", e);
}});
VideoDecoder class constructor has the following signature:
const videoDecoder = new VideoDecoder({
output: processVideo,
error: onEncoderError,
});
In cpp I initiate VideoDecoder like this:
static void OnVideoFrame(emscripten::val frame)
{
}
static void OnError(emscripten::val error)
{
}
struct DecodeSettings_t
{
void (*output)(emscripten::val);
void (*error)(emscripten::val);
};
void VideoManager::Init(){
emscripten::val VideoDecoder = emscripten::val::global("VideoDecoder");
DecodeSettings_t set;
set.output = &OnError;
set.error = &OnVideoFrame;
videoDecoderInst = VideoDecoder.new_(set);
}
When launching the app I am getting the following error:
{name: 'BindingError', message: 'parameter 0 has unknown type
N2sn16DecodeSettings_tE', stack: 'BindingError: parameter 0 has
unknown type ..}
Looks like DecodeSettings_t struct is unrecognized, which kind of makes sense. So I tried to simulate a dynamic JS object creation in C++ and passing it into the constructor:
emscripten::val obj = emscripten::val::object();
obj.set("output", &OnVideoFrame);
obj.set("error", &OnError);
videoDecoderInst = VideoDecoder.new_(obj);
Now I am getting this error on web app startup:
RuntimeError: Aborted(LinkError: WebAssembly.instantiate(): Import
#116 module="env" function="_emval_new_object" error: function import requires a callable)
What am I missing here?

Related

com.google.gwt.core.client.JavaScriptException: (TypeError) when I call method from constant in JS file from GWT

I have a file with this JS
const sdk = new ChartsEmbedSDK({
baseUrl: 'https://mongodb.com....',
});
const chart = sdk.createChart({chartId: '1111111111111111111111111111'});
function loadDashboard() {
chart.render(document.getElementById('chart'));
}
And call that from GWT code:
public static native void loadDashboard() /*-{
$wnd.loadDashboard();
}-*/;
It works. But when I do next In JS:
const sdk = new ChartsEmbedSDK({
baseUrl: 'https://mongodb.com....',
});
const chart = sdk.createChart({chartId: '1111111111111111111111111111'});
and call:
public static native void loadDashboard() /*-{
$wnd.chart.render($doc.getElementById('chart'));
}-*/;
I get error:
Caused by: com.google.gwt.core.client.JavaScriptException: (TypeError) : ((intermediate value)(intermediate value) , $wnd).chart.render is not a function

Get the calling object

I am using websocket from node, and I am trying to implement a broadcast method that will send a message to all clients except for the client that sent the message.
To do this, I need to know the
export class WebSocketRoom {
private _clients: WebSocketConnection[] = []
public get clients(): WebSocketConnection[] { return this._clients }
public broadcast(event: string, message: any) {
this.clients.forEach(client => {
client.emit(event, message)
})
return this
}
}
To access the method broadcast, I do this:
class Test extends Module {
public constructor(client: WebSocketConnection) {
super(client)
let room = new WebSocketRoom('hi')
room.broadcast('cool', 'sweet')
}
}
I tried doing a console log of WebSocketRoom.caller but that gives me this error:
TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.
Is there a way that I can access the object that called broadcast from within the broadcast method without passing it as a parameter?
this.clients.forEach(client => {
if(client == sender) return
client.emit(event, message)
})
Side note
In C#, it is done like so:
public static void MyMethod(this GameObject obj, int var1, int var2) {
obj.add(var1, var2)
}
MyMethod(1,2)
As you can see obj is not passed in when it is called.

JavaScript: Parse Java source code, extract method

I'm trying to build a module that returns all methods of a given Java source code using nodeJs. So far I can get the AST tree built using "java-parser" module but I need to traverse it to filter out methods.
code = ' public class CallingMethodsInSameClass
{
public static void main(String[] args) {
printOne();
printOne();
printTwo();
}
public static void printOne() {
System.out.println("Hello World");
}
public static void printTwo() {
printOne();
printOne();
} }';
var javaParser = require("java-parser");
var traverse = require("babel-traverse").default;
var methodsList = [];
traverse(ast, {
enter(path){
//do extraction
}
}
I understand that babel-traverse is for Js but I wanted a way to traverse so I can filter the methods.
I'm getting this error
throw new Error(messages.get("traverseNeedsParent", parent.type));
^
Error: You must pass a scope and parentPath unless traversing a
Program/File. Instead of that you tried to traverse a undefined node
without passing scope and parentPath.
The AST if logged looks like
{ node: 'CompilationUnit',
types:
[ { node: 'TypeDeclaration',
name: [Object],
superInterfaceTypes: [],
superclassType: null,
bodyDeclarations: [Array],
typeParameters: [],
interface: false,
modifiers: [Array] } ],
package: null,
imports: [] }
where a method will be identified by "MethodDeclaration" within types. Any help is appreciated.
The AST is just another JSON object. Try jsonpath.
npm install jsonpath
To extract all methods, just filter on condition node=="MethodDeclaration":
var jp = require('jsonpath');
var methods = jp.query(ast, '$.types..[?(#.node=="MethodDeclaration")]');
console.log(methods);
See here for more JSON path syntax.

DeSerializing JSON string into a TS object

I am struggling over what should appear to be a very simple procedure.
In the "geolocate.ts" function "setData", the model indexes? "flightplan" and "config" are shown by Chrome debugger to be "undefined" when referenced from "model.flightplan" or "model.config". The "model" object itself seems to be fine even when expanded in the debugger.
Any thoughts or pointers would be very much appreciated ;)
geolocate.d.ts
export class FmsFlightPlan {
public status: string[];
...
}
export class Config {
public airportIcon: IconSettings;
...
}
export class InitModel {
public config: Config;
public flightplan: FmsFlightPlan;
}
geolocate.ts
import * as passedData from "./geoLocate.d";
let config: passedData.Config;
let flightPlan: passedData.FmsFlightPlan;
export function setModel( json: string): void {
console.log( json); // '{"Config": { "AirportIcon": {...} ...}, {"Flightplan": {"Status": [], ... } ...}' --- As expected (JSONlint OK)
const model: passedData.InitModel = JSON.parse( json);
console.log(model); // Chrome console: {Config: {…}, Flightplan: {…}}
flightPlan = model.flightplan; // flightPlan and config are assigned "undefined"
config = model.config; // "model" looks OK and Intellisense works.
flightplanDraw();
}
TSC generated javascript
function setModel(o) {
console.log(o);
var e = JSON.parse(o);
console.log(e), flightPlan = e.flightplan, config = e.config, flightplanDraw()
}
.NET Core View Javascript
function gmapsReady() {
initMap();
$.getJSON("/Home/GetConfig",
null,
function(data) {
setModel(data);
});
}
.NET MVC Controller
public JsonResult GetConfig()
{
// Load fplan and config objects
...
...
InitModel initModel = new InitModel
{
Flightplan = fplan,
Config = _config
};
string json = JsonConvert.SerializeObject(initModel);
return new JsonResult(json);
}
A first issue seems to be that you are accessing fields like flightplan and config, whereas in the JSON they are FlightPlan and Config. That's why you're getting undefineds.
A slightly bigger issue after that, which will mostly bite you if you plan on adding methods to your classes, is that the thing produced by JSON.parse is a simple JavaScript object, whereas Config, FlightPlan etc are classes, and instances of them would belong to that class. So if you had something like this:
let x = new Config();
x.airportIcon = 'foo';
console.log(x.constructor); // Prints 'Config'
let y = JSON.parse('{"airportIcon": "foo"}');
console.log(y.constructor); // Prints 'Object something or other'
So the two are structurally equivalent, but won't be functionally equivalent. Even by doing a TS cast you won't be able to call a function on y as you would on x. If these are simple DTOs than that's OK. But if not, you need to be explicit about this and do another step of translating from the JS object to your application ones.
Shameless plug: I wrote raynor to automate this exact process - of translating between a DTO type and a more useful JavaScript class.
You can also configure the JSON serializer on .net side to convert field names from PascalCase to 'camelCase`.

Why am I receiving a typescript error when migrating a Paho MQTT function from Angular 1 to Angular 2?

I am attempting to do several things on connecting to my MQTT broker, I have created an mqtt provider in my ionic 2, angular 2 application, the provider is given below:
import { Component } from '#angular/core';
import { NavController, ViewController } from 'ionic-angular';
import { Observable } from 'rxjs/Observable';
import { Paho } from 'ng2-mqtt/mqttws31';
#Component({
selector: 'page-greywater',
templateUrl: 'greywater.html'
})
export class MQTT_Greenchain {
private _client: Paho.MQTT.Client;
private options = {
userName: 'rdjghvoh',
password: 'w7Ex0VTqZViw',
timeout: 30,
useSSL:true,
onSuccess:this.onConnected,
};
private topic: string;
public displayedMessage: string;
public mes: Paho.MQTT.Message;
public constructor() {
this._client = new Paho.MQTT.Client(
"m20.cloudmqtt.com",
Number(30775),
"",
"peter"
);
this._client.onConnectionLost = (responseObject: {errorCode: Number, errorMessage: string}) => {
console.log('poes');
console.log(responseObject.errorMessage);
};
this._client.onMessageArrived = (message: Paho.MQTT.Message) => {
this.onMessageArr(message);
console.log('Message arrived.');
};
this.topic = "haha";
this.displayedMessage = "what I was";
}
connectMe() {
console.log("MQTT OPTIONS: " + this.options);
this._client.connect(this.options);
}
private onConnected(): void {
console.log('Connected to broker.');
this._client.subscribe(this.topic);
this.mes = new Paho.MQTT.Message("-1"); // -1 => Notify
this.mes.destinationName = this.topic;
this._client.send(this.mes);
}
private onMessageArr(message: Paho.MQTT.Message){
this.displayedMessage = message.payloadString;
}
}
I have been able to call the following in angular 1 without trouble, and I was able to get everything MQTT-related, working. The function in angular 1 is as follows:
function onConnect() {
sharedUtils.hideLoading();
console.log("onConnect, CURRENT TOPIC: " + mqttData);
client.subscribe(mqttData.currentTopic);
}
In the above, mqttData.currentTopic is merely a string.
The function accepts 1 argument, even though it can accept 2 (an options object).
In angular 2, typescript gives me an error:
Supplied parameters do not match any signature of call target
Why is it not allowing me to call the function with one argument as in angular 1? If I give it {} as a second argument:
this._client.subscribe(this.topic, {});
I am given the error that:
AMQJS0005E Internal error. Error Message: Cannot read property 'subscribe' of undefined, Stack trace: TypeError: Cannot read property 'subscribe' of undefined
This is the error received in the response object parameter, passed to the onConnectionLost callback function.
I am quite certain that my 'this._client' is not undefined since the message 'Connected to broker.' appears in the console, indicating that onConnected, the onSuccess property callback of the connect method was obviously called?
What am I not getting here?
Try this and reply if it is working fine
this.client.subscribe(this.topic, '');

Categories