blob: cc18f1bf9e018fea5d5d373b51ff2ab9ceed8cc8 [file] [log] [blame]
Scott Baker6cf525a2019-05-09 12:25:08 -07001/*
2 * Portions copyright 2019-present Open Networking Foundation
3 * Original copyright 2019-present Ciena Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package commands
18
19import (
20 "context"
Scott Baker72efd752019-05-15 13:12:20 -070021 "crypto/sha256"
22 "fmt"
Scott Baker6cf525a2019-05-09 12:25:08 -070023 "github.com/fullstorydev/grpcurl"
24 "github.com/golang/protobuf/proto"
25 "github.com/jhump/protoreflect/dynamic"
26 "google.golang.org/grpc"
27 "hash"
28 "io"
29 "os"
30)
31
32/* Handlers for streaming upload and download */
33
34type DownloadHandler struct {
35 RpcEventHandler
36 f *os.File
37 chunks int
38 bytes int
39 status string
40 hash hash.Hash
41}
42
43type UploadHandler struct {
44 RpcEventHandler
45 chunksize int
46 f *os.File
47 uri string
Scott Baker72efd752019-05-15 13:12:20 -070048 hash hash.Hash
Scott Baker6cf525a2019-05-09 12:25:08 -070049}
50
51func (h *DownloadHandler) OnReceiveResponse(m proto.Message) {
52 d, err := dynamic.AsDynamicMessage(m)
53 if err != nil {
54 h.status = "ERROR"
55 // TODO(smbaker): How to raise an exception?
56 return
57 }
58 chunk := d.GetFieldByName("chunk").(string)
59 io.WriteString(h.hash, chunk)
60 h.f.Write([]byte(chunk))
61 h.chunks += 1
62 h.bytes += len(chunk)
63}
64
Scott Baker72efd752019-05-15 13:12:20 -070065func (h *DownloadHandler) GetChecksum() string {
66 return fmt.Sprintf("sha256:%x", h.hash.Sum(nil))
67}
68
Scott Baker6cf525a2019-05-09 12:25:08 -070069func (h *UploadHandler) GetParams(msg proto.Message) error {
70 dmsg, err := dynamic.AsDynamicMessage(msg)
71 if err != nil {
72 return err
73 }
74
75 //fmt.Printf("streamer, MessageName: %s\n", dmsg.XXX_MessageName())
76
77 block := make([]byte, h.chunksize)
78 bytes_read, err := h.f.Read(block)
79
80 if err == io.EOF {
81 h.f.Close()
82 //fmt.Print("EOF\n")
83 return err
84 }
85
86 if err != nil {
87 //fmt.Print("ERROR!\n")
88 return err
89 }
90
Scott Baker72efd752019-05-15 13:12:20 -070091 chunk := string(block[:bytes_read])
92 io.WriteString(h.hash, chunk)
93
Scott Baker6cf525a2019-05-09 12:25:08 -070094 dmsg.TrySetFieldByName("uri", h.uri)
Scott Baker72efd752019-05-15 13:12:20 -070095 dmsg.TrySetFieldByName("chunk", chunk)
Scott Baker6cf525a2019-05-09 12:25:08 -070096
97 return nil
98}
99
Scott Baker72efd752019-05-15 13:12:20 -0700100func (h *UploadHandler) GetChecksum() string {
101 return fmt.Sprintf("sha256:%x", h.hash.Sum(nil))
102}
103
104func UploadFile(conn *grpc.ClientConn, descriptor grpcurl.DescriptorSource, local_name string, uri string, chunkSize int) (*UploadHandler, *dynamic.Message, error) {
Scott Baker6cf525a2019-05-09 12:25:08 -0700105 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
106 defer cancel()
107
108 headers := GenerateHeaders()
109
110 f, err := os.Open(local_name)
111 if err != nil {
Scott Baker72efd752019-05-15 13:12:20 -0700112 return nil, nil, err
Scott Baker6cf525a2019-05-09 12:25:08 -0700113 }
114
Scott Baker72efd752019-05-15 13:12:20 -0700115 h := &UploadHandler{uri: uri,
116 f: f,
117 chunksize: chunkSize,
118 hash: sha256.New()}
Scott Baker6cf525a2019-05-09 12:25:08 -0700119
120 err = grpcurl.InvokeRPC(ctx, descriptor, conn, "xos.filetransfer/Upload", headers, h, h.GetParams)
121 if err != nil {
Scott Baker72efd752019-05-15 13:12:20 -0700122 return nil, nil, err
Scott Baker6cf525a2019-05-09 12:25:08 -0700123 }
Scott Baker55694ca2019-06-13 14:52:28 -0700124 if h.Status.Err() != nil {
125 return nil, nil, h.Status.Err()
126 }
Scott Baker6cf525a2019-05-09 12:25:08 -0700127 d, err := dynamic.AsDynamicMessage(h.Response)
128 if err != nil {
Scott Baker72efd752019-05-15 13:12:20 -0700129 return nil, nil, err
Scott Baker6cf525a2019-05-09 12:25:08 -0700130 }
131
Scott Baker72efd752019-05-15 13:12:20 -0700132 return h, d, err
Scott Baker6cf525a2019-05-09 12:25:08 -0700133}
134
135func DownloadFile(conn *grpc.ClientConn, descriptor grpcurl.DescriptorSource, uri string, local_name string) (*DownloadHandler, error) {
136 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
137 defer cancel()
138
139 headers := GenerateHeaders()
140
141 f, err := os.Create(local_name)
142 if err != nil {
143 return nil, err
144 }
145
146 dm := make(map[string]interface{})
147 dm["uri"] = uri
148
149 h := &DownloadHandler{
150 RpcEventHandler: RpcEventHandler{
151 Fields: map[string]map[string]interface{}{"xos.FileRequest": dm},
152 },
153 f: f,
Scott Baker72efd752019-05-15 13:12:20 -0700154 hash: sha256.New(),
Scott Baker6cf525a2019-05-09 12:25:08 -0700155 status: "SUCCESS"}
156
157 err = grpcurl.InvokeRPC(ctx, descriptor, conn, "xos.filetransfer/Download", headers, h, h.GetParams)
158 if err != nil {
159 return nil, err
160 }
161
Scott Baker55694ca2019-06-13 14:52:28 -0700162 if h.Status.Err() != nil {
163 return nil, h.Status.Err()
164 }
165
Scott Baker6cf525a2019-05-09 12:25:08 -0700166 return h, err
167}