Preparar o código do plug-in

O código personalizado criado para plug-ins do Service Extensions precisa ser empacotado e enviado ao Artifact Registry antes que outros serviços possam acessá-lo. Esta página descreve como criar código de plug-in, empacotar o código e fazer upload dele para um repositório do Artifact Registry.

Esse recurso está em pré-lançamento para a Media CDN.

Para mais informações sobre as Service Extensions, consulte Visão geral das Service Extensions.

Antes de começar, consulte as práticas recomendadas para escrever código de plug-in.

Para mais exemplos, consulte Exemplos de código para plug-ins.

Antes de começar

  1. Faça login na sua conta do Google Cloud . Se você começou a usar o Google Cloud, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. Instale a CLI do Google Cloud.

  6. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na gcloud CLI com sua identidade federada.

  7. Para inicializar a gcloud CLI, execute o seguinte comando:

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  11. Instale a CLI do Google Cloud.

  12. Ao usar um provedor de identidade (IdP) externo, primeiro faça login na gcloud CLI com sua identidade federada.

  13. Para inicializar a gcloud CLI, execute o seguinte comando:

    gcloud init

Configurar o conjunto de ferramentas

C++

O SDK C++ do Proxy-Wasm permite que os desenvolvedores usem C++ para implementar plug-ins do WebAssembly (Wasm) para Service Extensions. O SDK usa a cadeia de ferramentas WebAssembly C++ Emscripten, além de outras bibliotecas, como protobuf e, opcionalmente, Abseil.

Como a criação de plug-ins escritos em C++ depende de versões específicas dessas ferramentas e bibliotecas, recomendamos usar a imagem Docker fornecida pelo SDK do Proxy-Wasm C++. As instruções para C++ nesta página usam o método Docker. Para criar plug-ins C++ sem usar o Docker, consulte a documentação do SDK Proxy-Wasm C++.

  1. Instale o Docker se ele ainda não estiver instalado. O Docker está incluído no Cloud Shell, ambiente shell interativo Google Cloud .

  2. Baixe uma cópia do SDK C++ do Proxy-Wasm. A maneira mais simples de fazer isso é clonar o repositório Git:

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. Crie a imagem Docker do SDK C++ do Proxy-Wasm com o Dockerfile fornecido pelo SDK:

    cd proxy-wasm-cpp-sdk
    docker build -t wasmsdk:v3 -f Dockerfile-sdk .
    

    Quando o comando terminar de criar as bibliotecas e dependências do SDK, a imagem Docker resultante será associada à tag especificada, que é wasmsdk:v3 neste exemplo.

Go

O SDK do Proxy-Wasm Go oferece um SDK do Go completo. O Go oferece bom desempenho e suporte completo para bibliotecas de terceiros escritas em Go puro.

Instale o conjunto de ferramentas Go v1.24.0.

Rust

A capacidade de personalização das Service Extensions é fornecida pelo uso do WebAssembly e do Proxy-Wasm. O WebAssembly é compatível com várias linguagens de programação. O Google recomenda o Rust porque ele oferece excelente suporte ao WebAssembly, e o Proxy-Wasm fornece um SDK Rust completo. O Rust também oferece bom desempenho e segurança de tipos.

  1. Instale a cadeia de ferramentas do Rust.

    Ao final do processo de instalação, siga as instruções impressas no console para concluir a configuração.

  2. Adicione suporte ao Wasm ao conjunto de ferramentas do Rust:

    rustup target add wasm32-wasip1
    

Criar o pacote de plug-in

