Search code examples
server-sideassemblyscriptwasi

Server-side AssemblyScript: How to read a file?


I'd like to write some server-side AssemblyScript that uses the WASI interface to read a file and process the contents.

I know that AssemblyScript and the ByteCode Alliance have recently had a falling out over the "openness" of the WASI standard, but I was hoping that they would still play nicely together...

I've found several AssemblyScript tools/libraries that appear to bridge this gap, and the one that seems the simplest to use is as-wasi. After following the installation instructions, I'm just trying to run the little demo app.

All the VSCode design time errors have disappeared, but the AssemblyScript compiler still barfs at the initial import statement.

import "wasi"

import { Console, Environ } from "as-wasi/assembly";

// Create an environ instance
let env = new Environ();

// Get the HOME Environment variable
let home = env.get("HOME")!;

// Log the HOME string to stdout
Console.log(home);

Running npm run asbuild gives.

$ npm run asbuild

> [email protected] asbuild
> npm run asbuild:debug && npm run asbuild:release


> [email protected] asbuild:debug
> asc assembly/index.ts --target debug

ERROR TS6054: File '~lib/wasi.ts' not found.
   :
 1 │ import "wasi"
   │        ~~~~~~
   └─ in assembly/index.ts(1,8)

FAILURE 1 parse error(s)

The file ~lib/wasi.ts does not exist and creating this file as a softlink pointing to the index.ts in the ./node_modules/as-wasi/assembly/ directory makes no difference.

Since the library is called as-wasi and not wasi, I've tried importing as-wasi, but this also fails.

I've also tried adapting tsconfig.json to include

{
  "extends": "assemblyscript/std/assembly.json",
  "include": [
    "../node_modules/as-wasi/assembly/*.ts",
    "./**/*.ts"
  ]
}

But this also has no effect.

What is causing asc to think that the required library should be in the directory called ~lib/ and how should I point it to the correct place?

Thanks


Solution

  • Your question threw me in a bit of a rabbit hole, but I think I solved it.

    So, apparently, after the wasi schism, AssemblyScript added the wasi-shim repository, that you have to install as well:

    npm install --save wasi-shim
    

    The import "wasi" is no longer necessary after version 0.20 of AssemblyScript according to the same page, so you have to remove that import entirely. Also, be sure to add the extends to your asconfig.json, as recommended in the same wasi-shim page. Mine looks like this:

    {
      "extends": "./node_modules/@assemblyscript/wasi-shim/asconfig.json",
      "targets": {
        "debug": {
          "outFile": "build/debug.wasm",
          "textFile": "build/debug.wat",
          "sourceMap": true,
          "debug": true
        },
        "release": {
          "outFile": "build/release.wasm",
          "textFile": "build/release.wat",
          "sourceMap": true,
          "optimizeLevel": 3,
          "shrinkLevel": 0,
          "converge": false,
          "noAssert": false
        }
      },
      "options": {
        "bindings": "esm"
      }
    }
    

    It is just the generated original asconfig.json plus that extends.

    Now the things got interesting. I got a compilation error:

    ERROR TS2300: Duplicate identifier 'wasi_abort'.
          :
     1100 │ export function wasi_abort(
          │                 ~~~~~~~~~~
          └─ in ~lib/as-wasi/assembly/as-wasi.ts(1100,17)
        :
     19 │ export function wasi_abort(
        │                 ~~~~~~~~~~
        └─ in ~lib/wasi_internal.ts(19,17)
    

    So I investigated, and it seems that as-wasi was exporting a symbol that was the same as a symbol exported by wasi_shim. No biggie, I went into node_modules/as-wasi/, and I renamed that function into as_wasi_abort. I did this also with the invokations of the function, namely three instances found in the package.json from as-wasi:

    {
        "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --use abort=as_wasi_abort --debug",
        "asbuild:small": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --use abort=as_wasi_abort -O3z ",
        "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --use abort=as_wasi_abort -O3",
    }
    

    Having done all this, the package compiled and the example from Wasm By Example finally worked.

    Your code should compile now, and I will try to make a pull request to all the places necessary so that the examples are updated, the code in as-wasi is updated, and so that nobody has to go through this again. Please comment if there are further problems.

    Edit: It seems that I was right about the wasi_abort function being a problem. It is actually removed on the as-wasi repo, but the npm package is outdated. I asked in my pull request for it to be updated.