首页 > 其他分享 >rust使用proxy-wasm-rust-sdk开发envoy wasm 进行GRPC调用

rust使用proxy-wasm-rust-sdk开发envoy wasm 进行GRPC调用

时间:2024-02-01 20:00:39浏览次数:22  
标签:name GRPC self envoy grpc let wasm rust

在一些业务中,对于客户端发送的请求,需要调用grcp服务来确认是否合规,这个时候可以在入口网关做些统一的处理。

之前写的用go来编写wasm,在编写grpc调用时发现由于tinygo的原因导致无法进行grpc请求,在找了一圈后决定使用proxy-wasm-rust-sdk来完成该部分功能。

一、创建项目

cargo new --lib grpc_call

二、安装依赖

cargo add proxy-wasm
rustup target add wasm32-unknown-unknown --执行一次就好了,安装目标平台

三、定义protocol协议文件

syntax = "proto3";

package hello;

service HelloService {
    rpc Hello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}

message HelloReply{
    string message =1;
}

四、生成代码

4.1、安装protocol代码生成工具

cargo add protoc-rust --build

4.2、添加build.rs文件

fn main() {
    let proto_files = vec!["./protos/hello.proto"];
    protoc_rust::Codegen::new()
        .out_dir("./src/pb")
        .inputs(proto_files)
        .run()
        .expect("build error");
}

指定输入文件、输出目录。需要注意的是输出目录必须存在。

4.3、生成代码

cargo build

 

示例项目目录结构如下

五、配置文件定义

#[derive(Deserialize, Debug)]
struct VmConfig {
    cluster: String,
}

cluster参数 指定grpc服务后端集群,在envoy中必须要定义。

六、加载配置文件

 

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

    fn on_vm_start(&mut self, _vm_configuration_size: usize) -> bool {
        let vm_config = self.get_vm_configuration();
        match vm_config {
            Some(v) => unsafe {
                let d = v.as_slice();
                let result: Result<VmConfig, serde_json::Error> = serde_json::from_slice(d);
                if let Ok(vm_json) = result {
                    VM_CONFIG_GLBOAL = vm_json;
                }
            },
            None => {}
        }
        true
    }

    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.header_content = String::from_utf8(config_bytes).unwrap()
        }
        true
    }

    fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(HttpHeaders { context_id }))
    }
}

  代码中在vm_start 加载了配置文件,并将加载的值赋值给全局变量,在envoy配置中同样需要在vm节点配置配置项。

七、发送grpc请求

在HttpContext实现中编写代码

fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        let path = self.get_http_request_header(":path").unwrap_or_default();
        let grpc_name: &str;
        if !path.contains("name") {
            return Action::Continue;
        }
        let uparms_arr: Vec<&str> = path.split("name=").collect();
        if uparms_arr[1].contains("&") {
            let real_uparms: Vec<&str> = uparms_arr[1].split("&").collect();
            grpc_name = real_uparms[0];
        } else {
            grpc_name = uparms_arr[1]
        }
        if grpc_name.is_empty() {
            return Action::Continue;
        }
        let mut req = pb::hello::HelloRequest::new();
        req.set_name(grpc_name.to_string());
        let message = req.write_to_bytes().unwrap();
        unsafe {
            match self.dispatch_grpc_call(
                &VM_CONFIG_GLBOAL.cluster,
                "hello.HelloService",
                "Hello",
                Vec::<(&str, &[u8])>::new(),
                Some(message.as_slice()),
                Duration::from_millis(20),
            ) {
                Ok(_) => error!("grpc send success"),
                Err(e) => error!("grpc send error:{:?}", e),
            }
        }
        Action::Pause
    }

这里取url参数,如果有name参数,则发送grpc请求,调用grpc服务,注意cluster,是从配置文件中获取的,这里是个变量,其他的参数没变化,所以就写死了。

超时、grpc元数据也可以放在配置文件,示例不需要就没写。

八、接收grpc响应,并恢复请求

在Context实现中编写代码

impl Context for HttpHeaders {
    fn on_grpc_call_response(&mut self, _token_id: u32, _status_code: u32, response_size: usize) {
        if let Some(body) = self.get_grpc_call_response_body(0, response_size) {
            let mut hp = pb::hello::HelloReply::new();
            match hp.merge_from_bytes(body.as_slice()) {
                Ok(_) => {
                    let msg = hp.get_message();
                    error!("{}", msg);
                    self.set_http_request_header("hello", Some(&msg.to_string()));
                }
                Err(e) => {
                    error!("{}", e)
                }
            }
        }
        self.resume_http_request();
    }
}