C++

  1. Crie um novo diretório, separado de proxy-wasm-cpp-sdk:

    mkdir myproject
    
  2. No diretório, crie um Makefile com o seguinte conteúdo:

    # Express any dependencies
    PROTOBUF=     # full / lite / none
    WASM_DEPS=    # absl_base re2 ...
    
    # Include the SDK Makefile
    PROXY_WASM_CPP_SDK=/sdk
    include ${PROXY_WASM_CPP_SDK}/Makefile
    
  3. Adicione um arquivo de origem C++ para o plug-in no mesmo diretório. Os nomes dos arquivos de origem C++ precisam corresponder aos arquivos Wasm que o Makefile segmenta, com o sufixo .wasm substituído por .cc. Neste exemplo, o arquivo de origem precisa ser chamado de myproject.cc.

  4. Adicione o código do plug-in ao arquivo de origem.

    O exemplo de código-fonte a seguir é um plug-in que reescreve o host da solicitação e emite um cabeçalho de resposta:

    #include "proxy_wasm_intrinsics.h"
    
    class MyHttpContext : public Context {
     public:
      explicit MyHttpContext(uint32_t id, RootContext* root) : Context(id, root) {}
    
      FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                           bool end_of_stream) override {
        LOG_INFO("onRequestHeaders: hello from wasm");
    
        // Route Extension example: host rewrite
        if (replaceRequestHeader(":authority", "service-extensions.com") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :authority header");
        }
        if (replaceRequestHeader(":path", "/") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :path header");
        }
        return FilterHeadersStatus::Continue;
      }
    
      FilterHeadersStatus onResponseHeaders(uint32_t headers,
                                            bool end_of_stream) override {
        LOG_INFO("onResponseHeaders: hello from wasm");
    
        // Traffic Extension example: add response header
        if (addResponseHeader("hello", "service-extensions") != WasmResult::Ok) {
          LOG_ERROR("Failed to add response header");
        }
        return FilterHeadersStatus::Continue;
      }
    };
    
    static RegisterContextFactory register_StaticContext(
        CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(RootContext));

    O método onRequestHeaders é um callback invocado pelas Service Extensions.

Go

  1. Crie um novo diretório para o plug-in:

    mkdir go-plugin
    
  2. No diretório, crie um arquivo go.mod usando a ferramenta Go:

    go mod init go-plugin
    
  3. No mesmo diretório, crie um arquivo de origem chamado main.go e adicione o código do plug-in a ele.

    O exemplo de código-fonte a seguir é um plug-in que reescreve o host da solicitação e emite um cabeçalho de resposta:

    package main
    
    import (
    	"fmt"
    
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
    )
    
    func main() {}
    func init() {
    	proxywasm.SetVMContext(&vmContext{})
    }
    
    type vmContext struct {
    	types.DefaultVMContext
    }
    
    type pluginContext struct {
    	types.DefaultPluginContext
    }
    
    type httpContext struct {
    	types.DefaultHttpContext
    }
    
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    
    func (*pluginContext) NewHttpContext(uint32) types.HttpContext {
    	return &httpContext{}
    }
    
    func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onRequestHeaders: hello from wasm")
    
    	// Route Extension example: host rewrite
    	err := proxywasm.ReplaceHttpRequestHeader(":authority", "service-extensions.com")
    	if err != nil {
    		panic(err)
    	}
    	err = proxywasm.ReplaceHttpRequestHeader(":path", "/")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    
    func (ctx *httpContext) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onResponseHeaders: hello from wasm")
    
    	// Traffic Extension example: add response header
    	err := proxywasm.AddHttpResponseHeader("hello", "service-extensions")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    

    O método OnHttpRequestHeaders é um callback invocado pelas Service Extensions.

  4. Para fazer o download e fixar as dependências da biblioteca, execute go mod tidy:

    go mod tidy
    

