diff --git a/go/framework/chatbridge/bridge.go b/go/framework/chatbridge/bridge.go index 89717f96b0..6c7499e76e 100644 --- a/go/framework/chatbridge/bridge.go +++ b/go/framework/chatbridge/bridge.go @@ -25,28 +25,56 @@ import ( ) type Bridge struct { - cerr chan error - cclose chan struct{} - once sync.Once - workers run.Group - grpcServer *grpc.Server - logger *zap.Logger - chatDB *gorm.DB - protocolDB *gorm.DB - chatClient bertychat.Client - protocolClient bertyprotocol.Client + cerr chan error + cclose chan struct{} + once sync.Once + workers run.Group + grpcServer *grpc.Server + logger *zap.Logger + chatDB *gorm.DB + protocolDB *gorm.DB + chatClient bertychat.Client + protocolClient bertyprotocol.Client + grpcListenerAddr string + grpcWebListenerAddr string + grpcClient *Client +} + +type Opts struct { + LogLevel string + GRPCListener string + GRPCWebListener string + NoGRPCClient bool } // NewBridge is the main entrypoint for gomobile and should only take simple configuration as argument -func NewBridge(logLevel string) (*Bridge, error) { - logger, err := setupLogger(logLevel) - if err != nil { - return nil, errors.Wrap(err, "logger setup") +func NewBridge(opts Opts) (*Bridge, error) { + var logger *zap.Logger + { + config := zap.NewDevelopmentConfig() + config.DisableStacktrace = true + config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + switch opts.LogLevel { + case "warn": + config.Level.SetLevel(zap.WarnLevel) + case "info": + config.Level.SetLevel(zap.InfoLevel) + case "debug": + config.Level.SetLevel(zap.DebugLevel) + default: + return nil, fmt.Errorf("unsupported log level: %q", opts.LogLevel) + } + var err error + logger, err = config.Build() + if err != nil { + return nil, errors.Wrap(err, "logger setup") + } } - return newBridge(logger) + + return newBridge(logger, opts) } -func newBridge(logger *zap.Logger) (*Bridge, error) { +func newBridge(logger *zap.Logger, opts Opts) (*Bridge, error) { b := &Bridge{ cerr: make(chan error), cclose: make(chan struct{}), @@ -68,7 +96,7 @@ func newBridge(logger *zap.Logger) (*Bridge, error) { var err error b.protocolDB, err = gorm.Open("sqlite3", ":memory:") if err != nil { - return nil, errors.Wrap(err, "failed to initialize gorm") + return nil, errors.Wrap(err, "initialize gorm") } // initialize new protocol client @@ -78,7 +106,7 @@ func newBridge(logger *zap.Logger) (*Bridge, error) { b.protocolClient, err = bertyprotocol.New(b.protocolDB, protocolOpts) if err != nil { - return nil, errors.Wrap(err, "failed to initialize protocol") + return nil, errors.Wrap(err, "initialize protocol") } } @@ -88,7 +116,7 @@ func newBridge(logger *zap.Logger) (*Bridge, error) { // initialize sqlite3 gorm database b.chatDB, err = gorm.Open("sqlite3", ":memory:") if err != nil { - return nil, errors.Wrap(err, "failed to initialize gorm") + return nil, errors.Wrap(err, "initialize gorm") } // initialize bertychat client @@ -98,41 +126,52 @@ func newBridge(logger *zap.Logger) (*Bridge, error) { b.chatClient, err = bertychat.New(b.chatDB, b.protocolClient, chatOpts) if err != nil { - return nil, errors.Wrap(err, "failed to initialize chat") + return nil, errors.Wrap(err, "initialize chat") } } // register service bertychat.RegisterAccountServer(b.grpcServer, b.chatClient) - return b, nil -} + // optional gRPC listener + if opts.GRPCListener != "" { + var err error + b.grpcListenerAddr, err = b.addGRPCListener(opts.GRPCListener) + if err != nil { + return nil, errors.Wrap(err, "add gRPC listener") + } + } -func setupLogger(level string) (*zap.Logger, error) { - config := zap.NewDevelopmentConfig() - config.DisableStacktrace = true - config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder - switch level { - case "warn": - config.Level.SetLevel(zap.WarnLevel) - case "info": - config.Level.SetLevel(zap.InfoLevel) - case "debug": - config.Level.SetLevel(zap.DebugLevel) - default: - return nil, fmt.Errorf("unsupported log level: %q", level) + // optional gRPC web listener + if opts.GRPCWebListener != "" { + var err error + b.grpcWebListenerAddr, err = b.addGRPCWebListener(opts.GRPCWebListener) + if err != nil { + return nil, errors.Wrap(err, "add gRPC web listener") + } + } + + if !opts.NoGRPCClient { + var err error + b.grpcClient, err = b.newGRPCClient() + if err != nil { + return nil, errors.Wrap(err, "init gRPC client") + } } - return config.Build() -} -// Start bridge -func (b *Bridge) Start() { + // start bridge b.logger.Debug("starting bridge") go func() { b.cerr <- b.workers.Run() }() + + return b, nil } +func (b *Bridge) GRPCListenerAddr() string { return b.grpcListenerAddr } +func (b *Bridge) GRPCWebListenerAddr() string { return b.grpcWebListenerAddr } +func (b *Bridge) GRPCClient() *Client { return b.grpcClient } + func (b *Bridge) isClosed() bool { select { case <-b.cclose: @@ -142,10 +181,8 @@ func (b *Bridge) isClosed() bool { } } -// Close bridge, once the bridge is closed you will not be able to start it -// again until you create a new bridge instance +// Close bridge func (b *Bridge) Close() (err error) { - // is bridge closed if b.isClosed() { return ErrNotRunning } @@ -182,10 +219,10 @@ func (b *Bridge) Close() (err error) { // AddGRPCListener start a new grpc listener // `:0` will listen on localhost with a random port // Return current listening port on success -func (b *Bridge) AddGRPCListener(addr string) (string, error) { +func (b *Bridge) addGRPCListener(addr string) (string, error) { l, err := net.Listen("tcp", addr) if err != nil { - return "", errors.Wrap(err, "failed to listen") + return "", errors.Wrap(err, "listen") } b.workers.Add(func() error { @@ -194,7 +231,6 @@ func (b *Bridge) AddGRPCListener(addr string) (string, error) { }, func(error) { b.logger.Debug("closing grpc server") l.Close() - }) return l.Addr().String(), nil @@ -203,10 +239,10 @@ func (b *Bridge) AddGRPCListener(addr string) (string, error) { // AddGRPCWebListener start a new grpc listener // `:0` will listen on localhost with a random port // Return current listening port on success -func (b *Bridge) AddGRPCWebListener(addr string) (string, error) { +func (b *Bridge) addGRPCWebListener(addr string) (string, error) { l, err := net.Listen("tcp", addr) if err != nil { - return "", errors.Wrap(err, "failed to listen") + return "", errors.Wrap(err, "listen") } // setup grpc web @@ -265,7 +301,11 @@ func (b *Bridge) AddGRPCWebListener(addr string) (string, error) { } // NewGRPCClient return client service on success -func (b *Bridge) NewGRPCClient() (client *Client, err error) { +func (b *Bridge) newGRPCClient() (client *Client, err error) { + if b.isClosed() { + return nil, ErrNotRunning + } + var grpcClient *grpc.ClientConn // create pipe listener diff --git a/go/framework/chatbridge/bridge_test.go b/go/framework/chatbridge/bridge_test.go index 7fc683fe33..19e7b508a7 100644 --- a/go/framework/chatbridge/bridge_test.go +++ b/go/framework/chatbridge/bridge_test.go @@ -6,6 +6,7 @@ import ( "berty.tech/go/internal/testutil" "berty.tech/go/pkg/bertychat" "github.com/gogo/protobuf/proto" + "go.uber.org/zap" ) func TestBridge(t *testing.T) { @@ -16,7 +17,11 @@ func TestBridge(t *testing.T) { req, res []byte ) - bridge, err = newBridge(testutil.Logger(t)) + logger := testutil.Logger(t) + bridge, err = newBridge(logger, Opts{ + GRPCListener: ":0", + GRPCWebListener: ":0", + }) if err != nil { t.Fatalf("create bridge: %v", err) } @@ -26,22 +31,17 @@ func TestBridge(t *testing.T) { } }() - if _, err = bridge.AddGRPCListener(":0"); err != nil { - t.Fatalf("add grpc listener: %v", err) - } - - if _, err = bridge.AddGRPCWebListener(":0"); err != nil { - t.Fatalf("add grpc-web listener: %v", err) - } + logger.Info( + "listeners", + zap.String("gRPC", bridge.GRPCListenerAddr()), + zap.String("gRPC web", bridge.GRPCWebListenerAddr()), + ) - client, err = bridge.NewGRPCClient() - if err != nil { - t.Fatalf("failed to setup client: %v", err) + client = bridge.GRPCClient() + if client == nil { + t.Fatalf("expected client to be initialized, got nil.") } - // start bridge - bridge.Start() - msg := &bertychat.ConversationGetRequest{ ID: "testid", } diff --git a/js/package.json b/js/package.json index bd3e2468a8..55379453f3 100644 --- a/js/package.json +++ b/js/package.json @@ -37,7 +37,7 @@ "create-react-native-module": "^0.11.1", "eslint-plugin-jest": "^22.17.0", "json": "^9.0.6", - "lerna": "^3.18.1", + "lerna": "^3.18.3", "lerna-update-wizard": "^0.16.0", "react-native-create-library": "^3.1.2", "text-transform-cli": "^1.5.0", diff --git a/js/yarn.lock b/js/yarn.lock index 44fa9eec45..b2c59e48e0 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -1548,15 +1548,15 @@ read-package-tree "^5.1.6" semver "^6.2.0" -"@lerna/changed@3.18.2": - version "3.18.2" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.18.2.tgz#4d7c2cd5de92808064891f99fb7c29711439deb9" +"@lerna/changed@3.18.3": + version "3.18.3" + resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.18.3.tgz#50529e8bd5d7fe2d0ace046a6e274d3de652a493" dependencies: "@lerna/collect-updates" "3.18.0" "@lerna/command" "3.18.0" "@lerna/listable" "3.18.0" "@lerna/output" "3.13.0" - "@lerna/version" "3.18.2" + "@lerna/version" "3.18.3" "@lerna/check-working-tree@3.16.5": version "3.16.5" @@ -1949,9 +1949,9 @@ inquirer "^6.2.0" npmlog "^4.1.2" -"@lerna/publish@3.18.2": - version "3.18.2" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.18.2.tgz#96f65f2d5ecf8cc7803050482b2d144e768b994d" +"@lerna/publish@3.18.3": + version "3.18.3" + resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.18.3.tgz#478bb94ee712a40b723413e437bcb9e307d3709c" dependencies: "@evocateur/libnpmaccess" "^3.1.2" "@evocateur/npm-registry-fetch" "^4.0.0" @@ -1974,7 +1974,7 @@ "@lerna/run-lifecycle" "3.16.2" "@lerna/run-topologically" "3.18.0" "@lerna/validation-error" "3.13.0" - "@lerna/version" "3.18.2" + "@lerna/version" "3.18.3" figgy-pudding "^3.5.1" fs-extra "^8.1.0" npm-package-arg "^6.1.0" @@ -2075,9 +2075,9 @@ dependencies: npmlog "^4.1.2" -"@lerna/version@3.18.2": - version "3.18.2" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.18.2.tgz#f2b54aed7f41d293d0fc5f79baf5cba166bc7e34" +"@lerna/version@3.18.3": + version "3.18.3" + resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.18.3.tgz#01344b39c0749fdeb6c178714733bacbde4d602f" dependencies: "@lerna/check-working-tree" "3.16.5" "@lerna/child-process" "3.16.5" @@ -10366,13 +10366,13 @@ lerna-update-wizard@^0.16.0: prettier-package-json "^2.1.0" semver-compare "^1.0.0" -lerna@^3.18.1: - version "3.18.2" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.18.2.tgz#a7bdcd4f0989723044d705da74d573a1e7249237" +lerna@^3.18.3: + version "3.18.3" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.18.3.tgz#c94556e76f98df9c7ae4ed3bc0166117cc42cd13" dependencies: "@lerna/add" "3.18.0" "@lerna/bootstrap" "3.18.0" - "@lerna/changed" "3.18.2" + "@lerna/changed" "3.18.3" "@lerna/clean" "3.18.0" "@lerna/cli" "3.18.0" "@lerna/create" "3.18.0" @@ -10382,9 +10382,9 @@ lerna@^3.18.1: "@lerna/init" "3.18.0" "@lerna/link" "3.18.0" "@lerna/list" "3.18.0" - "@lerna/publish" "3.18.2" + "@lerna/publish" "3.18.3" "@lerna/run" "3.18.0" - "@lerna/version" "3.18.2" + "@lerna/version" "3.18.3" import-local "^2.0.0" npmlog "^4.1.2"