Prepara el código del complemento

El código personalizado que creas para los complementos de Service Extensions debe empaquetarse y subirse a Artifact Registry antes de que otros servicios puedan acceder a él. En esta página, se describe cómo crear código de complementos, empaquetarlo y subirlo a un repositorio de Artifact Registry.

Esta función está en vista previa para Media CDN.

Para obtener información sobre las extensiones de servicio, consulta la Descripción general de las extensiones de servicio.

Antes de comenzar, revisa las prácticas recomendadas para escribir código de complementos.

Para obtener más ejemplos, consulta Muestras de código para complementos.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud . Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  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. Instala Google Cloud CLI.

  6. Si usas un proveedor de identidad externo (IdP), primero debes acceder a la gcloud CLI con tu identidad federada.

  7. Para inicializar gcloud CLI, ejecuta el siguiente 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. Instala Google Cloud CLI.

  12. Si usas un proveedor de identidad externo (IdP), primero debes acceder a la gcloud CLI con tu identidad federada.

  13. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init

Configura la cadena de herramientas

C++

El SDK de C++ de Proxy-Wasm permite que los desarrolladores usen C++ para implementar complementos de WebAssembly (Wasm) para Service Extensions. El SDK usa la cadena de herramientas de WebAssembly de C++ Emscripten, así como otras bibliotecas, como protobuf y, de forma opcional, Abseil.

Dado que la compilación de complementos escritos en C++ depende de versiones específicas de estas herramientas y bibliotecas, te recomendamos que uses la imagen de Docker proporcionada por el SDK de C++ de Proxy-Wasm. Las instrucciones para C++ en esta página usan el método de Docker. Para compilar complementos de C++ sin usar Docker, consulta la documentación del SDK de C++ de Proxy-Wasm.

  1. Instala Docker si aún no lo hiciste. Docker está incluido en Cloud Shell, el Google Cloud entorno de shell interactivo.

  2. Descarga una copia del SDK de C++ de Proxy-Wasm. La forma más sencilla de hacerlo es clonar el repositorio de Git:

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. Compila la imagen de Docker del SDK de C++ de Proxy-Wasm a partir del Dockerfile proporcionado por el SDK:

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

    Cuando el comando termina de compilar las bibliotecas y las dependencias del SDK, la imagen de Docker resultante se asocia con la etiqueta especificada, que es wasmsdk:v3 en este ejemplo.

Go

El SDK de Go de Proxy-Wasm proporciona un SDK de Go con todas las funciones. Go proporciona un buen rendimiento y una gran compatibilidad con las bibliotecas de terceros escritas en Go puro.

Instala la cadena de herramientas de Go v1.24.0.

Rust

La capacidad de personalización de Service Extensions se proporciona a través del uso de WebAssembly y Proxy-Wasm. WebAssembly admite varios lenguajes de programación. Google recomienda Rust porque proporciona una excelente compatibilidad con WebAssembly y Proxy-Wasm ofrece un SDK de Rust con todas las funciones. Rust también proporciona un buen rendimiento y una gran seguridad de tipos.

  1. Instala la cadena de herramientas de Rust.

    Al final del proceso de instalación, sigue las instrucciones impresas en la consola para finalizar el proceso de configuración.

  2. Agrega compatibilidad con Wasm a la cadena de herramientas de Rust:

    rustup target add wasm32-wasip1
    

Crea el paquete del complemento

C++

  1. Crea un directorio nuevo, separado de proxy-wasm-cpp-sdk:

    mkdir myproject
    
  2. En el directorio, crea un archivo Makefile con el siguiente contenido:

    # 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. Agrega un archivo fuente de C++ para el complemento en el mismo directorio. Los nombres de los archivos fuente de C++ deben coincidir con los archivos Wasm a los que se dirige el archivo Makefile, con el sufijo .wasm reemplazado por .cc. En este ejemplo, el archivo fuente debe llamarse myproject.cc.

  4. Agrega el código del complemento al archivo fuente.

    El siguiente código fuente de ejemplo es un complemento que reescribe el host de la solicitud y emite un encabezado de respuesta:

    #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));

    El método onRequestHeaders es una devolución de llamada que invocan las extensiones de servicio.