Rust

  1. Crie um diretório de pacote do Rust usando o comando cargo new do gerenciador de pacotes do Rust, o Cargo:

    cargo new --lib my-wasm-plugin
    

    O comando cria um diretório que contém um arquivo cargo.toml que pode ser atualizado para descrever como criar o pacote Rust e um diretório src em que você armazena o código do plug-in.

  2. Atualize o arquivo cargo.toml para especificar os parâmetros necessários para criar o pacote:

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Para registrar o SDK do Proxy-Wasm Rust e o suporte a registros como dependências, adicione a seção dependencies. Exemplo:

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. Para criar uma biblioteca dinâmica conforme necessário para plug-ins, adicione a seção lib. Exemplo:

    [lib]
    crate-type = ["cdylib"]
    
  5. Para reduzir o tamanho do plug-in compilado, adicione a seção profile.release. Exemplo:

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. Adicione o código do plug-in ao arquivo lib.rs no diretório src.

    O exemplo de código-fonte a seguir é um plug-in que reescreve o host da solicitação e emite um cabeçalho de resposta:

    use log::info;
    use proxy_wasm::traits::*;
    use proxy_wasm::types::*;
    
    proxy_wasm::main! { {
        proxy_wasm::set_log_level(LogLevel::Trace);
        proxy_wasm::set_http_context(|_, _| -> Box<dyn HttpContext> { Box::new(MyHttpContext) });
    } }
    
    struct MyHttpContext;
    
    impl Context for MyHttpContext {}
    
    impl HttpContext for MyHttpContext {
        fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onRequestHeaders: hello from wasm");
    
            // Route extension example: host rewrite
            self.set_http_request_header(":authority", Some("service-extensions.com"));
            self.set_http_request_header(":path", Some("/"));
            return Action::Continue;
        }
    
        fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onResponseHeaders: hello from wasm");
    
            // Traffic extension example: add response header
            self.add_http_response_header("hello", "service-extensions");
            return Action::Continue;
        }
    }

    O método on_http_request_headers é um callback invocado pelas Service Extensions.

Compilar o plug-in

C++

Para compilar o plug-in, execute o seguinte comando no diretório em que o Makefile e os arquivos de origem do plug-in C++ estão localizados:

docker run -v $PWD:/work -w /work wasmsdk:v3 /build_wasm.sh myproject.wasm

Esse comando mapeia o diretório atual para o diretório work na imagem Docker e executa o script build_wasm.sh fornecido pela imagem Docker para criar o código do plug-in. Quando a operação de compilação for concluída com êxito, um arquivo myproject.wasm, que contém o bytecode Wasm compilado, será criado no diretório atual.

Na primeira vez que o código do plug-in é compilado usando a imagem Docker, o Emscripten gera as bibliotecas padrão. Para armazenar em cache na imagem do Docker e não precisar regenerar a cada vez, faça o commit da imagem com as bibliotecas padrão após a primeira compilação bem-sucedida:

docker commit `docker ps -l | grep wasmsdk:v3 | awk '{print $1}'` wasmsdk:v3

Para mais informações sobre como criar plug-ins C++, consulte a documentação do SDK C++ do Proxy-Wasm.

Go

Para compilar o código do plug-in, execute o comando go build:

env GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm main.go

Uma compilação bem-sucedida cria um arquivo main.wasm no diretório atual.

Rust

Para compilar o código do plug-in, execute o comando cargo build:

cargo build --release --target wasm32-wasip1

Quando a build for concluída, uma mensagem Finished release [optimized] target(s) vai aparecer. Se você conhece o Envoy, carregue o plug-in nele e verifique o comportamento.

Fazer upload do código do plug-in compilado para o Artifact Registry

Faça upload do código do plug-in compilado para um repositório do Artifact Registry para que os serviços do Google Cloud possam acessá-lo.

Se você estiver usando Service Extensions com um balanceador de carga global, use um repositório em um local us multirregional. Se você estiver usando um balanceador de carga regional, use um repositório na mesma região ou em um local multirregional no mesmo continente.

Quando você anexa um plug-in a um balanceador de carga global, o Service Extensions copia o módulo Wasm do repositório do Artifact Registry para o próprio armazenamento em locais do mundo todo. Portanto, o local do repositório não afeta a latência das solicitações enviadas ao balanceador de carga. Para balanceadores de carga regionais, o plug-in é copiado para locais na mesma região em que o balanceador de carga está localizado.

Os plug-ins do Service Extensions podem ser enviados para repositórios genéricos ou do Docker do Artifact Registry.

Para uma abordagem mais direta de gerenciamento de binários independentes, recomendamos usar um repositório genérico para armazenar seus arquivos Wasm. Essa opção está em pré-lançamento.

