diff --git a/README.md b/README.md index eab12260..de52fa40 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,8 @@ Here is the current set of supported services. For low-level access use the clie | Service Set | Service | Client | Notes | |-----------------------------|-------------------------------|--------|--------------| -| Discovery Service Set | FindServers | | | -| | FindServersOnNetwork | | | +| Discovery Service Set | FindServers | Yes | | +| | FindServersOnNetwork | Yes | | | | GetEndpoints | Yes | | | | RegisterServer | | | | | RegisterServer2 | | | diff --git a/client.go b/client.go index 67bbb0a6..077796a4 100644 --- a/client.go +++ b/client.go @@ -27,6 +27,36 @@ import ( "github.com/gopcua/opcua/uasc" ) +// FindServers returns the servers known to a server or discovery server. +func FindServers(ctx context.Context, endpoint string, opts ...Option) ([]*ua.ApplicationDescription, error) { + opts = append(opts, AutoReconnect(false)) + c := NewClient(endpoint, opts...) + if err := c.Dial(ctx); err != nil { + return nil, err + } + c.Close(ctx) + res, err := c.FindServers(ctx) + if err != nil { + return nil, err + } + return res.Servers, nil +} + +// FindServersOnNetwork returns the servers known to a server or discovery server. Unlike FindServers, this service is only implemented by discovery servers. +func FindServersOnNetwork(ctx context.Context, endpoint string, opts ...Option) ([]*ua.ServerOnNetwork, error) { + opts = append(opts, AutoReconnect(false)) + c := NewClient(endpoint, opts...) + if err := c.Dial(ctx); err != nil { + return nil, err + } + c.Close(ctx) + res, err := c.FindServersOnNetwork(ctx) + if err != nil { + return nil, err + } + return res.Servers, nil +} + // 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)) @@ -926,6 +956,32 @@ func (c *Client) Node(id *ua.NodeID) *Node { return &Node{ID: id, c: c} } +// FindServers finds the servers available at an endpoint +func (c *Client) FindServers(ctx context.Context) (*ua.FindServersResponse, error) { + stats.Client().Add("FindServers", 1) + + req := &ua.FindServersRequest{ + EndpointURL: c.endpointURL, + } + var res *ua.FindServersResponse + err := c.Send(ctx, req, func(v interface{}) error { + return safeAssign(v, &res) + }) + return res, err +} + +// FindServersOnNetwork finds the servers available at an endpoint +func (c *Client) FindServersOnNetwork(ctx context.Context) (*ua.FindServersOnNetworkResponse, error) { + stats.Client().Add("FindServersOnNetwork", 1) + + req := &ua.FindServersOnNetworkRequest{} + var res *ua.FindServersOnNetworkResponse + err := c.Send(ctx, req, func(v interface{}) error { + return safeAssign(v, &res) + }) + return res, err +} + // GetEndpoints returns the list of available endpoints of the server. func (c *Client) GetEndpoints(ctx context.Context) (*ua.GetEndpointsResponse, error) { stats.Client().Add("GetEndpoints", 1) diff --git a/examples/discovery/discovery.go b/examples/discovery/discovery.go new file mode 100644 index 00000000..a1939de6 --- /dev/null +++ b/examples/discovery/discovery.go @@ -0,0 +1,57 @@ +// Copyright 2018-2020 opcua authors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. + +package main + +import ( + "context" + "flag" + "fmt" + "github.com/gopcua/opcua" + "github.com/gopcua/opcua/debug" + "log" +) + +func main() { + endpoint := flag.String("endpoint", "opc.tcp://localhost:4840", "OPC UA Endpoint URL") + flag.BoolVar(&debug.Enable, "debug", false, "enable debug logging") + flag.Parse() + log.SetFlags(0) + + ctx := context.Background() + + { + log.Println("Finding servers on network") + servers, err := opcua.FindServersOnNetwork(ctx, *endpoint) + if err != nil { + log.Printf("Error calling find servers on network: %v", err) + } else { + for i, server := range servers { + fmt.Printf("%d Server on network:\n", i) + fmt.Printf(" -- RecordID: %v\n", server.RecordID) + fmt.Printf(" -- ServerName: %v\n", server.ServerName) + fmt.Printf(" -- DiscoveryURL: %v\n", server.DiscoveryURL) + fmt.Printf(" -- ServerCapabilities: %v\n", server.ServerCapabilities) + } + } + } + + { + log.Println("Finding servers") + servers, err := opcua.FindServers(ctx, *endpoint) + if err != nil { + log.Fatal(err) + } + for i, server := range servers { + fmt.Printf("%dth Server:\n", i+1) + fmt.Printf(" -- ApplicationURI: %v\n", server.ApplicationURI) + fmt.Printf(" -- ProductURI: %v\n", server.ProductURI) + fmt.Printf(" -- ApplicationName: %v\n", server.ApplicationName) + fmt.Printf(" -- ApplicationType: %v\n", server.ApplicationType) + fmt.Printf(" -- GatewayServerURI: %v\n", server.GatewayServerURI) + fmt.Printf(" -- DiscoveryProfileURI: %v\n", server.DiscoveryProfileURI) + fmt.Printf(" -- DiscoveryURLs: %v\n", server.DiscoveryURLs) + } + } +}