O WebAssembly foi originalmente projetado para fornecer aos aplicativos da Web no navegador uma maneira de executar binários portáteis, em área restrita e de alto desempenho. À medida que o WASM amadurece além do navegador, novos usos para a tecnologia surgem. Usar o WASM para criar programabilidade e extensibilidade em aplicativos é um caso de uso que está ganhando força.
A biblioteca de software Extism permite escrever programas que podem interagir com extensões escritas em WebAssembly. O Extism lida com a interface de chamada de dados e funções entre o código escrito em seu aplicativo host e as extensões WASM. Isso permite que você se concentre em escrever a funcionalidade em seu aplicativo e extensões, em vez de lidar manualmente com os tipos de dados ou convenções de chamada do WASM.
Escrevendo um aplicativo baseado no Extism
A biblioteca Extism funciona com praticamente qualquer linguagem amplamente utilizada. Atualmente, suporta C/C++, Java, JavaScript, Go, Rust, Ruby, Python, a família de linguagens .NET (C# e F#, em particular), Elixir, PHP, OCaml, Zig, Haskell e D. Desde a biblioteca em si é escrito em Rust e expõe uma interface do tipo C, qualquer linguagem com uma interface de função externa C pode suportar o Extism com um pouco de trabalho.
Plugins, ou extensões WASM, podem ser escritos em qualquer linguagem que seja compilada para WASM. Rust é uma escolha óbvia, sendo a linguagem em que o Extism está escrito, mas os desenvolvedores podem usar AssemblyScript (que compila diretamente para WASM) ou JavaScript, Go, C#, F#, C, Haskell ou Zig.
A filosofia do Extism é apoiar a escrita de programas de tal forma que sua funcionalidade possa ser estendida livremente com plugins escritos em WASM. Essa extensibilidade pode ser tão superficial ou profunda quanto você desejar. O tempo de execução WASM do Extism também lida automaticamente com coisas como execução de sandbox e acesso à memória. Como tal, fornece mais proteção ao processo do que outras soluções que você pode usar para expandir a funcionalidade de um programa, como incorporar um interpretador Lua.
Exemplo de um plugin Extism
Aqui está um exemplo simples de um plugin Extism e um aplicativo host que o utiliza. O plugin tem uma única função, greet
, que recebe uma string e retorna uma saudação usando a string fornecida. Esta encarnação do plugin (também adaptado dos documentos do Extism) é escrita em AssemblyScript para simplificar:
import { Host } from '@extism/as-pdk';
export function greet(): i32 {
let name = Host.inputString();
let output = `Hello, ${name}!`;
Host.outputString(output);
return 0;
}
O kit de desenvolvimento de plugins Extism, ou PDK, fornece objetos que usamos para criar interfaces com o mundo exterior. O Host
O objeto contém várias abstrações para receber a entrada do host e retorná-la em diferentes formatos — neste caso, strings. Outra opção é receber e retornar JSON, já que é uma maneira conveniente de lidar com dados estruturados no Extism, mas strings funcionam para este exemplo.
Também precisamos definir quais funções do nosso plugin estão disponíveis externamente. Isso varia entre as linguagens, mas no AssemblyScript é feito através do export
palavra-chave. Também poderíamos definir recursos avançados de tratamento de erros — por exemplo, uma função a ser chamada se o próprio plug-in gerar um erro — mas deixaremos isso de fora para simplificar.
Exemplo de um aplicativo Extism
Para escrever um aplicativo que usa um plug-in Extism, você usa a biblioteca Extism da linguagem que está usando para escrever o aplicativo. Para este exemplo, usaremos Python, já que tanto a linguagem quanto a forma como o Extism trabalha com ela são bastante simples.
Aqui está o programa Python que estamos usando para trabalhar com este plugin:
import extism
manifest = {"wasm": ({"path":"myplugin/example.wasm"})}
plugin = extism.Plugin(manifest)
def greet(text: str):
return plugin.call("greet", text)
print(greet("Jeffrey"))
Execute isso e você receberá a resposta: Hello, Jeffrey!
Para usar nosso plugin, precisamos criar um manifesto – um dicionário Python, neste caso – que descreva onde o plugin pode ser encontrado (aqui, está em um subdiretório do projeto chamado myplugin
). Os manifestos também podem ser usados para descrever outros comportamentos, como quanta memória o plugin pode alocar ou quais caminhos no disco ele pode usar.
Depois de criarmos um objeto para representar o plugin, podemos fazer chamadas de função para ele usando o comando .call()
método.
Observe que este exemplo simples funciona apenas para um único plugin predeterminado. Se seu aplicativo quiser aceitar plug-ins arbitrários, ele precisará definir interfaces para conectar os plug-ins. Ele pode então descobrir a presença de plug-ins automaticamente ou usar algum tipo de metadado fornecido pelo usuário.
Conclusão
O extismo, como o próprio WASM, é relativamente jovem e seus melhores casos de uso ainda estão em evolução. Com sua baixa barreira de entrada tanto para escrever plug-ins WASM quanto para criar aplicativos que os utilizam, o Extism é uma maneira útil de experimentar o WASM fora do navegador. Você colherá os frutos em descobertas e dividendos.