Repository: codenotary/immudb
File: pkg/client/session.go (Go)

Code before:
package client

import (
	"context"
	"fmt"

	"github.com/codenotary/immudb/pkg/api/schema"
	"github.com/codenotary/immudb/pkg/client/cache"
	"github.com/codenotary/immudb/pkg/client/errors"
	"github.com/codenotary/immudb/pkg/client/heartbeater"
	"github.com/codenotary/immudb/pkg/client/state"
	"github.com/codenotary/immudb/pkg/signer"
	"github.com/codenotary/immudb/pkg/stream"
	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/grpc"
)

func (c *immuClient) OpenSession(ctx context.Context, user []byte, pass []byte, database string) (err error) {
	defer func() {
		if err != nil {
			c.SessionID = ""
			c.HeartBeater = nil
			c.ServiceClient = nil
		}
	}()
	if c.IsConnected() {
		return errors.FromError(ErrSessionAlreadyOpen)
	}

	c.Options.DialOptions = c.SetupDialOptions(c.Options)

	if c.Options.ServerSigningPubKey != "" {
		pk, e := signer.ParsePublicKeyFile(c.Options.ServerSigningPubKey)
		if e != nil {
			return e
		}
		c.WithServerSigningPubKey(pk)
	}

	if c.Options.StreamChunkSize < stream.MinChunkSize {
		return errors.New(stream.ErrChunkTooSmall).WithCode(errors.CodInvalidParameterValue)
	}

	if c.clientConn, err = grpc.Dial(c.Options.Bind(), c.Options.DialOptions...); err != nil {

Review comment (suggestion):
Please add separate defer statements for each of the variables zeroed below. Those should be set up right after assigning value to them.

Also each of them will require some kind of deinitialization:

E.g. for the `SessionId` the defer right after assignment:

```go
	c.SessionID = resp.GetSessionID()
	defer func(){
		if err != nil {
			c.ServiceClient.CloseSession(ctx, new(empty.Empty))
			c.SessionID = nil
		}
	}()
```

For the `HeartBeater` it will require `c.HearBeater.Stop()`.

The `ServiceClient` member does not need deinitialization.

There's one more value to deinitialize in case of an error: `c.clientConn`, that one should be deinitialized with `c.clientConn.Close()` and set to nil too.

Code after:
package client

import (
	"context"
	"fmt"
	"github.com/codenotary/immudb/pkg/api/schema"
	"github.com/codenotary/immudb/pkg/client/cache"
	"github.com/codenotary/immudb/pkg/client/errors"
	"github.com/codenotary/immudb/pkg/client/heartbeater"
	"github.com/codenotary/immudb/pkg/client/state"
	"github.com/codenotary/immudb/pkg/signer"
	"github.com/codenotary/immudb/pkg/stream"
	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/grpc"
)

func (c *immuClient) OpenSession(ctx context.Context, user []byte, pass []byte, database string) (err error) {
	if c.IsConnected() {
		return errors.FromError(ErrSessionAlreadyOpen)
	}

	if c.Options.ServerSigningPubKey != "" {
		pk, e := signer.ParsePublicKeyFile(c.Options.ServerSigningPubKey)
		if e != nil {
			return e
		}
		c.WithServerSigningPubKey(pk)
	}

	if c.Options.StreamChunkSize < stream.MinChunkSize {
		return errors.New(stream.ErrChunkTooSmall).WithCode(errors.CodInvalidParameterValue)
	}

	dialOptions := c.SetupDialOptions(c.Options)

	clientConn, err := grpc.Dial(c.Options.Bind(), dialOptions...)
	if err != nil {
		return err
	}
	defer func(){
		if err != nil {
			_ = clientConn.Close()
		}
	}()