Menyiapkan kode plugin

Kode kustom yang Anda buat untuk plugin Service Extensions harus dikemas dan diupload ke Artifact Registry sebelum layanan lain dapat mengaksesnya. Halaman ini menjelaskan cara membuat kode plugin, memaketkan kode, dan menguploadnya ke repositori Artifact Registry.

Fitur ini berada dalam Pratinjau untuk Media CDN.

Untuk mengetahui informasi tentang Service Extensions, lihat Ringkasan Service Extensions.

Sebelum memulai, tinjau praktik terbaik untuk menulis kode plugin.

Untuk contoh lainnya, lihat Contoh kode untuk plugin.

Sebelum memulai

  1. Login ke akun Google Cloud Anda. Jika Anda baru menggunakan Google Cloud, buat akun untuk mengevaluasi performa produk kami dalam skenario dunia nyata. Pelanggan baru juga mendapatkan kredit gratis senilai $300 untuk menjalankan, menguji, dan men-deploy workload.
  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. Instal Google Cloud CLI.

  6. Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

  7. Untuk melakukan inisialisasi gcloud CLI, jalankan perintah berikut:

    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. Instal Google Cloud CLI.

  12. Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

  13. Untuk melakukan inisialisasi gcloud CLI, jalankan perintah berikut:

    gcloud init

Menyiapkan toolchain

C++

SDK C++ Proxy-Wasm memungkinkan developer menggunakan C++ untuk menerapkan plugin WebAssembly (Wasm) untuk Service Extensions. SDK ini menggunakan toolchain WebAssembly C++ Emscripten, serta library lain, seperti protobuf dan, secara opsional, Abseil.

Karena pembuatan plugin yang ditulis dalam C++ bergantung pada versi tertentu dari alat dan library ini, sebaiknya gunakan image Docker yang disediakan oleh Proxy-Wasm C++ SDK. Petunjuk untuk C++ di halaman ini menggunakan metode Docker. Untuk membuat plugin C++ tanpa menggunakan Docker, lihat dokumentasi Proxy-Wasm C++ SDK.

  1. Instal Docker jika belum diinstal. Docker disertakan dalam Cloud Shell, lingkungan shell interaktif Google Cloud .

  2. Download salinan Proxy-Wasm C++ SDK. Cara paling sederhana untuk melakukannya adalah dengan meng-clone repositori Git:

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. Bangun image Docker Proxy-Wasm C++ SDK dari Dockerfile yang disediakan oleh SDK:

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

    Setelah perintah selesai membangun library dan dependensi SDK, image Docker yang dihasilkan akan dikaitkan dengan tag yang ditentukan, yaitu wasmsdk:v3 dalam contoh ini.

Go

Proxy-Wasm Go SDK menyediakan Go SDK berfitur lengkap. Go memberikan performa yang baik dan dukungan yang kaya untuk library pihak ketiga yang ditulis dalam Go murni.

Instal toolchain Go v1.24.0.

Rust

Kemampuan penyesuaian Service Extensions disediakan melalui penggunaan WebAssembly dan Proxy-Wasm. WebAssembly mendukung sejumlah bahasa pemrograman. Google merekomendasikan Rust karena menyediakan dukungan WebAssembly yang sangat baik dan Proxy-Wasm menyediakan SDK Rust yang kaya fitur. Rust juga memberikan performa yang baik dan keamanan jenis yang kuat.

  1. Instal toolchain Rust.

    Di akhir proses penginstalan, ikuti petunjuk yang dicetak ke konsol untuk menyelesaikan proses konfigurasi.

  2. Menambahkan dukungan Wasm ke toolchain Rust:

    rustup target add wasm32-wasip1
    

Membuat paket plugin

C++

  1. Buat direktori baru, terpisah dari proxy-wasm-cpp-sdk:

    mkdir myproject
    
  2. Di direktori, buat Makefile dengan konten berikut:

    # 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. Tambahkan file sumber C++ untuk plugin di direktori yang sama. Nama file sumber C++ harus cocok dengan file Wasm yang ditargetkan Makefile, dengan akhiran .wasm diganti dengan .cc. Dalam contoh ini, file sumber harus diberi nama myproject.cc.

  4. Tambahkan kode plugin Anda ke file sumber.

    Kode sumber contoh berikut adalah plugin yang menulis ulang host permintaan, dan memancarkan header respons:

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

    Metode onRequestHeaders adalah callback yang dipanggil oleh Ekstensi Layanan.

