mirror of
https://github.com/alibaba/higress.git
synced 2026-02-25 21:21:01 +08:00
Compare commits
21 Commits
plugins/wa
...
v2.0.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dbd1b2731 | ||
|
|
7f23980bf5 | ||
|
|
6fb0684c39 | ||
|
|
dfac9fa5e6 | ||
|
|
bfd9e3026d | ||
|
|
49aad4152c | ||
|
|
94aacf5153 | ||
|
|
efcfdbf36e | ||
|
|
2dbde1833f | ||
|
|
7272eff8b6 | ||
|
|
a84a382f1d | ||
|
|
477e44b9f1 | ||
|
|
512385d225 | ||
|
|
b997e6fd26 | ||
|
|
fab3ebb35a | ||
|
|
1431ff9cfe | ||
|
|
fac2c3e7a3 | ||
|
|
574d1aa36a | ||
|
|
7840167c4a | ||
|
|
9d8e78dae3 | ||
|
|
133a30b8d5 |
@@ -133,8 +133,8 @@ jobs:
|
||||
command="
|
||||
set -e
|
||||
cd /workspace/plugins/wasm-rust/extensions/${PLUGIN_NAME}
|
||||
cargo build --target wasm32-wasi --release
|
||||
cp target/wasm32-wasi/release/*.wasm plugin.wasm
|
||||
cargo build --target wasm32-wasip1 --release
|
||||
cp target/wasm32-wasip1/release/*.wasm plugin.wasm
|
||||
tar czvf plugin.tar.gz plugin.wasm
|
||||
echo ${{ secrets.REGISTRY_PASSWORD }} | oras login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin ${{ env.IMAGE_REGISTRY_SERVICE }}
|
||||
oras push ${target_image} ${push_command}
|
||||
|
||||
85
.github/workflows/helm-docs.yaml
vendored
85
.github/workflows/helm-docs.yaml
vendored
@@ -4,11 +4,15 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
paths:
|
||||
- 'helm/**'
|
||||
workflow_dispatch: ~
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'helm/**'
|
||||
|
||||
jobs:
|
||||
|
||||
helm:
|
||||
name: Helm Docs
|
||||
runs-on: ubuntu-latest
|
||||
@@ -32,4 +36,79 @@ jobs:
|
||||
echo "Please use helm-docs in your clone, of your fork, of the project, and commit a updated README.md for the chart."
|
||||
fi
|
||||
git diff --exit-code
|
||||
rm -f ./helm-docs
|
||||
rm -f ./helm-docs
|
||||
|
||||
translate-readme:
|
||||
needs: helm
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq
|
||||
|
||||
- name: Translate README.md to Chinese
|
||||
env:
|
||||
API_URL: ${{ secrets.HIGRESS_OPENAI_API_URL }}
|
||||
API_KEY: ${{ secrets.HIGRESS_OPENAI_API_KEY }}
|
||||
API_MODEL: ${{ secrets.HIGRESS_OPENAI_API_MODEL }}
|
||||
run: |
|
||||
cd ./helm/higress
|
||||
FILE_CONTENT=$(cat README.md)
|
||||
|
||||
PAYLOAD=$(jq -n \
|
||||
--arg model "$API_MODEL" \
|
||||
--arg content "$FILE_CONTENT" \
|
||||
'{
|
||||
model: $model,
|
||||
messages: [
|
||||
{"role": "system", "content": "You are a translation assistant that translates English Markdown text to Chinese."},
|
||||
{"role": "user", "content": $content}
|
||||
],
|
||||
temperature: 1.1,
|
||||
stream: false
|
||||
}')
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$API_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $API_KEY" \
|
||||
-d "$PAYLOAD")
|
||||
|
||||
echo "response: $RESPONSE"
|
||||
|
||||
TRANSLATED_CONTENT=$(echo "$RESPONSE" | jq -r '.choices[0].message.content')
|
||||
|
||||
if [ -z "$TRANSLATED_CONTENT" ]; then
|
||||
echo "Translation failed! Response: $RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$TRANSLATED_CONTENT" > README.zh.new.md
|
||||
echo "Translation completed and saved to README.zh.new.md."
|
||||
|
||||
- name: Compare README.zh.md
|
||||
id: compare
|
||||
run: |
|
||||
cd ./helm/higress
|
||||
NEW_README_ZH="README.zh.new.md"
|
||||
EXISTING_README_ZH="README.zh.md"
|
||||
|
||||
if [ ! -f "$EXISTING_README_ZH" ]; then
|
||||
echo "Add README.zh.md."
|
||||
mv "$NEW_README_ZH" "$EXISTING_README_ZH"
|
||||
echo "updated=true" >> $GITHUB_ENV
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! diff -q "$NEW_README_ZH" "$EXISTING_README_ZH"; then
|
||||
echo "Files are different. Updating README.zh.md."
|
||||
mv "$NEW_README_ZH" "$EXISTING_README_ZH"
|
||||
echo "updated=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Files are identical. No update needed."
|
||||
echo "updated=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,4 +17,3 @@ target/
|
||||
tools/hack/cluster.conf
|
||||
envoy/1.20
|
||||
istio/1.12
|
||||
Cargo.lock
|
||||
|
||||
@@ -144,7 +144,7 @@ docker-buildx-push: clean-env docker.higress-buildx
|
||||
export PARENT_GIT_TAG:=$(shell cat VERSION)
|
||||
export PARENT_GIT_REVISION:=$(TAG)
|
||||
|
||||
export ENVOY_PACKAGE_URL_PATTERN?=https://github.com/higress-group/proxy/releases/download/v2.1.0/envoy-symbol-ARCH.tar.gz
|
||||
export ENVOY_PACKAGE_URL_PATTERN?=https://github.com/higress-group/proxy/releases/download/v2.1.1/envoy-symbol-ARCH.tar.gz
|
||||
|
||||
build-envoy: prebuild
|
||||
./tools/hack/build-envoy.sh
|
||||
|
||||
@@ -34,7 +34,7 @@ Higress 在阿里内部为解决 Tengine reload 对长连接业务有损,以
|
||||
|
||||
阿里云基于 Higress 构建了云原生 API 网关产品,为大量企业客户提供 99.99% 的网关高可用保障服务能力。
|
||||
|
||||
Higress 基于 AI 网关能力,支撑了通义千问 APP、百炼大模型 API、机器学习 PAI 平台等 AI 业务。同时服务国内头部的 AIGC 企业(如零一万物),以及 AI 产品(如 FastGPT)
|
||||
Higress 的 AI 网关能力支持国内外所有[主流模型供应商](https://github.com/alibaba/higress/tree/main/plugins/wasm-go/extensions/ai-proxy/provider)和基于 vllm/ollama 等自建的 DeepSeek 模型;在阿里云内部支撑了通义千问 APP、百炼大模型 API、机器学习 PAI 平台等 AI 业务。同时服务国内头部的 AIGC 企业(如零一万物),以及 AI 产品(如 FastGPT)
|
||||
|
||||

|
||||
|
||||
|
||||
Submodule envoy/envoy updated: 440fb1b0f3...c2471f1247
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 2.0.6
|
||||
appVersion: 2.0.7
|
||||
description: Helm chart for deploying higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
@@ -10,4 +10,4 @@ name: higress-core
|
||||
sources:
|
||||
- http://github.com/alibaba/higress
|
||||
type: application
|
||||
version: 2.0.6
|
||||
version: 2.0.7
|
||||
|
||||
@@ -3,7 +3,7 @@ global:
|
||||
enableH3: false
|
||||
enableIPv6: false
|
||||
enableProxyProtocol: false
|
||||
enableLDSCache: true
|
||||
enableLDSCache: false
|
||||
enablePushAllMCPClusters: true
|
||||
liteMetrics: false
|
||||
xdsMaxRecvMsgSize: "104857600"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: file://../core
|
||||
version: 2.0.6
|
||||
version: 2.0.7
|
||||
- name: higress-console
|
||||
repository: https://higress.io/helm-charts/
|
||||
version: 2.0.2
|
||||
digest: sha256:9c84a628df434c4bf23ec10d62ad7ddf4b15957f797b01bbaa492ede33d87003
|
||||
generated: "2025-01-17T15:10:43.589701962+08:00"
|
||||
version: 2.0.4
|
||||
digest: sha256:ca9cc8bdac0488d79c20e7a4e3d7b3a436a59b697a37728daa462601b4d1ea65
|
||||
generated: "2025-02-19T16:23:39.424987+08:00"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: 2.0.6
|
||||
appVersion: 2.0.7
|
||||
description: Helm chart for deploying Higress gateways
|
||||
icon: https://higress.io/img/higress_logo_small.png
|
||||
home: http://higress.io/
|
||||
@@ -12,9 +12,9 @@ sources:
|
||||
dependencies:
|
||||
- name: higress-core
|
||||
repository: "file://../core"
|
||||
version: 2.0.6
|
||||
version: 2.0.7
|
||||
- name: higress-console
|
||||
repository: "https://higress.io/helm-charts/"
|
||||
version: 2.0.2
|
||||
version: 2.0.4
|
||||
type: application
|
||||
version: 2.0.6
|
||||
version: 2.0.7
|
||||
|
||||
188
helm/higress/README.zh.md
Normal file
188
helm/higress/README.zh.md
Normal file
@@ -0,0 +1,188 @@
|
||||
## Higress for Kubernetes
|
||||
|
||||
Higress 是基于阿里巴巴内部网关实践构建的云原生 API 网关。
|
||||
|
||||
依托 Istio 和 Envoy,Higress 实现了流量网关、微服务网关和安全网关三重架构的融合,从而大幅降低了部署、运维成本。
|
||||
|
||||
## 设置仓库信息
|
||||
|
||||
```console
|
||||
helm repo add higress.io https://higress.io/helm-charts
|
||||
helm repo update
|
||||
```
|
||||
|
||||
## 安装
|
||||
|
||||
以 `higress` 为发布名称安装 chart:
|
||||
|
||||
```console
|
||||
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes
|
||||
```
|
||||
|
||||
## 卸载
|
||||
|
||||
要卸载/删除 higress 部署:
|
||||
|
||||
```console
|
||||
helm delete higress -n higress-system
|
||||
```
|
||||
|
||||
该命令会移除与 chart 相关的所有 Kubernetes 组件,并删除发布。
|
||||
|
||||
## 参数
|
||||
|
||||
## 值
|
||||
|
||||
| 键 | 类型 | 默认值 | 描述 |
|
||||
|-----|------|---------|-------------|
|
||||
| clusterName | 字符串 | `""` | |
|
||||
| controller.affinity | 对象 | `{}` | |
|
||||
| controller.automaticHttps.email | 字符串 | `""` | |
|
||||
| controller.automaticHttps.enabled | 布尔值 | `true` | |
|
||||
| controller.autoscaling.enabled | 布尔值 | `false` | |
|
||||
| controller.autoscaling.maxReplicas | 整数 | `5` | |
|
||||
| controller.autoscaling.minReplicas | 整数 | `1` | |
|
||||
| controller.autoscaling.targetCPUUtilizationPercentage | 整数 | `80` | |
|
||||
| controller.env | 对象 | `{}` | |
|
||||
| controller.hub | 字符串 | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
|
||||
| controller.image | 字符串 | `"higress"` | |
|
||||
| controller.imagePullSecrets | 列表 | `[]` | |
|
||||
| controller.labels | 对象 | `{}` | |
|
||||
| controller.name | 字符串 | `"higress-controller"` | |
|
||||
| controller.nodeSelector | 对象 | `{}` | |
|
||||
| controller.podAnnotations | 对象 | `{}` | |
|
||||
| controller.podSecurityContext | 对象 | `{}` | |
|
||||
| controller.ports[0].name | 字符串 | `"http"` | |
|
||||
| controller.ports[0].port | 整数 | `8888` | |
|
||||
| controller.ports[0].protocol | 字符串 | `"TCP"` | |
|
||||
| controller.ports[0].targetPort | 整数 | `8888` | |
|
||||
| controller.ports[1].name | 字符串 | `"http-solver"` | |
|
||||
| controller.ports[1].port | 整数 | `8889` | |
|
||||
| controller.ports[1].protocol | 字符串 | `"TCP"` | |
|
||||
| controller.ports[1].targetPort | 整数 | `8889` | |
|
||||
| controller.ports[2].name | 字符串 | `"grpc"` | |
|
||||
| controller.ports[2].port | 整数 | `15051` | |
|
||||
| controller.ports[2].protocol | 字符串 | `"TCP"` | |
|
||||
| controller.ports[2].targetPort | 整数 | `15051` | |
|
||||
| controller.probe.httpGet.path | 字符串 | `"/ready"` | |
|
||||
| controller.probe.httpGet.port | 整数 | `8888` | |
|
||||
| controller.probe.initialDelaySeconds | 整数 | `1` | |
|
||||
| controller.probe.periodSeconds | 整数 | `3` | |
|
||||
| controller.probe.timeoutSeconds | 整数 | `5` | |
|
||||
| controller.rbac.create | 布尔值 | `true` | |
|
||||
| controller.replicas | 整数 | `1` | Higress Controller 的 Pod 数量 |
|
||||
| controller.resources.limits.cpu | 字符串 | `"1000m"` | |
|
||||
| controller.resources.limits.memory | 字符串 | `"2048Mi"` | |
|
||||
| controller.resources.requests.cpu | 字符串 | `"500m"` | |
|
||||
| controller.resources.requests.memory | 字符串 | `"2048Mi"` | |
|
||||
| controller.securityContext | 对象 | `{}` | |
|
||||
| controller.service.type | 字符串 | `"ClusterIP"` | |
|
||||
| controller.serviceAccount.annotations | 对象 | `{}` | 添加到服务账户的注解 |
|
||||
| controller.serviceAccount.create | 布尔值 | `true` | 指定是否创建服务账户 |
|
||||
| controller.serviceAccount.name | 字符串 | `""` | 如果未设置且 create 为 true,则使用 fullname 模板生成名称 |
|
||||
| controller.tag | 字符串 | `""` | |
|
||||
| controller.tolerations | 列表 | `[]` | |
|
||||
| downstream | 对象 | `{"connectionBufferLimits":32768,"http2":{"initialConnectionWindowSize":1048576,"initialStreamWindowSize":65535,"maxConcurrentStreams":100},"idleTimeout":180,"maxRequestHeadersKb":60,"routeTimeout":0}` | 下游配置设置 |
|
||||
| gateway.affinity | 对象 | `{}` | |
|
||||
| gateway.annotations | 对象 | `{}` | 应用到所有资源的注解 |
|
||||
| gateway.autoscaling.enabled | 布尔值 | `false` | |
|
||||
| gateway.autoscaling.maxReplicas | 整数 | `5` | |
|
||||
| gateway.autoscaling.minReplicas | 整数 | `1` | |
|
||||
| gateway.autoscaling.targetCPUUtilizationPercentage | 整数 | `80` | |
|
||||
| gateway.containerSecurityContext | 字符串 | `nil` | |
|
||||
| gateway.env | 对象 | `{}` | Pod 环境变量 |
|
||||
| gateway.hostNetwork | 布尔值 | `false` | |
|
||||
| gateway.httpPort | 整数 | `80` | |
|
||||
| gateway.httpsPort | 整数 | `443` | |
|
||||
| gateway.hub | 字符串 | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | |
|
||||
| gateway.image | 字符串 | `"gateway"` | |
|
||||
| gateway.kind | 字符串 | `"Deployment"` | 使用 `DaemonSet` 或 `Deployment` |
|
||||
| gateway.labels | 对象 | `{}` | 应用到所有资源的标签 |
|
||||
| gateway.metrics.enabled | 布尔值 | `false` | 如果为 true,则为网关创建 PodMonitor 或 VMPodScrape |
|
||||
| gateway.metrics.honorLabels | 布尔值 | `false` | |
|
||||
| gateway.metrics.interval | 字符串 | `""` | |
|
||||
| gateway.metrics.metricRelabelConfigs | 列表 | `[]` | 用于 operator.victoriametrics.com/v1beta1.VMPodScrape |
|
||||
| gateway.metrics.metricRelabelings | 列表 | `[]` | 用于 monitoring.coreos.com/v1.PodMonitor |
|
||||
| gateway.metrics.provider | 字符串 | `"monitoring.coreos.com"` | CustomResourceDefinition 的提供者组名,可以是 monitoring.coreos.com 或 operator.victoriametrics.com |
|
||||
| gateway.metrics.rawSpec | 对象 | `{}` | 更多原始的 podMetricsEndpoints 规范 |
|
||||
| gateway.metrics.relabelConfigs | 列表 | `[]` | |
|
||||
| gateway.metrics.relabelings | 列表 | `[]` | |
|
||||
| gateway.metrics.scrapeTimeout | 字符串 | `""` | |
|
||||
| gateway.name | 字符串 | `"higress-gateway"` | |
|
||||
| gateway.networkGateway | 字符串 | `""` | 如果指定,网关将作为给定网络的网络网关。 |
|
||||
| gateway.nodeSelector | 对象 | `{}` | |
|
||||
| gateway.podAnnotations."prometheus.io/path" | 字符串 | `"/stats/prometheus"` | |
|
||||
| gateway.podAnnotations."prometheus.io/port" | 字符串 | `"15020"` | |
|
||||
| gateway.podAnnotations."prometheus.io/scrape" | 字符串 | `"true"` | |
|
||||
| gateway.podAnnotations."sidecar.istio.io/inject" | 字符串 | `"false"` | |
|
||||
| gateway.rbac.enabled | 布尔值 | `true` | 如果启用,将创建角色以启用从网关访问证书。当使用 http://gateway-api.org/ 时不需要。 |
|
||||
| gateway.readinessFailureThreshold | 整数 | `30` | 指示准备失败前的连续失败探测次数。 |
|
||||
| gateway.readinessInitialDelaySeconds | 整数 | `1` | 准备探测的初始延迟秒数。 |
|
||||
| gateway.readinessPeriodSeconds | 整数 | `2` | 准备探测之间的间隔。 |
|
||||
| gateway.readinessSuccessThreshold | 整数 | `1` | 指示准备成功前的连续成功探测次数。 |
|
||||
| gateway.readinessTimeoutSeconds | 整数 | `3` | 准备探测的超时秒数 |
|
||||
| gateway.replicas | 整数 | `2` | Higress Gateway 的 Pod 数量 |
|
||||
| gateway.resources.limits.cpu | 字符串 | `"2000m"` | |
|
||||
| gateway.resources.limits.memory | 字符串 | `"2048Mi"` | |
|
||||
| gateway.resources.requests.cpu | 字符串 | `"2000m"` | |
|
||||
| gateway.resources.requests.memory | 字符串 | `"2048Mi"` | |
|
||||
| gateway.revision | 字符串 | `""` | 修订声明此网关属于哪个修订 |
|
||||
| gateway.rollingMaxSurge | 字符串 | `"100%"` | |
|
||||
| gateway.rollingMaxUnavailable | 字符串 | `"25%"` | |
|
||||
| gateway.securityContext | 字符串 | `nil` | 定义 Pod 的安全上下文。如果未设置,将自动设置为绑定到端口 80 和 443 所需的最小权限。在 Kubernetes 1.22+ 上,这只需要 `net.ipv4.ip_unprivileged_port_start` 系统调用。 |
|
||||
| gateway.service.annotations | 对象 | `{}` | |
|
||||
| gateway.service.externalTrafficPolicy | 字符串 | `""` | |
|
||||
| gateway.service.loadBalancerClass | 字符串 | `""` | |
|
||||
| gateway.service.loadBalancerIP | 字符串 | `""` | |
|
||||
| gateway.service.loadBalancerSourceRanges | 列表 | `[]` | |
|
||||
| gateway.service.ports[0].name | 字符串 | `"http2"` | |
|
||||
| gateway.service.ports[0].port | 整数 | `80` | |
|
||||
| gateway.service.ports[0].protocol | 字符串 | `"TCP"` | |
|
||||
| gateway.service.ports[0].targetPort | 整数 | `80` | |
|
||||
| gateway.service.ports[1].name | 字符串 | `"https"` | |
|
||||
| gateway.service.ports[1].port | 整数 | `443` | |
|
||||
| gateway.service.ports[1].protocol | 字符串 | `"TCP"` | |
|
||||
| gateway.service.ports[1].targetPort | 整数 | `443` | |
|
||||
| gateway.service.type | 字符串 | `"LoadBalancer"` | 服务类型。设置为 "None" 以完全禁用服务 |
|
||||
| gateway.serviceAccount.annotations | 对象 | `{}` | 添加到服务账户的注解 |
|
||||
| gateway.serviceAccount.create | 布尔值 | `true` | 如果设置,将创建服务账户。否则,使用默认值 |
|
||||
| gateway.serviceAccount.name | 字符串 | `""` | 要使用的服务账户名称。如果未设置,则使用发布名称 |
|
||||
| gateway.tag | 字符串 | `""` | |
|
||||
| gateway.tolerations | 列表 | `[]` | |
|
||||
| gateway.unprivilegedPortSupported | 字符串 | `nil` | |
|
||||
| global.autoscalingv2API | 布尔值 | `true` | 是否使用 autoscaling/v2 模板进行 HPA 设置,仅供内部使用,用户不应配置。 |
|
||||
| global.caAddress | 字符串 | `""` | 自定义的 CA 地址,用于为集群中的 Pod 检索证书。CSR 客户端(如 Istio Agent 和 ingress gateways)可以使用此地址指定 CA 端点。如果未明确设置,则默认为 Istio 发现地址。 |
|
||||
| global.caName | 字符串 | `""` | 工作负载证书的 CA 名称。例如,当 caName=GkeWorkloadCertificate 时,GKE 工作负载证书将用作工作负载的证书。默认值为 "",当 caName="" 时,CA 将通过其他机制(如环境变量 CA_PROVIDER)配置。 |
|
||||
| global.configCluster | 布尔值 | `false` | 将远程集群配置为外部 istiod 的配置集群。 |
|
||||
| global.defaultPodDisruptionBudget | 对象 | `{"enabled":false}` | 为控制平面启用 Pod 中断预算,用于确保 Istio 控制平面组件逐步升级或恢复。 |
|
||||
| global.defaultResources | 对象 | `{"requests":{"cpu":"10m"}}` | 应用于所有部署的最小请求资源集,以便 Horizontal Pod Autoscaler 能够正常工作(如果设置)。每个组件可以通过在相关部分添加自己的资源块并设置所需的资源值来覆盖这些默认值。 |
|
||||
| global.defaultUpstreamConcurrencyThreshold | 整数 | `10000` | |
|
||||
| global.disableAlpnH2 | 布尔值 | `false` | 是否在 ALPN 中禁用 HTTP/2 |
|
||||
| global.enableGatewayAPI | 布尔值 | `false` | 如果为 true,Higress Controller 还将监控 Gateway API 资源 |
|
||||
| global.enableH3 | 布尔值 | `false` | |
|
||||
| global.enableIPv6 | 布尔值 | `false` | |
|
||||
| global.enableIstioAPI | 布尔值 | `true` | 如果为 true,Higress Controller 还将监控 istio 资源 |
|
||||
| global.enableLDSCache | 布尔值 | `true` | |
|
||||
| global.enableProxyProtocol | 布尔值 | `false` | |
|
||||
| global.enablePushAllMCPClusters | 布尔值 | `true` | |
|
||||
| global.enableSRDS | 布尔值 | `true` | |
|
||||
| global.enableStatus | 布尔值 | `true` | 如果为 true,Higress Controller 将更新 Ingress 资源的状态字段。从 Nginx Ingress 迁移时,为了避免 Ingress 对象的状态字段被覆盖,需要将此参数设置为 false,以便 Higress 不会将入口 IP 写入相应 Ingress 对象的状态字段。 |
|
||||
| global.externalIstiod | 布尔值 | `false` | 配置由外部 istiod 控制的远程集群数据平面。当设置为 true 时,本地不部署 istiod,仅启用其他发现 chart 的子集。 |
|
||||
| global.hostRDSMergeSubset | 布尔值 | `false` | |
|
||||
| global.hub | 字符串 | `"higress-registry.cn-hangzhou.cr.aliyuncs.com/higress"` | Istio 镜像的默认仓库。发布版本发布到 docker hub 的 'istio' 项目下。来自 prow 的开发构建位于 gcr.io |
|
||||
| global.imagePullPolicy | 字符串 | `""` | 如果不需要默认行为,则指定镜像拉取策略。默认行为:最新镜像将始终拉取,否则 IfNotPresent。 |
|
||||
| global.imagePullSecrets | 列表 | `[]` | 所有 ServiceAccount 的 ImagePullSecrets,用于引用此 ServiceAccount 的 Pod 拉取任何镜像的同一命名空间中的秘密列表。对于不使用 ServiceAccount 的组件(即 grafana、servicegraph、tracing),ImagePullSecrets 将添加到相应的 Deployment(StatefulSet) 对象中。对于配置了私有 docker 注册表的任何集群,必须设置。 |
|
||||
| global.ingressClass | 字符串 | `"higress"` | IngressClass 过滤 higress controller 监听的 ingress 资源。默认的 ingress class 是 higress。有一些特殊情况用于特殊的 ingress class。1. 当 ingress class 设置为 nginx 时,higress controller 将监听带有 nginx ingress class 或没有任何 ingress class 的 ingress 资源。2. 当 ingress class 设置为空时,higress controller 将监听 k8s 集群中的所有 ingress 资源。 |
|
||||
| global.istioNamespace | 字符串 | `"istio-system"` | 用于定位 istiod。 |
|
||||
| global.istiod | 对象 | `{"enableAnalysis":false}` | 默认在主分支中启用以最大化测试。 |
|
||||
| global.jwtPolicy | 字符串 | `"third-party-jwt"` | 配置验证 JWT 的策略。目前支持两个选项:"third-party-jwt" 和 "first-party-jwt"。 |
|
||||
| global.kind | 布尔值 | `false` | |
|
||||
| global.liteMetrics | 布尔值 | `false` | |
|
||||
| global.local | 布尔值 | `false` | 当部署到本地集群(如:kind 集群)时,将此设置为 true。 |
|
||||
| global.logAsJson | 布尔值 | `false` | |
|
||||
| global.logging | 对象 | `{"level":"default:info"}` | 以逗号分隔的每个范围的最小日志级别,格式为 <scope>:<level>,<scope>:<level> 控制平面根据组件不同有不同的范围,但可以配置所有组件的默认日志级别 如果为空,将使用代码中配置的默认范围和级别 |
|
||||
| global.meshID | 字符串 | `""` | 如果网格管理员未指定值,Istio 将使用网格的信任域的值。最佳实践是选择一个合适的信任域值。 |
|
||||
| global.meshNetworks | 对象 | `{}` | |
|
||||
| global.mountMtlsCerts | 布尔值 | `false` | 使用用户指定的、挂载的密钥和证书用于 Pilot 和工作负载。 |
|
||||
| global.multiCluster.clusterName | 字符串 | `""` | 应设置为此安装运行的集群的名称。这是为了正确标记代理的 sidecar 注入所必需的 |
|
||||
| global.multiCluster.enabled | 布尔值 | `true` | 设置为 true 以通过各自的 ingressgateway 服务连接两个 kubernetes 集群,当每个集群中的 Pod 无法直接相互通信时。
|
||||
Submodule istio/istio updated: ad7d051f38...5a5aa495c7
Submodule istio/proxy updated: 4e8eba8fc8...8a85c12b89
@@ -15,12 +15,6 @@
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
. "github.com/alibaba/higress/pkg/ingress/log"
|
||||
)
|
||||
@@ -57,101 +51,10 @@ func (a auth) Parse(annotations Annotations, config *Ingress, globalContext *Glo
|
||||
if !needAuthConfig(annotations) {
|
||||
return nil
|
||||
}
|
||||
|
||||
authConfig := &AuthConfig{
|
||||
AuthType: defaultAuthType,
|
||||
}
|
||||
|
||||
// Check auth type
|
||||
authType, err := annotations.ParseStringASAP(authType)
|
||||
if err != nil {
|
||||
IngressLog.Errorf("Parse auth type error %v within ingress %/%s", err, config.Namespace, config.Name)
|
||||
return nil
|
||||
}
|
||||
if authType != defaultAuthType {
|
||||
IngressLog.Errorf("Auth type %s within ingress %/%s is not supported yet.", authType, config.Namespace, config.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
secretName, _ := annotations.ParseStringASAP(authSecretAnn)
|
||||
namespaced := util.SplitNamespacedName(secretName)
|
||||
if namespaced.Name == "" {
|
||||
IngressLog.Errorf("Auth secret name within ingress %s/%s is invalid", config.Namespace, config.Name)
|
||||
return nil
|
||||
}
|
||||
if namespaced.Namespace == "" {
|
||||
namespaced.Namespace = config.Namespace
|
||||
}
|
||||
|
||||
configKey := util.ClusterNamespacedName{
|
||||
NamespacedName: namespaced,
|
||||
ClusterId: config.ClusterId,
|
||||
}
|
||||
authConfig.AuthSecret = configKey
|
||||
|
||||
// Subscribe secret
|
||||
globalContext.WatchedSecrets.Insert(configKey.String())
|
||||
|
||||
secretType := authFileAuthSecretType
|
||||
if rawSecretType, err := annotations.ParseStringASAP(authSecretTypeAnn); err == nil {
|
||||
resultAuthSecretType := authSecretType(rawSecretType)
|
||||
if resultAuthSecretType == authFileAuthSecretType || resultAuthSecretType == authMapAuthSecretType {
|
||||
secretType = resultAuthSecretType
|
||||
}
|
||||
}
|
||||
|
||||
authConfig.AuthRealm, _ = annotations.ParseStringASAP(authRealm)
|
||||
|
||||
// Process credentials.
|
||||
secretLister, exist := globalContext.ClusterSecretLister[config.ClusterId]
|
||||
if !exist {
|
||||
IngressLog.Errorf("secret lister of cluster %s doesn't exist", config.ClusterId)
|
||||
return nil
|
||||
}
|
||||
authSecret, err := secretLister.Secrets(namespaced.Namespace).Get(namespaced.Name)
|
||||
if err != nil {
|
||||
IngressLog.Errorf("Secret %s within ingress %s/%s is not found",
|
||||
namespaced.String(), config.Namespace, config.Name)
|
||||
return nil
|
||||
}
|
||||
credentials, err := convertCredentials(secretType, authSecret)
|
||||
if err != nil {
|
||||
IngressLog.Errorf("Parse auth secret fail, err %v", err)
|
||||
return nil
|
||||
}
|
||||
authConfig.Credentials = credentials
|
||||
|
||||
config.Auth = authConfig
|
||||
IngressLog.Error("The annotation nginx.ingress.kubernetes.io/auth-type is no longer supported after version 2.0.0, please use the higress wasm plugin (e.g., basic-auth) as an alternative.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertCredentials(secretType authSecretType, secret *corev1.Secret) ([]string, error) {
|
||||
var result []string
|
||||
switch secretType {
|
||||
case authFileAuthSecretType:
|
||||
users, exist := secret.Data[authFileKey]
|
||||
if !exist {
|
||||
return nil, errors.New("the auth file type must has auth key in secret data")
|
||||
}
|
||||
userList := strings.Split(string(users), "\n")
|
||||
for _, item := range userList {
|
||||
if !strings.Contains(item, ":") {
|
||||
continue
|
||||
}
|
||||
result = append(result, item)
|
||||
}
|
||||
case authMapAuthSecretType:
|
||||
for name, password := range secret.Data {
|
||||
result = append(result, name+":"+string(password))
|
||||
}
|
||||
}
|
||||
sort.SliceStable(result, func(i, j int) bool {
|
||||
return result[i] < result[j]
|
||||
})
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func needAuthConfig(annotations Annotations) bool {
|
||||
return annotations.HasASAP(authType) &&
|
||||
annotations.HasASAP(authSecretAnn)
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package annotations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"istio.io/istio/pkg/cluster"
|
||||
"istio.io/istio/pkg/util/sets"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
listerv1 "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||
)
|
||||
|
||||
func TestAuthParse(t *testing.T) {
|
||||
auth := auth{}
|
||||
inputCases := []struct {
|
||||
input map[string]string
|
||||
secret *v1.Secret
|
||||
expect *AuthConfig
|
||||
watchedSecret string
|
||||
}{
|
||||
{
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"auth": []byte("A:a\nB:b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: map[string]string{
|
||||
buildNginxAnnotationKey(authType): "digest",
|
||||
},
|
||||
expect: nil,
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"auth": []byte("A:a\nB:b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: map[string]string{
|
||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
||||
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
|
||||
},
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"auth": []byte("A:a\nB:b"),
|
||||
},
|
||||
},
|
||||
expect: &AuthConfig{
|
||||
AuthType: defaultAuthType,
|
||||
AuthSecret: util.ClusterNamespacedName{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
ClusterId: "cluster",
|
||||
},
|
||||
Credentials: []string{"A:a", "B:b"},
|
||||
},
|
||||
watchedSecret: "cluster/foo/bar",
|
||||
},
|
||||
{
|
||||
input: map[string]string{
|
||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
||||
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
|
||||
buildNginxAnnotationKey(authSecretTypeAnn): string(authMapAuthSecretType),
|
||||
},
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"A": []byte("a"),
|
||||
"B": []byte("b"),
|
||||
},
|
||||
},
|
||||
expect: &AuthConfig{
|
||||
AuthType: defaultAuthType,
|
||||
AuthSecret: util.ClusterNamespacedName{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Namespace: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
ClusterId: "cluster",
|
||||
},
|
||||
Credentials: []string{"A:a", "B:b"},
|
||||
},
|
||||
watchedSecret: "cluster/foo/bar",
|
||||
},
|
||||
{
|
||||
input: map[string]string{
|
||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
||||
buildHigressAnnotationKey(authSecretAnn): "bar",
|
||||
buildNginxAnnotationKey(authSecretTypeAnn): string(authFileAuthSecretType),
|
||||
},
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"auth": []byte("A:a\nB:b"),
|
||||
},
|
||||
},
|
||||
expect: &AuthConfig{
|
||||
AuthType: defaultAuthType,
|
||||
AuthSecret: util.ClusterNamespacedName{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Namespace: "default",
|
||||
Name: "bar",
|
||||
},
|
||||
ClusterId: "cluster",
|
||||
},
|
||||
Credentials: []string{"A:a", "B:b"},
|
||||
},
|
||||
watchedSecret: "cluster/default/bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, inputCase := range inputCases {
|
||||
t.Run("", func(t *testing.T) {
|
||||
config := &Ingress{
|
||||
Meta: Meta{
|
||||
Namespace: "default",
|
||||
ClusterId: "cluster",
|
||||
},
|
||||
}
|
||||
|
||||
globalContext, cancel := initGlobalContext(inputCase.secret)
|
||||
defer cancel()
|
||||
|
||||
_ = auth.Parse(inputCase.input, config, globalContext)
|
||||
if !reflect.DeepEqual(inputCase.expect, config.Auth) {
|
||||
t.Fatal("Should be equal")
|
||||
}
|
||||
|
||||
if inputCase.watchedSecret != "" {
|
||||
if !globalContext.WatchedSecrets.Contains(inputCase.watchedSecret) {
|
||||
t.Fatalf("Should watch secret %s", inputCase.watchedSecret)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func initGlobalContext(secret *v1.Secret) (*GlobalContext, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
client := fake.NewSimpleClientset(secret)
|
||||
informerFactory := informers.NewSharedInformerFactory(client, time.Hour)
|
||||
secretInformer := informerFactory.Core().V1().Secrets()
|
||||
go secretInformer.Informer().Run(ctx.Done())
|
||||
cache.WaitForCacheSync(ctx.Done(), secretInformer.Informer().HasSynced)
|
||||
|
||||
return &GlobalContext{
|
||||
WatchedSecrets: sets.New[string](),
|
||||
ClusterSecretLister: map[cluster.ID]listerv1.SecretLister{
|
||||
"cluster": secretInformer.Lister(),
|
||||
},
|
||||
}, cancel
|
||||
}
|
||||
@@ -30,7 +30,7 @@ LLM 结果缓存插件,默认配置方式可以直接用于 openai 协议的
|
||||
|
||||
## 配置说明
|
||||
|
||||
本插件同时支持基于向量数据库的语义化缓存和基于字符串匹配的缓存方法,如果同时配置了向量数据库和缓存数据库,优先使用向量数据库。
|
||||
本插件同时支持基于向量数据库的语义化缓存和基于字符串匹配的缓存方法,如果同时配置了向量数据库和缓存数据库,优先使用缓存数据库,未命中场景下使用向量数据库能力。
|
||||
|
||||
*Note*: 向量数据库(vector) 和 缓存数据库(cache) 不能同时为空,否则本插件无法提供缓存服务。
|
||||
|
||||
|
||||
@@ -104,11 +104,11 @@ func onHttpRequestBody(ctx wrapper.HttpContext, c config.PluginConfig, body []by
|
||||
key = strings.Join(userMessages, "\n")
|
||||
} else if c.CacheKeyStrategy == config.CACHE_KEY_STRATEGY_DISABLED {
|
||||
log.Info("[onHttpRequestBody] cache key strategy is disabled")
|
||||
ctx.DontReadRequestBody()
|
||||
ctx.DontReadResponseBody()
|
||||
return types.ActionContinue
|
||||
} else {
|
||||
log.Warnf("[onHttpRequestBody] unknown cache key strategy: %s", c.CacheKeyStrategy)
|
||||
ctx.DontReadRequestBody()
|
||||
ctx.DontReadResponseBody()
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -147,11 +147,6 @@ func onHttpResponseHeaders(ctx wrapper.HttpContext, c config.PluginConfig, log w
|
||||
ctx.SetResponseBodyBufferLimit(DEFAULT_MAX_BODY_BYTES)
|
||||
}
|
||||
|
||||
if ctx.GetContext(ERROR_PARTIAL_MESSAGE_KEY) != nil {
|
||||
ctx.DontReadResponseBody()
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -159,7 +154,7 @@ func onHttpResponseBody(ctx wrapper.HttpContext, c config.PluginConfig, chunk []
|
||||
log.Debugf("[onHttpResponseBody] is last chunk: %v", isLastChunk)
|
||||
log.Debugf("[onHttpResponseBody] chunk: %s", string(chunk))
|
||||
|
||||
if ctx.GetContext(TOOL_CALLS_CONTEXT_KEY) != nil {
|
||||
if ctx.GetContext(TOOL_CALLS_CONTEXT_KEY) != nil || ctx.GetContext(ERROR_PARTIAL_MESSAGE_KEY) != nil {
|
||||
return chunk
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ description: AI 代理插件配置参考
|
||||
| `customSettings` | array of customSetting | 非必填 | - | 为AI请求指定覆盖或者填充参数 |
|
||||
| `failover` | object | 非必填 | - | 配置 apiToken 的 failover 策略,当 apiToken 不可用时,将其移出 apiToken 列表,待健康检测通过后重新添加回 apiToken 列表 |
|
||||
| `retryOnFailure` | object | 非必填 | - | 当请求失败时立即进行重试 |
|
||||
| `capabilities` | map of string | 非必填 | - | 部分provider的部分ai能力原生兼容openai/v1格式,不需要重写,可以直接转发,通过此配置项指定来开启转发, key表示的是采用的厂商协议能力,values表示的真实的厂商该能力的api path, 厂商协议能力当前支持: openai/v1/chatcompletions, openai/v1/embeddings, openai/v1/imagegeneration, openai/v1/audiospeech, cohere/v1/rerank |
|
||||
|
||||
`context`的配置字段说明如下:
|
||||
|
||||
@@ -130,10 +131,11 @@ Azure OpenAI 所对应的 `type` 为 `azure`。它特有的配置字段如下:
|
||||
|
||||
通义千问所对应的 `type` 为 `qwen`。它特有的配置字段如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
|--------------------|-----------------|------|-----|------------------------------------------------------------------|
|
||||
| `qwenEnableSearch` | boolean | 非必填 | - | 是否启用通义千问内置的互联网搜索功能。 |
|
||||
| `qwenFileIds` | array of string | 非必填 | - | 通过文件接口上传至Dashscope的文件 ID,其内容将被用做 AI 对话的上下文。不可与 `context` 字段同时配置。 |
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ---------------------- | --------------- | -------- | ------ | ------------------------------------------------------------ |
|
||||
| `qwenEnableSearch` | boolean | 非必填 | - | 是否启用通义千问内置的互联网搜索功能。 |
|
||||
| `qwenFileIds` | array of string | 非必填 | - | 通过文件接口上传至Dashscope的文件 ID,其内容将被用做 AI 对话的上下文。不可与 `context` 字段同时配置。 |
|
||||
| `qwenEnableCompatible` | boolean | 非必填 | false | 开启通义千问兼容模式。启用通义千问兼容模式后,将调用千问的兼容模式接口,同时对请求/响应不做修改。 |
|
||||
|
||||
#### 百川智能 (Baichuan AI)
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ For Qwen (Tongyi Qwen), the corresponding `type` is `qwen`. Its unique configura
|
||||
|--------------------|-----------------|----------------------|---------------|------------------------------------------------------------------------------------------------------------------------|
|
||||
| `qwenEnableSearch` | boolean | Optional | - | Whether to enable the built-in Internet search function provided by Qwen. |
|
||||
| `qwenFileIds` | array of string | Optional | - | The file IDs uploaded via the Dashscope file interface, whose content will be used as context for AI conversations. Cannot be configured with the `context` field. |
|
||||
| `qwenEnableCompatible` | boolean | Optional | false | Enable Qwen compatibility mode. When Qwen compatibility mode is enabled, the compatible mode interface of Qwen will be called, and the request/response will not be modified. |
|
||||
|
||||
#### Baichuan AI
|
||||
|
||||
|
||||
1
plugins/wasm-go/extensions/ai-proxy/VERSION
Normal file
1
plugins/wasm-go/extensions/ai-proxy/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0-alpha
|
||||
@@ -78,7 +78,7 @@ func onHttpRequestHeader(ctx wrapper.HttpContext, pluginConfig config.PluginConf
|
||||
|
||||
rawPath := ctx.Path()
|
||||
path, _ := url.Parse(rawPath)
|
||||
apiName := getOpenAiApiName(path.Path)
|
||||
apiName := getApiName(path.Path)
|
||||
providerConfig := pluginConfig.GetProviderConfig()
|
||||
if providerConfig.IsOriginal() {
|
||||
if handler, ok := activeProvider.(provider.ApiNameHandler); ok {
|
||||
@@ -87,37 +87,37 @@ func onHttpRequestHeader(ctx wrapper.HttpContext, pluginConfig config.PluginConf
|
||||
}
|
||||
|
||||
if apiName == "" {
|
||||
log.Warnf("[onHttpRequestHeader] unsupported path: %s", path.Path)
|
||||
return types.ActionContinue
|
||||
ctx.DontReadRequestBody()
|
||||
ctx.DontReadResponseBody()
|
||||
log.Warnf("[onHttpRequestHeader] unsupported path: %s, will not process http path and body", path.Path)
|
||||
}
|
||||
|
||||
ctx.SetContext(provider.CtxKeyApiName, apiName)
|
||||
// Disable the route re-calculation since the plugin may modify some headers related to the chosen route.
|
||||
ctx.DisableReroute()
|
||||
|
||||
_, needHandleStreamingBody := activeProvider.(provider.StreamingResponseBodyHandler)
|
||||
if needHandleStreamingBody {
|
||||
proxywasm.RemoveHttpRequestHeader("Accept-Encoding")
|
||||
}
|
||||
// Always remove the Accept-Encoding header to prevent the LLM from sending compressed responses,
|
||||
// allowing plugins to inspect or modify the response correctly
|
||||
proxywasm.RemoveHttpRequestHeader("Accept-Encoding")
|
||||
|
||||
if handler, ok := activeProvider.(provider.RequestHeadersHandler); ok {
|
||||
// Set the apiToken for the current request.
|
||||
providerConfig.SetApiTokenInUse(ctx, log)
|
||||
|
||||
hasRequestBody := wrapper.HasRequestBody()
|
||||
err := handler.OnRequestHeaders(ctx, apiName, log)
|
||||
if err == nil {
|
||||
if hasRequestBody {
|
||||
proxywasm.RemoveHttpRequestHeader("Content-Length")
|
||||
ctx.SetRequestBodyBufferLimit(defaultMaxBodyBytes)
|
||||
// Delay the header processing to allow changing in OnRequestBody
|
||||
return types.HeaderStopIteration
|
||||
}
|
||||
ctx.DontReadRequestBody()
|
||||
if err != nil {
|
||||
util.ErrorHandler("ai-proxy.proc_req_headers_failed", fmt.Errorf("failed to process request headers: %v", err))
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
util.ErrorHandler("ai-proxy.proc_req_headers_failed", fmt.Errorf("failed to process request headers: %v", err))
|
||||
hasRequestBody := wrapper.HasRequestBody()
|
||||
if hasRequestBody {
|
||||
proxywasm.RemoveHttpRequestHeader("Content-Length")
|
||||
ctx.SetRequestBodyBufferLimit(defaultMaxBodyBytes)
|
||||
// Delay the header processing to allow changing in OnRequestBody
|
||||
return types.HeaderStopIteration
|
||||
}
|
||||
ctx.DontReadRequestBody()
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
@@ -200,8 +200,11 @@ func onHttpResponseHeaders(ctx wrapper.HttpContext, pluginConfig config.PluginCo
|
||||
util.ReplaceResponseHeaders(headers)
|
||||
|
||||
checkStream(ctx, log)
|
||||
_, needHandleBody := activeProvider.(provider.TransformResponseBodyHandler)
|
||||
_, needHandleStreamingBody := activeProvider.(provider.StreamingResponseBodyHandler)
|
||||
if !needHandleStreamingBody {
|
||||
if !needHandleBody && !needHandleStreamingBody {
|
||||
ctx.DontReadResponseBody()
|
||||
} else if !needHandleStreamingBody {
|
||||
ctx.BufferResponseBody()
|
||||
}
|
||||
|
||||
@@ -265,12 +268,26 @@ func checkStream(ctx wrapper.HttpContext, log wrapper.Log) {
|
||||
}
|
||||
}
|
||||
|
||||
func getOpenAiApiName(path string) provider.ApiName {
|
||||
func getApiName(path string) provider.ApiName {
|
||||
// openai style
|
||||
if strings.HasSuffix(path, "/v1/completions") {
|
||||
return provider.ApiNameCompletion
|
||||
}
|
||||
if strings.HasSuffix(path, "/v1/chat/completions") {
|
||||
return provider.ApiNameChatCompletion
|
||||
}
|
||||
if strings.HasSuffix(path, "/v1/embeddings") {
|
||||
return provider.ApiNameEmbeddings
|
||||
}
|
||||
if strings.HasSuffix(path, "/v1/audio/speech") {
|
||||
return provider.ApiNameAudioSpeech
|
||||
}
|
||||
if strings.HasSuffix(path, "/v1/images/generations") {
|
||||
return provider.ApiNameImageGeneration
|
||||
}
|
||||
// cohere style
|
||||
if strings.HasSuffix(path, "/v1/rerank") {
|
||||
return provider.ApiNameCohereV1Rerank
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -22,6 +22,13 @@ type ai360Provider struct {
|
||||
contextCache *contextCache
|
||||
}
|
||||
|
||||
func (m *ai360ProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): PathOpenAIChatCompletions,
|
||||
string(ApiNameEmbeddings): PathOpenAIEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ai360ProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
if config.apiTokens == nil || len(config.apiTokens) == 0 {
|
||||
return errors.New("no apiToken found in provider config")
|
||||
@@ -30,6 +37,7 @@ func (m *ai360ProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
}
|
||||
|
||||
func (m *ai360ProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &ai360Provider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -41,16 +49,13 @@ func (m *ai360Provider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *ai360Provider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
// Delay the header processing to allow changing streaming mode in OnRequestBody
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ai360Provider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
@@ -58,5 +63,6 @@ func (m *ai360Provider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
|
||||
|
||||
func (m *ai360Provider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestHostHeader(headers, ai360Domain)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, m.config.GetApiTokenInUse(ctx))
|
||||
}
|
||||
|
||||
@@ -15,6 +15,14 @@ import (
|
||||
type azureProviderInitializer struct {
|
||||
}
|
||||
|
||||
func (m *azureProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
// TODO: azure's pattern is the same as openai, just need to handle the prefix, can be done in TransformRequestHeaders to support general capabilities
|
||||
string(ApiNameChatCompletion): PathOpenAIChatCompletions,
|
||||
string(ApiNameEmbeddings): PathOpenAIEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *azureProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
if config.azureServiceUrl == "" {
|
||||
return errors.New("missing azureServiceUrl in provider config")
|
||||
@@ -35,6 +43,7 @@ func (m *azureProviderInitializer) CreateProvider(config ProviderConfig) (Provid
|
||||
} else {
|
||||
serviceUrl = u
|
||||
}
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &azureProvider{
|
||||
config: config,
|
||||
serviceUrl: serviceUrl,
|
||||
@@ -54,36 +63,35 @@ func (m *azureProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *azureProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *azureProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *azureProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
u, e := url.Parse(ctx.Path())
|
||||
if e == nil {
|
||||
customApiVersion := u.Query().Get("api-version")
|
||||
if customApiVersion == "" {
|
||||
util.OverwriteRequestPathHeader(headers, m.serviceUrl.RequestURI())
|
||||
if apiName != "" {
|
||||
u, e := url.Parse(ctx.Path())
|
||||
if e == nil {
|
||||
customApiVersion := u.Query().Get("api-version")
|
||||
if customApiVersion == "" {
|
||||
util.OverwriteRequestPathHeader(headers, m.serviceUrl.RequestURI())
|
||||
} else {
|
||||
q := m.serviceUrl.Query()
|
||||
q.Set("api-version", customApiVersion)
|
||||
newUrl := *m.serviceUrl
|
||||
newUrl.RawQuery = q.Encode()
|
||||
util.OverwriteRequestPathHeader(headers, newUrl.RequestURI())
|
||||
}
|
||||
} else {
|
||||
q := m.serviceUrl.Query()
|
||||
q.Set("api-version", customApiVersion)
|
||||
newUrl := *m.serviceUrl
|
||||
newUrl.RawQuery = q.Encode()
|
||||
util.OverwriteRequestPathHeader(headers, newUrl.RequestURI())
|
||||
log.Errorf("failed to parse request path: %v", e)
|
||||
util.OverwriteRequestPathHeader(headers, m.serviceUrl.RequestURI())
|
||||
}
|
||||
} else {
|
||||
log.Errorf("failed to parse request path: %v", e)
|
||||
util.OverwriteRequestPathHeader(headers, m.serviceUrl.RequestURI())
|
||||
}
|
||||
util.OverwriteRequestHostHeader(headers, m.serviceUrl.Host)
|
||||
headers.Set("api-key", m.config.GetApiTokenInUse(ctx))
|
||||
|
||||
@@ -12,8 +12,7 @@ import (
|
||||
// baichuanProvider is the provider for baichuan Ai service.
|
||||
|
||||
const (
|
||||
baichuanDomain = "api.baichuan-ai.com"
|
||||
baichuanChatCompletionPath = "/v1/chat/completions"
|
||||
baichuanDomain = "api.baichuan-ai.com"
|
||||
)
|
||||
|
||||
type baichuanProviderInitializer struct {
|
||||
@@ -26,7 +25,15 @@ func (m *baichuanProviderInitializer) ValidateConfig(config *ProviderConfig) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *baichuanProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): PathOpenAIChatCompletions,
|
||||
string(ApiNameEmbeddings): PathOpenAIEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *baichuanProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &baichuanProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -43,22 +50,19 @@ func (m *baichuanProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *baichuanProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *baichuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *baichuanProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, baichuanChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, baichuanDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
const (
|
||||
baiduDomain = "qianfan.baidubce.com"
|
||||
baiduChatCompletionPath = "/v2/chat/completions"
|
||||
baiduEmbeddings = "/v2/embeddings"
|
||||
)
|
||||
|
||||
type baiduProviderInitializer struct{}
|
||||
@@ -25,7 +26,15 @@ func (g *baiduProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *baiduProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): baiduChatCompletionPath,
|
||||
string(ApiNameEmbeddings): baiduEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *baiduProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(g.DefaultCapabilities())
|
||||
return &baiduProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -42,22 +51,19 @@ func (g *baiduProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (g *baiduProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
g.config.handleRequestHeaders(g, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *baiduProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !g.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return g.config.handleRequestBody(g, g.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (g *baiduProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, baiduChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), g.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, baiduDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+g.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
const (
|
||||
claudeDomain = "api.anthropic.com"
|
||||
claudeChatCompletionPath = "/v1/messages"
|
||||
claudeCompletionPath = "/v1/complete"
|
||||
defaultVersion = "2023-06-01"
|
||||
defaultMaxTokens = 4096
|
||||
)
|
||||
@@ -85,7 +86,17 @@ func (c *claudeProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *claudeProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): claudeChatCompletionPath,
|
||||
string(ApiNameCompletion): claudeCompletionPath,
|
||||
// docs: https://docs.anthropic.com/en/docs/build-with-claude/embeddings#voyage-http-api
|
||||
string(ApiNameEmbeddings): PathOpenAIEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *claudeProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(c.DefaultCapabilities())
|
||||
return &claudeProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -102,15 +113,12 @@ func (c *claudeProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (c *claudeProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
c.config.handleRequestHeaders(c, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *claudeProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, claudeChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), c.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, claudeDomain)
|
||||
|
||||
headers.Set("x-api-key", c.config.GetApiTokenInUse(ctx))
|
||||
@@ -123,13 +131,16 @@ func (c *claudeProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiNam
|
||||
}
|
||||
|
||||
func (c *claudeProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !c.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return c.config.handleRequestBody(c, c.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (c *claudeProvider) TransformRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return c.config.defaultTransformRequestBody(ctx, apiName, body, log)
|
||||
}
|
||||
request := &chatCompletionRequest{}
|
||||
if err := c.config.parseRequestAndMapModel(ctx, request, body, log); err != nil {
|
||||
return nil, err
|
||||
@@ -139,6 +150,9 @@ func (c *claudeProvider) TransformRequestBody(ctx wrapper.HttpContext, apiName A
|
||||
}
|
||||
|
||||
func (c *claudeProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
claudeResponse := &claudeTextGenResponse{}
|
||||
if err := json.Unmarshal(body, claudeResponse); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal claude response: %v", err)
|
||||
@@ -154,6 +168,10 @@ func (c *claudeProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name A
|
||||
if isLastChunk || len(chunk) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// only process the response from chat completion, skip other responses
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
|
||||
responseBuilder := &strings.Builder{}
|
||||
lines := strings.Split(string(chunk), "\n")
|
||||
|
||||
@@ -25,8 +25,14 @@ func (c *cloudflareProviderInitializer) ValidateConfig(config *ProviderConfig) e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *cloudflareProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): cloudflareChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cloudflareProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(c.DefaultCapabilities())
|
||||
return &cloudflareProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -43,15 +49,12 @@ func (c *cloudflareProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (c *cloudflareProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
c.config.handleRequestHeaders(c, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cloudflareProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !c.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return c.config.handleRequestBody(c, c.contextCache, ctx, apiName, body, log)
|
||||
|
||||
@@ -12,8 +12,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
cohereDomain = "api.cohere.com"
|
||||
cohereDomain = "api.cohere.com"
|
||||
// TODO: support more capabilities, upgrade to v2, docs: https://docs.cohere.com/v2/reference/chat
|
||||
cohereChatCompletionPath = "/v1/chat"
|
||||
cohereRerankPath = "/v1/rerank"
|
||||
)
|
||||
|
||||
type cohereProviderInitializer struct{}
|
||||
@@ -25,7 +27,15 @@ func (m *cohereProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *cohereProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): cohereChatCompletionPath,
|
||||
string(ApiNameCohereV1Rerank): cohereRerankPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *cohereProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &cohereProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -56,15 +66,12 @@ func (m *cohereProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *cohereProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *cohereProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
@@ -90,13 +97,16 @@ func (m *cohereProvider) buildCohereRequest(origin *chatCompletionRequest) *cohe
|
||||
}
|
||||
|
||||
func (m *cohereProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, cohereChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, cohereDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
}
|
||||
|
||||
func (m *cohereProvider) TransformRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return m.config.defaultTransformRequestBody(ctx, apiName, body, log)
|
||||
}
|
||||
request := &chatCompletionRequest{}
|
||||
if err := m.config.parseRequestAndMapModel(ctx, request, body, log); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -21,7 +21,12 @@ func (m *cozeProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *cozeProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (m *cozeProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &cozeProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
|
||||
@@ -64,7 +64,14 @@ func (d *deeplProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deeplProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): deeplChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deeplProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(d.DefaultCapabilities())
|
||||
return &deeplProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -76,20 +83,21 @@ func (d *deeplProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (d *deeplProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
d.config.handleRequestHeaders(d, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deeplProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, deeplChatCompletionPath)
|
||||
if apiName != "" {
|
||||
util.OverwriteRequestPathHeader(headers, deeplChatCompletionPath)
|
||||
}
|
||||
// TODO: Support default host through configuration
|
||||
util.OverwriteRequestHostHeader(headers, deeplHostFree)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "DeepL-Auth-Key "+d.config.GetApiTokenInUse(ctx))
|
||||
}
|
||||
|
||||
func (d *deeplProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !d.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return d.config.handleRequestBody(d, d.contextCache, ctx, apiName, body, log)
|
||||
@@ -112,6 +120,9 @@ func (d *deeplProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, api
|
||||
}
|
||||
|
||||
func (d *deeplProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
deeplResponse := &deeplResponse{}
|
||||
if err := json.Unmarshal(body, deeplResponse); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal deepl response: %v", err)
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
// deepseekProvider is the provider for deepseek Ai service.
|
||||
|
||||
const (
|
||||
deepseekDomain = "api.deepseek.com"
|
||||
deepseekDomain = "api.deepseek.com"
|
||||
// TODO: docs: https://api-docs.deepseek.com/api/create-chat-completion
|
||||
// accourding to the docs, the path should be /chat/completions, need to be verified
|
||||
deepseekChatCompletionPath = "/v1/chat/completions"
|
||||
)
|
||||
|
||||
@@ -26,7 +28,14 @@ func (m *deepseekProviderInitializer) ValidateConfig(config *ProviderConfig) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *deepseekProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): deepseekChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *deepseekProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &deepseekProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -43,22 +52,19 @@ func (m *deepseekProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *deepseekProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *deepseekProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *deepseekProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, deepseekChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, deepseekDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/extensions/ai-proxy/util"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,9 +51,6 @@ func (d *difyProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (d *difyProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
d.config.handleRequestHeaders(d, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
@@ -83,6 +81,9 @@ func (d *difyProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, b
|
||||
}
|
||||
|
||||
func (d *difyProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, apiName ApiName, body []byte, headers http.Header, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return d.config.defaultTransformRequestBody(ctx, apiName, body, log)
|
||||
}
|
||||
request := &chatCompletionRequest{}
|
||||
err := d.config.parseRequestAndMapModel(ctx, request, body, log)
|
||||
if err != nil {
|
||||
@@ -95,6 +96,9 @@ func (d *difyProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, apiN
|
||||
}
|
||||
|
||||
func (d *difyProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
difyResponse := &DifyChatResponse{}
|
||||
if err := json.Unmarshal(body, difyResponse); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal dify response: %v", err)
|
||||
@@ -146,6 +150,9 @@ func (d *difyProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name Api
|
||||
if isLastChunk || len(chunk) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
// sample event response:
|
||||
// data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
|
||||
|
||||
@@ -180,6 +187,7 @@ func (d *difyProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name Api
|
||||
func (d *difyProvider) streamResponseDify2OpenAI(ctx wrapper.HttpContext, response *DifyChunkChatResponse) *chatCompletionResponse {
|
||||
var choice chatCompletionChoice
|
||||
var id string
|
||||
var responseUsage usage
|
||||
switch d.config.botType {
|
||||
case BotTypeChat, BotTypeAgent:
|
||||
choice = chatCompletionChoice{
|
||||
@@ -203,6 +211,13 @@ func (d *difyProvider) streamResponseDify2OpenAI(ctx wrapper.HttpContext, respon
|
||||
}
|
||||
if response.Event == "message_end" || response.Event == "workflow_finished" {
|
||||
choice.FinishReason = finishReasonStop
|
||||
if response.Event == "message_end" {
|
||||
responseUsage = usage{
|
||||
PromptTokens: response.MetaData.Usage.PromptTokens,
|
||||
CompletionTokens: response.MetaData.Usage.CompletionTokens,
|
||||
TotalTokens: response.MetaData.Usage.TotalTokens,
|
||||
}
|
||||
}
|
||||
}
|
||||
return &chatCompletionResponse{
|
||||
Id: id,
|
||||
@@ -211,6 +226,7 @@ func (d *difyProvider) streamResponseDify2OpenAI(ctx wrapper.HttpContext, respon
|
||||
SystemFingerprint: "",
|
||||
Object: objectChatCompletionChunk,
|
||||
Choices: []chatCompletionChoice{choice},
|
||||
Usage: responseUsage,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
const (
|
||||
doubaoDomain = "ark.cn-beijing.volces.com"
|
||||
doubaoChatCompletionPath = "/api/v3/chat/completions"
|
||||
doubaoEmbeddingsPath = "/api/v3/embeddings"
|
||||
)
|
||||
|
||||
type doubaoProviderInitializer struct{}
|
||||
@@ -24,7 +25,15 @@ func (m *doubaoProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *doubaoProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): doubaoChatCompletionPath,
|
||||
string(ApiNameEmbeddings): doubaoEmbeddingsPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *doubaoProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &doubaoProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -41,22 +50,19 @@ func (m *doubaoProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *doubaoProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *doubaoProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *doubaoProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, doubaoChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, doubaoDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
@@ -66,5 +72,8 @@ func (m *doubaoProvider) GetApiName(path string) ApiName {
|
||||
if strings.Contains(path, doubaoChatCompletionPath) {
|
||||
return ApiNameChatCompletion
|
||||
}
|
||||
if strings.Contains(path, doubaoEmbeddingsPath) {
|
||||
return ApiNameEmbeddings
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -35,7 +35,12 @@ func (g *geminiProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *geminiProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (g *geminiProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(g.DefaultCapabilities())
|
||||
return &geminiProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -52,9 +57,6 @@ func (g *geminiProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (g *geminiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
g.config.handleRequestHeaders(g, ctx, apiName, log)
|
||||
// Delay the header processing to allow changing streaming mode in OnRequestBody
|
||||
return nil
|
||||
@@ -66,7 +68,7 @@ func (g *geminiProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiNam
|
||||
}
|
||||
|
||||
func (g *geminiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
if !g.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return g.config.handleRequestBody(g, g.contextCache, ctx, apiName, body, log)
|
||||
@@ -110,6 +112,9 @@ func (g *geminiProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name A
|
||||
if isLastChunk || len(chunk) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
// sample end event response:
|
||||
// data: {"candidates": [{"content": {"parts": [{"text": "我是 Gemini,一个大型多模态模型,由 Google 训练。我的职责是尽我所能帮助您,并尽力提供全面且信息丰富的答复。"}],"role": "model"},"finishReason": "STOP","index": 0,"safetyRatings": [{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HATE_SPEECH","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HARASSMENT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_DANGEROUS_CONTENT","probability": "NEGLIGIBLE"}]}],"usageMetadata": {"promptTokenCount": 2,"candidatesTokenCount": 35,"totalTokenCount": 37}}
|
||||
responseBuilder := &strings.Builder{}
|
||||
|
||||
@@ -32,7 +32,15 @@ func (m *githubProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *githubProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): githubCompletionPath,
|
||||
string(ApiNameEmbeddings): githubEmbeddingPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *githubProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &githubProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -44,16 +52,13 @@ func (m *githubProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *githubProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
// Delay the header processing to allow changing streaming mode in OnRequestBody
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *githubProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
@@ -61,12 +66,7 @@ func (m *githubProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName,
|
||||
|
||||
func (m *githubProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestHostHeader(headers, githubDomain)
|
||||
if apiName == ApiNameChatCompletion {
|
||||
util.OverwriteRequestPathHeader(headers, githubCompletionPath)
|
||||
}
|
||||
if apiName == ApiNameEmbeddings {
|
||||
util.OverwriteRequestPathHeader(headers, githubEmbeddingPath)
|
||||
}
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, m.config.GetApiTokenInUse(ctx))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,14 @@ func (g *groqProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *groqProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): groqChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *groqProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(g.DefaultCapabilities())
|
||||
return &groqProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -42,22 +49,19 @@ func (g *groqProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (g *groqProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
g.config.handleRequestHeaders(g, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *groqProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !g.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return g.config.handleRequestBody(g, g.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (g *groqProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, groqChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), g.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, groqDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+g.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -39,6 +39,11 @@ const (
|
||||
|
||||
hunyuanAuthKeyLen = 32
|
||||
hunyuanAuthIdLen = 36
|
||||
|
||||
// docs: https://cloud.tencent.com/document/product/1729/111007
|
||||
hunyuanOpenAiDomain = "api.hunyuan.cloud.tencent.com"
|
||||
hunyuanOpenAiRequestPath = "/v1/chat/completions"
|
||||
hunyuanOpenAiEmbeddings = "/v1/embeddings"
|
||||
)
|
||||
|
||||
type hunyuanProviderInitializer struct {
|
||||
@@ -86,6 +91,10 @@ type hunyuanChatMessage struct {
|
||||
}
|
||||
|
||||
func (m *hunyuanProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
// 允许 hunyuanauthid 和 hunyuanauthkey 为空, 当他们都为空的时候,认为是使用openai的 兼容接口
|
||||
if len(config.hunyuanAuthId) == 0 && len(config.hunyuanAuthKey) == 0 {
|
||||
return nil
|
||||
}
|
||||
// 校验hunyuan id 和 key的合法性
|
||||
if len(config.hunyuanAuthId) != hunyuanAuthIdLen || len(config.hunyuanAuthKey) != hunyuanAuthKeyLen {
|
||||
return errors.New("hunyuanAuthId / hunyuanAuthKey is illegal in config file")
|
||||
@@ -93,7 +102,15 @@ func (m *hunyuanProviderInitializer) ValidateConfig(config *ProviderConfig) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *hunyuanProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): hunyuanOpenAiRequestPath,
|
||||
string(ApiNameEmbeddings): hunyuanOpenAiEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *hunyuanProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &hunyuanProvider{
|
||||
config: config,
|
||||
client: wrapper.NewClusterClient(wrapper.RouteCluster{
|
||||
@@ -114,29 +131,38 @@ func (m *hunyuanProvider) GetProviderType() string {
|
||||
return providerTypeHunyuan
|
||||
}
|
||||
|
||||
func (m *hunyuanProvider) useOpenAICompatibleAPI() bool {
|
||||
return len(m.config.hunyuanAuthId) == 0 && len(m.config.hunyuanAuthKey) == 0
|
||||
}
|
||||
|
||||
func (m *hunyuanProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
// Delay the header processing to allow changing streaming mode in OnRequestBody
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *hunyuanProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestHostHeader(headers, hunyuanDomain)
|
||||
util.OverwriteRequestPathHeader(headers, hunyuanRequestPath)
|
||||
|
||||
// 添加 hunyuan 需要的自定义字段
|
||||
headers.Set(actionKey, hunyuanChatCompletionTCAction)
|
||||
headers.Set(versionKey, versionValue)
|
||||
if m.useOpenAICompatibleAPI() {
|
||||
util.OverwriteRequestHostHeader(headers, hunyuanOpenAiDomain)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
} else {
|
||||
util.OverwriteRequestHostHeader(headers, hunyuanDomain)
|
||||
util.OverwriteRequestPathHeader(headers, hunyuanRequestPath)
|
||||
// 添加 hunyuan 需要的自定义字段
|
||||
headers.Set(actionKey, hunyuanChatCompletionTCAction)
|
||||
headers.Set(versionKey, versionValue)
|
||||
}
|
||||
}
|
||||
|
||||
// hunyuan 的 OnRequestBody 逻辑中包含了对 headers 签名的逻辑,并且插入 context 以后还要重新计算签名,因此无法复用 handleRequestBody 方法
|
||||
func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
if m.useOpenAICompatibleAPI() {
|
||||
return types.ActionContinue, nil
|
||||
}
|
||||
|
||||
// 为header添加时间戳字段 (因为需要根据body进行签名时依赖时间戳,故于body处理部分创建时间戳)
|
||||
var timestamp int64 = time.Now().Unix()
|
||||
@@ -264,6 +290,9 @@ func (m *hunyuanProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName
|
||||
|
||||
// hunyuan 的 TransformRequestBodyHeaders 方法只在 failover 健康检查的时候会调用
|
||||
func (m *hunyuanProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, apiName ApiName, body []byte, headers http.Header, log wrapper.Log) ([]byte, error) {
|
||||
if m.useOpenAICompatibleAPI() {
|
||||
return m.config.defaultTransformRequestBody(ctx, apiName, body, log)
|
||||
}
|
||||
request := &chatCompletionRequest{}
|
||||
err := m.config.parseRequestAndMapModel(ctx, request, body, log)
|
||||
if err != nil {
|
||||
@@ -289,7 +318,7 @@ func (m *hunyuanProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, a
|
||||
}
|
||||
|
||||
func (m *hunyuanProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name ApiName, chunk []byte, isLastChunk bool, log wrapper.Log) ([]byte, error) {
|
||||
if m.config.protocol == protocolOriginal {
|
||||
if m.config.IsOriginal() || m.useOpenAICompatibleAPI() || name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
|
||||
@@ -405,6 +434,12 @@ func (m *hunyuanProvider) convertChunkFromHunyuanToOpenAI(ctx wrapper.HttpContex
|
||||
}
|
||||
|
||||
func (m *hunyuanProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if m.config.IsOriginal() || m.useOpenAICompatibleAPI() {
|
||||
return body, nil
|
||||
}
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
log.Debugf("#debug nash5# onRespBody's resp is: %s", string(body))
|
||||
hunyuanResponse := &hunyuanTextGenResponseNonStreaming{}
|
||||
if err := json.Unmarshal(body, hunyuanResponse); err != nil {
|
||||
|
||||
@@ -41,7 +41,7 @@ type minimaxProviderInitializer struct {
|
||||
func (m *minimaxProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
// If using the chat completion Pro API, a group ID must be set.
|
||||
if minimaxApiTypePro == config.minimaxApiType && config.minimaxGroupId == "" {
|
||||
return errors.New(fmt.Sprintf("missing minimaxGroupId in provider config when minimaxApiType is %s", minimaxApiTypePro))
|
||||
return fmt.Errorf("missing minimaxGroupId in provider config when minimaxApiType is %s", minimaxApiTypePro)
|
||||
}
|
||||
if config.apiTokens == nil || len(config.apiTokens) == 0 {
|
||||
return errors.New("no apiToken found in provider config")
|
||||
@@ -49,7 +49,15 @@ func (m *minimaxProviderInitializer) ValidateConfig(config *ProviderConfig) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *minimaxProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
// minimax 替换path的时候,要根据modelmapping替换,这儿的配置无实质作用,只是为了保持和其他provider的一致性
|
||||
string(ApiNameChatCompletion): minimaxChatCompletionV2Path,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *minimaxProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &minimaxProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -66,9 +74,6 @@ func (m *minimaxProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *minimaxProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
// Delay the header processing to allow changing streaming mode in OnRequestBody
|
||||
return nil
|
||||
@@ -81,7 +86,7 @@ func (m *minimaxProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiNa
|
||||
}
|
||||
|
||||
func (m *minimaxProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
if minimaxApiTypePro == m.config.minimaxApiType {
|
||||
@@ -159,6 +164,9 @@ func (m *minimaxProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name
|
||||
if isLastChunk || len(chunk) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
// Sample event response:
|
||||
// data: {"created":1689747645,"model":"abab6.5s-chat","reply":"","choices":[{"messages":[{"sender_type":"BOT","sender_name":"MM智能助理","text":"am from China."}]}],"output_sensitive":false}
|
||||
|
||||
@@ -192,6 +200,9 @@ func (m *minimaxProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name
|
||||
|
||||
// TransformResponseBody handles the final response body from the Minimax service only for requests using the OpenAI protocol and corresponding to the chat completion Pro API.
|
||||
func (m *minimaxProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
minimaxResp := &minimaxChatCompletionProResp{}
|
||||
if err := json.Unmarshal(body, minimaxResp); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal minimax response: %v", err)
|
||||
@@ -268,18 +279,6 @@ type minimaxUsage struct {
|
||||
CompletionTokens int64 `json:"completion_tokens"`
|
||||
}
|
||||
|
||||
func (m *minimaxProvider) parseModel(body []byte) (string, error) {
|
||||
var tempMap map[string]interface{}
|
||||
if err := json.Unmarshal(body, &tempMap); err != nil {
|
||||
return "", err
|
||||
}
|
||||
model, ok := tempMap["model"].(string)
|
||||
if !ok {
|
||||
return "", errors.New("missing model in chat completion request")
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func (m *minimaxProvider) setBotSettings(request *minimaxChatCompletionProRequest, botSettingContent string) {
|
||||
if len(request.BotSettings) == 0 {
|
||||
request.BotSettings = []minimaxBotSetting{
|
||||
|
||||
@@ -22,7 +22,16 @@ func (m *mistralProviderInitializer) ValidateConfig(config *ProviderConfig) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mistralProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
// The chat interface of mistral is the same as that of OpenAI. docs: https://docs.mistral.ai/api/
|
||||
string(ApiNameChatCompletion): PathOpenAIChatCompletions,
|
||||
string(ApiNameEmbeddings): PathOpenAIEmbeddings,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mistralProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &mistralProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -39,15 +48,12 @@ func (m *mistralProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *mistralProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mistralProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
|
||||
@@ -19,22 +19,55 @@ const (
|
||||
)
|
||||
|
||||
type chatCompletionRequest struct {
|
||||
Messages []chatMessage `json:"messages"`
|
||||
Model string `json:"model"`
|
||||
Store bool `json:"store,omitempty"`
|
||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
|
||||
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||
Logprobs bool `json:"logprobs,omitempty"`
|
||||
TopLogprobs int `json:"top_logprobs,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Modalities []string `json:"modalities,omitempty"`
|
||||
Prediction map[string]interface{} `json:"prediction,omitempty"`
|
||||
Audio map[string]interface{} `json:"audio,omitempty"`
|
||||
PresencePenalty float64 `json:"presence_penalty,omitempty"`
|
||||
ResponseFormat map[string]interface{} `json:"response_format,omitempty"`
|
||||
Seed int `json:"seed,omitempty"`
|
||||
ServiceTier string `json:"service_tier,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *streamOptions `json:"stream_options,omitempty"`
|
||||
Temperature float64 `json:"temperature,omitempty"`
|
||||
TopP float64 `json:"top_p,omitempty"`
|
||||
Tools []tool `json:"tools,omitempty"`
|
||||
ToolChoice *toolChoice `json:"tool_choice,omitempty"`
|
||||
ParallelToolCalls bool `json:"parallel_tool_calls,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
type CompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []chatMessage `json:"messages"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
Prompt string `json:"prompt"`
|
||||
BestOf int `json:"best_of,omitempty"`
|
||||
Echo bool `json:"echo,omitempty"`
|
||||
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
|
||||
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||
Logprobs int `json:"logprobs,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
PresencePenalty float64 `json:"presence_penalty,omitempty"`
|
||||
Seed int `json:"seed,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *streamOptions `json:"stream_options,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty"`
|
||||
Temperature float64 `json:"temperature,omitempty"`
|
||||
TopP float64 `json:"top_p,omitempty"`
|
||||
Tools []tool `json:"tools,omitempty"`
|
||||
ToolChoice *toolChoice `json:"tool_choice,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Stop []string `json:"stop,omitempty"`
|
||||
ResponseFormat map[string]interface{} `json:"response_format,omitempty"`
|
||||
}
|
||||
|
||||
type streamOptions struct {
|
||||
@@ -62,16 +95,18 @@ type chatCompletionResponse struct {
|
||||
Choices []chatCompletionChoice `json:"choices"`
|
||||
Created int64 `json:"created,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ServiceTier string `json:"service_tier,omitempty"`
|
||||
SystemFingerprint string `json:"system_fingerprint,omitempty"`
|
||||
Object string `json:"object,omitempty"`
|
||||
Usage usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type chatCompletionChoice struct {
|
||||
Index int `json:"index"`
|
||||
Message *chatMessage `json:"message,omitempty"`
|
||||
Delta *chatMessage `json:"delta,omitempty"`
|
||||
FinishReason string `json:"finish_reason,omitempty"`
|
||||
Index int `json:"index"`
|
||||
Message *chatMessage `json:"message,omitempty"`
|
||||
Delta *chatMessage `json:"delta,omitempty"`
|
||||
FinishReason string `json:"finish_reason,omitempty"`
|
||||
Logprobs map[string]interface{} `json:"logprobs,omitempty"`
|
||||
}
|
||||
|
||||
type usage struct {
|
||||
@@ -81,10 +116,14 @@ type usage struct {
|
||||
}
|
||||
|
||||
type chatMessage struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Content any `json:"content,omitempty"`
|
||||
ToolCalls []toolCall `json:"tool_calls,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
Audio map[string]interface{} `json:"audio,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Content any `json:"content,omitempty"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []toolCall `json:"tool_calls,omitempty"`
|
||||
Refusal string `json:"refusal,omitempty"`
|
||||
}
|
||||
|
||||
type messageContent struct {
|
||||
@@ -230,6 +269,21 @@ func (e *streamEvent) setValue(key, value string) {
|
||||
}
|
||||
}
|
||||
|
||||
// https://platform.openai.com/docs/guides/images
|
||||
type imageGenerationRequest struct {
|
||||
Model string `json:"model"`
|
||||
Prompt string `json:"prompt"`
|
||||
N int `json:"n,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// https://platform.openai.com/docs/guides/speech-to-text
|
||||
type audioSpeechRequest struct {
|
||||
Model string `json:"model"`
|
||||
Input string `json:"input"`
|
||||
Voice string `json:"voice"`
|
||||
}
|
||||
|
||||
type embeddingsRequest struct {
|
||||
Input interface{} `json:"input"`
|
||||
Model string `json:"model"`
|
||||
|
||||
@@ -34,7 +34,14 @@ func (m *moonshotProviderInitializer) ValidateConfig(config *ProviderConfig) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *moonshotProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): moonshotChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *moonshotProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &moonshotProvider{
|
||||
config: config,
|
||||
client: wrapper.NewClusterClient(wrapper.RouteCluster{
|
||||
@@ -57,15 +64,12 @@ func (m *moonshotProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *moonshotProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *moonshotProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, moonshotChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, moonshotDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
@@ -74,9 +78,13 @@ func (m *moonshotProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiN
|
||||
// moonshot 有自己获取 context 的配置(moonshotFileId),因此无法复用 handleRequestBody 方法
|
||||
// moonshot 的 body 没有修改,无须实现TransformRequestBody,使用默认的 defaultTransformRequestBody 方法
|
||||
func (m *moonshotProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
// 非chat类型的请求,不做处理
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return types.ActionContinue, nil
|
||||
}
|
||||
|
||||
request := &chatCompletionRequest{}
|
||||
if err := m.config.parseRequestAndMapModel(ctx, request, body, log); err != nil {
|
||||
@@ -154,6 +162,9 @@ func (m *moonshotProvider) sendRequest(method, path, body, apiKey string, callba
|
||||
}
|
||||
|
||||
func (m *moonshotProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name ApiName, chunk []byte, isLastChunk bool, log wrapper.Log) ([]byte, error) {
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
receivedBody := chunk
|
||||
if bufferedStreamingBody, has := ctx.GetContext(ctxKeyStreamingBody).([]byte); has {
|
||||
receivedBody = append(bufferedStreamingBody, chunk...)
|
||||
|
||||
@@ -12,10 +12,6 @@ import (
|
||||
|
||||
// ollamaProvider is the provider for Ollama service.
|
||||
|
||||
const (
|
||||
ollamaChatCompletionPath = "/v1/chat/completions"
|
||||
)
|
||||
|
||||
type ollamaProviderInitializer struct {
|
||||
}
|
||||
|
||||
@@ -29,9 +25,17 @@ func (m *ollamaProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ollamaProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
// ollama的chat接口path和OpenAI的chat接口一样
|
||||
string(ApiNameChatCompletion): PathOpenAIChatCompletions,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ollamaProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
serverPortStr := fmt.Sprintf("%d", config.ollamaServerPort)
|
||||
serviceDomain := config.ollamaServerHost + ":" + serverPortStr
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &ollamaProvider{
|
||||
config: config,
|
||||
serviceDomain: serviceDomain,
|
||||
@@ -50,22 +54,19 @@ func (m *ollamaProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *ollamaProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ollamaProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *ollamaProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, ollamaChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, m.serviceDomain)
|
||||
headers.Del("Content-Length")
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/extensions/ai-proxy/util"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
)
|
||||
|
||||
@@ -16,7 +18,10 @@ import (
|
||||
const (
|
||||
defaultOpenaiDomain = "api.openai.com"
|
||||
defaultOpenaiChatCompletionPath = "/v1/chat/completions"
|
||||
defaultOpenaiCompletionPath = "/v1/completions"
|
||||
defaultOpenaiEmbeddingsPath = "/v1/chat/embeddings"
|
||||
defaultOpenaiAudioSpeech = "/v1/audio/speech"
|
||||
defaultOpenaiImageGeneration = "/v1/images/generations"
|
||||
)
|
||||
|
||||
type openaiProviderInitializer struct {
|
||||
@@ -26,8 +31,26 @@ func (m *openaiProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *openaiProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameCompletion): defaultOpenaiCompletionPath,
|
||||
string(ApiNameChatCompletion): defaultOpenaiChatCompletionPath,
|
||||
string(ApiNameEmbeddings): defaultOpenaiEmbeddingsPath,
|
||||
string(ApiNameImageGeneration): defaultOpenaiImageGeneration,
|
||||
string(ApiNameAudioSpeech): defaultOpenaiAudioSpeech,
|
||||
}
|
||||
}
|
||||
|
||||
func isDirectPath(path string) bool {
|
||||
return strings.HasSuffix(path, "/completions") ||
|
||||
strings.HasSuffix(path, "/chat/embeddings") ||
|
||||
strings.HasSuffix(path, "/audio/speech") ||
|
||||
strings.HasSuffix(path, "/images/generations")
|
||||
}
|
||||
|
||||
func (m *openaiProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
if config.openaiCustomUrl == "" {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &openaiProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -38,19 +61,32 @@ func (m *openaiProviderInitializer) CreateProvider(config ProviderConfig) (Provi
|
||||
if len(pairs) != 2 {
|
||||
return nil, fmt.Errorf("invalid openaiCustomUrl:%s", config.openaiCustomUrl)
|
||||
}
|
||||
customPath := "/" + pairs[1]
|
||||
isDirectCustomPath := isDirectPath(customPath)
|
||||
capabilities := m.DefaultCapabilities()
|
||||
if !isDirectCustomPath {
|
||||
for key, mapPath := range capabilities {
|
||||
capabilities[key] = path.Join(customPath, strings.TrimPrefix(mapPath, "/v1"))
|
||||
}
|
||||
}
|
||||
config.setDefaultCapabilities(capabilities)
|
||||
proxywasm.LogDebugf("ai-proxy: openai provider customDomain:%s, customPath:%s, isDirectCustomPath:%v, capabilities:%v",
|
||||
pairs[0], customPath, isDirectCustomPath, capabilities)
|
||||
return &openaiProvider{
|
||||
config: config,
|
||||
customDomain: pairs[0],
|
||||
customPath: "/" + pairs[1],
|
||||
contextCache: createContextCache(&config),
|
||||
config: config,
|
||||
customDomain: pairs[0],
|
||||
customPath: customPath,
|
||||
isDirectCustomPath: isDirectCustomPath,
|
||||
contextCache: createContextCache(&config),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type openaiProvider struct {
|
||||
config ProviderConfig
|
||||
customDomain string
|
||||
customPath string
|
||||
contextCache *contextCache
|
||||
config ProviderConfig
|
||||
customDomain string
|
||||
customPath string
|
||||
isDirectCustomPath bool
|
||||
contextCache *contextCache
|
||||
}
|
||||
|
||||
func (m *openaiProvider) GetProviderType() string {
|
||||
@@ -63,21 +99,19 @@ func (m *openaiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiNa
|
||||
}
|
||||
|
||||
func (m *openaiProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
if m.customPath == "" {
|
||||
switch apiName {
|
||||
case ApiNameChatCompletion:
|
||||
util.OverwriteRequestPathHeader(headers, defaultOpenaiChatCompletionPath)
|
||||
case ApiNameEmbeddings:
|
||||
ctx.DontReadRequestBody()
|
||||
util.OverwriteRequestPathHeader(headers, defaultOpenaiEmbeddingsPath)
|
||||
if m.customPath != "" {
|
||||
if m.isDirectCustomPath || apiName == "" {
|
||||
util.OverwriteRequestPathHeader(headers, m.customPath)
|
||||
} else {
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
}
|
||||
} else {
|
||||
util.OverwriteRequestPathHeader(headers, m.customPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
}
|
||||
if m.customDomain == "" {
|
||||
util.OverwriteRequestHostHeader(headers, defaultOpenaiDomain)
|
||||
} else {
|
||||
if m.customDomain != "" {
|
||||
util.OverwriteRequestHostHeader(headers, m.customDomain)
|
||||
} else {
|
||||
util.OverwriteRequestHostHeader(headers, defaultOpenaiDomain)
|
||||
}
|
||||
if len(m.config.apiTokens) > 0 {
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
@@ -12,14 +11,29 @@ import (
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
type ApiName string
|
||||
type Pointcut string
|
||||
|
||||
const (
|
||||
ApiNameChatCompletion ApiName = "chatCompletion"
|
||||
ApiNameEmbeddings ApiName = "embeddings"
|
||||
|
||||
// ApiName 格式 {vendor}/{version}/{apitype}
|
||||
// 表示遵循 厂商/版本/接口类型 的格式
|
||||
// 目前openai是事实意义上的标准,但是也有其他厂商存在其他任务的一些可能的标准,比如cohere的rerank
|
||||
ApiNameCompletion ApiName = "openai/v1/completions"
|
||||
ApiNameChatCompletion ApiName = "openai/v1/chatcompletions"
|
||||
ApiNameEmbeddings ApiName = "openai/v1/embeddings"
|
||||
ApiNameImageGeneration ApiName = "openai/v1/imagegeneration"
|
||||
ApiNameAudioSpeech ApiName = "openai/v1/audiospeech"
|
||||
|
||||
PathOpenAICompletions = "/v1/completions"
|
||||
PathOpenAIChatCompletions = "/v1/chat/completions"
|
||||
PathOpenAIEmbeddings = "/v1/embeddings"
|
||||
|
||||
// TODO: 以下是一些非标准的API名称,需要进一步确认是否支持
|
||||
ApiNameCohereV1Rerank ApiName = "cohere/v1/rerank"
|
||||
|
||||
providerTypeMoonshot = "moonshot"
|
||||
providerTypeAzure = "azure"
|
||||
@@ -250,6 +264,9 @@ type ProviderConfig struct {
|
||||
inputVariable string `required:"false" yaml:"inputVariable" json:"inputVariable"`
|
||||
// @Title zh-CN dify中应用类型为workflow时需要设置输出变量,当botType为workflow时一起使用
|
||||
outputVariable string `required:"false" yaml:"outputVariable" json:"outputVariable"`
|
||||
// @Title zh-CN 额外支持的ai能力
|
||||
// @Description zh-CN 开放的ai能力和urlpath映射,例如: {"openai/v1/chatcompletions": "/v1/chat/completions"}
|
||||
capabilities map[string]string
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) GetId() string {
|
||||
@@ -361,12 +378,22 @@ func (c *ProviderConfig) FromJson(json gjson.Result) {
|
||||
c.botType = json.Get("botType").String()
|
||||
c.inputVariable = json.Get("inputVariable").String()
|
||||
c.outputVariable = json.Get("outputVariable").String()
|
||||
|
||||
c.capabilities = make(map[string]string)
|
||||
for capability, pathJson := range json.Get("capabilities").Map() {
|
||||
// 过滤掉不受支持的能力
|
||||
switch capability {
|
||||
case string(ApiNameChatCompletion),
|
||||
string(ApiNameEmbeddings),
|
||||
string(ApiNameImageGeneration),
|
||||
string(ApiNameAudioSpeech),
|
||||
string(ApiNameCohereV1Rerank):
|
||||
c.capabilities[capability] = pathJson.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) Validate() error {
|
||||
if c.timeout < 0 {
|
||||
return errors.New("invalid timeout in config")
|
||||
}
|
||||
if c.protocol != protocolOpenAI && c.protocol != protocolOriginal {
|
||||
return errors.New("invalid protocol in config")
|
||||
}
|
||||
@@ -499,7 +526,7 @@ func getMappedModel(model string, modelMapping map[string]string, log wrapper.Lo
|
||||
}
|
||||
|
||||
func doGetMappedModel(model string, modelMapping map[string]string, log wrapper.Log) string {
|
||||
if modelMapping == nil || len(modelMapping) == 0 {
|
||||
if len(modelMapping) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -527,11 +554,22 @@ func doGetMappedModel(model string, modelMapping map[string]string, log wrapper.
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) isSupportedAPI(apiName ApiName) bool {
|
||||
_, exist := c.capabilities[string(apiName)]
|
||||
return exist
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) setDefaultCapabilities(capabilities map[string]string) {
|
||||
for capability, path := range capabilities {
|
||||
c.capabilities[capability] = path
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) handleRequestBody(
|
||||
provider Provider, contextCache *contextCache, ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log,
|
||||
) (types.Action, error) {
|
||||
// use original protocol
|
||||
if c.protocol == protocolOriginal {
|
||||
if c.IsOriginal() {
|
||||
return types.ActionContinue, nil
|
||||
}
|
||||
|
||||
@@ -578,17 +616,21 @@ func (c *ProviderConfig) handleRequestHeaders(provider Provider, ctx wrapper.Htt
|
||||
}
|
||||
}
|
||||
|
||||
// defaultTransformRequestBody 默认的请求体转换方法,只做模型映射,用slog替换模型名称,不用序列化和反序列化,提高性能
|
||||
func (c *ProviderConfig) defaultTransformRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
var request interface{}
|
||||
if apiName == ApiNameChatCompletion {
|
||||
request = &chatCompletionRequest{}
|
||||
} else {
|
||||
request = &embeddingsRequest{}
|
||||
switch apiName {
|
||||
case ApiNameChatCompletion:
|
||||
stream := gjson.GetBytes(body, "stream").Bool()
|
||||
if stream {
|
||||
_ = proxywasm.ReplaceHttpRequestHeader("Accept", "text/event-stream")
|
||||
ctx.SetContext(ctxKeyIsStreaming, true)
|
||||
} else {
|
||||
ctx.SetContext(ctxKeyIsStreaming, false)
|
||||
}
|
||||
}
|
||||
if err := c.parseRequestAndMapModel(ctx, request, body, log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(request)
|
||||
model := gjson.GetBytes(body, "model").String()
|
||||
ctx.SetContext(ctxKeyOriginalRequestModel, model)
|
||||
return sjson.SetBytes(body, "model", getMappedModel(model, c.modelMapping, log))
|
||||
}
|
||||
|
||||
func (c *ProviderConfig) DefaultTransformResponseHeaders(ctx wrapper.HttpContext, headers http.Header) {
|
||||
|
||||
@@ -52,7 +52,15 @@ func (m *qwenProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *qwenProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): qwenChatCompletionPath,
|
||||
string(ApiNameEmbeddings): qwenTextEmbeddingPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *qwenProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &qwenProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -75,18 +83,19 @@ func (m *qwenProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName
|
||||
if m.config.IsOriginal() {
|
||||
} else if m.config.qwenEnableCompatible {
|
||||
util.OverwriteRequestPathHeader(headers, qwenCompatiblePath)
|
||||
} else if apiName == ApiNameChatCompletion {
|
||||
util.OverwriteRequestPathHeader(headers, qwenChatCompletionPath)
|
||||
} else if apiName == ApiNameEmbeddings {
|
||||
util.OverwriteRequestPathHeader(headers, qwenTextEmbeddingPath)
|
||||
} else if apiName == ApiNameChatCompletion || apiName == ApiNameEmbeddings {
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *qwenProvider) TransformRequestBodyHeaders(ctx wrapper.HttpContext, apiName ApiName, body []byte, headers http.Header, log wrapper.Log) ([]byte, error) {
|
||||
if apiName == ApiNameChatCompletion {
|
||||
switch apiName {
|
||||
case ApiNameChatCompletion:
|
||||
return m.onChatCompletionRequestBody(ctx, body, headers, log)
|
||||
} else {
|
||||
case ApiNameEmbeddings:
|
||||
return m.onEmbeddingsRequestBody(ctx, body, log)
|
||||
default:
|
||||
return m.config.defaultTransformRequestBody(ctx, apiName, body, log)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,10 +104,6 @@ func (m *qwenProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *qwenProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
|
||||
if m.config.protocol == protocolOriginal {
|
||||
@@ -140,7 +145,7 @@ func (m *qwenProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, b
|
||||
return types.ActionContinue, nil
|
||||
}
|
||||
|
||||
if apiName != ApiNameChatCompletion && apiName != ApiNameEmbeddings {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
@@ -278,6 +283,9 @@ func (m *qwenProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName Ap
|
||||
if apiName == ApiNameEmbeddings {
|
||||
return m.onEmbeddingsResponseBody(ctx, body, log)
|
||||
}
|
||||
if m.config.isSupportedAPI(apiName) {
|
||||
return body, nil
|
||||
}
|
||||
return nil, errUnsupportedApiName
|
||||
}
|
||||
|
||||
@@ -640,10 +648,11 @@ type qwenUsage struct {
|
||||
}
|
||||
|
||||
type qwenMessage struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role"`
|
||||
Content any `json:"content"`
|
||||
ToolCalls []toolCall `json:"tool_calls,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role"`
|
||||
Content any `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []toolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type qwenVlMessageContent struct {
|
||||
|
||||
@@ -55,7 +55,14 @@ func (i *sparkProviderInitializer) ValidateConfig(config *ProviderConfig) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *sparkProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): sparkChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *sparkProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(i.DefaultCapabilities())
|
||||
return &sparkProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -67,21 +74,21 @@ func (p *sparkProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (p *sparkProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
p.config.handleRequestHeaders(p, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *sparkProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !p.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return p.config.handleRequestBody(p, p.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (p *sparkProvider) TransformResponseBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) ([]byte, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return body, nil
|
||||
}
|
||||
sparkResponse := &sparkResponse{}
|
||||
if err := json.Unmarshal(body, sparkResponse); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal spark response: %v", err)
|
||||
@@ -97,6 +104,9 @@ func (p *sparkProvider) OnStreamingResponseBody(ctx wrapper.HttpContext, name Ap
|
||||
if isLastChunk || len(chunk) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if name != ApiNameChatCompletion {
|
||||
return chunk, nil
|
||||
}
|
||||
responseBuilder := &strings.Builder{}
|
||||
lines := strings.Split(string(chunk), "\n")
|
||||
for _, data := range lines {
|
||||
@@ -168,7 +178,7 @@ func (p *sparkProvider) appendResponse(responseBuilder *strings.Builder, respons
|
||||
}
|
||||
|
||||
func (p *sparkProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, sparkChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), p.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, sparkHost)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+p.config.GetApiTokenInUse(ctx))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,15 @@ func (m *stepfunProviderInitializer) ValidateConfig(config *ProviderConfig) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *stepfunProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
// stepfun的chat接口path和OpenAI的chat接口一样
|
||||
string(ApiNameChatCompletion): stepfunChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *stepfunProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &stepfunProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -41,22 +49,19 @@ func (m *stepfunProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *stepfunProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *stepfunProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *stepfunProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, stepfunChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, stepfunDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -2,11 +2,12 @@ package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/extensions/ai-proxy/util"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,7 +24,14 @@ func (m *togetherAIProviderInitializer) ValidateConfig(config *ProviderConfig) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *togetherAIProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): togetherAICompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *togetherAIProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &togetherAIProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -40,22 +48,19 @@ func (m *togetherAIProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *togetherAIProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *togetherAIProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *togetherAIProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, togetherAICompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, togetherAIDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -24,7 +24,14 @@ func (m *yiProviderInitializer) ValidateConfig(config *ProviderConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *yiProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): yiChatCompletionPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *yiProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &yiProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -41,22 +48,19 @@ func (m *yiProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *yiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *yiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *yiProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, yiChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, yiDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
const (
|
||||
zhipuAiDomain = "open.bigmodel.cn"
|
||||
zhipuAiChatCompletionPath = "/api/paas/v4/chat/completions"
|
||||
zhipuAiEmbeddingsPath = "/api/paas/v4/embeddings"
|
||||
)
|
||||
|
||||
type zhipuAiProviderInitializer struct{}
|
||||
@@ -24,7 +25,15 @@ func (m *zhipuAiProviderInitializer) ValidateConfig(config *ProviderConfig) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *zhipuAiProviderInitializer) DefaultCapabilities() map[string]string {
|
||||
return map[string]string{
|
||||
string(ApiNameChatCompletion): zhipuAiChatCompletionPath,
|
||||
string(ApiNameEmbeddings): zhipuAiEmbeddingsPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *zhipuAiProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {
|
||||
config.setDefaultCapabilities(m.DefaultCapabilities())
|
||||
return &zhipuAiProvider{
|
||||
config: config,
|
||||
contextCache: createContextCache(&config),
|
||||
@@ -41,22 +50,19 @@ func (m *zhipuAiProvider) GetProviderType() string {
|
||||
}
|
||||
|
||||
func (m *zhipuAiProvider) OnRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, log wrapper.Log) error {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
return errUnsupportedApiName
|
||||
}
|
||||
m.config.handleRequestHeaders(m, ctx, apiName, log)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *zhipuAiProvider) OnRequestBody(ctx wrapper.HttpContext, apiName ApiName, body []byte, log wrapper.Log) (types.Action, error) {
|
||||
if apiName != ApiNameChatCompletion {
|
||||
if !m.config.isSupportedAPI(apiName) {
|
||||
return types.ActionContinue, errUnsupportedApiName
|
||||
}
|
||||
return m.config.handleRequestBody(m, m.contextCache, ctx, apiName, body, log)
|
||||
}
|
||||
|
||||
func (m *zhipuAiProvider) TransformRequestHeaders(ctx wrapper.HttpContext, apiName ApiName, headers http.Header, log wrapper.Log) {
|
||||
util.OverwriteRequestPathHeader(headers, zhipuAiChatCompletionPath)
|
||||
util.OverwriteRequestPathHeaderByCapability(headers, string(apiName), m.config.capabilities)
|
||||
util.OverwriteRequestHostHeader(headers, zhipuAiDomain)
|
||||
util.OverwriteRequestAuthorizationHeader(headers, "Bearer "+m.config.GetApiTokenInUse(ctx))
|
||||
headers.Del("Content-Length")
|
||||
@@ -66,5 +72,8 @@ func (m *zhipuAiProvider) GetApiName(path string) ApiName {
|
||||
if strings.Contains(path, zhipuAiChatCompletionPath) {
|
||||
return ApiNameChatCompletion
|
||||
}
|
||||
if strings.Contains(path, zhipuAiEmbeddingsPath) {
|
||||
return ApiNameEmbeddings
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -57,6 +57,17 @@ func OverwriteRequestPathHeader(headers http.Header, path string) {
|
||||
headers.Set(":path", path)
|
||||
}
|
||||
|
||||
func OverwriteRequestPathHeaderByCapability(headers http.Header, apiName string, mapping map[string]string) {
|
||||
mappedPath, exist := mapping[apiName]
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
if originPath, err := proxywasm.GetHttpRequestHeader(":path"); err == nil {
|
||||
headers.Set("X-ENVOY-ORIGINAL-PATH", originPath)
|
||||
}
|
||||
headers.Set(":path", mappedPath)
|
||||
}
|
||||
|
||||
func OverwriteRequestAuthorizationHeader(headers http.Header, credential string) {
|
||||
if exist := headers.Get("X-HI-ORIGINAL-AUTH"); exist == "" {
|
||||
if originAuth := headers.Get("Authorization"); originAuth != "" {
|
||||
|
||||
@@ -65,7 +65,7 @@ func ParseConfig(json gjson.Result, config *ExtAuthConfig, log wrapper.Log) erro
|
||||
return err
|
||||
}
|
||||
|
||||
if err := parseMatchRules(json, config, log); err != nil {
|
||||
if err := parseMatchRules(json, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ func parseAuthorizationResponseConfig(json gjson.Result, httpService *HttpServic
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMatchRules(json gjson.Result, config *ExtAuthConfig, log wrapper.Log) error {
|
||||
func parseMatchRules(json gjson.Result, config *ExtAuthConfig) error {
|
||||
matchListConfig := json.Get("match_list")
|
||||
if !matchListConfig.Exists() {
|
||||
config.MatchRules = expr.MatchRulesDefaults()
|
||||
@@ -260,10 +260,15 @@ func parseMatchRules(json gjson.Result, config *ExtAuthConfig, log wrapper.Log)
|
||||
var err error
|
||||
|
||||
matchListConfig.ForEach(func(key, value gjson.Result) bool {
|
||||
pathMatcher, err := expr.BuildStringMatcher(
|
||||
pathMatcher, buildErr := expr.BuildStringMatcher(
|
||||
value.Get("match_rule_type").Str,
|
||||
value.Get("match_rule_path").Str, false)
|
||||
if err != nil {
|
||||
if buildErr != nil {
|
||||
err = fmt.Errorf("failed to build string matcher for rule with domain %q, path %q, type %q: %w",
|
||||
value.Get("match_rule_domain").Str,
|
||||
value.Get("match_rule_path").Str,
|
||||
value.Get("match_rule_type").Str,
|
||||
buildErr)
|
||||
return false // stop iterating
|
||||
}
|
||||
ruleList = append(ruleList, expr.Rule{
|
||||
@@ -274,7 +279,7 @@ func parseMatchRules(json gjson.Result, config *ExtAuthConfig, log wrapper.Log)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build string matcher for rule %v: %w", matchListConfig, err)
|
||||
return err
|
||||
}
|
||||
|
||||
config.MatchRules = expr.MatchRules{
|
||||
|
||||
@@ -1,136 +1,368 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
regexp "github.com/wasilibs/go-re2"
|
||||
"ext-auth/expr"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
MatchPatternExact string = "exact"
|
||||
MatchPatternPrefix string = "prefix"
|
||||
MatchPatternSuffix string = "suffix"
|
||||
MatchPatternContains string = "contains"
|
||||
MatchPatternRegex string = "regex"
|
||||
|
||||
MatchIgnoreCase string = "ignore_case"
|
||||
)
|
||||
|
||||
type Matcher interface {
|
||||
Match(s string) bool
|
||||
}
|
||||
|
||||
type stringExactMatcher struct {
|
||||
target string
|
||||
ignoreCase bool
|
||||
}
|
||||
|
||||
func (m *stringExactMatcher) Match(s string) bool {
|
||||
if m.ignoreCase {
|
||||
return strings.ToLower(s) == m.target
|
||||
func TestParseConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
json string
|
||||
expected ExtAuthConfig
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "Valid Config with Default Values",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: ExtAuthConfig{
|
||||
HttpService: HttpService{
|
||||
EndpointMode: "envoy",
|
||||
Client: wrapper.NewClusterClient(wrapper.FQDNCluster{
|
||||
FQDN: "example.com",
|
||||
Port: 80,
|
||||
Host: "",
|
||||
}),
|
||||
PathPrefix: "/auth",
|
||||
Timeout: 1000,
|
||||
},
|
||||
MatchRules: expr.MatchRulesDefaults(),
|
||||
FailureModeAllow: false,
|
||||
FailureModeAllowHeaderAdd: false,
|
||||
StatusOnError: 403,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid Config with Custom Values",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "forward_auth",
|
||||
"endpoint": {
|
||||
"service_name": "auth.example.com",
|
||||
"service_port": 8080,
|
||||
"service_host": "auth.example.com",
|
||||
"request_method": "POST",
|
||||
"path": "/auth"
|
||||
},
|
||||
"timeout": 2000,
|
||||
"authorization_request": {
|
||||
"headers_to_add": {
|
||||
"X-Auth-Source": "wasm"
|
||||
},
|
||||
"with_request_body": true,
|
||||
"max_request_body_bytes": 1048576
|
||||
}
|
||||
},
|
||||
"skipped_path_prefixes": ["/health", "/metrics"],
|
||||
"failure_mode_allow": true,
|
||||
"failure_mode_allow_header_add": true,
|
||||
"status_on_error": 500
|
||||
}`,
|
||||
expected: ExtAuthConfig{
|
||||
HttpService: HttpService{
|
||||
EndpointMode: "forward_auth",
|
||||
Client: wrapper.NewClusterClient(wrapper.FQDNCluster{
|
||||
FQDN: "auth.example.com",
|
||||
Port: 8080,
|
||||
Host: "auth.example.com",
|
||||
}),
|
||||
RequestMethod: "POST",
|
||||
Path: "/auth",
|
||||
Timeout: 2000,
|
||||
AuthorizationRequest: AuthorizationRequest{
|
||||
HeadersToAdd: map[string]string{
|
||||
"X-Auth-Source": "wasm",
|
||||
},
|
||||
WithRequestBody: true,
|
||||
MaxRequestBodyBytes: 1048576,
|
||||
},
|
||||
},
|
||||
MatchRules: expr.MatchRulesDefaults(),
|
||||
FailureModeAllow: true,
|
||||
FailureModeAllowHeaderAdd: true,
|
||||
StatusOnError: 500,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Missing HttpService Configuration",
|
||||
json: `{}`,
|
||||
expectedErr: "missing http_service in config",
|
||||
},
|
||||
{
|
||||
name: "Invalid Endpoint Mode",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "invalid_mode",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedErr: "endpoint_mode invalid_mode is not supported",
|
||||
},
|
||||
{
|
||||
name: "Missing Endpoint Configuration",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy"
|
||||
}
|
||||
}`,
|
||||
expectedErr: "missing endpoint in config",
|
||||
},
|
||||
{
|
||||
name: "Empty Service Name",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "",
|
||||
"service_port": 80
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedErr: "endpoint service name must not be empty",
|
||||
},
|
||||
{
|
||||
name: "Invalid Request Method with Request Body",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "forward_auth",
|
||||
"endpoint": {
|
||||
"service_name": "auth.example.com",
|
||||
"service_port": 8080,
|
||||
"request_method": "GET",
|
||||
"path": "/auth"
|
||||
},
|
||||
"authorization_request": {
|
||||
"with_request_body": true
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedErr: "requestMethod GET does not support with_request_body set to true",
|
||||
},
|
||||
{
|
||||
name: "Missing Path for Forward Auth",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "forward_auth",
|
||||
"endpoint": {
|
||||
"service_name": "auth.example.com",
|
||||
"service_port": 8080,
|
||||
"service_host": "auth.example.com",
|
||||
"request_method": "POST"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedErr: "when endpoint_mode is forward_auth, endpoint path must not be empty",
|
||||
},
|
||||
{
|
||||
name: "Missing Path Prefix for Envoy",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expectedErr: "when endpoint_mode is envoy, endpoint path_prefix must not be empty",
|
||||
},
|
||||
{
|
||||
name: "Valid Match Rules with Blacklist",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
},
|
||||
"match_type": "blacklist",
|
||||
"match_list": [
|
||||
{
|
||||
"match_rule_domain": "*.bar.com",
|
||||
"match_rule_path": "/headers",
|
||||
"match_rule_type": "prefix"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expected: ExtAuthConfig{
|
||||
HttpService: HttpService{
|
||||
EndpointMode: "envoy",
|
||||
Client: wrapper.NewClusterClient(wrapper.FQDNCluster{
|
||||
FQDN: "example.com",
|
||||
Port: 80,
|
||||
Host: "",
|
||||
}),
|
||||
PathPrefix: "/auth",
|
||||
Timeout: 1000,
|
||||
},
|
||||
MatchRules: expr.MatchRules{
|
||||
Mode: "blacklist",
|
||||
RuleList: []expr.Rule{
|
||||
{
|
||||
Domain: "*.bar.com",
|
||||
Path: func() expr.Matcher {
|
||||
pathMatcher, err := expr.BuildStringMatcher(expr.MatchPatternPrefix, "/headers", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Matcher: %v", err)
|
||||
}
|
||||
return pathMatcher
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
FailureModeAllow: false,
|
||||
FailureModeAllowHeaderAdd: false,
|
||||
StatusOnError: 403,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid Match Rules with Whitelist",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
},
|
||||
"match_type": "whitelist",
|
||||
"match_list": [
|
||||
{
|
||||
"match_rule_domain": "*.foo.com",
|
||||
"match_rule_path": "/api",
|
||||
"match_rule_type": "exact"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expected: ExtAuthConfig{
|
||||
HttpService: HttpService{
|
||||
EndpointMode: "envoy",
|
||||
Client: wrapper.NewClusterClient(wrapper.FQDNCluster{
|
||||
FQDN: "example.com",
|
||||
Port: 80,
|
||||
Host: "",
|
||||
}),
|
||||
PathPrefix: "/auth",
|
||||
Timeout: 1000,
|
||||
},
|
||||
MatchRules: expr.MatchRules{
|
||||
Mode: "whitelist",
|
||||
RuleList: []expr.Rule{
|
||||
{
|
||||
Domain: "*.foo.com",
|
||||
Path: func() expr.Matcher {
|
||||
pathMatcher, err := expr.BuildStringMatcher(expr.MatchPatternExact, "/api", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Matcher: %v", err)
|
||||
}
|
||||
return pathMatcher
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
FailureModeAllow: false,
|
||||
FailureModeAllowHeaderAdd: false,
|
||||
StatusOnError: 403,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Missing Match Type",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
},
|
||||
"match_list": [
|
||||
{
|
||||
"match_rule_domain": "*.bar.com",
|
||||
"match_rule_path": "/headers",
|
||||
"match_rule_type": "prefix"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectedErr: "missing match_type in config",
|
||||
},
|
||||
{
|
||||
name: "Invalid Match Type",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
},
|
||||
"match_type": "invalid_type",
|
||||
"match_list": [
|
||||
{
|
||||
"match_rule_domain": "*.bar.com",
|
||||
"match_rule_path": "/headers",
|
||||
"match_rule_type": "prefix"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectedErr: "invalid match_type in config, must be 'whitelist' or 'blacklist'",
|
||||
},
|
||||
{
|
||||
name: "Invalid Match Rule Type",
|
||||
json: `{
|
||||
"http_service": {
|
||||
"endpoint_mode": "envoy",
|
||||
"endpoint": {
|
||||
"service_name": "example.com",
|
||||
"service_port": 80,
|
||||
"path_prefix": "/auth"
|
||||
}
|
||||
},
|
||||
"match_type": "blacklist",
|
||||
"match_list": [
|
||||
{
|
||||
"match_rule_domain": "*.bar.com",
|
||||
"match_rule_path": "/headers",
|
||||
"match_rule_type": "invalid_type"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectedErr: `failed to build string matcher for rule with domain "*.bar.com", path "/headers", type "invalid_type": unknown string matcher type`,
|
||||
},
|
||||
}
|
||||
return s == m.target
|
||||
}
|
||||
|
||||
type stringPrefixMatcher struct {
|
||||
target string
|
||||
ignoreCase bool
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var config ExtAuthConfig
|
||||
result := gjson.Parse(tt.json)
|
||||
err := ParseConfig(result, &config, &wrapper.DefaultLog{})
|
||||
|
||||
func (m *stringPrefixMatcher) Match(s string) bool {
|
||||
if m.ignoreCase {
|
||||
return strings.HasPrefix(strings.ToLower(s), m.target)
|
||||
if tt.expectedErr != "" {
|
||||
assert.EqualError(t, err, tt.expectedErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, config)
|
||||
}
|
||||
})
|
||||
}
|
||||
return strings.HasPrefix(s, m.target)
|
||||
}
|
||||
|
||||
type stringSuffixMatcher struct {
|
||||
target string
|
||||
ignoreCase bool
|
||||
}
|
||||
|
||||
func (m *stringSuffixMatcher) Match(s string) bool {
|
||||
if m.ignoreCase {
|
||||
return strings.HasSuffix(strings.ToLower(s), m.target)
|
||||
}
|
||||
return strings.HasSuffix(s, m.target)
|
||||
}
|
||||
|
||||
type stringContainsMatcher struct {
|
||||
target string
|
||||
ignoreCase bool
|
||||
}
|
||||
|
||||
func (m *stringContainsMatcher) Match(s string) bool {
|
||||
if m.ignoreCase {
|
||||
return strings.Contains(strings.ToLower(s), m.target)
|
||||
}
|
||||
return strings.Contains(s, m.target)
|
||||
}
|
||||
|
||||
type stringRegexMatcher struct {
|
||||
regex *regexp.Regexp
|
||||
}
|
||||
|
||||
func (m *stringRegexMatcher) Match(s string) bool {
|
||||
return m.regex.MatchString(s)
|
||||
}
|
||||
|
||||
type MatcherConstructor func(string, bool) (Matcher, error)
|
||||
|
||||
var matcherConstructors = map[string]MatcherConstructor{
|
||||
MatchPatternExact: newStringExactMatcher,
|
||||
MatchPatternPrefix: newStringPrefixMatcher,
|
||||
MatchPatternSuffix: newStringSuffixMatcher,
|
||||
MatchPatternContains: newStringContainsMatcher,
|
||||
MatchPatternRegex: newStringRegexMatcher,
|
||||
}
|
||||
|
||||
func newStringExactMatcher(target string, ignoreCase bool) (Matcher, error) {
|
||||
if ignoreCase {
|
||||
target = strings.ToLower(target)
|
||||
}
|
||||
return &stringExactMatcher{target: target, ignoreCase: ignoreCase}, nil
|
||||
}
|
||||
|
||||
func newStringPrefixMatcher(target string, ignoreCase bool) (Matcher, error) {
|
||||
if ignoreCase {
|
||||
target = strings.ToLower(target)
|
||||
}
|
||||
return &stringPrefixMatcher{target: target, ignoreCase: ignoreCase}, nil
|
||||
}
|
||||
|
||||
func newStringSuffixMatcher(target string, ignoreCase bool) (Matcher, error) {
|
||||
if ignoreCase {
|
||||
target = strings.ToLower(target)
|
||||
}
|
||||
return &stringSuffixMatcher{target: target, ignoreCase: ignoreCase}, nil
|
||||
}
|
||||
|
||||
func newStringContainsMatcher(target string, ignoreCase bool) (Matcher, error) {
|
||||
if ignoreCase {
|
||||
target = strings.ToLower(target)
|
||||
}
|
||||
return &stringContainsMatcher{target: target, ignoreCase: ignoreCase}, nil
|
||||
}
|
||||
|
||||
func newStringRegexMatcher(target string, ignoreCase bool) (Matcher, error) {
|
||||
if ignoreCase && !strings.HasPrefix(target, "(?i)") {
|
||||
target = "(?i)" + target
|
||||
}
|
||||
re, err := regexp.Compile(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &stringRegexMatcher{regex: re}, nil
|
||||
}
|
||||
|
||||
func BuildStringMatcher(matchType, target string, ignoreCase bool) (Matcher, error) {
|
||||
for constructorType, constructor := range matcherConstructors {
|
||||
if constructorType == matchType {
|
||||
return constructor(target, ignoreCase)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("unknown string matcher type")
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"ext-auth/config"
|
||||
"ext-auth/util"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
@@ -50,25 +51,23 @@ const (
|
||||
)
|
||||
|
||||
func onHttpRequestHeaders(ctx wrapper.HttpContext, config config.ExtAuthConfig, log wrapper.Log) types.Action {
|
||||
path, _ := wrapper.GetRequestPathWithoutQuery()
|
||||
path := wrapper.GetRequestPathWithoutQuery()
|
||||
// If the request's domain and path match the MatchRules, skip authentication
|
||||
if config.MatchRules.IsAllowedByMode(ctx.Host(), path) {
|
||||
ctx.DontReadRequestBody()
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
if wrapper.HasRequestBody() {
|
||||
ctx.SetRequestBodyBufferLimit(config.HttpService.AuthorizationRequest.MaxRequestBodyBytes)
|
||||
// Disable the route re-calculation since the plugin may modify some headers related to the chosen route.
|
||||
ctx.DisableReroute()
|
||||
|
||||
// If withRequestBody is true AND the HTTP request contains a request body,
|
||||
// it will be handled in the onHttpRequestBody phase.
|
||||
if config.HttpService.AuthorizationRequest.WithRequestBody {
|
||||
// Disable the route re-calculation since the plugin may modify some headers related to the chosen route.
|
||||
ctx.DisableReroute()
|
||||
// The request has a body and requires delaying the header transmission until a cache miss occurs,
|
||||
// at which point the header should be sent.
|
||||
return types.HeaderStopIteration
|
||||
}
|
||||
// If withRequestBody is true AND the HTTP request contains a request body,
|
||||
// it will be handled in the onHttpRequestBody phase.
|
||||
if wrapper.HasRequestBody() && config.HttpService.AuthorizationRequest.WithRequestBody {
|
||||
ctx.SetRequestBodyBufferLimit(config.HttpService.AuthorizationRequest.MaxRequestBodyBytes)
|
||||
// The request has a body and requires delaying the header transmission until a cache miss occurs,
|
||||
// at which point the header should be sent.
|
||||
return types.HeaderStopIteration
|
||||
}
|
||||
|
||||
ctx.DontReadRequestBody()
|
||||
@@ -77,7 +76,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config config.ExtAuthConfig,
|
||||
|
||||
func onHttpRequestBody(ctx wrapper.HttpContext, config config.ExtAuthConfig, body []byte, log wrapper.Log) types.Action {
|
||||
if config.HttpService.AuthorizationRequest.WithRequestBody {
|
||||
return checkExtAuth(ctx, config, body, log, types.ActionPause)
|
||||
return checkExtAuth(ctx, config, body, log, types.DataStopIterationAndBuffer)
|
||||
}
|
||||
return types.ActionContinue
|
||||
}
|
||||
@@ -86,17 +85,18 @@ func checkExtAuth(ctx wrapper.HttpContext, cfg config.ExtAuthConfig, body []byte
|
||||
httpServiceConfig := cfg.HttpService
|
||||
|
||||
extAuthReqHeaders := buildExtAuthRequestHeaders(ctx, cfg)
|
||||
|
||||
// Set the requestMethod and requestPath based on the endpoint_mode
|
||||
requestMethod := httpServiceConfig.RequestMethod
|
||||
requestPath := httpServiceConfig.Path
|
||||
if httpServiceConfig.EndpointMode == config.EndpointModeEnvoy {
|
||||
requestMethod = ctx.Method()
|
||||
requestPath, _ = url.JoinPath(httpServiceConfig.PathPrefix, ctx.Path())
|
||||
requestPath = path.Join(httpServiceConfig.PathPrefix, ctx.Path())
|
||||
}
|
||||
|
||||
// Call ext auth server
|
||||
err := httpServiceConfig.Client.Call(requestMethod, requestPath, util.ReconvertHeaders(extAuthReqHeaders), body,
|
||||
func(statusCode int, responseHeaders http.Header, responseBody []byte) {
|
||||
defer proxywasm.ResumeHttpRequest()
|
||||
if statusCode != http.StatusOK {
|
||||
log.Errorf("failed to call ext auth server, status: %d", statusCode)
|
||||
callExtAuthServerErrorHandler(cfg, statusCode, responseHeaders, responseBody)
|
||||
@@ -110,6 +110,7 @@ func checkExtAuth(ctx wrapper.HttpContext, cfg config.ExtAuthConfig, body []byte
|
||||
}
|
||||
}
|
||||
}
|
||||
proxywasm.ResumeHttpRequest()
|
||||
|
||||
}, httpServiceConfig.Timeout)
|
||||
|
||||
@@ -122,6 +123,7 @@ func checkExtAuth(ctx wrapper.HttpContext, cfg config.ExtAuthConfig, body []byte
|
||||
return pauseAction
|
||||
}
|
||||
|
||||
// buildExtAuthRequestHeaders builds the request headers to be sent to the ext auth server.
|
||||
func buildExtAuthRequestHeaders(ctx wrapper.HttpContext, cfg config.ExtAuthConfig) http.Header {
|
||||
extAuthReqHeaders := http.Header{}
|
||||
|
||||
@@ -166,6 +168,7 @@ func callExtAuthServerErrorHandler(config config.ExtAuthConfig, statusCode int,
|
||||
if config.FailureModeAllowHeaderAdd {
|
||||
_ = proxywasm.ReplaceHttpRequestHeader(HeaderFailureModeAllow, "true")
|
||||
}
|
||||
proxywasm.ResumeHttpRequest()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
func parseConfig(json gjson.Result, grayConfig *config.GrayConfig, log wrapper.Log) error {
|
||||
// 解析json 为GrayConfig
|
||||
config.JsonToGrayConfig(json, grayConfig)
|
||||
log.Debugf("Rewrite: %v, GrayDeployments: %v", json.Get("rewrite"), json.Get("grayDeployments"))
|
||||
log.Infof("Rewrite: %v, GrayDeployments: %v", json.Get("rewrite"), json.Get("grayDeployments"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
|
||||
ctx.SetContext(config.EnabledGray, enabledGray)
|
||||
|
||||
if !enabledGray {
|
||||
log.Infof("gray not enabled")
|
||||
ctx.DontReadRequestBody()
|
||||
return types.ActionContinue
|
||||
}
|
||||
@@ -104,7 +105,10 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
|
||||
|
||||
rewrite := grayConfig.Rewrite
|
||||
if rewrite.Host != "" {
|
||||
proxywasm.ReplaceHttpRequestHeader("HOST", rewrite.Host)
|
||||
err := proxywasm.ReplaceHttpRequestHeader(":authority", rewrite.Host)
|
||||
if err != nil {
|
||||
log.Errorf("host rewrite failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if hasRewrite {
|
||||
@@ -119,6 +123,7 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, grayConfig config.GrayConfig,
|
||||
proxywasm.ReplaceHttpRequestHeader(":path", rewritePath)
|
||||
}
|
||||
}
|
||||
log.Infof("request path:%s, has rewrited:%v, rewrite config:%+v", requestPath, hasRewrite, rewrite)
|
||||
return types.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -49,13 +49,17 @@ func GetRequestPath() string {
|
||||
return path
|
||||
}
|
||||
|
||||
func GetRequestPathWithoutQuery() (string, error) {
|
||||
func GetRequestPathWithoutQuery() string {
|
||||
rawPath := GetRequestPath()
|
||||
if rawPath == "" {
|
||||
return ""
|
||||
}
|
||||
path, err := url.Parse(rawPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
proxywasm.LogErrorf("failed to parse request path '%s': %v", rawPath, err)
|
||||
return ""
|
||||
}
|
||||
return path.Path, nil
|
||||
return path.Path
|
||||
}
|
||||
|
||||
func GetRequestMethod() string {
|
||||
|
||||
599
plugins/wasm-rust/Cargo.lock
generated
Normal file
599
plugins/wasm-rust/Cargo.lock
generated
Normal file
@@ -0,0 +1,599 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "higress-wasm-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-wasm"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#8c902102091698bec953471c850bdf9799bc344d"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"hashbrown",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
@@ -9,7 +9,6 @@ edition = "2021"
|
||||
proxy-wasm = { git="https://github.com/higress-group/proxy-wasm-rust-sdk", branch="main", version="0.2.2" }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
multimap = "0"
|
||||
http = "1"
|
||||
lazy_static = "1"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
FROM rust:1.80 as builder
|
||||
WORKDIR /workspace
|
||||
RUN rustup target add wasm32-wasi
|
||||
RUN rustup target add wasm32-wasip1
|
||||
ARG PLUGIN_NAME="say-hello"
|
||||
ARG BUILD_OPTS="--release"
|
||||
ARG BUILDRC=".buildrc"
|
||||
COPY . .
|
||||
WORKDIR /workspace/extensions/$PLUGIN_NAME
|
||||
RUN if [ -f $BUILDRC ]; then sh $BUILDRC; fi
|
||||
RUN cargo build --target wasm32-wasi $BUILD_OPTS \
|
||||
&& cp target/wasm32-wasi/release/*.wasm /main.wasm
|
||||
RUN cargo build --target wasm32-wasip1 $BUILD_OPTS \
|
||||
&& cp target/wasm32-wasip1/release/*.wasm /main.wasm
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /main.wasm plugin.wasm
|
||||
|
||||
@@ -8,7 +8,7 @@ FROM $BASE_IMAGE
|
||||
|
||||
LABEL rust_version=$RUST_VERSION oras_version=$ORAS_VERSION
|
||||
|
||||
RUN rustup target add wasm32-wasi
|
||||
RUN rustup target add wasm32-wasi wasm32-wasip1
|
||||
|
||||
RUN arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
|
||||
rust_version=${RUST_VERSION:-1.82}; \
|
||||
|
||||
1231
plugins/wasm-rust/extensions/ai-data-masking/Cargo.lock
generated
Normal file
1231
plugins/wasm-rust/extensions/ai-data-masking/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
847
plugins/wasm-rust/extensions/ai-intent/Cargo.lock
generated
Normal file
847
plugins/wasm-rust/extensions/ai-intent/Cargo.lock
generated
Normal file
@@ -0,0 +1,847 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ai-intent"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"higress-wasm-rust",
|
||||
"http",
|
||||
"jsonpath-rust",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "higress-wasm-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "jsonpath-rust"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-wasm"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#8c902102091698bec953471c850bdf9799bc344d"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"hashbrown 0.14.5",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
612
plugins/wasm-rust/extensions/demo-wasm/Cargo.lock
generated
Normal file
612
plugins/wasm-rust/extensions/demo-wasm/Cargo.lock
generated
Normal file
@@ -0,0 +1,612 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo-wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"higress-wasm-rust",
|
||||
"http",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "higress-wasm-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-wasm"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#8c902102091698bec953471c850bdf9799bc344d"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"hashbrown",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
649
plugins/wasm-rust/extensions/request-block/Cargo.lock
generated
Normal file
649
plugins/wasm-rust/extensions/request-block/Cargo.lock
generated
Normal file
@@ -0,0 +1,649 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "higress-wasm-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-wasm"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#8c902102091698bec953471c850bdf9799bc344d"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"hashbrown",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "request-block"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"higress-wasm-rust",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
609
plugins/wasm-rust/extensions/say-hello/Cargo.lock
generated
Normal file
609
plugins/wasm-rust/extensions/say-hello/Cargo.lock
generated
Normal file
@@ -0,0 +1,609 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "higress-wasm-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"http",
|
||||
"lazy_static",
|
||||
"multimap",
|
||||
"proxy-wasm",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proxy-wasm"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/higress-group/proxy-wasm-rust-sdk?branch=main#8c902102091698bec953471c850bdf9799bc344d"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"hashbrown",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"combine",
|
||||
"itoa",
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"ryu",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "say-hello"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"higress-wasm-rust",
|
||||
"proxy-wasm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
46
test/e2e/conformance/base/llm-mock.yaml
Normal file
46
test/e2e/conformance/base/llm-mock.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2025 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: higress-conformance-ai-backend
|
||||
labels:
|
||||
higress-conformance: infra
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: llm-mock
|
||||
namespace: higress-conformance-ai-backend
|
||||
labels:
|
||||
name: llm-mock
|
||||
spec:
|
||||
containers:
|
||||
- name: llm-mock
|
||||
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/llm-mock:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: llm-mock-service
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
selector:
|
||||
name: llm-mock
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: 3000
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
# Copyright (c) 2025 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -14,42 +14,306 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
name: wasmplugin-ai-proxy-openai
|
||||
namespace: higress-conformance-infra
|
||||
name: wasmplugin-ai-proxy-ai360
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "openai.ai.com"
|
||||
- host: "api.360.cn"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: infra-backend-v1
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 8080
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
name: wasmplugin-ai-proxy-qwen
|
||||
namespace: higress-conformance-infra
|
||||
name: wasmplugin-ai-proxy-baichuan
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "qwen.ai.com"
|
||||
- host: "api.baichuan-ai.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: infra-backend-v1
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 8080
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-baidu
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "qianfan.baidubce.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-deepseek
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.deepseek.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-doubao
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "ark.cn-beijing.volces.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-github
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "models.inference.ai.azure.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-groq
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.groq.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-minimax-v2-api
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.minimax.chat-v2-api"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-minimax-pro-api
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.minimax.chat-pro-api"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-mistral
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.mistral.ai"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-qwen-compatible-mode
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "dashscope.aliyuncs.com-compatible-mode"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-qwen
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "dashscope.aliyuncs.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-stepfun
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.stepfun.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-together-ai
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.together.xyz"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-yi
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "api.lingyiwanwu.com"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wasmplugin-ai-proxy-zhipuai
|
||||
namespace: higress-conformance-ai-backend
|
||||
spec:
|
||||
ingressClassName: higress
|
||||
rules:
|
||||
- host: "open.bigmodel.cn"
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: llm-mock-service
|
||||
port:
|
||||
number: 3000
|
||||
---
|
||||
apiVersion: extensions.higress.io/v1alpha1
|
||||
kind: WasmPlugin
|
||||
@@ -57,31 +321,176 @@ metadata:
|
||||
name: ai-proxy
|
||||
namespace: higress-system
|
||||
spec:
|
||||
priority: 200
|
||||
defaultConfigDisable: true
|
||||
phase: UNSPECIFIED_PHASE
|
||||
priority: 100
|
||||
matchRules:
|
||||
- config:
|
||||
provider:
|
||||
type: "openai"
|
||||
customSettings:
|
||||
- name: "max_tokens"
|
||||
value: 123
|
||||
overwrite: false
|
||||
- name: "temperature"
|
||||
value: 0.66
|
||||
overwrite: true
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': 360gpt-turbo
|
||||
'*': 360gpt-pro
|
||||
type: ai360
|
||||
ingress:
|
||||
- higress-conformance-infra/wasmplugin-ai-proxy-openai
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-ai360
|
||||
- config:
|
||||
provider:
|
||||
type: "qwen"
|
||||
apiTokens: "fake-token"
|
||||
customSettings:
|
||||
- name: "max_tokens"
|
||||
value: 123
|
||||
overwrite: false
|
||||
- name: "temperature"
|
||||
value: 0.66
|
||||
overwrite: true
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': baichuan2-13b-chat-v1
|
||||
'*': baichuan-7b-v1
|
||||
type: baichuan
|
||||
ingress:
|
||||
- higress-conformance-infra/wasmplugin-ai-proxy-qwen
|
||||
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/ai-proxy:1.0.0
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-baichuan
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': ernie-3.5-8k
|
||||
'*': ernie-3.5-8k
|
||||
type: baidu
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-baidu
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': deepseek-reasoner
|
||||
'*': deepseek-chat
|
||||
type: deepseek
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-deepseek
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'*': fake_doubao_endpoint
|
||||
type: doubao
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-doubao
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': cohere-command-r-08-2024
|
||||
'*': Phi-3.5-MoE-instruct
|
||||
type: github
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-github
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': llama3-8b-8192
|
||||
'*': llama-3.1-8b-instant
|
||||
type: groq
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-groq
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': abab6.5s-chat
|
||||
'gpt-4': abab6.5g-chat
|
||||
'*': abab6.5t-chat
|
||||
type: minimax
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-minimax-v2-api
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': abab6.5s-chat
|
||||
'gpt-4': abab6.5g-chat
|
||||
'*': abab6.5t-chat
|
||||
type: minimax
|
||||
minimaxApiType: pro
|
||||
minimaxGroupId: 1
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-minimax-pro-api
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': mistral-tiny
|
||||
'*': mistral-large-latest
|
||||
type: mistral
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-mistral
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': qwen-turbo
|
||||
'gpt-35-turbo': qwen-plus
|
||||
'gpt-4-*': qwen-max
|
||||
'*': qwen-turbo
|
||||
type: qwen
|
||||
qwenEnableCompatible: true
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-qwen-compatible-mode
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': qwen-turbo
|
||||
'gpt-35-turbo': qwen-plus
|
||||
'gpt-4-*': qwen-max
|
||||
'*': qwen-turbo
|
||||
type: qwen
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-qwen
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': step-1-8k
|
||||
'*': step-1-32k
|
||||
type: stepfun
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-stepfun
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': meta-llama/Meta-Llama-3-8B-Instruct-Turbo
|
||||
'*': meta-llama/Llama-3-8b-chat-hf
|
||||
type: together-ai
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-together-ai
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': Yi-Medium
|
||||
'*': Yi-Large
|
||||
type: yi
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-yi
|
||||
- config:
|
||||
provider:
|
||||
apiTokens:
|
||||
- fake_token
|
||||
modelMapping:
|
||||
'gpt-3': glm-4-plus
|
||||
'*': glm-4-long
|
||||
type: zhipuai
|
||||
ingress:
|
||||
- higress-conformance-ai-backend/wasmplugin-ai-proxy-zhipuai
|
||||
url: file:///opt/plugins/wasm-go/extensions/ai-proxy/plugin.wasm
|
||||
@@ -76,6 +76,7 @@ const (
|
||||
ContentTypeFormUrlencoded = "application/x-www-form-urlencoded"
|
||||
ContentTypeMultipartForm = "multipart/form-data"
|
||||
ContentTypeTextPlain = "text/plain"
|
||||
ContentTypeTextEventStream = "text/event-stream"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -140,11 +141,12 @@ type ExpectedRequest struct {
|
||||
|
||||
// Response defines expected properties of a response from a backend.
|
||||
type Response struct {
|
||||
StatusCode int
|
||||
Headers map[string]string
|
||||
Body []byte
|
||||
ContentType string
|
||||
AbsentHeaders []string
|
||||
StatusCode int
|
||||
Headers map[string]string
|
||||
Body []byte
|
||||
JsonBodyIgnoreFields []string
|
||||
ContentType string
|
||||
AbsentHeaders []string
|
||||
}
|
||||
|
||||
// requiredConsecutiveSuccesses is the number of requests that must succeed in a row
|
||||
@@ -601,6 +603,7 @@ func CompareResponse(cRes *roundtripper.CapturedResponse, expected Assertion) er
|
||||
|
||||
switch cTyp {
|
||||
case ContentTypeTextPlain:
|
||||
case ContentTypeTextEventStream:
|
||||
if !bytes.Equal(expected.Response.ExpectedResponse.Body, cRes.Body) {
|
||||
return fmt.Errorf("expected %s body to be %s, got %s", cTyp, string(expected.Response.ExpectedResponse.Body), string(cRes.Body))
|
||||
}
|
||||
@@ -616,7 +619,7 @@ func CompareResponse(cRes *roundtripper.CapturedResponse, expected Assertion) er
|
||||
return fmt.Errorf("failed to unmarshall CapturedResponse body %s, %s", string(cRes.Body), err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(eResBody, cResBody) {
|
||||
if err := CompareJSONWithIgnoreFields(eResBody, cResBody, expected.Response.ExpectedResponse.JsonBodyIgnoreFields); err != nil {
|
||||
return fmt.Errorf("expected %s body to be %s, got %s", cTyp, string(expected.Response.ExpectedResponse.Body), string(cRes.Body))
|
||||
}
|
||||
case ContentTypeFormUrlencoded:
|
||||
@@ -663,6 +666,47 @@ func CompareResponse(cRes *roundtripper.CapturedResponse, expected Assertion) er
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CompareJSONWithIgnoreFields compares two JSON objects, ignoring specified fields
|
||||
func CompareJSONWithIgnoreFields(eResBody, cResBody map[string]interface{}, ignoreFields []string) error {
|
||||
for key, eVal := range eResBody {
|
||||
if contains(ignoreFields, key) {
|
||||
continue
|
||||
}
|
||||
|
||||
cVal, exists := cResBody[key]
|
||||
if !exists {
|
||||
return fmt.Errorf("field %s exists in expected response but not in captured response", key)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(eVal, cVal) {
|
||||
return fmt.Errorf("field %s mismatch: expected %v, got %v", key, eVal, cVal)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if captured response has extra fields (excluding ignored fields)
|
||||
for key := range cResBody {
|
||||
if contains(ignoreFields, key) {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := eResBody[key]; !exists {
|
||||
return fmt.Errorf("field %s exists in captured response but not in expected response", key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(slice []string, str string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseFormUrlencodedBody(body []byte) (map[string][]string, error) {
|
||||
ret := make(map[string][]string)
|
||||
kvs, err := url.ParseQuery(string(body))
|
||||
|
||||
@@ -136,6 +136,7 @@ func New(s Options) *ConformanceTestSuite {
|
||||
"base/nacos.yaml",
|
||||
"base/dubbo.yaml",
|
||||
"base/opa.yaml",
|
||||
"base/llm-mock.yaml",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +174,7 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T) {
|
||||
"higress-conformance-infra",
|
||||
"higress-conformance-app-backend",
|
||||
"higress-conformance-web-backend",
|
||||
"higress-conformance-ai-backend",
|
||||
}
|
||||
kubernetes.NamespacesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, namespaces)
|
||||
|
||||
|
||||
@@ -71,7 +71,19 @@ else
|
||||
version=$(cat "$version_file")
|
||||
if [[ "$version" =~ -alpha$ ]]; then
|
||||
echo "🚀 Build Go WasmPlugin: $name (version $version)"
|
||||
PLUGIN_NAME=${name} make build
|
||||
# Load .buildrc file
|
||||
buildrc_file="$EXTENSIONS_DIR$file/.buildrc"
|
||||
if [ -f "$buildrc_file" ]; then
|
||||
echo "Found .buildrc file, sourcing it..."
|
||||
. "$buildrc_file"
|
||||
else
|
||||
echo ".buildrc file not found"
|
||||
fi
|
||||
echo "EXTRA_TAGS=${EXTRA_TAGS:-}"
|
||||
# Build plugin
|
||||
PLUGIN_NAME=${name} EXTRA_TAGS=${EXTRA_TAGS:-} make build
|
||||
# Clean up EXTRA_TAGS environment variable
|
||||
unset EXTRA_TAGS
|
||||
else
|
||||
echo "Plugin version $version not ends with '-alpha', skipping compilation for $name."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user