@higress/wasm-assemblyscript
Advanced tools
Comparing version 0.0.3 to 0.0.4
@@ -21,11 +21,11 @@ import { | ||
export interface HttpClient { | ||
get(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
head(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
options(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
post(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
put(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
patch(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
delete(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
connect(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
trace(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): bool; | ||
get(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
head(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
options(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
post(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
put(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
patch(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
delete(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
connect(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
trace(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32): boolean; | ||
} | ||
@@ -46,3 +46,3 @@ | ||
private httpCall(method: string, path: string, headers: Headers, body: ArrayBuffer, callback: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
private httpCall(method: string, path: string, headers: Headers, body: ArrayBuffer, callback: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
if (root_context == null) { | ||
@@ -87,37 +87,37 @@ log(LogLevelValues.error, "Root context is null"); | ||
get(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
get(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("GET", path, headers, new ArrayBuffer(0), cb, timeoutMillisecond); | ||
} | ||
head(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
head(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("HEAD", path, headers, new ArrayBuffer(0), cb, timeoutMillisecond); | ||
} | ||
options(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
options(path: string, headers: Headers, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("OPTIONS", path, headers, new ArrayBuffer(0), cb, timeoutMillisecond); | ||
} | ||
post(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
post(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("POST", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
put(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
put(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("PUT", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
patch(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
patch(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("PATCH", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
delete(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
delete(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("DELETE", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
connect(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
connect(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("CONNECT", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
trace(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): bool { | ||
trace(path: string, headers: Headers, body: ArrayBuffer, cb: ResponseCallBack, timeoutMillisecond: u32 = 500): boolean { | ||
return this.httpCall("TRACE", path, headers, body, cb, timeoutMillisecond); | ||
} | ||
} |
@@ -92,2 +92,3 @@ import { Log } from "./log_wrapper"; | ||
this.hasCustomConfig = false; | ||
this.parseConfig = (json: JSON.Obj): ParseResult<PluginConfig> =>{ return new ParseResult<PluginConfig>(null, true); }; | ||
} | ||
@@ -100,13 +101,10 @@ } | ||
onConfigure(configuration_size: u32): bool { | ||
onConfigure(configuration_size: u32): boolean { | ||
super.onConfigure(configuration_size); | ||
const data = this.getConfiguration(); | ||
let jsonData: JSON.Obj; | ||
if (data.length == 0) { | ||
let jsonData: JSON.Obj = new JSON.Obj(); | ||
if (data == "{}") { | ||
if (this.hasCustomConfig) { | ||
log(LogLevelValues.warn, "config is empty, but has ParseConfigFunc"); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
} | ||
} else { | ||
@@ -121,6 +119,2 @@ const parseData = JSON.parse(data); | ||
} | ||
if (!this.hasCustomConfig) { | ||
log(LogLevelValues.warn, "config is not empty, but has no ParseConfigFunc") | ||
this.parseConfig = (json: JSON.Obj): ParseResult<PluginConfig> =>{ return new ParseResult<PluginConfig>(null, true); }; | ||
} | ||
@@ -127,0 +121,0 @@ if (!this.ruleMatcher.parseRuleConfig(jsonData, this.parseConfig as ParseConfigFunc<PluginConfig>)) { |
@@ -13,2 +13,4 @@ import { getRequestHost } from "./request_wrapper"; | ||
Host, | ||
RoutePrefix, | ||
Service | ||
} | ||
@@ -25,2 +27,4 @@ | ||
const MATCH_DOMAIN_KEY: string = "_match_domain_"; | ||
const MATCH_SERVICE_KEY: string = "_match_service_"; | ||
const MATCH_ROUTE_PREFIX_KEY: string = "_match_route_prefix_" | ||
@@ -38,6 +42,8 @@ class HostMatcher { | ||
class RuleConfig<PluginConfig> { | ||
category: Category; | ||
routes!: Map<string, boolean>; | ||
hosts!: Array<HostMatcher>; | ||
config: PluginConfig | null; | ||
category: Category; | ||
routes!: Map<string, boolean>; | ||
services!: Map<string, boolean>; | ||
routePrefixs!: Map<string, boolean>; | ||
hosts!: Array<HostMatcher>; | ||
config: PluginConfig | null; | ||
@@ -72,12 +78,20 @@ constructor() { | ||
const host = getRequestHost(); | ||
if (!host) { | ||
if (host == "") { | ||
return new ParseResult<PluginConfig>(null, false); | ||
} | ||
const result = get_property("route_name") | ||
if (result.status != WasmResultValues.Ok) { | ||
let result = get_property("route_name"); | ||
if (result.status != WasmResultValues.Ok && result.status != WasmResultValues.NotFound) { | ||
return new ParseResult<PluginConfig>(null, false); | ||
} | ||
const routeName = String.UTF8.decode(result.returnValue); | ||
result = get_property("cluster_name"); | ||
if (result.status != WasmResultValues.Ok && result.status != WasmResultValues.NotFound) { | ||
return new ParseResult<PluginConfig>(null, false); | ||
} | ||
const serviceName = String.UTF8.decode(result.returnValue); | ||
for (let i = 0; i < this.ruleConfig.length; i++) { | ||
const rule = this.ruleConfig[i]; | ||
// category == Host | ||
if (rule.category == Category.Host) { | ||
@@ -89,3 +103,4 @@ if (this.hostMatch(rule, host)) { | ||
} | ||
if (routeName) { | ||
// category == Route | ||
if (rule.category == Category.Route) { | ||
if (rule.routes.has(routeName)) { | ||
@@ -96,2 +111,15 @@ log(LogLevelValues.debug, "getMatchConfig: match route " + routeName); | ||
} | ||
// category == RoutePrefix | ||
if (rule.category == Category.RoutePrefix) { | ||
for (let i = 0; i < rule.routePrefixs.keys().length; i++) { | ||
const routePrefix = rule.routePrefixs.keys()[i]; | ||
if (routeName.startsWith(routePrefix)) { | ||
return new ParseResult<PluginConfig>(rule.config, true); | ||
} | ||
} | ||
} | ||
// category == Cluster | ||
if (this.serviceMatch(rule, serviceName)) { | ||
return new ParseResult<PluginConfig>(rule.config, true); | ||
} | ||
} | ||
@@ -158,11 +186,26 @@ | ||
} | ||
rule.routes = this.parseRouteMatchConfig(ruleJson); | ||
rule.hosts = this.parseHostMatchConfig(ruleJson); | ||
rule.services = this.parseServiceMatchConfig(ruleJson); | ||
rule.routePrefixs = this.parseRoutePrefixMatchConfig(ruleJson); | ||
const noRoute = rule.routes.size == 0; | ||
const noHosts = rule.hosts.length == 0; | ||
if ((noRoute && noHosts) || (!noRoute && !noHosts)) { | ||
log(LogLevelValues.error, "there is only one of '_match_route_' and '_match_domain_' can present in configuration."); | ||
const noServices = rule.services.size == 0; | ||
const noRoutePrefixs = rule.routePrefixs.size == 0; | ||
if ((boolToInt(noRoute) + boolToInt(noHosts) + boolToInt(noServices) + boolToInt(noRoutePrefixs)) != 3) { | ||
log(LogLevelValues.error, "there is only one of '_match_route_', '_match_domain_', '_match_service_' and '_match_route_prefix_' can present in configuration."); | ||
return false; | ||
} | ||
rule.category = noRoute ? Category.Host : Category.Route; | ||
if (!noRoute) { | ||
rule.category = Category.Route; | ||
} else if (!noHosts) { | ||
rule.category = Category.Host; | ||
} else if (!noServices) { | ||
rule.category = Category.Service; | ||
} else { | ||
rule.category = Category.RoutePrefix; | ||
} | ||
this.ruleConfig.push(rule); | ||
@@ -188,2 +231,32 @@ } | ||
parseRoutePrefixMatchConfig(config: JSON.Obj): Map<string, boolean> { | ||
const keys = config.getArr(MATCH_ROUTE_PREFIX_KEY); | ||
const routePrefixs = new Map<string, boolean>(); | ||
if (keys) { | ||
const array = keys.valueOf(); | ||
for (let i = 0; i < array.length; i++) { | ||
const key = array[i].toString(); | ||
if (key != "") { | ||
routePrefixs.set(key, true); | ||
} | ||
} | ||
} | ||
return routePrefixs; | ||
} | ||
parseServiceMatchConfig(config: JSON.Obj): Map<string, boolean> { | ||
const keys = config.getArr(MATCH_SERVICE_KEY); | ||
const clusters = new Map<string, boolean>(); | ||
if (keys) { | ||
const array = keys.valueOf(); | ||
for (let i = 0; i < array.length; i++) { | ||
const key = array[i].toString(); | ||
if (key != "") { | ||
clusters.set(key, true); | ||
} | ||
} | ||
} | ||
return clusters; | ||
} | ||
parseHostMatchConfig(config: JSON.Obj): Array<HostMatcher> { | ||
@@ -256,2 +329,27 @@ const hostMatchers = new Array<HostMatcher>(); | ||
} | ||
serviceMatch(rule: RuleConfig<PluginConfig>, serviceName: string): boolean { | ||
const parts = serviceName.split('|'); | ||
if (parts.length != 4) { | ||
return false; | ||
} | ||
const port = parts[1]; | ||
const fqdn = parts[3]; | ||
for (let i = 0; i < rule.services.keys().length; i++) { | ||
let configServiceName = rule.services.keys()[i]; | ||
let colonIndex = configServiceName.lastIndexOf(':'); | ||
if (colonIndex != -1) { | ||
let configFQDN = configServiceName.slice(0, colonIndex); | ||
let configPort = configServiceName.slice(colonIndex + 1); | ||
if (fqdn == configFQDN && port == configPort) return true; | ||
} else if (fqdn == configServiceName) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
function boolToInt(value: boolean): i32 { | ||
return value ? 1 : 0; | ||
} |
{ | ||
"name": "@higress/wasm-assemblyscript", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"main": "assembly/index.ts", | ||
@@ -19,3 +19,3 @@ "scripts": { | ||
"assemblyscript-json": "^1.1.0", | ||
"@higress/proxy-wasm-assemblyscript-sdk": "^0.0.1" | ||
"@higress/proxy-wasm-assemblyscript-sdk": "^0.0.2" | ||
}, | ||
@@ -22,0 +22,0 @@ "type": "module", |
@@ -7,3 +7,3 @@ ## 介绍 | ||
创建一个新的 AssemblyScript 项目 | ||
创建一个新的 AssemblyScript 项目。 | ||
@@ -26,3 +26,3 @@ ``` | ||
将`"@higress/proxy-wasm-assemblyscript-sdk": "^0.0.1"`和`"@higress/wasm-assemblyscript": "^0.0.1"`添加到你的依赖项中,然后运行`npm install`。 | ||
将`"@higress/proxy-wasm-assemblyscript-sdk": "^0.0.1"`和`"@higress/wasm-assemblyscript": "^0.0.3"`添加到你的依赖项中,然后运行`npm install`。 | ||
@@ -35,2 +35,22 @@ ### 本地构建 | ||
构建结果将在`build`文件夹中。其中,`debug.wasm`和`release.wasm`是已编译的文件。 | ||
构建结果将在`build`文件夹中。其中,`debug.wasm`和`release.wasm`是已编译的文件,在生产环境中建议使用`release.wasm`。 | ||
注:如果需要插件带有 name section 信息需要带上`"debug": true`,编译参数解释详见[using-the-compiler](https://www.assemblyscript.org/compiler.html#using-the-compiler)。 | ||
```json | ||
"release": { | ||
"outFile": "build/release.wasm", | ||
"textFile": "build/release.wat", | ||
"sourceMap": true, | ||
"optimizeLevel": 3, | ||
"shrinkLevel": 0, | ||
"converge": false, | ||
"noAssert": false, | ||
"debug": true | ||
} | ||
``` | ||
### AssemblyScript 限制 | ||
此 SDK 使用的 AssemblyScript 版本为`0.27.29`,参考[AssemblyScript Status](https://www.assemblyscript.org/status.html)该版本尚未支持闭包、异常、迭代器等特性,并且JSON,正则表达式等功能还尚未在标准库中实现,暂时需要使用社区提供的实现。 | ||
50499
1124
54