Go

  1. Crea un directorio nuevo para el complemento:

    mkdir go-plugin
    
  2. En el directorio, crea un archivo go.mod con la herramienta Go:

    go mod init go-plugin
    
  3. En el mismo directorio, crea un archivo fuente llamado main.go y agrega el código de tu complemento.

    El siguiente código fuente de ejemplo es un complemento que reescribe el host de la solicitud y emite un encabezado de respuesta:

    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
    }
    

    El método OnHttpRequestHeaders es una devolución de llamada que invocan las extensiones de servicio.

  4. Para descargar y fijar las dependencias de la biblioteca, ejecuta go mod tidy:

    go mod tidy
    

Rust

  1. Crea un directorio de paquetes de Rust con el comando cargo new del administrador de paquetes de Rust, Cargo:

    cargo new --lib my-wasm-plugin
    

    El comando crea un directorio que contiene un archivo cargo.toml que puedes actualizar para describir cómo compilar el paquete de Rust y un directorio src en el que almacenas el código del complemento.

  2. Actualiza el archivo cargo.toml para especificar los parámetros necesarios para compilar el paquete:

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Para registrar el SDK de Proxy-Wasm Rust y la compatibilidad con el registro como dependencias, agrega la sección dependencies. Por ejemplo:

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. Para compilar una biblioteca dinámica como se requiere para los complementos, agrega la sección lib. Por ejemplo:

    [lib]
    crate-type = ["cdylib"]
    
  5. Para reducir el tamaño del complemento compilado, agrega la sección profile.release. Por ejemplo:

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. Agrega el código del complemento al archivo lib.rs en el directorio src.

    El siguiente código fuente de ejemplo es un complemento que reescribe el host de la solicitud y emite un encabezado de respuesta:

    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;
        }
    }

    El método on_http_request_headers es una devolución de llamada que invocan las extensiones de servicio.

Compila el complemento

C++

Para compilar el complemento, ejecuta el siguiente comando desde el directorio en el que se encuentran el archivo Makefile y los archivos fuente del complemento en C++:

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

Este comando asigna el directorio actual al directorio work dentro de la imagen de Docker y, luego, ejecuta la secuencia de comandos build_wasm.sh proporcionada por la imagen de Docker para compilar el código del complemento. Cuando la operación de compilación se completa correctamente, se crea un archivo myproject.wasm, que contiene el bytecode de Wasm compilado, en el directorio actual.

La primera vez que se compila el código del complemento con la imagen de Docker, Emscripten genera las bibliotecas estándar. Para almacenarlas en caché en la imagen de Docker de modo que no sea necesario volver a generarlas cada vez, confirma la imagen con las bibliotecas estándar después de la primera compilación exitosa:

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

Para obtener más información sobre cómo compilar complementos en C++, consulta la documentación del SDK de Proxy-Wasm en C++.

Go

Para compilar el código del complemento, ejecuta el comando go build:

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

Si la compilación se realiza correctamente, se crea un archivo main.wasm en el directorio actual.

Rust

Para compilar el código del complemento, ejecuta el comando cargo build:

cargo build --release --target wasm32-wasip1

Cuando la compilación se completa correctamente, aparece un mensaje Finished release [optimized] target(s). Si conoces Envoy, tal vez quieras cargar el complemento en Envoy y verificar su comportamiento.

Sube el código del complemento compilado a Artifact Registry

Sube el código del complemento compilado a un repositorio de Artifact Registry para que los servicios de Google Cloud puedan acceder a él.

Si usas Service Extensions con un balanceador de cargas global, usa un repositorio en una ubicación us multirregional. Si usas un balanceador de cargas regional, usa un repositorio en la misma región o en una ubicación multirregional del mismo continente.

Cuando conectas un complemento a un balanceador de cargas global, Service Extensions copia el módulo de Wasm del repositorio de Artifact Registry a su propio almacenamiento en ubicaciones de todo el mundo. Por lo tanto, la ubicación del repositorio no afecta la latencia de las solicitudes enviadas al balanceador de cargas. En el caso de los balanceadores de cargas regionales, el complemento se copia a ubicaciones de la misma región en la que se encuentra el balanceador de cargas.

Los complementos de Service Extensions se pueden subir a los repositorios genéricos o de Docker de Artifact Registry.

Para un enfoque más directo de la administración de archivos binarios independientes, te recomendamos que uses un repositorio genérico para almacenar tus archivos Wasm. Esta opción se encuentra en Vista previa.

