Skip to content

Commit

Permalink
add web workers in jsbridge
Browse files Browse the repository at this point in the history
  • Loading branch information
Hitenjain14 committed Jun 4, 2024
1 parent 3b1c83d commit f97113e
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 3 deletions.
2 changes: 1 addition & 1 deletion core/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
//====== THIS IS AUTOGENERATED FILE. DO NOT MODIFY ========

package version
const VERSIONSTR = "v1.15.1"
const VERSIONSTR = "v1.15.1-1-g3b1c83d8"

3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
)

require (
github.com/hack-pad/go-webworkers v0.1.0
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/minio/sha256-simd v1.0.1
github.com/ybbus/jsonrpc/v3 v3.1.5
Expand Down Expand Up @@ -130,6 +131,7 @@ require (

require (
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/hack-pad/safejs v0.1.1
github.com/klauspost/compress v1.17.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/remeh/sizedwaitgroup v1.0.0
Expand All @@ -142,3 +144,4 @@ require (
)

//replace github.com/ethereum/go-ethereum => github.com/certifaction/go-ethereum v1.10.3-wasm
replace github.com/hack-pad/go-webworkers => ../go-webworkers
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/h2non/filetype v1.1.4-0.20231228185113-6469358c2bcb h1:GlQyMv2C48qmfPItvAXFoyN341Swxp9JNVeUZxnmbJw=
github.com/h2non/filetype v1.1.4-0.20231228185113-6469358c2bcb/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/hack-pad/go-webworkers v0.1.0 h1:QHBJpkXJgW0QRi2iiUGcxwGnmy7lQJL0F8UfsgMXKhA=
github.com/hack-pad/go-webworkers v0.1.0/go.mod h1:/rmjjgnlw0CursmeqRtP0NGIqo8CR+0o6AtzFydUHJ4=
github.com/hack-pad/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
Expand All @@ -304,8 +308,6 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/herumi/bls-go-binary v1.31.0 h1:L1goQ2tMtGgpXCg5AwHAdJQpLs/pfnWWEc3Wog6OhmI=
github.com/herumi/bls-go-binary v1.31.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y=
github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17 h1:FbyIK0BfvXVZTOxKOe2dlxJqSPSF2ZXOv2Mc7dvS7sc=
github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/hitenjain14/fasthttp v0.0.0-20240527123209-06019e79bff9 h1:Z6Mu2JCsW2hbqx91L0HNPRPQ10RyAFvPocQHlrRo1Jk=
github.com/hitenjain14/fasthttp v0.0.0-20240527123209-06019e79bff9/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
Expand Down
76 changes: 76 additions & 0 deletions wasmsdk/jsbridge/template_data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//go:build js && wasm

package jsbridge

import (
"bytes"
_ "embed"
"fmt"
"net/url"
"os"
"strings"
"syscall/js"
"text/template"
)

//go:embed zcnworker.js.tpl
var WorkerJSTpl []byte

func buildWorkerJS(args, env []string, path string) (string, error) {
return buildJS(args, env, path, WorkerJSTpl)
}

func buildJS(args, env []string, path string, tpl []byte) (string, error) {
var workerJS bytes.Buffer

if len(args) == 0 {
args = []string{path}
}

if len(env) == 0 {
env = os.Environ()
}

if uRL, err := url.ParseRequestURI(path); err != nil || !uRL.IsAbs() {
origin := js.Global().Get("location").Get("origin").String()
baseURL, err := url.ParseRequestURI(origin)
if err != nil {
return "", err
}
path = baseURL.JoinPath(path).String()
}

data := templateData{
Path: path,
Args: args,
Env: env,
}
if err := template.Must(template.New("js").Parse(string(tpl))).Execute(&workerJS, data); err != nil {
return "", err
}
return workerJS.String(), nil
}

type templateData struct {
Path string
Args []string
Env []string
}

func (d templateData) ArgsToJS() string {
el := []string{}
for _, e := range d.Args {
el = append(el, `"`+e+`"`)
}
return "[" + strings.Join(el, ",") + "]"
}

func (d templateData) EnvToJS() string {
el := []string{}
for _, entry := range d.Env {
if k, v, ok := strings.Cut(entry, "="); ok {
el = append(el, fmt.Sprintf(`"%s":"%s"`, k, v))
}
}
return "{" + strings.Join(el, ",") + "}"
}
84 changes: 84 additions & 0 deletions wasmsdk/jsbridge/webworker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//go:build js && wasm
// +build js,wasm

package jsbridge

import (
"context"

"github.com/google/uuid"
"github.com/hack-pad/go-webworkers/worker"
"github.com/hack-pad/safejs"
)

type WasmWebWorker struct {
// Name specifies an identifying name for the DedicatedWorkerGlobalScope representing the scope of the worker, which is mainly useful for debugging purposes.
// If this is not specified, `Start` will create a UUIDv4 for it and populate back.
Name string

// Path is the path of the WASM to run as the Web Worker.
// This can be a relative path on the server, or an abosolute URL.
Path string

// Args holds command line arguments, including the WASM as Args[0].
// If the Args field is empty or nil, Run uses {Path}.
Args []string

// Env specifies the environment of the process.
// Each entry is of the form "key=value".
// If Env is nil, the new Web Worker uses the current context's
// environment.
// If Env contains duplicate environment keys, only the last
// value in the slice for each duplicate key is used.
Env []string

worker *worker.Worker
}

func NewWasmWebWorker(blobberURL, clientID, privateKey string) (*WasmWebWorker, error) {
w := &WasmWebWorker{
Name: blobberURL,
Env: []string{"BLOBBER_URL=" + blobberURL, "CLIENT_ID=" + clientID, "PRIVATE_KEY=" + privateKey, "MODE=worker"},
}

if err := w.Start(); err != nil {
return nil, err
}
return w, nil
}

func (ww *WasmWebWorker) Start() error {
workerJS, err := buildWorkerJS(ww.Args, ww.Env, ww.Path)
if err != nil {
return err
}

if ww.Name == "" {
ww.Name = uuid.New().String()
}

wk, err := worker.NewFromScript(workerJS, worker.Options{Name: ww.Name})
if err != nil {
return err
}

ww.worker = wk

return nil
}

// PostMessage sends data in a message to the worker, optionally transferring ownership of all items in transfers.
func (ww *WasmWebWorker) PostMessage(data safejs.Value, transfers []safejs.Value) error {
return ww.worker.PostMessage(data, transfers)
}

// Terminate immediately terminates the Worker.
func (ww *WasmWebWorker) Terminate() {
ww.worker.Terminate()
}

// Listen sends message events on a channel for events fired by self.postMessage() calls inside the Worker's global scope.
// Stops the listener and closes the channel when ctx is canceled.
func (ww *WasmWebWorker) Listen(ctx context.Context) (<-chan worker.MessageEvent, error) {
return ww.worker.Listen(ctx)
}
43 changes: 43 additions & 0 deletions wasmsdk/jsbridge/zcnworker.js.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
importScripts('https://cdn.jsdelivr.net/gh/golang/[email protected]/misc/wasm/wasm_exec.js');
importScripts('https://herumi.github.io/bls-wasm/browser/bls.js')

const go = new Go();
go.argv = {{.ArgsToJS}}
go.env = {{.EnvToJS}}
const bls = self.bls
bls.init(bls.BN254).then(()=>{})
WebAssembly.instantiateStreaming(fetch("http://localhost:8080/wasmsdk/demo/zcn.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});

function hexStringToByte(str) {
if (!str) return new Uint8Array()
const a = []
for (let i = 0, len = str.length; i < len; i += 2) {
a.push(parseInt(str.substr(i, 2), 16))
}

return new Uint8Array(a)
}

self.__zcn_worker_wasm__ = {
sign: async (hash, secretKey) => {
if (!secretKey){
const errMsg = 'err: wasm blsSign function requires a secret key'
console.warn(errMsg)
throw new Error(errMsg)
}
const bytes = hexStringToByte(hash)
const sk = bls.deserializeHexStrToSecretKey(secretKey)
const sig = sk.sign(bytes)

if (!sig) {
const errMsg = 'err: wasm blsSign function failed to sign transaction'
console.warn(errMsg)
throw new Error(errMsg)
}

return sig.serializeToHexStr()
}
}
43 changes: 43 additions & 0 deletions wasmsdk/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main
import (
"errors"
"fmt"
"os"
"runtime/debug"
"sync"
"time"
Expand Down Expand Up @@ -36,6 +37,9 @@ func main() {

window := js.Global()

fmt.Println("initializing: ", os.Getenv("BLOBBER_URL"), os.Getenv("CLIENT_ID"), os.Getenv("PRIVATE_KEY"), os.Getenv("MODE"))
mode := os.Getenv("MODE")

zcn := window.Get("__zcn_wasm__")
if !(zcn.IsNull() || zcn.IsUndefined()) {

Expand Down Expand Up @@ -274,9 +278,48 @@ func main() {

}

if mode != "" {
jsProxy := window.Get("__zcn_worker_wasm__")
if !(jsProxy.IsNull() || jsProxy.IsUndefined()) {
jsSign := jsProxy.Get("sign")
if !(jsSign.IsNull() || jsSign.IsUndefined()) {
signFunc := func(hash string) (string, error) {
c := client.GetClient()
pk := c.Keys[0].PrivateKey
result, err := jsbridge.Await(jsSign.Invoke(hash, pk))

if len(err) > 0 && !err[0].IsNull() {
return "", errors.New("sign: " + err[0].String())
}
return result[0].String(), nil
}
fmt.Println("setting up sign function in worker")
//update sign with js sign
zcncrypto.Sign = signFunc
zcncore.SignFn = signFunc
sys.Sign = func(hash, signatureScheme string, keys []sys.KeyPair) (string, error) {
// js already has signatureScheme and keys
return signFunc(hash)
}
} else {
PrintError("__zcn_worker_wasm__.jsProxy.sign is not installed yet")
}
} else {
PrintError("__zcn_worker_wasm__ is not installed yet")
}
}

hideLogs()
debug.SetGCPercent(40)
debug.SetMemoryLimit(2.5 * 1024 * 1024 * 1024) //2.5 GB
if mode == "" {
for i := 0; i < 3; i++ {
_, err := jsbridge.NewWasmWebWorker("https://blobber.com"+fmt.Sprint(i), "clientID", "privateKey")
if err != nil {
fmt.Println("Error creating web worker", err)
}
}
}

<-make(chan bool)

Expand Down

0 comments on commit f97113e

Please sign in to comment.