Repositório genérico

  1. Crie um diretório package/ local e copie o módulo do plug-in publicável nele. O artefato do plug-in precisa ser chamado plugin.wasm. O comando de exemplo a seguir copia o artefato do plug-in criado pelo Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. Crie um repositório do Artifact Registry com --repository-format definido como generic.

  3. Verifique se você tem as permissões necessárias para o repositório.

  4. Para fazer upload do módulo Wasm como um artefato genérico para o repositório, use o comando gcloud artifacts generic upload.

    gcloud artifacts generic upload \
        --project=PROJECT_ID \
        --location=LOCATION \
        --repository=REPOSITORY \
        --source=package/plugin.wasm \
        --package=PACKAGE \
        --version=VERSION
    

    Substitua:

    Quando o upload for concluído, observe o nome do artefato genérico, conforme mencionado com o rótulo name, por exemplo, add_header_plugin:v4 no exemplo a seguir. Especifique esse nome ao criar um plug-in ou uma versão dele.

    Uploading file: plugin.wasm...done.
    '@type': type.googleapis.com/google.devtools.artifactregistry.v1.GenericArtifact
    createTime: '2025-06-16T11:02:25.080248Z'
    name: projects/my-project/locations/us/repositories/my-generic-repo/genericArtifacts/add_header_plugin:v4
    updateTime: '2025-06-16T11:02:25.080248Z'
    version: v4
    
  5. Para confirmar se o artefato foi enviado ao Artifact Registry, execute o comando gcloud artifacts files list e verifique se a lista tem um arquivo chamado PACKAGE:VERSION:plugin.wasm.

     gcloud artifacts files list \
         --project=PROJECT_ID \
         --location=LOCATION \
         --repository=REPOSITORY
    

Repositório do Docker

  1. Crie um repositório do Artifact Registry com --repository-format definido como docker.

  2. Verifique se você tem as permissões necessárias para o repositório.

  3. Crie um diretório package/ local e copie o artefato do plug-in publicável para ele. O exemplo a seguir copia o artefato do plug-in criado pelo Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. Crie um arquivo package/Dockerfile com o seguinte conteúdo:

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Empacote o código do plug-in usando o Cloud Build ou o Docker.

    Cloud Build

    1. Crie um arquivo de configuração de build package/cloudbuild.yaml com o seguinte conteúdo:

      steps:
        - name: 'gcr.io/cloud-builders/docker'
          args: [ 'build', '--no-cache', '--platform', 'wasm',
                '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG', '.' ]
      images: [ 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG' ]
      

      O caminho em que você armazena o plug-in precisa estar no seguinte formato:

      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Substitua:

      • LOCATION: o local regional ou multirregional do repositório
      • PROJECT_ID: o ID do projeto do console do Google Cloud
      • REPOSITORY: o nome do repositório onde você pretende armazenar a imagem.
      • IMAGE: o nome da imagem do contêiner no repositório. Por exemplo, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: a tag da imagem a ser atribuída ao contêiner, por exemplo, production
    2. Acione a operação para criar o contêiner do plug-in e fazer upload dele no Artifact Registry:

      gcloud builds submit --config package/cloudbuild.yaml package/
      

    Docker

    1. Instale o Docker se ele ainda não estiver instalado. O Docker está incluído no Cloud Shell, ambiente shell interativo Google Cloud .

    2. Configure o Docker para autenticar no Artifact Registry. Exemplo:

      gcloud auth login
      gcloud auth configure-docker LOCATION-docker.pkg.dev
      gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://LOCATION-docker.pkg.dev
      
    3. Crie a imagem do contêiner:

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. Para marcar a imagem local com o nome da imagem do repositório, use tags de imagem:

      docker tag my-wasm-plugin LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      Substitua:

      • LOCATION: o local regional ou multirregional do repositório
      • PROJECT_ID: o ID do projeto do console do Google Cloud
      • REPOSITORY: o nome do repositório em que você pretende armazenar a imagem.
      • IMAGE: o nome da imagem do contêiner no repositório, por exemplo, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin.
      • IMAGE_TAG: a tag da imagem a ser atribuída ao contêiner, por exemplo, production
    5. Faça upload da imagem de contêiner marcada para o Artifact Registry.

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. Para confirmar se a imagem foi enviada ao Artifact Registry, execute o comando gcloud artifacts docker images list.

    gcloud artifacts docker images list LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \
        --include-tags
    

Preparar e fazer upload do arquivo de configuração

Os plug-ins podem receber dados de configuração, o que pode afetar o comportamento deles durante a execução. Os dados de configuração podem ser de texto ou binários e em qualquer formato aceito pelo plug-in. Se o tamanho dos dados de configuração for grande, talvez seja necessário fazer upload do arquivo de configuração para o Artifact Registry.

Escrever código de plug-in para ler dados de configuração

C++

Os dados de configuração são transmitidos ao método onConfigure do objeto de contexto raiz, que é instanciado uma vez na inicialização do plug-in e permanece ativo durante todo o ciclo de vida do ambiente de execução do Wasm que hospeda o plug-in. O objeto de contexto raiz é uma instância da classe RootContext ou de uma subclasse de RootContext.

O código do plug-in pode controlar qual classe é usada para o contexto raiz pelo valor RegisterContextFactory. Por exemplo, o código de plug-in a seguir registra MyRootContext e MyHttpContext como as classes a serem usadas para instâncias de contexto raiz e de fluxo. Em seguida, ele lê um valor secreto dos dados de configuração do plug-in, que as instâncias de contexto de fluxo podem acessar pelo objeto de contexto raiz.

#include <string>
#include <string_view>

#include "proxy_wasm_intrinsics.h"

class MyRootContext : public RootContext {
 public:
  explicit MyRootContext(uint32_t id, std::string_view root_id)
      : RootContext(id, root_id) {}

  bool onConfigure(size_t config_len) override {
    auto buffer = getBufferBytes(WasmBufferType::PluginConfiguration, 0, config_len);
    if (!buffer) {
      LOG_ERROR("Failed to retrieve plugin configuration");
      return false;
    }
    secret_ = buffer->toString();
    return true;
  }

  const std::string& secret() const { return secret_; }

 private:
  std::string secret_;
};

class MyHttpContext : public Context {
 public:
  explicit MyHttpContext(uint32_t id, RootContext* root)
      : Context(id, root),
        secret_(static_cast<MyRootContext*>(root)->secret()) {}

  FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                       bool end_of_stream) override {
    // Use secret here...
    LOG_INFO("secret: " + secret_);
    return FilterHeadersStatus::Continue;
  }

 private:
  const std::string& secret_;
};