Go

  1. Buat direktori baru untuk plugin:

    mkdir go-plugin
    
  2. Di direktori, buat file go.mod menggunakan alat Go:

    go mod init go-plugin
    
  3. Di direktori yang sama, buat file sumber bernama main.go, lalu tambahkan kode plugin Anda ke file tersebut.

    Kode sumber contoh berikut adalah plugin yang menulis ulang host permintaan, dan memancarkan header respons:

    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
    }
    

    Metode OnHttpRequestHeaders adalah callback yang dipanggil oleh Ekstensi Layanan.

  4. Untuk mendownload dan menyematkan dependensi library, jalankan go mod tidy:

    go mod tidy
    

Rust

  1. Buat direktori paket Rust menggunakan perintah cargo new dari pengelola paket Rust, Cargo:

    cargo new --lib my-wasm-plugin
    

    Perintah ini membuat direktori yang berisi file cargo.toml yang dapat Anda update untuk menjelaskan cara membuat paket Rust dan direktori src tempat Anda menyimpan kode plugin.

  2. Perbarui file cargo.toml untuk menentukan parameter yang diperlukan untuk membangun paket:

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Untuk mendaftarkan dukungan logging dan Proxy-Wasm Rust SDK sebagai dependensi, tambahkan bagian dependencies. Contoh:

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. Untuk membuat library dinamis seperti yang diperlukan untuk plugin, tambahkan bagian lib. Contoh:

    [lib]
    crate-type = ["cdylib"]
    
  5. Untuk mengurangi ukuran plugin yang dikompilasi, tambahkan bagian profile.release. Contoh:

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. Tambahkan kode plugin Anda ke file lib.rs di direktori src.

    Kode sumber contoh berikut adalah plugin yang menulis ulang host permintaan, dan memancarkan header respons:

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

    Metode on_http_request_headers adalah callback yang dipanggil oleh Ekstensi Layanan.

Kompilasi plugin

C++

Untuk mengompilasi plugin, jalankan perintah berikut dari dalam direktori tempat file sumber plugin C++ dan Makefile berada:

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

Perintah ini memetakan direktori saat ini ke direktori work dalam image Docker, lalu menjalankan skrip build_wasm.sh yang disediakan oleh image Docker untuk membangun kode plugin. Saat operasi kompilasi selesai dengan berhasil, file myproject.wasm, yang berisi bytecode Wasm yang dikompilasi, akan dibuat di direktori saat ini.

Saat kode plugin dikompilasi pertama kali menggunakan image Docker, Emscripten akan menghasilkan library standar. Untuk menyimpannya dalam cache di image Docker agar tidak perlu dibuat ulang setiap kali, lakukan commit image dengan library standar setelah kompilasi pertama berhasil:

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

Untuk mengetahui informasi selengkapnya tentang cara membuat plugin C++, lihat dokumentasi SDK C++ Proxy-Wasm.

Go

Untuk mengompilasi kode plugin, jalankan perintah go build:

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

Kompilasi yang berhasil akan membuat file main.wasm di direktori saat ini.

Rust

Untuk mengompilasi kode plugin, jalankan perintah cargo build:

cargo build --release --target wasm32-wasip1

Jika build berhasil diselesaikan, pesan Finished release [optimized] target(s) akan muncul. Jika Anda sudah memahami Envoy, Anda dapat memuat plugin di Envoy dan memverifikasi perilakunya.

Mengupload kode plugin yang dikompilasi ke Artifact Registry

Upload kode plugin yang dikompilasi ke repositori Artifact Registry agar layanan dapat mengaksesnya. Google Cloud

Jika Anda menggunakan Service Extensions dengan load balancer global, gunakan repositori di lokasi us multi-regional. Jika Anda menggunakan load balancer regional, gunakan repositori di region yang sama atau di lokasi multi-regional di benua yang sama.

Saat Anda melampirkan plugin ke load balancer global, Service Extensions akan menyalin modul Wasm dari repositori Artifact Registry ke penyimpanan sendiri di berbagai lokasi di seluruh dunia. Jadi, lokasi repositori tidak memengaruhi latensi permintaan yang dikirim ke load balancer. Untuk load balancer regional, plugin disalin ke lokasi di region yang sama dengan lokasi load balancer.

Plugin Ekstensi Layanan dapat diupload ke repositori Docker atau generik Artifact Registry.

