/
clientRetrieveHandler.go
120 lines (110 loc) · 4.3 KB
/
clientRetrieveHandler.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package service
import (
"context"
"fmt"
"io"
"strings"
"github.com/plgd-dev/cloud/coap-gateway/coapconv"
pbGRPC "github.com/plgd-dev/cloud/grpc-gateway/pb"
"github.com/plgd-dev/go-coap/v2/message"
coapCodes "github.com/plgd-dev/go-coap/v2/message/codes"
"github.com/plgd-dev/go-coap/v2/mux"
kitNetGrpc "github.com/plgd-dev/kit/net/grpc"
"google.golang.org/grpc/status"
)
// URIToDeviceIDHref convert uri to deviceID and href. Expected input "/oic/route/{deviceID}/{Href}".
func URIToDeviceIDHref(msg *mux.Message) (deviceID, href string, err error) {
wholePath, err := msg.Options.Path()
if err != nil {
return "", "", fmt.Errorf("cannot parse deviceID, href from uri: %w", err)
}
path := strings.Split(wholePath, "/")
if len(path) < 4 {
return "", "", fmt.Errorf("cannot parse deviceID, href from uri")
}
return path[2], fixHref(strings.Join(path[3:], "/")), nil
}
func getResourceInterface(msg *mux.Message) string {
queries, _ := msg.Options.Queries()
for _, query := range queries {
if strings.HasPrefix(query, "if=") {
return strings.TrimLeft(query, "if=")
}
}
return ""
}
func clientRetrieveHandler(s mux.ResponseWriter, req *mux.Message, client *Client) {
authCtx := client.loadAuthorizationContext()
deviceID, href, err := URIToDeviceIDHref(req)
if err != nil {
client.logAndWriteErrorResponse(fmt.Errorf("DeviceId: %v: cannot handle retrieve resource: %w", authCtx.DeviceId, err), coapCodes.BadRequest, req.Token)
return
}
var content *pbGRPC.Content
var code coapCodes.Code
resourceInterface := getResourceInterface(req)
if resourceInterface == "" {
content, code, err = clientRetrieveFromResourceShadowHandler(req.Context, client, deviceID, href)
if err != nil {
client.logAndWriteErrorResponse(fmt.Errorf("DeviceId: %v: cannot retrieve resource /%v%v from resource shadow: %w", authCtx.DeviceId, deviceID, href, err), code, req.Token)
return
}
} else {
content, code, err = clientRetrieveFromDeviceHandler(req, client, deviceID, href, resourceInterface)
if err != nil {
client.logAndWriteErrorResponse(fmt.Errorf("DeviceId: %v: cannot retrieve resource /%v%v from device: %w", authCtx.DeviceId, deviceID, href, err), code, req.Token)
return
}
}
if content == nil || len(content.Data) == 0 {
client.sendResponse(code, req.Token, message.TextPlain, nil)
return
}
mediaType, err := coapconv.MakeMediaType(-1, content.ContentType)
if err != nil {
client.logAndWriteErrorResponse(fmt.Errorf("DeviceId: %v: cannot retrieve resource /%v%v: %w", authCtx.DeviceId, deviceID, href, err), code, req.Token)
return
}
client.sendResponse(code, req.Token, mediaType, content.Data)
}
func clientRetrieveFromResourceShadowHandler(ctx context.Context, client *Client, deviceID, href string) (*pbGRPC.Content, coapCodes.Code, error) {
retrieveResourcesValuesClient, err := client.server.rdClient.RetrieveResourcesValues(ctx, &pbGRPC.RetrieveResourcesValuesRequest{
ResourceIdsFilter: []*pbGRPC.ResourceId{
{
DeviceId: deviceID,
Href: href,
},
},
})
if err != nil {
return nil, coapconv.GrpcCode2CoapCode(status.Convert(err).Code(), coapCodes.GET), err
}
defer retrieveResourcesValuesClient.CloseSend()
for {
resourceValue, err := retrieveResourcesValuesClient.Recv()
if err == io.EOF {
break
}
if err != nil {
return nil, coapconv.GrpcCode2CoapCode(status.Convert(err).Code(), coapCodes.GET), err
}
if resourceValue.GetResourceId().GetDeviceId() == deviceID && resourceValue.GetResourceId().GetHref() == href && resourceValue.Content != nil {
return resourceValue.Content, coapCodes.Content, nil
}
}
return nil, coapCodes.NotFound, fmt.Errorf("not found")
}
func clientRetrieveFromDeviceHandler(req *mux.Message, client *Client, deviceID, href, resourceInterface string) (*pbGRPC.Content, coapCodes.Code, error) {
authCtx := client.loadAuthorizationContext()
processed, err := client.server.rdClient.RetrieveResourceFromDevice(kitNetGrpc.CtxWithUserID(req.Context, authCtx.UserID), &pbGRPC.RetrieveResourceFromDeviceRequest{
ResourceId: &pbGRPC.ResourceId{
DeviceId: deviceID,
Href: href,
},
ResourceInterface: resourceInterface,
})
if err != nil {
return nil, coapconv.GrpcCode2CoapCode(status.Convert(err).Code(), coapCodes.GET), err
}
return processed.GetContent(), coapconv.StatusToCoapCode(pbGRPC.Status_OK, coapCodes.GET), nil
}