static RegisterContextFactory register_MyHttpContext(
    CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(MyRootContext));

Go

Os dados de configuração são lidos durante a execução de OnPluginStart, um receptor de método que o tempo de execução executa na struct PluginContext uma vez na inicialização do plug-in. Os dados de configuração não mudam durante o ciclo de vida do tempo de execução do Wasm que hospeda o plug-in. O PluginContext é útil para realizar a lógica de inicialização e manter o estado em várias solicitações.

O código do plug-in pode controlar qual contexto é usado para PluginContext implementando o método NewPluginContext em VMContext, que cria uma instância de PluginContext. Em seguida, PluginContext cria instâncias de contextos HttpContext.

Por exemplo, o código do plug-in a seguir registra VMContext, que instancia PluginContext, o contexto responsável por ler dados de configuração e instanciar contextos HttpContext conforme necessário. PluginContext lê um valor secreto dos dados de configuração do plug-in, armazena no contexto PluginContext e transmite para HttpContext em NewHttpContext.

package main

import (
	"fmt"

	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
)

func main() {}
func init() {
	proxywasm.SetVMContext(&vmContext{})
}

type vmContext struct {
	types.DefaultVMContext
}

type pluginContext struct {
	types.DefaultPluginContext
	secret string
}

type httpContext struct {
	types.DefaultHttpContext
	pluginContext *pluginContext
}

func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
	return &pluginContext{}
}

func (ctx *pluginContext) OnPluginStart(int) types.OnPluginStartStatus {
	config, err := proxywasm.GetPluginConfiguration()
	if err != nil {
		proxywasm.LogErrorf("Error reading the configuration: %v", err)
		return types.OnPluginStartStatusFailed
	}
	if config == nil {
		proxywasm.LogError("Configuration is nil")
		return types.OnPluginStartStatusFailed
	}
	ctx.secret = string(config)
	return types.OnPluginStartStatusOK
}