Untuk pendekatan yang lebih langsung dalam mengelola biner mandiri, sebaiknya Anda menggunakan repositori generik untuk menyimpan file Wasm. Opsi ini berada dalam Pratinjau.

Repositori generik

  1. Buat direktori package/ lokal dan salin modul plugin yang dapat dipublikasikan ke dalamnya. Artefak plugin harus diberi nama plugin.wasm Perintah contoh berikut menyalin artefak plugin yang dibuat oleh Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. Buat repositori Artifact Registry dengan --repository-format ditetapkan ke generic.

  3. Verifikasi bahwa Anda memiliki izin yang diperlukan untuk repositori.

  4. Untuk mengupload modul Wasm sebagai artefak generik ke repositori, gunakan perintah gcloud artifacts generic upload.

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

    Ganti kode berikut:

    • PROJECT_ID: Google Cloud Project ID Anda
    • LOCATION: lokasi repositori regional atau multi-regional
    • REPOSITORY: nama repositori tempat Anda ingin mengupload modul Wasm
    • PACKAGE: nama paket file
    • VERSION: versi modul Wasm

    Setelah upload selesai, catat nama artefak generik seperti yang disebutkan dengan label name, misalnya add_header_plugin:v4 dalam contoh berikut. Tentukan nama ini saat Anda membuat plugin atau versi plugin.

    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. Untuk mengonfirmasi bahwa artefak berhasil diupload ke Artifact Registry, jalankan perintah gcloud artifacts files list dan verifikasi bahwa daftar memiliki file bernama PACKAGE:VERSION:plugin.wasm.

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

Repositori Docker

  1. Buat repositori Artifact Registry dengan --repository-format ditetapkan ke docker.

  2. Verifikasi bahwa Anda memiliki izin yang diperlukan untuk repositori.

  3. Buat direktori package/ lokal dan salin artefak plugin yang dapat dipublikasikan ke dalamnya. Contoh berikut menyalin artefak plugin yang dibuat oleh Rust:

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. Buat file package/Dockerfile dengan konten berikut:

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Kemasi kode plugin menggunakan Cloud Build atau Docker.

    Cloud Build

    1. Buat file package/cloudbuild.yaml konfigurasi build dengan konten berikut:

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

      Jalur tempat Anda menyimpan plugin harus dalam format berikut:

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

      Ganti kode berikut:

      • LOCATION: lokasi regional atau multi-regional dari repositori
      • PROJECT_ID: project ID konsol Google Cloud Anda
      • REPOSITORY: nama repositori tempat Anda ingin menyimpan image
      • IMAGE: nama image container di repositori—misalnya, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: tag image yang akan ditetapkan ke container—misalnya, production
    2. Picu operasi untuk membangun container plugin dan menguploadnya ke Artifact Registry:

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

    Docker

    1. Instal Docker jika belum diinstal. Docker disertakan dalam Cloud Shell, lingkungan shell interaktif Google Cloud .

    2. Konfigurasi Docker untuk melakukan autentikasi ke Artifact Registry. Contoh:

      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. Bangun image container:

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. Untuk memberi tag pada image lokal dengan nama image repositori, gunakan tag image:

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

      Ganti kode berikut:

      • LOCATION: lokasi regional atau multi-regional repositori
      • PROJECT_ID: project ID konsol Google Cloud Anda
      • REPOSITORY: nama repositori tempat Anda ingin menyimpan image
      • IMAGE: nama image container di repositori—misalnya, us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin.
      • IMAGE_TAG: tag image yang akan ditetapkan ke container—misalnya, production
    5. Upload image container yang diberi tag ke Artifact Registry.

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. Untuk mengonfirmasi bahwa image berhasil diupload ke Artifact Registry, jalankan perintah gcloud artifacts docker images list.

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

Menyiapkan dan mengupload file konfigurasi

Plugin dapat menerima data konfigurasi secara opsional, yang dapat memengaruhi perilaku plugin saat runtime. Data konfigurasi dapat berupa teks atau biner dan dalam format apa pun yang diterima oleh plugin. Jika ukuran data konfigurasi besar, Anda mungkin perlu mengupload file konfigurasi ke Artifact Registry.

Menulis kode plugin untuk membaca data konfigurasi

C++

Data konfigurasi diteruskan ke metode onConfigure objek konteks root, yang di-instance satu kali saat plugin dimulai, dan tetap aktif selama masa aktif runtime Wasm yang menghosting plugin. Objek konteks root adalah instance class RootContext atau subclass dari RootContext.

