/
discoverDevices.go
68 lines (60 loc) · 2.09 KB
/
discoverDevices.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package core
import (
"context"
"fmt"
"github.com/plgd-dev/go-coap/v2/message"
"github.com/plgd-dev/go-coap/v2/message/codes"
"github.com/plgd-dev/go-coap/v2/udp/client"
"github.com/plgd-dev/go-coap/v2/udp/message/pool"
"github.com/plgd-dev/kit/codec/ocf"
"github.com/plgd-dev/kit/net"
"github.com/plgd-dev/kit/net/coap"
"github.com/plgd-dev/sdk/schema"
)
// DiscoverDevicesHandler receives device links and errors from the discovery multicast request.
type DiscoverDevicesHandler interface {
Handle(ctx context.Context, client *client.ClientConn, device schema.ResourceLinks)
Error(err error)
}
// DiscoverDevices discovers devices using a CoAP multicast request via UDP.
// It waits for device responses until the context is canceled.
// Device resources can be queried in DiscoveryHandler.
// An empty typeFilter queries all resource types.
// Note: Iotivity 1.3 which responds with BadRequest if more than 1 resource type is queried.
func DiscoverDevices(
ctx context.Context,
conn []*DiscoveryClient,
handler DiscoverDevicesHandler,
options ...coap.OptionFunc,
) error {
options = append(options, coap.WithAccept(message.AppOcfCbor))
return Discover(ctx, conn, "/oic/res", handleResponse(ctx, handler), options...)
}
func handleResponse(ctx context.Context, handler DiscoverDevicesHandler) func(*client.ClientConn, *pool.Message) {
return func(cc *client.ClientConn, r *pool.Message) {
req, err := pool.ConvertTo(r)
if err != nil {
handler.Error(fmt.Errorf("cannot convert message: %w", err))
}
if req.Code != codes.Content {
handler.Error(fmt.Errorf("request failed: %s", ocf.Dump(req)))
return
}
var links schema.ResourceLinks
var codec DiscoverDeviceCodec
err = codec.Decode(req, &links)
if err != nil {
handler.Error(fmt.Errorf("decoding %v failed: %w", ocf.DumpHeader(req), err))
return
}
addr, err := net.Parse(string(schema.UDPScheme), cc.RemoteAddr())
if err != nil {
handler.Error(fmt.Errorf("invalid address %v: %w", cc.RemoteAddr(), err))
return
}
links = links.PatchEndpoint(addr, nil)
if len(links) > 0 {
handler.Handle(ctx, cc, links)
}
}
}