wa-lang.org/wazero@v1.0.2/imports/go/example/stars.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  	"time"
    13  
    14  	"wa-lang.org/wazero"
    15  	"wa-lang.org/wazero/experimental"
    16  	gojs "wa-lang.org/wazero/imports/go"
    17  	"wa-lang.org/wazero/sys"
    18  )
    19  
    20  // main invokes Wasm compiled via `GOARCH=wasm GOOS=js`, which reports the star
    21  // count of wazero.
    22  //
    23  // This shows how to integrate an HTTP client with wasm using gojs.
    24  func main() {
    25  	// The Wasm binary (stars/main.wasm) is very large (>7.5MB). Use wazero's
    26  	// compilation cache to reduce performance penalty of multiple runs.
    27  	compilationCacheDir := ".build"
    28  	ctx, err := experimental.WithCompilationCacheDirName(context.Background(), compilationCacheDir)
    29  	if err != nil {
    30  		log.Panicln(err)
    31  	}
    32  
    33  	// Create a new WebAssembly Runtime.
    34  	r := wazero.NewRuntime(ctx)
    35  	defer r.Close(ctx) // This closes everything this Runtime created.
    36  
    37  	// Combine the above into our baseline config, overriding defaults.
    38  	config := wazero.NewModuleConfig().
    39  		// By default, I/O streams are discarded, so you won't see output.
    40  		WithStdout(os.Stdout).WithStderr(os.Stderr)
    41  
    42  	bin, err := os.ReadFile(path.Join("stars", "main.wasm"))
    43  	if err != nil {
    44  		log.Panicln(err)
    45  	}
    46  
    47  	// Compile the WebAssembly module using the default configuration.
    48  	start := time.Now()
    49  	compiled, err := r.CompileModule(ctx, bin)
    50  	if err != nil {
    51  		log.Panicln(err)
    52  	}
    53  	compilationTime := time.Since(start).Milliseconds()
    54  	log.Printf("CompileModule took %dms with %dKB cache", compilationTime, dirSize(compilationCacheDir)/1024)
    55  
    56  	// Instead of making real HTTP calls, return fake data.
    57  	ctx = gojs.WithRoundTripper(ctx, &fakeGitHub{})
    58  
    59  	// Execute the "run" function, which corresponds to "main" in stars/main.go.
    60  	start = time.Now()
    61  	err = gojs.Run(ctx, r, compiled, config)
    62  	runTime := time.Since(start).Milliseconds()
    63  	log.Printf("gojs.Run took %dms", runTime)
    64  	if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
    65  		log.Panicln(err)
    66  	} else if !ok {
    67  		log.Panicln(err)
    68  	}
    69  }
    70  
    71  // compile-time check to ensure fakeGitHub implements http.RoundTripper
    72  var _ http.RoundTripper = &fakeGitHub{}
    73  
    74  type fakeGitHub struct{}
    75  
    76  func (f *fakeGitHub) RoundTrip(*http.Request) (*http.Response, error) {
    77  	fakeResponse := `{"stargazers_count": 9999999}`
    78  	return &http.Response{
    79  		StatusCode:    http.StatusOK,
    80  		Status:        http.StatusText(http.StatusOK),
    81  		Body:          io.NopCloser(strings.NewReader(fakeResponse)),
    82  		ContentLength: int64(len(fakeResponse)),
    83  	}, nil
    84  }
    85  
    86  func dirSize(dir string) int64 {
    87  	var size int64
    88  	_ = filepath.Walk(dir, func(_ string, info os.FileInfo, err error) error {
    89  		if err != nil {
    90  			log.Panicln(err)
    91  		}
    92  		if !info.IsDir() {
    93  			size += info.Size()
    94  		}
    95  		return nil
    96  	})
    97  	return size
    98  }