diff --git a/space/examples.json b/space/examples.json index cdabc49..b8f4ee9 100644 --- a/space/examples.json +++ b/space/examples.json @@ -87,6 +87,26 @@ "name": "images/file.jpg" }, "response": { + "object": { + "name": "images/file.jpg", + "modified": 1638549232, + "created": 1638546232, + "url": "https://example.com/foo/bar/images/file.jpg", + "visibility": "public", + "data": "" + } + } + } + ], + "download": [ + { + "title": "Download an object", + "run_check": false, + "request": { + "name": "images/file.jpg" + }, + "response": { + "url": "https://example.com/foo/bar/images/file.jpg" } } ] diff --git a/space/generate.go b/space/generate.go index 96f431a..7d9db91 100644 --- a/space/generate.go +++ b/space/generate.go @@ -1,2 +1,3 @@ package main + //go:generate make proto diff --git a/space/handler/space.go b/space/handler/space.go index 93b9073..8ad6792 100644 --- a/space/handler/space.go +++ b/space/handler/space.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "io/ioutil" "strconv" "strings" "time" @@ -37,6 +38,9 @@ const ( visibilityPublic = "public" prefixByUser = "byUser" + + // max read 5mb for small objects + maxReadSize = 5 * 1024 * 1024 ) type Space struct { @@ -311,12 +315,92 @@ func (s Space) Head(ctx context.Context, request *pb.HeadRequest, response *pb.H return nil } -func (s *Space) Read(ctx context.Context, req *api.Request, rsp *api.Response) error { +func (s *Space) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error { method := "space.Read" tnt, ok := tenant.FromContext(ctx) if !ok { return errors.Unauthorized(method, "Unauthorized") } + + name := req.Name + + if len(req.Name) == 0 { + return errors.BadRequest(method, "Missing name param") + } + + objectName := fmt.Sprintf("%s/%s", tnt, name) + + goo, err := s.client.HeadObject(&sthree.HeadObjectInput{ + Bucket: aws.String(s.conf.SpaceName), + Key: aws.String(objectName), + }) + if err != nil { + aerr, ok := err.(awserr.Error) + if ok && aerr.Code() == "NotFound" { + return errors.BadRequest(method, "Object not found") + } + log.Errorf("Error s3 %s", err) + return errors.InternalServerError(method, "Error reading object") + } + + _, gooreq := s.client.GetObjectRequest(&sthree.GetObjectInput{ + Bucket: aws.String(s.conf.SpaceName), + Key: aws.String(objectName), + }) + + + vis := visibilityPrivate + if md, ok := goo.Metadata[mdVisibility]; ok && len(*md) > 0 { + vis = *md + } + + var created string + if md, ok := goo.Metadata[mdCreated]; ok && len(*md) > 0 { + t, err := time.Parse(time.RFC3339Nano, *md) + if err != nil { + // try as unix ts + createdI, err := strconv.ParseInt(*md, 10, 64) + if err != nil { + log.Errorf("Error %s", err) + } else { + t = time.Unix(createdI, 0) + } + } + created = t.Format(time.RFC3339Nano) + } + + url := "" + if vis == "public" { + url = fmt.Sprintf("%s/%s", s.conf.BaseURL, objectName) + } + + if *gooreq.ContentLength > maxReadSize { + return errors.BadRequest(method, "Exceeds max read size: %v bytes", maxReadSize) + } + + b, err := ioutil.ReadAll(gooreq.Body) + if err != nil { + return errors.InternalServerError(method, "Failed to read data") + } + + rsp.Object = &pb.Object{ + Name: req.Name, + Modified: goo.LastModified.Format(time.RFC3339Nano), + Created: created, + Visibility: vis, + Url: url, + Data: b, + } + + return nil +} + +func (s *Space) Download(ctx context.Context, req *api.Request, rsp *api.Response) error { + method := "space.Download" + tnt, ok := tenant.FromContext(ctx) + if !ok { + return errors.Unauthorized(method, "Unauthorized") + } var input map[string]string if err := json.Unmarshal([]byte(req.Body), &input); err != nil { log.Errorf("Error unmarshalling %s", err) @@ -368,5 +452,12 @@ func (s *Space) Read(ctx context.Context, req *api.Request, rsp *api.Response) e } rsp.StatusCode = 302 + resp := map[string]interface{}{ + "url": urlStr, + } + + b, _ := json.Marshal(resp) + rsp.Body = string(b) + return nil } diff --git a/space/proto/space.pb.go b/space/proto/space.pb.go index b33ed26..414e8d6 100644 --- a/space/proto/space.pb.go +++ b/space/proto/space.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.15.5 +// protoc-gen-go v1.27.1 +// protoc v3.15.6 // source: proto/space.proto package space @@ -254,13 +254,13 @@ func (x *UpdateResponse) GetUrl() string { return "" } -// Delete an object +// Delete an object from space type DeleteRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The name of the object. Use forward slash delimiter to implement a nested directory-like structure e.g. images/foo.jpg + // Name of the object Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -341,7 +341,7 @@ func (*DeleteResponse) Descriptor() ([]byte, []int) { return file_proto_space_proto_rawDescGZIP(), []int{5} } -// List the objects in the space +// List the objects in space type ListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -696,7 +696,100 @@ func (x *HeadObject) GetUrl() string { return "" } -// Read an object in storage. Use for private objects. +type Object struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // name of object + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // when was this last modified + Modified string `protobuf:"bytes,2,opt,name=modified,proto3" json:"modified,omitempty"` + // when was this created + Created string `protobuf:"bytes,3,opt,name=created,proto3" json:"created,omitempty"` + // is this public or private + Visibility string `protobuf:"bytes,4,opt,name=visibility,proto3" json:"visibility,omitempty"` + // URL to access the object if it is public + Url string `protobuf:"bytes,5,opt,name=url,proto3" json:"url,omitempty"` + // the data within the object + Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Object) Reset() { + *x = Object{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_space_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Object) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Object) ProtoMessage() {} + +func (x *Object) ProtoReflect() protoreflect.Message { + mi := &file_proto_space_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Object.ProtoReflect.Descriptor instead. +func (*Object) Descriptor() ([]byte, []int) { + return file_proto_space_proto_rawDescGZIP(), []int{12} +} + +func (x *Object) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Object) GetModified() string { + if x != nil { + return x.Modified + } + return "" +} + +func (x *Object) GetCreated() string { + if x != nil { + return x.Created + } + return "" +} + +func (x *Object) GetVisibility() string { + if x != nil { + return x.Visibility + } + return "" +} + +func (x *Object) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Object) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +// Read an object in space type ReadRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -709,7 +802,7 @@ type ReadRequest struct { func (x *ReadRequest) Reset() { *x = ReadRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_space_proto_msgTypes[12] + mi := &file_proto_space_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -722,7 +815,7 @@ func (x *ReadRequest) String() string { func (*ReadRequest) ProtoMessage() {} func (x *ReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_space_proto_msgTypes[12] + mi := &file_proto_space_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -735,7 +828,7 @@ func (x *ReadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead. func (*ReadRequest) Descriptor() ([]byte, []int) { - return file_proto_space_proto_rawDescGZIP(), []int{12} + return file_proto_space_proto_rawDescGZIP(), []int{13} } func (x *ReadRequest) GetName() string { @@ -751,14 +844,14 @@ type ReadResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Returns the response as raw data - Object string `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` + // The object itself + Object *Object `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` } func (x *ReadResponse) Reset() { *x = ReadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_space_proto_msgTypes[13] + mi := &file_proto_space_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -771,7 +864,7 @@ func (x *ReadResponse) String() string { func (*ReadResponse) ProtoMessage() {} func (x *ReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_space_proto_msgTypes[13] + mi := &file_proto_space_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -784,13 +877,110 @@ func (x *ReadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadResponse.ProtoReflect.Descriptor instead. func (*ReadResponse) Descriptor() ([]byte, []int) { - return file_proto_space_proto_rawDescGZIP(), []int{13} + return file_proto_space_proto_rawDescGZIP(), []int{14} } -func (x *ReadResponse) GetObject() string { +func (x *ReadResponse) GetObject() *Object { if x != nil { return x.Object } + return nil +} + +// Download an object via a presigned url +type DownloadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // name of object + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DownloadRequest) Reset() { + *x = DownloadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_space_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DownloadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownloadRequest) ProtoMessage() {} + +func (x *DownloadRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_space_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DownloadRequest.ProtoReflect.Descriptor instead. +func (*DownloadRequest) Descriptor() ([]byte, []int) { + return file_proto_space_proto_rawDescGZIP(), []int{15} +} + +func (x *DownloadRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DownloadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // presigned url + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *DownloadResponse) Reset() { + *x = DownloadResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_space_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DownloadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownloadResponse) ProtoMessage() {} + +func (x *DownloadResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_space_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DownloadResponse.ProtoReflect.Descriptor instead. +func (*DownloadResponse) Descriptor() ([]byte, []int) { + return file_proto_space_proto_rawDescGZIP(), []int{16} +} + +func (x *DownloadResponse) GetUrl() string { + if x != nil { + return x.Url + } return "" } @@ -847,34 +1037,54 @@ var file_proto_space_proto_rawDesc = []byte{ 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x21, 0x0a, 0x0b, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x26, - 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x32, 0xcb, 0x02, 0x0a, 0x05, 0x53, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x98, 0x01, 0x0a, 0x06, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, + 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x21, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a, 0x0c, 0x52, 0x65, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x22, 0x25, 0x0a, 0x0f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x24, 0x0a, 0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x32, 0x8a, 0x03, + 0x0a, 0x05, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x12, 0x14, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, - 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x31, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, + 0x12, 0x12, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x08, 0x44, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -889,43 +1099,49 @@ func file_proto_space_proto_rawDescGZIP() []byte { return file_proto_space_proto_rawDescData } -var file_proto_space_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_proto_space_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_proto_space_proto_goTypes = []interface{}{ - (*CreateRequest)(nil), // 0: space.CreateRequest - (*CreateResponse)(nil), // 1: space.CreateResponse - (*UpdateRequest)(nil), // 2: space.UpdateRequest - (*UpdateResponse)(nil), // 3: space.UpdateResponse - (*DeleteRequest)(nil), // 4: space.DeleteRequest - (*DeleteResponse)(nil), // 5: space.DeleteResponse - (*ListRequest)(nil), // 6: space.ListRequest - (*ListResponse)(nil), // 7: space.ListResponse - (*ListObject)(nil), // 8: space.ListObject - (*HeadRequest)(nil), // 9: space.HeadRequest - (*HeadResponse)(nil), // 10: space.HeadResponse - (*HeadObject)(nil), // 11: space.HeadObject - (*ReadRequest)(nil), // 12: space.ReadRequest - (*ReadResponse)(nil), // 13: space.ReadResponse + (*CreateRequest)(nil), // 0: space.CreateRequest + (*CreateResponse)(nil), // 1: space.CreateResponse + (*UpdateRequest)(nil), // 2: space.UpdateRequest + (*UpdateResponse)(nil), // 3: space.UpdateResponse + (*DeleteRequest)(nil), // 4: space.DeleteRequest + (*DeleteResponse)(nil), // 5: space.DeleteResponse + (*ListRequest)(nil), // 6: space.ListRequest + (*ListResponse)(nil), // 7: space.ListResponse + (*ListObject)(nil), // 8: space.ListObject + (*HeadRequest)(nil), // 9: space.HeadRequest + (*HeadResponse)(nil), // 10: space.HeadResponse + (*HeadObject)(nil), // 11: space.HeadObject + (*Object)(nil), // 12: space.Object + (*ReadRequest)(nil), // 13: space.ReadRequest + (*ReadResponse)(nil), // 14: space.ReadResponse + (*DownloadRequest)(nil), // 15: space.DownloadRequest + (*DownloadResponse)(nil), // 16: space.DownloadResponse } var file_proto_space_proto_depIdxs = []int32{ 8, // 0: space.ListResponse.objects:type_name -> space.ListObject 11, // 1: space.HeadResponse.object:type_name -> space.HeadObject - 0, // 2: space.Space.Create:input_type -> space.CreateRequest - 2, // 3: space.Space.Update:input_type -> space.UpdateRequest - 4, // 4: space.Space.Delete:input_type -> space.DeleteRequest - 6, // 5: space.Space.List:input_type -> space.ListRequest - 9, // 6: space.Space.Head:input_type -> space.HeadRequest - 12, // 7: space.Space.Read:input_type -> space.ReadRequest - 1, // 8: space.Space.Create:output_type -> space.CreateResponse - 3, // 9: space.Space.Update:output_type -> space.UpdateResponse - 5, // 10: space.Space.Delete:output_type -> space.DeleteResponse - 7, // 11: space.Space.List:output_type -> space.ListResponse - 10, // 12: space.Space.Head:output_type -> space.HeadResponse - 13, // 13: space.Space.Read:output_type -> space.ReadResponse - 8, // [8:14] is the sub-list for method output_type - 2, // [2:8] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 12, // 2: space.ReadResponse.object:type_name -> space.Object + 0, // 3: space.Space.Create:input_type -> space.CreateRequest + 2, // 4: space.Space.Update:input_type -> space.UpdateRequest + 4, // 5: space.Space.Delete:input_type -> space.DeleteRequest + 6, // 6: space.Space.List:input_type -> space.ListRequest + 9, // 7: space.Space.Head:input_type -> space.HeadRequest + 13, // 8: space.Space.Read:input_type -> space.ReadRequest + 15, // 9: space.Space.Download:input_type -> space.DownloadRequest + 1, // 10: space.Space.Create:output_type -> space.CreateResponse + 3, // 11: space.Space.Update:output_type -> space.UpdateResponse + 5, // 12: space.Space.Delete:output_type -> space.DeleteResponse + 7, // 13: space.Space.List:output_type -> space.ListResponse + 10, // 14: space.Space.Head:output_type -> space.HeadResponse + 14, // 15: space.Space.Read:output_type -> space.ReadResponse + 16, // 16: space.Space.Download:output_type -> space.DownloadResponse + 10, // [10:17] is the sub-list for method output_type + 3, // [3:10] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_proto_space_proto_init() } @@ -1079,7 +1295,7 @@ func file_proto_space_proto_init() { } } file_proto_space_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadRequest); i { + switch v := v.(*Object); i { case 0: return &v.state case 1: @@ -1091,6 +1307,18 @@ func file_proto_space_proto_init() { } } file_proto_space_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_space_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReadResponse); i { case 0: return &v.state @@ -1102,6 +1330,30 @@ func file_proto_space_proto_init() { return nil } } + file_proto_space_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DownloadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_space_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DownloadResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1109,7 +1361,7 @@ func file_proto_space_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_space_proto_rawDesc, NumEnums: 0, - NumMessages: 14, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/space/proto/space.pb.micro.go b/space/proto/space.pb.micro.go index a210ada..06f94c3 100644 --- a/space/proto/space.pb.micro.go +++ b/space/proto/space.pb.micro.go @@ -48,6 +48,7 @@ type SpaceService interface { List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) Head(ctx context.Context, in *HeadRequest, opts ...client.CallOption) (*HeadResponse, error) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) + Download(ctx context.Context, in *DownloadRequest, opts ...client.CallOption) (*DownloadResponse, error) } type spaceService struct { @@ -122,6 +123,16 @@ func (c *spaceService) Read(ctx context.Context, in *ReadRequest, opts ...client return out, nil } +func (c *spaceService) Download(ctx context.Context, in *DownloadRequest, opts ...client.CallOption) (*DownloadResponse, error) { + req := c.c.NewRequest(c.name, "Space.Download", in) + out := new(DownloadResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Space service type SpaceHandler interface { @@ -131,6 +142,7 @@ type SpaceHandler interface { List(context.Context, *ListRequest, *ListResponse) error Head(context.Context, *HeadRequest, *HeadResponse) error Read(context.Context, *ReadRequest, *ReadResponse) error + Download(context.Context, *DownloadRequest, *DownloadResponse) error } func RegisterSpaceHandler(s server.Server, hdlr SpaceHandler, opts ...server.HandlerOption) error { @@ -141,6 +153,7 @@ func RegisterSpaceHandler(s server.Server, hdlr SpaceHandler, opts ...server.Han List(ctx context.Context, in *ListRequest, out *ListResponse) error Head(ctx context.Context, in *HeadRequest, out *HeadResponse) error Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error + Download(ctx context.Context, in *DownloadRequest, out *DownloadResponse) error } type Space struct { space @@ -176,3 +189,7 @@ func (h *spaceHandler) Head(ctx context.Context, in *HeadRequest, out *HeadRespo func (h *spaceHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error { return h.SpaceHandler.Read(ctx, in, out) } + +func (h *spaceHandler) Download(ctx context.Context, in *DownloadRequest, out *DownloadResponse) error { + return h.SpaceHandler.Download(ctx, in, out) +} diff --git a/space/proto/space.proto b/space/proto/space.proto index e7b9957..36279dd 100644 --- a/space/proto/space.proto +++ b/space/proto/space.proto @@ -11,6 +11,7 @@ service Space { rpc List(ListRequest) returns (ListResponse) {} rpc Head(HeadRequest) returns (HeadResponse) {} rpc Read(ReadRequest) returns (ReadResponse) {} + rpc Download(DownloadRequest) returns (DownloadResponse) {} } // Create an object. Returns error if object with this name already exists. If you want to update an existing object use the `Update` endpoint @@ -96,7 +97,22 @@ message HeadObject { string url = 5; } -// Read an object in space. Use for private objects. +message Object { + // name of object + string name = 1; + // when was this last modified + string modified = 2; + // when was this created + string created = 3; + // is this public or private + string visibility = 4; + // URL to access the object if it is public + string url = 5; + // the data within the object + bytes data = 6; +} + +// Read an object in space message ReadRequest { // name of the object string name = 1; @@ -104,6 +120,17 @@ message ReadRequest { // Returns the raw object message ReadResponse { - // Returns the object as raw data - string object = 1; + // The object itself + Object object = 1; +} + +// Download an object via a presigned url +message DownloadRequest { + // name of object + string name = 1; +} + +message DownloadResponse { + // presigned url + string url = 2; }