func (ctx *pluginContext) NewHttpContext(uint32) types.HttpContext {
	return &httpContext{pluginContext: ctx}
}

func (ctx *pluginContext) Secret() string {
	return ctx.secret
}

func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
	defer func() {
		err := recover()
		if err != nil {
			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
		}
	}()
	// Use secret here...
	proxywasm.LogInfof("secret: %v", ctx.pluginContext.Secret())
	return types.ActionContinue
}

Rust

Os dados de configuração são lidos de uma característica RootContext, que é instanciada uma vez na inicialização do plug-in e permanece ativa durante todo o ciclo de vida do ambiente de execução do Wasm que hospeda o plug-in. As características RootContext são úteis para realizar operações ou manter o estado em várias solicitações.

O código do plug-in pode controlar qual classe é usada para o contexto raiz pelo método set_root_context, e o contexto raiz cria instâncias de contextos de stream. Por exemplo, o código de plug-in a seguir registra MyRootContext, que instancia MyHttpContext conforme necessário. O contexto raiz lê um valor secreto dos dados de configuração do plug-in e o transmite para contextos de stream.

use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use std::rc::Rc;

proxy_wasm::main! { {
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(MyRootContext { secret: Rc::new("missing".to_string()) })
    });
} }

struct MyRootContext {
    secret: Rc<String>,
}

impl Context for MyRootContext {}

impl RootContext for MyRootContext {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.secret = Rc::new(String::from_utf8(config_bytes).unwrap())
        }
        true
    }

    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(MyHttpContext {
            secret: self.secret.clone(), // shallow copy, ref count only
        }))
    }

    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

struct MyHttpContext {
    secret: Rc<String>,
}

impl Context for MyHttpContext {}

impl HttpContext for MyHttpContext {
    fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        // Use secret here...
        info!("secret: {}", self.secret);
        Action::Continue
    }
}

Fazer upload do arquivo de configuração

Se o tamanho dos dados a serem entregues ao seu plug-in em on_configure exceder 900 KiB, faça upload para o Artifact Registry seguindo o método descrito em Fazer upload do código do plug-in compilado para o Artifact Registry. Nesse caso, salve o arquivo de configuração com o nome plugin.config (e não plugin.wasm).

A próxima etapa é criar um plug-in.

Ao criar o plug-in, você precisa fornecer o URI do módulo ou da imagem Wasm enviados.

Criar uma nova versão do código do plug-in

Para criar uma nova versão do código do plug-in, edite o arquivo dele. Em seguida, conforme descrito nas seções anteriores, compile o código do plug-in, reembale-o e faça upload dele para o Artifact Registry.

Chamadas de retorno

O código compilado em Wasm pode definir métodos ou funções arbitrárias, mas alguns deles têm um significado especial. Esses são os métodos definidos no SDK Proxy-Wasm para a linguagem de sua escolha e mapeados para as especificações da interface binária do aplicativo (ABI, na sigla em inglês) do Proxy-Wasm. As Service Extensions invocam esses callbacks em resposta a solicitações do usuário ou a eventos do ciclo de vida do plug-in.

Esses callbacks estão listados na tabela a seguir na ordem em que são normalmente invocados:

Nome e descrição do callback Nome do método C++ Nome do método Go Nome do método Rust
START_PLUGIN: invocado quando um plug-in é iniciado. RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: invocado depois que um plug-in é iniciado para fornecer dados de configuração a ele. RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: invocado quando um novo contexto de stream é criado. Cada fluxo corresponde a uma solicitação HTTP do cliente. Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: invocado para processar cabeçalhos de solicitação HTTP. Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: invocado repetidamente para processar partes do corpo da solicitação HTTP. Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: invocado para processar cabeçalhos de resposta HTTP. Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: invocado repetidamente para processar partes do corpo da resposta HTTP. Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: invocado quando o processamento de um plug-in é concluído. Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: invocado quando o objeto de contexto de fluxo correspondente a uma solicitação HTTP do cliente é excluído. Context::onDelete (sem retorno de chamada) (sem retorno de chamada)

A seguir