主要就是解析返回

九、打包部署

9.1 打包

cargo build --release

在项目目录 target/wasm32-unknown-unknown/release 目录下找到生成的wasm文件,放到envoy可访问目录。

9.2 部署

http_filters:
          - name: envoy.filters.http.wasm
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
              config:
                name: "xxx"
                root_id: "xxx"
                configuration:
                  '@type': type.googleapis.com/google.protobuf.StringValue
                  value: {}
                vm_config:
                  runtime: "envoy.wasm.runtime.v8"
                  configuration:
                    '@type': type.googleapis.com/google.protobuf.StringValue
                    value: |
                      {
                        "cluster": "grpc_server"
                      }
                  code:
                    local:
                      filename: '/root/envoy/grpc_call.wasm'
          - name: envoy.filters.http.router
            typedConfig:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

 这里在vm_config中设置的配置文件,与wasm 代码中保持一致

标签:name,GRPC,self,envoy,grpc,let,wasm,rust
From: https://www.cnblogs.com/pjjwpc/p/17996579

相关文章

  • 47从零开始用Rust编写nginx,配对还有这么多要求!负载均衡中的路径匹配
    wmproxywmproxy已用Rust实现http/https代理,socks5代理,反向代理,负载均衡,静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实现过程分享出来,感兴趣的可以一起造个轮子项目地址国内:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/wmpro......
  • Rust 关于 Cargo 和 Crates.io 的内容
    原文链接参考Rust关于Cargo和Crates.io的内容,注意Windows和Linux系统的文件路径差异。目录采用发布配置自定义构建将crate发布到Crates.io编写有用的文档注释常用(文档注释)部分文档注释作为测试注释包含项的结构使用pubuse导出合适的公有API创建Crates.io账号向新c......
  • WebAssembly核心编程[1]:wasm模块实例化的N种方式
    当我们在一个Web应用中使用WebAssembly,最终的目的要么是执行wasm模块的入口程序(通过start指令指定的函数),要么是调用其导出的函数,这一切的前提需要创建一个通过WebAssembly.Instance对象表示的wasm模块实例(源代码)。一、wasm模块实例化总体流程二、利用WebAssembly.Module创建实......
  • 浅谈Rust数据所有权
    Rust的目标之一,是能够作为一门内存高效且内存安全的语言。本文我们将重点关注Rust关于“内存高效”的语言设计,让读者能够建立起对Rust的基本认知。内存高效一个不恰当的比喻:将一座房子卖给另一个人的时候,究竟是从头开始建一座同样的房子,然后把这座新房子的房产证交给买家的方式......
  • 46从零开始用Rust编写nginx,数据还能这么传,多层代理(IP多级代理)搭建
    wmproxywmproxy已用Rust实现http/https代理,socks5代理,反向代理,负载均衡,静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实现过程分享出来,感兴趣的可以一起造个轮子项目地址国内:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/wmpro......
  • OpenHarmony 4.0的Rust开发
    OH4.0的Rust开发背景Rust是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust官方也使用Cargo工具来专门为Rust代码创建工程和构建编译。OpenHarmony为了集成C/C++代码和提升编译速度,使用了GN+Ninja的编译构建系统。GN的构建语言简洁......
  • 写一段rust代码,两个线程共享一个bool变量,一个写,一个读
    usestd::sync::{Arc,Mutex};usestd::thread;fnmain(){//创建一个布尔变量并用Arc和Mutex包装,使其可在多个线程间共享和修改letshared_bool=Arc::new(Mutex::new(false));//克隆Arc变量,以便在两个线程之间共享letwriter_shared_bool=Ar......
  • 26从零开始用Rust编写nginx,如何发布Rust项目到Docker
    wmproxywmproxy已用Rust实现http/https代理,socks5代理,反向代理,静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子项目地址国内:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/wmproxy容......
  • windows环境安装grpcui
    1. 首先安装golang语言环境  go语言中文官方下载地址:https://studygolang.com/dl选择windows版本 下载完成后直接双击msi文件根据提示进行安装安装成功后把安装目录配到环境变量例如,我安装到D盘下 命令行查看go version 安装成功 2. 安装grpcui包官方地......
  • Rust学习笔记
    迭代器迭代器是一个值,它可以生成一系列值Iterrator类型和IntoIterator类型迭代器是实现了Iterator类型的任意值IntoIterator是迭代器本身类型,Item是它生成的值的类型。任意实现了IntoIterator的类型都可以成为可迭代者,可以通过into_iter获得一个迭代器迭代器能生成值迭......