Skip to content

Commit

Permalink
feat(codegen): generated js client (the wrapper)
Browse files Browse the repository at this point in the history
it wraps generated protobufjs types and rest client, uses cosmjs and exports high level `txClient()` and `queryClient()` funcs for:

* creating messages, signing and broadcasting them,
* querying.

js client created individually for each module. within Vuex, it can be used like in below:

```js
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { txClient, queryClient } from "./store/tendermint/mars/mars/module";

async function main() {
    const wallet = await DirectSecp256k1HdWallet.fromMnemonic("alfa romeo...");

    const t = await txClient(wallet);
    const q = await queryClient();

    console.log(await t.signAndBroadcast([ t.msgCreateUser({ name: "mars", creator: wallet.address }) ]));
    console.log(await q.queryUserAll());
}

main()

```
  • Loading branch information
ilgooz committed Feb 20, 2021
1 parent db058b7 commit da2383e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 28 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/gookit/color v1.2.7
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/iancoleman/strcase v0.1.3
github.com/imdario/mergo v0.3.11
github.com/improbable-eng/grpc-web v0.13.0
github.com/jpillora/chisel v1.7.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDG
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.1.3 h1:dJBk1m2/qjL1twPLf68JND55vvivMupZ4wIzE8CTdBw=
github.com/iancoleman/strcase v0.1.3/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ilgooz/analytics-go v3.1.1-0.20200723195510-acde4190c655+incompatible/go.mod h1:36xDpOWfOEZLx5a4Qra2Ntu7by75m/qwZZx9/YrPrtY=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
Expand Down
10 changes: 5 additions & 5 deletions starport/pkg/cosmosanalysis/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ type Module struct {
// Name of the module.
Name string

// TypesImportPath is the Go import path of the types pkg of the module.
TypesImportPath string
// Pkg holds the proto package info.
Pkg protoanalysis.Package

// Msg is a list of sdk.Msg implementation of the module.
Msgs []Msg
Expand Down Expand Up @@ -103,9 +103,9 @@ func Discover(sourcePath string) ([]Module, error) {
var (
spname = strings.Split(xproto.Name, ".")
m = Module{
Name: spname[len(spname)-1],
TypesImportPath: xproto.GoImportName,
Msgs: msgs,
Name: spname[len(spname)-1],
Pkg: xproto,
Msgs: msgs,
}
)

Expand Down
64 changes: 47 additions & 17 deletions starport/pkg/cosmosgen/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ package cosmosgen

import (
"context"
"embed"
_ "embed" // embeds templates into binary.
"io/ioutil"
"os"
"path/filepath"
"strings"
"text/template"

"github.com/iancoleman/strcase"
"github.com/otiai10/copy"
"github.com/pkg/errors"
"github.com/tendermint/starport/starport/pkg/cmdrunner"
"github.com/tendermint/starport/starport/pkg/cmdrunner/step"
"github.com/tendermint/starport/starport/pkg/cosmosanalysis/module"
"github.com/tendermint/starport/starport/pkg/gomodule"
"github.com/tendermint/starport/starport/pkg/nodetime/protobufjs"
"github.com/tendermint/starport/starport/pkg/nodetime/sta"
"github.com/tendermint/starport/starport/pkg/protoanalysis"
"github.com/tendermint/starport/starport/pkg/protoc"
"github.com/tendermint/starport/starport/pkg/protopath"
"golang.org/x/mod/modfile"
Expand All @@ -37,9 +40,20 @@ var (
fileTypes = "types"
)

//go:embed templates/*
var templates embed.FS

var tpl = template.Must(
template.New("client.js.tpl").
Funcs(template.FuncMap{
"camelCase": strcase.ToLowerCamel,
}).
ParseFS(templates, "templates/client.js.tpl"),
)

type generateOptions struct {
gomodPath string
jsOut func(protoanalysis.Package, string) string
jsOut func(module.Module) string
}

// TODO add WithInstall.
Expand All @@ -48,7 +62,7 @@ type generateOptions struct {
type Target func(*generateOptions)

// WithJSGeneration adds JS code generation.
func WithJSGeneration(out func(pkg protoanalysis.Package, moduleName string) (path string)) Target {
func WithJSGeneration(out func(module.Module) (path string)) Target {
return func(o *generateOptions) {
o.jsOut = out
}
Expand Down Expand Up @@ -151,14 +165,14 @@ func (g *generator) generateGo() error {
defer os.RemoveAll(tmp)

// discover every sdk module.
pkgs, err := protoanalysis.DiscoverPackages(g.protoPath)
modules, err := module.Discover(g.projectPath)
if err != nil {
return err
}

// code generate for each module.
for _, pkg := range pkgs {
if err := protoc.Generate(g.ctx, tmp, pkg.Path, includePaths, protocOuts); err != nil {
for _, m := range modules {
if err := protoc.Generate(g.ctx, tmp, m.Pkg.Path, includePaths, protocOuts); err != nil {
return err
}
}
Expand All @@ -181,26 +195,21 @@ func (g *generator) generateJS() error {
}

// discover every sdk module.
pkgs, err := protoanalysis.DiscoverPackages(g.protoPath)
modules, err := module.Discover(g.projectPath)
if err != nil {
return err
}

// code generate for each module.
for _, pkg := range pkgs {
var (
msp = strings.Split(pkg.Name, ".")
moduleName = msp[len(msp)-1]

out = g.o.jsOut(pkg, moduleName)
)
for _, m := range modules {
out := g.o.jsOut(m)

// generate protobufjs types for each module.
err = protobufjs.Generate(
g.ctx,
out,
fileTypes,
pkg.Path,
m.Pkg.Path,
jsIncludePaths,
)
if err != nil {
Expand All @@ -217,7 +226,7 @@ func (g *generator) generateJS() error {
err = protoc.Generate(
g.ctx,
oaitemp,
pkg.Path,
m.Pkg.Path,
oaiIncludePaths,
openAPIOut,
)
Expand All @@ -233,6 +242,27 @@ func (g *generator) generateJS() error {
if err := sta.Generate(g.ctx, outjs, srcspec); err != nil {
return err
}

// generate the client, the js wrapper.
outclient := filepath.Join(out, "index.js")
f, err := os.OpenFile(outclient, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()

err = tpl.Execute(f, struct {
Module module.Module
TypesPath string
RESTPath string
}{
m,
"./types",
"./rest",
})
if err != nil {
return err
}
}

return nil
Expand Down
38 changes: 38 additions & 0 deletions starport/pkg/cosmosgen/templates/client.js.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { coins } from "@cosmjs/launchpad";
import { SigningStargateClient } from "@cosmjs/stargate";
import { Registry, DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import Types from "{{ .TypesPath }}";
import { Api } from "{{ .RESTPath }}";

const types = [
{{ range .Module.Msgs }}["/{{ .URI }}", Types.{{ .URI }}],
{{ end }}
];

const registry = new Registry(types);

const txClient = async (wallet, { addr: addr } = { addr: "http://localhost:26657" }) => {
if (!wallet) throw new Error("wallet is required");
const client = await SigningStargateClient.connectWithWallet(addr, wallet, { registry });
const { address } = wallet;
const fee = {
amount: coins(0, "token"),
gas: "200000",
};

return {
signAndBroadcast: (msgs) => client.signAndBroadcast(address, msgs, fee),
{{ range .Module.Msgs }}{{ camelCase .Name }}: (data) => ({ typeUrl: "/{{ .URI }}", value: data }),
{{ end }}
};
};

const queryClient = async ({ addr: addr } = { addr: "http://localhost:1317" }) => {
return new Api({ baseUrl: addr }).{{ .Module.Name }};
};

export {
txClient,
queryClient,
};
6 changes: 3 additions & 3 deletions starport/services/chain/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
starporterrors "github.com/tendermint/starport/starport/errors"
"github.com/tendermint/starport/starport/pkg/cmdrunner"
"github.com/tendermint/starport/starport/pkg/cmdrunner/step"
"github.com/tendermint/starport/starport/pkg/cosmosanalysis/module"
"github.com/tendermint/starport/starport/pkg/cosmosgen"
"github.com/tendermint/starport/starport/pkg/cosmosver"
"github.com/tendermint/starport/starport/pkg/giturl"
"github.com/tendermint/starport/starport/pkg/gocmd"
"github.com/tendermint/starport/starport/pkg/goenv"
"github.com/tendermint/starport/starport/pkg/protoanalysis"
"github.com/tendermint/starport/starport/pkg/xos"
)

Expand Down Expand Up @@ -184,8 +184,8 @@ func (c *Chain) buildProto(ctx context.Context) error {

// generate Vuex code as well if it is enabled.
if conf.Client.Vuex.Path != "" {
targets = append(targets, cosmosgen.WithJSGeneration(func(pkg protoanalysis.Package, moduleName string) string {
return filepath.Join(c.app.Path, conf.Client.Vuex.Path, giturl.UserAndRepo(pkg.GoImportName), moduleName, "module")
targets = append(targets, cosmosgen.WithJSGeneration(func(m module.Module) string {
return filepath.Join(c.app.Path, conf.Client.Vuex.Path, giturl.UserAndRepo(m.Pkg.GoImportName), m.Name, "module")
}))
}

Expand Down
6 changes: 3 additions & 3 deletions starport/services/scaffolder/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import (
"github.com/gobuffalo/genny"
conf "github.com/tendermint/starport/starport/chainconf"
"github.com/tendermint/starport/starport/errors"
"github.com/tendermint/starport/starport/pkg/cosmosanalysis/module"
"github.com/tendermint/starport/starport/pkg/cosmosgen"
"github.com/tendermint/starport/starport/pkg/cosmosver"
"github.com/tendermint/starport/starport/pkg/giturl"
"github.com/tendermint/starport/starport/pkg/gomodulepath"
"github.com/tendermint/starport/starport/pkg/protoanalysis"
"github.com/tendermint/starport/starport/pkg/xos"
"github.com/tendermint/starport/starport/templates/app"
)
Expand Down Expand Up @@ -112,8 +112,8 @@ func (s *Scaffolder) protoc(projectPath, gomodPath string, version cosmosver.Maj

// generate Vuex code as well if it is enabled.
if conf.Client.Vuex.Path != "" {
targets = append(targets, cosmosgen.WithJSGeneration(func(pkg protoanalysis.Package, moduleName string) string {
return filepath.Join(projectPath, conf.Client.Vuex.Path, giturl.UserAndRepo(pkg.GoImportName), moduleName, "module")
targets = append(targets, cosmosgen.WithJSGeneration(func(m module.Module) string {
return filepath.Join(projectPath, conf.Client.Vuex.Path, giturl.UserAndRepo(m.Pkg.GoImportName), m.Name, "module")
}))
}

Expand Down

0 comments on commit da2383e

Please sign in to comment.