Skip to content

Commit

Permalink
refactor: make NewClient return an error
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl committed Aug 21, 2023
1 parent 41d44f4 commit 88cd5e9
Show file tree
Hide file tree
Showing 28 changed files with 216 additions and 135 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ build/
dist/
__pycache__/
.vscode/
.idea/
48 changes: 16 additions & 32 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import (
// GetEndpoints returns the available endpoint descriptions for the server.
func GetEndpoints(ctx context.Context, endpoint string, opts ...Option) ([]*ua.EndpointDescription, error) {
opts = append(opts, AutoReconnect(false))
c := NewClient(endpoint, opts...)
c, err := NewClient(endpoint, opts...)
if err != nil {
return nil, err
}
if err := c.Dial(ctx); err != nil {
return nil, err
}
Expand Down Expand Up @@ -133,15 +136,6 @@ type Client struct {

// monitorOnce ensures only one connection monitor is running
monitorOnce sync.Once

// cfgerr contains an error that was captured in ApplyConfig.
// Since the API does not allow to bubble the error up in NewClient
// and we don't want to break existing code right away we carry the
// error here and bubble it up during Dial and Connect.
//
// Note: Starting with v0.5 NewClient will return the error and this
// variable needs to be removed.
cfgerr error
}

// NewClient creates a new Client.
Expand All @@ -155,10 +149,11 @@ type Client struct {
// #Option for details.
//
// https://godoc.org/github.com/gopcua/opcua#Option
//
// Note: Starting with v0.5 this function will return an error.
func NewClient(endpoint string, opts ...Option) *Client {
cfg := ApplyConfig(opts...)
func NewClient(endpoint string, opts ...Option) (*Client, error) {
cfg, err := ApplyConfig(opts...)
if err != nil {
return nil, err
}
c := Client{
endpointURL: endpoint,
cfg: cfg,
Expand All @@ -167,15 +162,14 @@ func NewClient(endpoint string, opts ...Option) *Client {
pendingAcks: make([]*ua.SubscriptionAcknowledgement, 0),
pausech: make(chan struct{}, 2),
resumech: make(chan struct{}, 2),
cfgerr: cfg.Error(), // todo(fs): remove with v0.5.0 and return the error
}
c.pauseSubscriptions(context.Background())
c.setPublishTimeout(uasc.MaxTimeout)
c.setState(Closed)
c.setSecureChannel(nil)
c.setSession(nil)
c.setNamespaces([]string{})
return &c
return &c, nil
}

// reconnectAction is a list of actions for the client reconnection logic.
Expand All @@ -194,11 +188,6 @@ const (

// Connect establishes a secure channel and creates a new session.
func (c *Client) Connect(ctx context.Context) error {
// todo(fs): remove with v0.5.0
if c.cfgerr != nil {
return c.cfgerr
}

// todo(fs): the secure channel is 'nil' during a re-connect
// todo(fs): but we expect this method to be called once during startup
// todo(fs): so this is probably safe
Expand Down Expand Up @@ -503,16 +492,16 @@ func (c *Client) monitor(ctx context.Context) {
// populated in the previous step.

activeSubs = 0
for _, id := range subsToRepublish {
if err := c.republishSubscription(ctx, id, availableSeqs[id]); err != nil {
dlog.Printf("republish of subscription %d failed", id)
subsToRecreate = append(subsToRecreate, id)
for _, subID := range subsToRepublish {
if err := c.republishSubscription(ctx, subID, availableSeqs[subID]); err != nil {
dlog.Printf("republish of subscription %d failed", subID)
subsToRecreate = append(subsToRecreate, subID)
}
activeSubs++
}

for _, id := range subsToRecreate {
if err := c.recreateSubscription(ctx, id); err != nil {
for _, subID := range subsToRecreate {
if err := c.recreateSubscription(ctx, subID); err != nil {
dlog.Printf("recreate subscripitions failed: %v", err)
action = recreateSession
continue
Expand Down Expand Up @@ -555,11 +544,6 @@ func (c *Client) monitor(ctx context.Context) {

// Dial establishes a secure channel.
func (c *Client) Dial(ctx context.Context) error {
// todo(fs): remove with v0.5.0
if c.cfgerr != nil {
return c.cfgerr
}

stats.Client().Add("Dial", 1)

if c.SecureChannel() != nil {
Expand Down
7 changes: 5 additions & 2 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import (
)

func TestClient_Send_DoesNotPanicWhenDisconnected(t *testing.T) {
c := NewClient("opc.tcp://example.com:4840")
err := c.Send(context.Background(), &ua.ReadRequest{}, func(i interface{}) error {
c, err := NewClient("opc.tcp://example.com:4840")
if err != nil {
t.Fatal(err)
}
err = c.Send(context.Background(), &ua.ReadRequest{}, func(i interface{}) error {
return nil
})
verify.Values(t, "", err, ua.StatusBadServerNotConnected)
Expand Down

0 comments on commit 88cd5e9

Please sign in to comment.