Kode plugin dapat mengontrol class yang digunakan untuk konteks root melalui nilai RegisterContextFactory. Misalnya, kode plugin berikut mendaftarkan MyRootContext dan MyHttpContext sebagai class yang akan digunakan untuk instance konteks root dan streaming. Kemudian, plugin membaca nilai rahasia dari data konfigurasi plugin, yang dapat diakses oleh instance konteks streaming melalui objek konteks root.

#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

Data konfigurasi dibaca saat menjalankan OnPluginStart, penerima metode yang dijalankan runtime pada struct PluginContext sekali saat plugin dimulai. Data konfigurasi tidak berubah selama masa aktif runtime Wasm yang menghosting plugin. PluginContext berguna untuk menjalankan logika inisialisasi dan mempertahankan status di banyak permintaan.

Kode plugin dapat mengontrol konteks yang digunakan untuk PluginContext dengan menerapkan metode NewPluginContext pada VMContext, yang meng-instance PluginContext. PluginContext kemudian membuat instance konteks HttpContext.

Misalnya, kode plugin berikut mendaftarkan VMContext, yang meng-instance PluginContext, konteks yang bertanggung jawab untuk membaca data konfigurasi dan meng-instance konteks HttpContext sesuai kebutuhan. PluginContext membaca nilai rahasia dari data konfigurasi plugin, menyimpannya di dalam konteks PluginContext, dan meneruskannya ke HttpContext di 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

Data konfigurasi dibaca dari trait RootContext, yang di-instansiasi sekali saat plugin dimulai, dan tetap aktif selama masa aktif runtime Wasm yang menghosting plugin. Trait RootContext berguna untuk melakukan operasi atau mempertahankan status di banyak permintaan.

Kode plugin dapat mengontrol class yang digunakan untuk konteks root melalui metode set_root_context, dan konteks root membuat instance konteks streaming. Misalnya, kode plugin berikut mendaftarkan MyRootContext, yang meng-instance MyHttpContext sesuai kebutuhan. Konteks root membaca nilai rahasia dari data konfigurasi plugin, dan meneruskannya ke konteks aliran.

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

Upload file konfigurasi

Jika ukuran data yang akan dikirimkan ke plugin Anda di on_configure melebihi 900 KiB, upload ke Artifact Registry dengan mengikuti metode yang dijelaskan dalam Mengupload kode plugin yang dikompilasi ke Artifact Registry. Dalam hal ini, simpan file konfigurasi dengan nama plugin.config (dan bukan plugin.wasm).

Langkah selanjutnya adalah membuat plugin.

Saat membuat plugin, Anda harus memberikan URI ke modul atau image Wasm yang diupload.

Membuat versi baru kode plugin

Untuk membuat versi baru kode plugin, edit file plugin. Kemudian, seperti yang dijelaskan di bagian sebelumnya, kompilasi kode plugin, kemas ulang, dan upload ke Artifact Registry.

Callback

Kode yang Anda kompilasi ke Wasm dapat menentukan metode atau fungsi arbitrer, tetapi beberapa di antaranya memiliki makna khusus. Ini adalah metode yang ditentukan dalam Proxy-Wasm SDK untuk bahasa pilihan Anda dan dipetakan ke spesifikasi Antarmuka Biner Aplikasi (ABI) Proxy-Wasm. Ekstensi Layanan memanggil callback ini sebagai respons terhadap permintaan pengguna atau sebagai respons terhadap peristiwa siklus proses plugin.

Callback ini tercantum dalam tabel berikut sesuai urutan pemanggilannya:

Nama dan deskripsi callback Nama metode C++ Nama metode Go Nama metode Rust
START_PLUGIN: Dipanggil saat plugin dimulai. RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: Dipanggil setelah plugin dimulai, untuk memberikan data konfigurasi ke plugin. RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: Dipanggil saat konteks streaming baru dibuat. Setiap aliran sesuai dengan permintaan HTTP klien. Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: Dipanggil untuk memproses header permintaan HTTP. Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: Dipanggil berulang kali untuk memproses potongan isi permintaan HTTP. Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: Dipanggil untuk memproses header respons HTTP. Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: Dipanggil berulang kali untuk memproses potongan isi respons HTTP. Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: Dipanggil saat pemrosesan plugin telah selesai. Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: Dipanggil saat objek konteks streaming yang sesuai dengan permintaan HTTP klien dihapus. Context::onDelete (tidak ada panggilan balik) (tidak ada panggilan balik)

Langkah berikutnya