Skip to content
This repository was archived by the owner on Apr 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,13 @@ jobs:
name: build examples
runs-on: ubuntu-latest
container:
image: tinygo/tinygo:0.15.0
image: getenvoy/extension-tinygo-builder:wasi-dev
steps:
- name: checkout
uses: actions/checkout@v2

- name: set up go 1.15
uses: actions/setup-go@v1
with:
go-version: 1.15

- name: build examples
run: find ./examples -type f -name "main.go" | xargs -Ip tinygo build -o p.wasm -target=wasm -wasm-abi=generic p
run: make build.examples

- name: upload wasm-binaries
uses: actions/upload-artifact@v2
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ build.example:
tinygo build -o ./examples/${name}/main.go.wasm -target=wasm -wasm-abi=generic ./examples/${name}/main.go

build.examples:
find ./examples -type f -name "main.go" | xargs -Ip tinygo build -o p.wasm -target=wasm -wasm-abi=generic p
find ./examples -type f -name "main.go" | xargs -Ip tinygo build -o p.wasm -target=wasi -wasm-abi=generic p

lint:
golangci-lint run --build-tags proxytest
Expand Down
30 changes: 18 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,22 @@ func (ctx *context) OnHttpRequestHeaders(int, bool) types.Action {

```


### requirements

- TinyGo(0.15.0+): https://tinygo.org
proxy-wasm-go-sdk depends on the latest TinyGo which supports WASI target([tinygo-org/tinygo#1373](https://github.com/tinygo-org/tinygo/pull/1373)).
In order to install that, simply run (Ubuntu/Debian):

```shell
# this corresponds to https://github.com/tinygo-org/tinygo/commit/f50ad3585d084b17f7754f4b3cb0d42661fee036
wget https://19227-136505169-gh.circle-artifacts.com/0/tmp/tinygo_amd64.deb
dpkg -i tinygo_amd64.deb
```

Alternatively, you can use the pre-built docker container `getenvoy/extention-tingyo-builder:wasi-dev` for any platform.

TinyGo's official release of WASI target will be soon, and after that you could
just follow https://tinygo.org/getting-started/ to install the requirement. Stay tuned!


### compatible Envoy builds

Expand Down Expand Up @@ -73,19 +85,13 @@ make test # run local tests without running envoy processes
make test.e2e # run e2e tests
```

## language and compiler limitations/considerations
## compiler limitations and considerations

- You can only use really limited set of existing libraries.
- Some of existing libraries are not available (importable but runtime panic / non-importable)
- There are two reasons for this:
1. TinyGo [uses](https://github.com/tinygo-org/tinygo/blob/release/loader/loader.go#L79-L83) the official parser, lexer, etc.,
which forces your program to implicitly import `syscall/js` package if you import packages using system calls.
The package expects the host environment to have the `syscall/js` specific ABI as in
[wasm_exec.js](https://github.com/tinygo-org/tinygo/blob/154d4a781f6121bd6f584cca4a88909e0b091f63/targets/wasm_exec.js)
which is not available outside of that javascript.
1. TinyGo's WASI target does not support some of syscall: For example, we cannot import `crypto/rand` package.
2. TinyGo does not implement all of reflect package([examples](https://github.com/tinygo-org/tinygo/blob/v0.14.1/src/reflect/value.go#L299-L305)).
- The syscall problem can be solved by one of the followings:
- emulate `syscall/js` function through WASI interface (which is implemented by V8 engine running on Envoy)
- support WASI target in TinyGo: https://github.com/tinygo-org/tinygo/pull/1373
- These issues will be mitigated as the TinyGo improves.
- There's performance overhead in using Go/TinyGo due to GC
- runtime.GC() is called whenever heap allocation happens (see [1](https://tinygo.org/lang-support/#garbage-collection),
[2](https://github.com/tinygo-org/tinygo/blob/v0.14.1/src/runtime/gc_conservative.go#L218-L239)).
Expand Down
7 changes: 2 additions & 5 deletions examples/helloworld/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package main

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
)

Expand All @@ -40,14 +38,13 @@ func newHelloWorld(contextID uint32) proxywasm.RootContext {
func (ctx *helloWorld) OnVMStart(int) bool {
proxywasm.LogInfo("proxy_on_vm_start from Go!")
if err := proxywasm.HostCallSetTickPeriodMilliSeconds(tickMilliseconds); err != nil {
proxywasm.LogCritical("failed to set tick period: ", err.Error())
proxywasm.LogCriticalf("failed to set tick period: %v", err)
}
return true
}

// override
func (ctx *helloWorld) OnTick() {
t := proxywasm.HostCallGetCurrentTime()
proxywasm.LogInfo("OnTick on ", strconv.FormatUint(uint64(ctx.contextID), 10),
", it's ", strconv.FormatInt(t, 10))
proxywasm.LogInfof("OnTick on %d, it's %d", ctx.contextID, t)
}
20 changes: 10 additions & 10 deletions examples/http_auth_random/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package main

import (
"hash/fnv"
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
Expand All @@ -42,19 +41,19 @@ func newContext(contextID uint32) proxywasm.HttpContext {
func (ctx *httpHeaders) OnHttpRequestHeaders(int, bool) types.Action {
hs, err := proxywasm.HostCallGetHttpRequestHeaders()
if err != nil {
proxywasm.LogCritical("failed to get request headers: ", err.Error())
proxywasm.LogCriticalf("failed to get request headers: %v", err)
return types.ActionContinue
}
for _, h := range hs {
proxywasm.LogInfo("request header: ", h[0], ": ", h[1])
proxywasm.LogInfof("request header from: %s: %s", h[0], h[1])
}

if _, err := proxywasm.HostCallDispatchHttpCall(
clusterName, hs, "", [][2]string{}, 50000); err != nil {
proxywasm.LogCritical("dipatch httpcall failed: ", err.Error())
proxywasm.LogCriticalf("dipatch httpcall failed: %v", err)
}

proxywasm.LogInfo("http call dispatched to ", clusterName)
proxywasm.LogInfof("http call dispatched to %s", clusterName)

return types.ActionPause
}
Expand All @@ -63,24 +62,25 @@ func (ctx *httpHeaders) OnHttpRequestHeaders(int, bool) types.Action {
func (ctx *httpHeaders) OnHttpCallResponse(_ int, bodySize int, _ int) {
hs, err := proxywasm.HostCallGetHttpCallResponseHeaders()
if err != nil {
proxywasm.LogCritical("failed to get response body: ", err.Error())

proxywasm.LogCriticalf("failed to get response body: %v", err)
return
}

for _, h := range hs {
proxywasm.LogInfo("response header from httpbin: ", h[0], ": ", h[1])
proxywasm.LogInfof("response header from %s: %s: %s", clusterName, h[0], h[1])
}

b, err := proxywasm.HostCallGetHttpCallResponseBody(0, bodySize)
if err != nil {
proxywasm.LogCritical("failed to get response body: ", err.Error())
proxywasm.LogCriticalf("failed to get response body: %v", err)
proxywasm.HostCallResumeHttpRequest()
return
}

s := fnv.New32a()
if _, err := s.Write(b); err != nil {
proxywasm.LogCritical("failed to calculate hash: ", err.Error())
proxywasm.LogCriticalf("failed to calculate hash: %v", err)
proxywasm.HostCallResumeHttpRequest()
return
}
Expand All @@ -100,5 +100,5 @@ func (ctx *httpHeaders) OnHttpCallResponse(_ int, bodySize int, _ int) {

// override default
func (ctx *httpHeaders) OnLog() {
proxywasm.LogInfo(strconv.FormatUint(uint64(ctx.contextID), 10), " finished")
proxywasm.LogInfof("%d finished", ctx.contextID)
}
12 changes: 5 additions & 7 deletions examples/http_headers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package main

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
Expand All @@ -39,11 +37,11 @@ func newContext(contextID uint32) proxywasm.HttpContext {
func (ctx *httpHeaders) OnHttpRequestHeaders(int, bool) types.Action {
hs, err := proxywasm.HostCallGetHttpRequestHeaders()
if err != nil {
proxywasm.LogCritical("failed to get request headers: ", err.Error())
proxywasm.LogCriticalf("failed to get request headers: %v", err)
}

for _, h := range hs {
proxywasm.LogInfo("request header: ", h[0], ": ", h[1])
proxywasm.LogInfof("request header: %s: %s", h[0], h[1])
}
return types.ActionContinue
}
Expand All @@ -52,16 +50,16 @@ func (ctx *httpHeaders) OnHttpRequestHeaders(int, bool) types.Action {
func (ctx *httpHeaders) OnHttpResponseHeaders(int, bool) types.Action {
hs, err := proxywasm.HostCallGetHttpResponseHeaders()
if err != nil {
proxywasm.LogCritical("failed to get request headers: ", err.Error())
proxywasm.LogCriticalf("failed to get request headers: %v", err)
}

for _, h := range hs {
proxywasm.LogInfo("response header: ", h[0], ": ", h[1])
proxywasm.LogInfof("response header: %s: %s", h[0], h[1])
}
return types.ActionContinue
}

// override
func (ctx *httpHeaders) OnLog() {
proxywasm.LogInfo(strconv.FormatUint(uint64(ctx.contextID), 10), " finished")
proxywasm.LogInfof("%d finished", ctx.contextID)
}
10 changes: 4 additions & 6 deletions examples/metrics/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package main

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
Expand All @@ -36,7 +34,7 @@ type metric struct{ proxywasm.DefaultContext }
func (ctx metric) OnVMStart(int) bool {
ct, err := proxywasm.DefineCounterMetric(metricsName)
if err != nil {
proxywasm.LogCritical("error defining metrics: ", err.Error())
proxywasm.LogCriticalf("error defining metrics: %v", err)
}
counter = ct
return true
Expand All @@ -46,13 +44,13 @@ func (ctx metric) OnVMStart(int) bool {
func (ctx metric) OnHttpRequestHeaders(int, bool) types.Action {
prev, err := counter.Get()
if err != nil {
proxywasm.LogCritical("error retrieving previous metric: ", err.Error())
proxywasm.LogCriticalf("error retrieving previous metric: %v", err)
}

proxywasm.LogInfo("previous value of ", metricsName, ": ", strconv.Itoa(int(prev)))
proxywasm.LogInfof("previous value of %s: %d", metricsName, prev)

if err := counter.Increment(1); err != nil {
proxywasm.LogCritical("error incrementing metrics", err.Error())
proxywasm.LogCriticalf("error incrementing metrics %v", err)
}
proxywasm.LogInfo("incremented")
return types.ActionContinue
Expand Down
10 changes: 5 additions & 5 deletions examples/network/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (ctx context) OnVMStart(int) bool {
var err error
counter, err = proxywasm.DefineCounterMetric(connectionCounterName)
if err != nil {
proxywasm.LogCritical("failed to initialize connection counter: ", err.Error())
proxywasm.LogCriticalf("failed to initialize connection counter: %v", err)
}
return true
}
Expand All @@ -57,7 +57,7 @@ func (ctx context) OnDownstreamData(dataSize int, _ bool) types.Action {
proxywasm.LogCritical(err.Error())
}

proxywasm.LogInfo("downstream data received: ", string(data))
proxywasm.LogInfof("downstream data received: %s", string(data))
return types.ActionContinue
}

Expand All @@ -72,7 +72,7 @@ func (ctx context) OnUpstreamData(dataSize int, _ bool) types.Action {
proxywasm.LogCritical(err.Error())
}

proxywasm.LogInfo("remote address: ", string(ret))
proxywasm.LogInfof("remote address: %s", string(ret))
if dataSize == 0 {
return types.ActionContinue
}
Expand All @@ -82,14 +82,14 @@ func (ctx context) OnUpstreamData(dataSize int, _ bool) types.Action {
proxywasm.LogCritical(err.Error())
}

proxywasm.LogInfo("upstream data received: ", string(data))
proxywasm.LogInfof("upstream data received: %s", string(data))
return types.ActionContinue
}

func (ctx context) OnDone() bool {
err := counter.Increment(1)
if err != nil {
proxywasm.LogCritical("failed to increment connection counter: ", err.Error())
proxywasm.LogCriticalf("failed to increment connection counter: %v", err)
}
proxywasm.LogInfo("connection complete!")
return true
Expand Down
10 changes: 4 additions & 6 deletions examples/shared_data/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package main

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
Expand All @@ -33,7 +31,7 @@ const sharedDataKey = "shared_data_key"
// override
func (ctx data) OnVMStart(int) bool {
if err := proxywasm.HostCallSetSharedData(sharedDataKey, []byte{0}, 0); err != nil {
proxywasm.LogWarn("error setting shared data on OnVMStart: ", err.Error())
proxywasm.LogWarnf("error setting shared data on OnVMStart: %v", err)
}
return true
}
Expand All @@ -42,16 +40,16 @@ func (ctx data) OnVMStart(int) bool {
func (ctx data) OnHttpRequestHeaders(int, bool) types.Action {
value, cas, err := proxywasm.HostCallGetSharedData(sharedDataKey)
if err != nil {
proxywasm.LogWarn("error getting shared data on OnHttpRequestHeaders: ", err.Error())
proxywasm.LogWarnf("error getting shared data on OnHttpRequestHeaders: %v", err)
return types.ActionContinue
}

value[0]++
if err := proxywasm.HostCallSetSharedData(sharedDataKey, value, cas); err != nil {
proxywasm.LogWarn("error setting shared data on OnHttpRequestHeaders: ", err.Error())
proxywasm.LogWarnf("error setting shared data on OnHttpRequestHeaders: %v", err)
return types.ActionContinue
}

proxywasm.LogInfo("shared value: ", strconv.Itoa(int(value[0])))
proxywasm.LogInfof("shared value: %d", value[0])
return types.ActionContinue
}
14 changes: 6 additions & 8 deletions examples/shared_queue/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package main

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
Expand All @@ -42,20 +40,20 @@ func (ctx queue) OnVMStart(int) bool {
panic(err.Error())
}
queueID = qID
proxywasm.LogInfo("queue registered, name: ", queueName, ", id: ", strconv.Itoa(int(qID)))
proxywasm.LogInfof("queue registered, name: %s, id: %d", queueName, qID)

if err := proxywasm.HostCallSetTickPeriodMilliSeconds(tickMilliseconds); err != nil {
proxywasm.LogCritical("failed to set tick period: ", err.Error())
proxywasm.LogCriticalf("failed to set tick period: %v", err)
}
proxywasm.LogInfo("set tick period milliseconds: ", strconv.Itoa(int(tickMilliseconds)))
proxywasm.LogInfof("set tick period milliseconds: %d", tickMilliseconds)
return true
}

// override
func (ctx queue) OnHttpRequestHeaders(int, bool) types.Action {
for _, msg := range []string{"hello", "world", "hello", "proxy-wasm"} {
if err := proxywasm.HostCallEnqueueSharedQueue(queueID, []byte(msg)); err != nil {
proxywasm.LogCritical("error queueing: ", err.Error())
proxywasm.LogCriticalf("error queueing: %v", err)
}
}
return types.ActionContinue
Expand All @@ -68,8 +66,8 @@ func (ctx queue) OnTick() {
case types.ErrorStatusEmpty:
return
case nil:
proxywasm.LogInfo("dequeued data: ", string(data))
proxywasm.LogInfof("dequeued data: %s", string(data))
default:
proxywasm.LogCritical("error retrieving data from queue ", strconv.Itoa(int(queueID)), ", ", err.Error())
proxywasm.LogCriticalf("error retrieving data from queue %d: %v", queueID, err)
}
}
Loading