Repositorio genérico

  1. Crea un directorio package/ local y copia en él el módulo del complemento publicable. El artefacto del complemento debe llamarse plugin.wasm. El siguiente comando de ejemplo copia el artefacto del complemento compilado por Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. Crea un repositorio de Artifact Registry con --repository-format establecido en generic.

  3. Verifica que tengas los permisos necesarios para el repositorio.

  4. Para subir tu módulo de Wasm como un artefacto genérico a tu repositorio, usa el comando gcloud artifacts generic upload.

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

    Reemplaza lo siguiente:

    Cuando se complete la carga, anota el nombre del artefacto genérico como se menciona con la etiqueta name, por ejemplo, add_header_plugin:v4 en el siguiente ejemplo. Especifica este nombre cuando crees un complemento o una versión del complemento.

    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 que el artefacto se subió correctamente a Artifact Registry, ejecuta el comando gcloud artifacts files list y verifica que la lista tenga un archivo llamado PACKAGE:VERSION:plugin.wasm.

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

Repositorio de Docker

  1. Crea un repositorio de Artifact Registry con --repository-format establecido en docker.

  2. Verifica que tengas los permisos necesarios para el repositorio.

  3. Crea un directorio package/ local y copia en él el artefacto del complemento publicable. En el siguiente ejemplo, se copia el artefacto del complemento compilado por Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. Crea un archivo package/Dockerfile con el siguiente contenido:

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Empaqueta el código del complemento con Cloud Build o Docker.

    Cloud Build

    1. Crea un archivo de configuración de compilación package/cloudbuild.yaml con el siguiente contenido:

      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' ]
      

      La ruta de acceso en la que almacenas el complemento debe tener el siguiente formato:

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

      Reemplaza lo siguiente:

      • LOCATION: la ubicación regional o multirregional del repositorio
      • PROJECT_ID: el ID de tu proyecto en la consola de Google Cloud
      • REPOSITORY: Es el nombre del repositorio en el que planeas almacenar la imagen.
      • IMAGE: Es el nombre de la imagen del contenedor en el repositorio, por ejemplo, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: Es la etiqueta de imagen que se asignará al contenedor, por ejemplo, production.
    2. Activa la operación para compilar el contenedor del complemento y subirlo a Artifact Registry:

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

    Docker

    1. Instala Docker si aún no lo hiciste. Docker está incluido en Cloud Shell, el Google Cloud entorno de shell interactivo.

    2. Configura Docker para que se autentique en Artifact Registry. Por ejemplo:

      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. Compila la imagen del contenedor:

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. Para etiquetar la imagen local con el nombre de la imagen del repositorio, usa etiquetas de imagen:

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

      Reemplaza lo siguiente:

      • LOCATION: la ubicación regional o multirregional del repositorio
      • PROJECT_ID: el ID de tu proyecto en la consola de Google Cloud
      • REPOSITORY: Es el nombre del repositorio en el que planeas almacenar la imagen.
      • IMAGE: Es el nombre de la imagen de contenedor en el repositorio, por ejemplo, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin.
      • IMAGE_TAG: Es la etiqueta de imagen que se asignará al contenedor, por ejemplo, production.
    5. Sube la imagen de contenedor etiquetada a Artifact Registry.

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. Para confirmar que la imagen se subió correctamente a Artifact Registry, ejecuta el comando gcloud artifacts docker images list.

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

Prepara y sube el archivo de configuración

Los complementos pueden recibir datos de configuración de forma opcional, lo que puede afectar su comportamiento en el tiempo de ejecución. Los datos de configuración pueden ser de texto o binarios, y en cualquier formato que acepte el complemento. Si el tamaño de los datos de configuración es grande, es posible que debas subir el archivo de configuración a Artifact Registry.

Escribe código de complemento para leer datos de configuración

C++

Los datos de configuración se pasan al método onConfigure del objeto de contexto raíz, que se instancia una vez en el inicio del complemento y permanece activo durante la vida útil del tiempo de ejecución de Wasm que aloja el complemento. El objeto de contexto raíz es una instancia de la clase RootContext o de una subclase de RootContext.

