Invalid function signature when loading Rust-generated webassembly binary from Python - javascript

The full code is here:
https://github.com/dmerejkowsky/chuck-norris-webassembly-plugins
Here's what's wrong
There's a get_fact method written in Rust and exported with wasm_bindgen:
#[wasm_bindgen]
pub fn get_fact() -> String {
"Chuck Norris can slam a revolving door".to_string()
}
When I build the wasm file with wasm-pack --target nodejs I can call the get_fact just fine from Javascript:
const assert = require('node:assert/strict');
const ck = require('../pkg/chuck_norris.js');
const actual = ck.get_fact();
assert.ok(actual.includes("Chuck Norris"));
But when trying to write the same test in Python:
from wasmer import engine, Store, Module, Instance
from wasmer_compiler_cranelift import Compiler
rust_wasm = Path / "to" / "chucknorris_bg.wasm"
store = Store(engine.Universal(Compiler))
module = Module(store, rust_wasm.read_bytes())
instance = Instance(module)
get_fact = instance.exports.get_fact
actual = get_fact()
assert "Chuck Norris" in actual
I get :
RuntimeError: Parameters of type [] did not match signature [I32] -> []
Any clues as to why NodeJs and Python disagree on the signature of the get_fact() function ?

Answering myself: you cannot use webassembly with strings this way. More info on this blog post: https://medium.com/wasm/strings-in-webassembly-wasm-57a05c1ea333

Related

Node.js basic error: Uncaught TypeError: Binance is not a function