El código del complemento puede controlar qué clase se usa para el contexto raíz a través del valor RegisterContextFactory. Por ejemplo, el siguiente código de complemento registra MyRootContext y MyHttpContext como las clases que se usarán para las instancias de contexto raíz y de transmisión. Luego, lee un valor secreto de los datos de configuración del complemento, a los que las instancias de contexto de transmisión pueden acceder a través del objeto de contexto raíz.

#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

Los datos de configuración se leen mientras se ejecuta OnPluginStart, un receptor de métodos que el tiempo de ejecución ejecuta en la estructura PluginContext una vez en el inicio del complemento. Los datos de configuración no cambian durante la vida útil del tiempo de ejecución de Wasm que aloja el complemento. PluginContext es útil para realizar la lógica de inicialización y mantener el estado en muchas solicitudes.

El código del complemento puede controlar qué contexto se usa para PluginContext implementando el método NewPluginContext en VMContext, que instancia PluginContext. Luego, PluginContext crea instancias de contextos de HttpContext.

Por ejemplo, el siguiente código de complemento registra VMContext, que crea una instancia de PluginContext, el contexto responsable de leer los datos de configuración y crear instancias de los contextos de HttpContext según sea necesario. PluginContext lee un valor secreto de los datos de configuración del complemento, lo almacena dentro del contexto PluginContext y lo pasa a HttpContext en 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

Los datos de configuración se leen desde un rasgo RootContext, que se instancia una vez en el inicio del complemento y permanece activo durante el ciclo de vida del tiempo de ejecución de Wasm que aloja el complemento. Los rasgos RootContext son útiles para realizar operaciones o mantener el estado en muchas solicitudes.

El código del complemento puede controlar qué clase se usa para el contexto raíz a través del método set_root_context, y el contexto raíz crea instancias de contextos de transmisión. Por ejemplo, el siguiente código de complemento registra MyRootContext, que crea una instancia de MyHttpContext según sea necesario. El contexto raíz lee un valor secreto de los datos de configuración del complemento y lo pasa a los contextos de transmisión.

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
    }
}

Sube el archivo de configuración

Si el tamaño de los datos que se entregarán a tu complemento en on_configure supera los 900 KiB, súbelos a Artifact Registry siguiendo el método que se describe en Cómo subir el código compilado del complemento a Artifact Registry. En este caso, guarda el archivo de configuración con el nombre plugin.config (y no plugin.wasm).

El siguiente paso es crear un complemento.

Cuando crees el complemento, deberás proporcionar el URI del módulo o la imagen de Wasm que se subieron.

Crea una versión nueva del código del complemento

Para crear una nueva versión del código del complemento, edita el archivo del complemento. Luego, como se describe en las secciones anteriores, compila el código del complemento, vuelve a empaquetarlo y súbelo a Artifact Registry.

Devoluciones de llamada

El código que compilas en Wasm puede definir métodos o funciones arbitrarios, pero algunos de ellos tienen un significado especial. Estos son los métodos que se definen en el SDK de Proxy-Wasm para el lenguaje que elijas y se asignan a las especificaciones de la interfaz binaria de la aplicación (ABI) de Proxy-Wasm. Las extensiones de servicio invocan estas devoluciones de llamada en respuesta a las solicitudes del usuario o a los eventos del ciclo de vida del complemento.

Estas devoluciones de llamada se enumeran en la siguiente tabla en el orden en que suelen invocarse:

Nombre y descripción de la devolución de llamada Nombre del método en C++ Nombre del método Go Nombre del método en Rust
START_PLUGIN: Se invoca cuando se inicia un complemento. RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: Se invoca después de que se inicia un complemento para proporcionar datos de configuración al complemento. RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: Se invoca cuando se crea un nuevo contexto de transmisión. Cada transmisión corresponde a una solicitud HTTP del cliente. Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: Se invoca para procesar los encabezados de la solicitud HTTP. Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: Se invoca de forma repetida para procesar fragmentos del cuerpo de la solicitud HTTP. Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: Se invoca para procesar los encabezados de respuesta HTTP. Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: Se invoca de forma repetida para procesar fragmentos del cuerpo de la respuesta HTTP. Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: Se invoca cuando se completa el procesamiento de un complemento. Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: Se invoca cuando se borra el objeto de contexto de transmisión correspondiente a una solicitud HTTP del cliente. Context::onDelete (sin devolución de llamada) (sin devolución de llamada)

¿Qué sigue?