newbie here! I'm trying to make a basic ping to the Binance crypto exchange using its exposed REST API and node.js. Instead of coding everything from 0, I'm planning to use a wrapper package in https://github.com/binance-exchange/binance-api-node that facilities interaction. I've downloaded the binance-api-node code from github into my node.js project.
After installing the package, when trying to run the included basic getting-started code to get the time from the server:
import Binance from 'binance-api-node';
const client = Binance();
client.time().then(time => console.log(time));
I’m getting this error:
Uncaught TypeError: Binance is not a function
I also tried:
const client = new Binance();
but I get another error saying Binance is not a constructor.
This is the function declaration in the index.d.ts of binance-api-node
declare module 'binance-api-node' {
export default function(options?: {
apiKey?: string
apiSecret?: string
getTime?: () => number | Promise<number>
httpBase?: string
httpFutures?: string
wsBase?: string
wsFutures?: string
proxy?: string
}): Binance
...
Any help will be appreciated.
Thanks!
As stated in documentation:
If you do not have an appropriate babel config, you will need to use the basic commonjs requires:
const Binance = require('binance-api-node').default
const client = Binance();
Or like this, it worked for me:
import Binance from 'binance-api-node';
const client = Binance.default();

Read strongly typed yaml file in Typescript?

I have the following yaml file:
trainingPhrases:
- help me
- what to do
- how to play
- help
I readi it from disk using readFile from node and parse it using load from js-yaml:
import { load } from "js-yaml";
import { readFile } from "fs/promises";
const phrases = load(await readFile(filepath, "utf8")).trainingPhrases as string[];
I get the following eslint warning:
ESLint: Unsafe member access .trainingPhrases on an any value.(#typescript-eslint/no-unsafe-member-access)
Instead of suppressing the warning, I would like to map it into a concrete type for the YAML file (as it happens in axios for example: axios.get<MyResponseInterface>(...) - performs a GET and MyResponseInterface defines the structure of the HTTP response).
Is there a dedicated library for that?
From what I can see when using #types/js-yaml is that load is not generic, meaning it does not accept a type parameter.
So the only way to get a type here is to use an assertion, for example:
const yaml = load(await readFile(filepath, "utf8")) as YourType;
const phrases = yaml.trainingPhrases;
Or in short:
const phrases = (load(await readFile(filepath, "utf8")) as YourType).trainingPhrases;
If you absolutely want a generic function, you can easily wrap the original, like:
import {load as original} from 'js-yaml';
export const load = <T = ReturnType<typeof original>>(...args: Parameters<typeof original>): T => load(...args);
And then you can use it as:
const phrases = load<YourType>('....').trainingPhrases;

How to calculate checksum in React Native and Node?

I'm uploading an image file from React Native to AWS Lambda (Node 10.x) and want to verify the hash of the file I've sent matches the file received. To do this I'm using hashing in React Native and again in Lambda, but the hashes never match. Here are the relevant bits of code I've tried.
React Native
import RNFS from "react-native-fs";
const contentChecksum = await RNFS.hash(post.contentUrl, "md5");
Lambda (Node)
import AWS from "aws-sdk";
const crypto = require("crypto");
const s3 = new AWS.S3();
const data = await s3
.getObject({
Bucket: file.bucket,
Key: file.key
})
.promise();
const contentChecksum = crypto
.createHash("md5")
.update(data.Body)
.digest("hex");
These checksums never match. I've tried using base64 encoding in Node (data.Body.toString("base64")) and also sha256. What is the trick to calculating the checksum so they match in React Native and Node?
Edit: Here are the results from a recent test.
post.contentUrl: file:///Users/xxxxxxx/Library/Developer/CoreSimulator/Devices/2F2F4FD3-574E-40D7-BE6B-7080E926E70A/data/Containers/Data/Application/65A3FF67-98B2-444D-B75D-3717C1274FBC/Library/Caches/Camera/FDCD8F90-D24F-4E64-851A-96AB388C4B59.jpg
(the file is local on an iPhone)
contentChecksum from React Native: 48aa5cdb30f01719a2b12d481dc22f04
contentChecksum from Node (Lambda): 7b30b61a55d2c39707082293c625fc10
data.Body is a Buffer.
I also note that the eTag attribute on the S3 object matches the md5 checksum I'm calculating in Node. Since eTag is usually the md5 hash of the file, this tells me that I'm likely calculating the hash incorrectly in React Native, but I'm not sure how. I'm using the hash function from the react-native-fs package.
You can use the same code on React and AWS Lambda, that is Node.js.
So in your React.js application you could use the following code:
import * as React from 'react';
import crypto from 'crypto';
var key = 'YOUR_KEY';
export default class Test extends React.Component {
render() {
var hash = crypto.createHash('md5').update(key).digest('hex');
return (
<div>
{hash}
</div>
)
}
}
And the variable hash have to contains the same value you get on AWS.
In order to run you have to install the crypto library:
npm i --save react-native-crypto
Change the variable YOUR_KEY, then run the application:
npm start
And in the browser you should get:
4b751fef5e9660e3943173fd3e6c4224
You can use the crypto module.
To get a list of all available hash algorithms, you can use crypto.getHashes().
Here is a Nodejs example:
var crypto = require('crypto')
crypto.getHashes() // [ 'dsa', 'dsa-sha', ..., 'md5', ... ]
Here is a helper method for generating checksum value from string input:
var crypto = require('crypto')
function checksum(str, algorithm, encoding) {
return crypto
.createHash(algorithm || 'md5')
.update(str, 'utf8')
.digest(encoding || 'hex')
}
checksum('This is my test text');
checksum('This is my test text', 'sha1');

How to gracefully convert a Windows path to a Unix path using JavaScript? [duplicate]

I'm developing on windows, but need to know how to convert a windows path (with backslashes \) into a POSIX path with forward slashes (/)?
My goal is to convert C:\repos\vue-t\tests\views\index\home.vue to C:/repos/vue-t/tests/views/index/home.vue
so I can use it in an import on a file I'm writing to the disk
const appImport = `
import Vue from "vue"
import App from '${path}'
function createApp (data) {
const app = new Vue({
data,
render: h => h(App)
})
return app
}`
//this string is then written to the disk as a file
I'd prefer not to .replace(/\\/g, '/') the string, and would rather prefer to use a require('path') function.
Given that all the other answers rely on installing (either way too large, or way too small) third party modules: this can also be done as a one-liner for relative paths (which you should be using 99.999% of the time already) using Node's standard library path module, and more specifically, taking advantage of its dedicated path.posix and path.win32 namespaced properties/functions (introduced in Node v0.11):
const path = require("path");
// ...
const definitelyPosix = somePathString.split(path.sep).join(path.posix.sep);
This will convert your path to POSIX format irrespective of whether you're already on a POSIX compliant platform, or on Windows, without needing any kind of external dependency.
Slash converts windows backslash paths to Unix paths
Usage:
const path = require('path');
const slash = require('slash');
const str = path.join('foo', 'bar');
slash(str);
// Unix => foo/bar
// Windows => foo/bar
There is node package called upath will convert windows path into unix.
upath = require('upath');
or
import * as upath from 'upath';
upath.toUnix(destination_path)
For those looking for an answer that doesn't depend on Node.js
One Liner (no 3rd party library)
//
// one-liner
//
let convertPath = (windowsPath) => windowsPath.replace(/^\\\\\?\\/,"").replace(/\\/g,'\/').replace(/\/\/+/g,'\/')
//
// usage
//
convertPath("C:\\repos\\vue-t\\tests\\views\\index\\home.vue")
// >>> "C:/repos/vue-t/tests/views/index/home.vue"
//
// multi-liner (commented and compatible with really old javascript versions)
//
function convertPath(windowsPath) {
// handle the edge-case of Window's long file names
// See: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#short-vs-long-names
windowsPath = windowsPath.replace(/^\\\\\?\\/,"");
// convert the separators, valid since both \ and / can't be in a windows filename
windowsPath = windowsPath.replace(/\\/g,'\/');
// compress any // or /// to be just /, which is a safe oper under POSIX
// and prevents accidental errors caused by manually doing path1+path2
windowsPath = windowsPath.replace(/\/\/+/g,'\/');
return windowsPath;
};
// dont want the C: to be inluded? here's a one-liner for that too
let convertPath = (windowsPath) => windowsPath.replace(/^\\\\\?\\/,"").replace(/(?:^C:)?\\/g,'\/').replace(/\/\/+/g,'\/')
Normally I import libraries. However, I went and read the source code for both slash and upath. The functions were not particularly up to date, and incredibly small at the time I checked. In fact, this one liner actually handles more cases than the slash library. Not everyone is looking for this kind of solution, but for those that are, here it is. By coincidence this has the fastest runtime of all the current answers.
I was looking for something similar, but a little more universal especially to include drives in the absolute path. Thus if you work with e.g. git-bash or WSL usually drives are mapped by default as letters from root / (git-bash) or /mnt (WSL). So here is a regex that does the job for me
// For git-bash Windows drives are mounted in the root like /C/ /D/ etc.
const toGitBashPosixPath = (windowsPath) => windowsPath.replace(/^(\w):|\\+/g,'/$1');
console.log(toGitBashPosixPath('c:\\\\\\project\\file.x')); // messy Windows path
console.log(toGitBashPosixPath('c:\\project\\file.x')); // regular Windows path
console.log(toGitBashPosixPath('c:/project/file.x')); // slash path acceptable by Windows
console.log(toGitBashPosixPath('project\\file.x'));// relative Windows path
console.log(toGitBashPosixPath('.\\project\\file.x'));// another relative Windows path
// For WSL Windows drives are mounted by default next to /mnt like /mnt/C/ /mnt/D/ etc.
const toWSLPosixPath = (windowsPath) => windowsPath.replace(/^(\w):|\\+/g,'/$1').replace(/^\//g,'/mnt/');
console.log(toWSLPosixPath('c:\\project\\file.x'))
Hopefully this will help someone.
Just use default lib as:
const {direname, resolve, basename}= require('path').posix;
or
import {posix} from 'path';
const {direname, resolve, basename}= posix;
const winPath = 'C:\\repos\\vue-t\\tests\\views\\index\\home.vue'
const posixPath = winPath.replace(/\\/g, '/').slice(2)
// Now posixPath = '/repos/vue-t/tests/views/index/home.vue'

TypeScript: Handling import from external libraries

I just started using Famo.us and wanted to use it as an opportunity to learn typescript at the same time to leverage on its awesomeness. So I did the following
Used yo famous to create the Famo.us project as per the documentation
I was not sure how to include typescript so I created a typeScriptHTML project, copies the .csproj file over and manually edited it. I tried using the NVTS and specified that it should create it from an existing folder but I always got an error saying that the file path was too long. It checked and some of the modules have very long path. Couldn't even delete them and the system was saying the same thing. In the end I discarded the idea and used the typescript html application. It generated no errors.
I added a file app.ts, wrote some sample code in it and it generated the js file as expected.
Now I wanted to translate main.js to main.ts and I'm stuck with the following issues
i. var Engine = require('famous/core/Engine'); gives the error could not find symbol 'require'.
ii. import Engine = require('famous/core/Engine') gives the error: Unable to resolve external module "famous/core/Engine". Changing the path to "../lib/famous/core/Engine" gives a similar error with a different file name.
iii. Created a file Famous.d.ts but I don't think I'm getting it I'm not doing something right
declare module "famous/core/Engine" {
class Engine{
public createContext(): Engine
}
export = Engine
}
In the end, my confusion is how to I translate the sample code to typescript:
/*globals define*/
define(function(require, exports, module) {
'use strict';
///first
var Engine = require('famous/core/Engine');
var DeviceView = require('./DeviceView');
var mainContext = Engine.createContext();
var device;
createDevice();
function createDevice() {
var deviceOptions = {
type: 'iphone',
height: window.innerHeight - 100
};
device = new DeviceView(deviceOptions);
mainContext.add(device);
}
});
Any assistance appreciated.
It turned out to be a lot easier than I thought. One way was to declare the class and export it as a module
declare class Engine{
...
}
export module 'famous/core/Engine'{ export = Engine; }
Manage to get a tiny definition of famous running using this.

Categories

Resources