From dbdd3715a97e575661c2234e71cd18af28bf00e9 Mon Sep 17 00:00:00 2001 From: Dominic Wong Date: Thu, 9 Dec 2021 16:25:34 +0000 Subject: [PATCH] Space updates (#299) * updates for timestamps and storing meta for quick retrieval * fix up head vis --- space/README.md | 4 +- space/handler/space.go | 83 ++++++++++++++++++--- space/handler/space_test.go | 90 +++++++++++++++++++---- space/proto/space.pb.go | 141 ++++++++++++++++++++++-------------- space/proto/space.proto | 8 +- 5 files changed, 239 insertions(+), 87 deletions(-) diff --git a/space/README.md b/space/README.md index 36a4062..a262182 100644 --- a/space/README.md +++ b/space/README.md @@ -2,8 +2,6 @@ Infinite cloud storage # Space Service -Space for simple object storage. Put anything in the cloud -forever. Objects can be public (readable by all via a public URL) or private. - +Space for simple object storage. Put anything in the cloud forever. Objects can be public (readable by all via a public URL) or private. Powered by S3 compatible storage API. diff --git a/space/handler/space.go b/space/handler/space.go index 800bbd6..aa75d60 100644 --- a/space/handler/space.go +++ b/space/handler/space.go @@ -14,6 +14,7 @@ import ( "github.com/micro/micro/v3/service/config" "github.com/micro/micro/v3/service/errors" log "github.com/micro/micro/v3/service/logger" + "github.com/micro/micro/v3/service/store" "github.com/micro/services/pkg/tenant" pb "github.com/micro/services/space/proto" "github.com/minio/minio-go/v7/pkg/s3utils" @@ -34,6 +35,8 @@ const ( visibilityPrivate = "private" visibilityPublic = "public" + + prefixByUser = "byUser" ) type Space struct { @@ -51,6 +54,12 @@ type conf struct { BaseURL string `json:"base_url"` } +type meta struct { + Visibility string + CreateTime string + ModifiedTime string +} + func NewSpace(srv *service.Service) *Space { var c conf val, err := config.Get("micro.space") @@ -119,7 +128,7 @@ func (s Space) upsert(ctx context.Context, object []byte, name, visibility, meth return "", errors.BadRequest(method, "Object already exists") } - createTime := aws.String(fmt.Sprintf("%d", time.Now().Unix())) + createTime := aws.String(time.Now().Format(time.RFC3339Nano)) if exists { createTime = hoo.Metadata[mdCreated] } @@ -146,8 +155,19 @@ func (s Space) upsert(ctx context.Context, object []byte, name, visibility, meth return "", errors.InternalServerError(method, "Error creating object") } - // TODO fix the url - return fmt.Sprintf("%s/%s", s.conf.BaseURL, objectName), nil + // store the metadata for easy retrieval for listing + if err := store.Write(store.NewRecord( + fmt.Sprintf("%s/%s", prefixByUser, objectName), + meta{Visibility: visibility, CreateTime: *createTime, ModifiedTime: time.Now().Format(time.RFC3339Nano)})); err != nil { + log.Errorf("Error writing object to store %s", err) + return "", errors.InternalServerError(method, "Error creating object") + } + retUrl := "" + if visibility == "public" { + retUrl = fmt.Sprintf("%s/%s", s.conf.BaseURL, objectName) + } + + return retUrl, nil } @@ -174,6 +194,10 @@ func (s Space) Delete(ctx context.Context, request *pb.DeleteRequest, response * log.Errorf("Error deleting object %s", err) return errors.InternalServerError(method, "Error deleting object") } + if err := store.Delete(fmt.Sprintf("%s/%s", prefixByUser, objectName)); err != nil { + log.Errorf("Error deleting store record %s", err) + return errors.InternalServerError(method, "Error deleting object") + } return nil } @@ -192,12 +216,38 @@ func (s Space) List(ctx context.Context, request *pb.ListRequest, response *pb.L log.Errorf("Error listing objects %s", err) return errors.InternalServerError(method, "Error listing objects") } + + recs, err := store.Read(fmt.Sprintf("%s/%s", prefixByUser, objectName), store.ReadPrefix()) + if err != nil { + log.Errorf("Error listing objects %s", err) + return errors.InternalServerError(method, "Error listing objects") + } + md := map[string]meta{} + for _, r := range recs { + var m meta + if err := json.Unmarshal(r.Value, &m); err != nil { + log.Errorf("Error unmarshaling meta %s", err) + return errors.InternalServerError(method, "Error listing objects") + } + md[strings.TrimPrefix(r.Key, prefixByUser+"/")] = m + } response.Objects = []*pb.ListObject{} for _, oi := range rsp.Contents { + m, ok := md[*oi.Key] + if !ok { + // hack for now + m = meta{} + } + url := "" + if m.Visibility == "public" { + url = fmt.Sprintf("%s/%s", s.conf.BaseURL, *oi.Key) + } response.Objects = append(response.Objects, &pb.ListObject{ - Name: strings.TrimPrefix(*oi.Key, tnt+"/"), - Modified: oi.LastModified.Unix(), - Url: fmt.Sprintf("%s/%s", s.conf.BaseURL, *oi.Key), + Name: strings.TrimPrefix(*oi.Key, tnt+"/"), + Modified: oi.LastModified.Format(time.RFC3339Nano), + Url: url, + Visibility: m.Visibility, + Created: m.CreateTime, }) } return nil @@ -231,20 +281,31 @@ func (s Space) Head(ctx context.Context, request *pb.HeadRequest, response *pb.H if md, ok := goo.Metadata[mdVisibility]; ok && len(*md) > 0 { vis = *md } - var created int64 + var created string if md, ok := goo.Metadata[mdCreated]; ok && len(*md) > 0 { - created, err = strconv.ParseInt(*md, 10, 64) + t, err := time.Parse(time.RFC3339Nano, *md) if err != nil { - log.Errorf("Error %s", err) + // 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) + } response.Object = &pb.HeadObject{ Name: request.Name, - Modified: goo.LastModified.Unix(), + Modified: goo.LastModified.Format(time.RFC3339Nano), Created: created, Visibility: vis, - Url: fmt.Sprintf("%s/%s", s.conf.BaseURL, objectName), + Url: url, } return nil diff --git a/space/handler/space_test.go b/space/handler/space_test.go index 7c3f349..e8eab24 100644 --- a/space/handler/space_test.go +++ b/space/handler/space_test.go @@ -11,6 +11,8 @@ import ( "github.com/aws/aws-sdk-go/service/s3/s3iface" "github.com/micro/micro/v3/service/auth" "github.com/micro/micro/v3/service/errors" + "github.com/micro/micro/v3/service/store" + "github.com/micro/micro/v3/service/store/memory" pb "github.com/micro/services/space/proto" . "github.com/onsi/gomega" @@ -96,7 +98,7 @@ func TestCreate(t *testing.T) { { name: "Simple case", objName: "foo.jpg", - url: "https://my-space.ams3.example.com/micro/123/foo.jpg", + url: "", head: func(input *sthree.HeadObjectInput) (*sthree.HeadObjectOutput, error) { return nil, mockError{code: "NotFound"} }, @@ -140,6 +142,7 @@ func TestCreate(t *testing.T) { }, }, } + store.DefaultStore = memory.NewStore() for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { @@ -196,7 +199,7 @@ func TestUpdate(t *testing.T) { { name: "Does not exist", objName: "foo.jpg", - url: "https://my-space.ams3.example.com/micro/123/foo.jpg", + url: "", head: func(input *sthree.HeadObjectInput) (*sthree.HeadObjectOutput, error) { return nil, mockError{code: "NotFound"} }, @@ -250,7 +253,7 @@ func TestUpdate(t *testing.T) { g.Expect(*input.Metadata[mdCreated]).To(Equal("1638541918")) return &sthree.PutObjectOutput{}, nil }, - url: "https://my-space.ams3.example.com/micro/123/foo.jpg", + url: "", }, { name: "Already exists public", @@ -277,6 +280,7 @@ func TestUpdate(t *testing.T) { visibility: "public", }, } + store.DefaultStore = memory.NewStore() for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { @@ -338,6 +342,7 @@ func TestDelete(t *testing.T) { err: errors.BadRequest("space.Delete", "Missing name param"), }, } + store.DefaultStore = memory.NewStore() for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { @@ -385,22 +390,38 @@ func TestDelete(t *testing.T) { func TestList(t *testing.T) { g := NewWithT(t) tcs := []struct { - name string - prefix string - err error - list func(input *sthree.ListObjectsInput) (*sthree.ListObjectsInput, error) + name string + prefix string + err error + list func(input *sthree.ListObjectsInput) (*sthree.ListObjectsOutput, error) + visibility string }{ { name: "Simple case", - prefix: "foo", + prefix: "file", }, { name: "Empty prefix", }, } + store.DefaultStore = memory.NewStore() for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { + store.Write( + store.NewRecord(fmt.Sprintf("%s/micro/123/file.jpg", prefixByUser), + meta{ + Visibility: "public", + CreateTime: "2009-11-10T23:00:00Z", + ModifiedTime: "2009-11-10T23:00:00Z", + })) + store.Write( + store.NewRecord(fmt.Sprintf("%s/micro/123/file2.jpg", prefixByUser), + meta{ + Visibility: "private", + CreateTime: "2009-11-10T23:00:01Z", + ModifiedTime: "2009-11-10T23:00:01Z", + })) handler := Space{ conf: conf{ AccessKey: "access", @@ -415,7 +436,18 @@ func TestList(t *testing.T) { list: func(input *sthree.ListObjectsInput) (*sthree.ListObjectsOutput, error) { g.Expect(input.Bucket).To(Equal(aws.String("my-space"))) g.Expect(input.Prefix).To(Equal(aws.String("micro/123/" + tc.prefix))) - return &sthree.ListObjectsOutput{}, nil + return &sthree.ListObjectsOutput{ + Contents: []*sthree.Object{ + { + Key: aws.String("micro/123/file.jpg"), + LastModified: aws.Time(time.Unix(1257894000, 0)), + }, + { + Key: aws.String("micro/123/file2.jpg"), + LastModified: aws.Time(time.Unix(1257894000, 0)), + }, + }, + }, nil }}, } ctx := context.Background() @@ -435,6 +467,11 @@ func TestList(t *testing.T) { g.Expect(err).To(Equal(tc.err)) } else { g.Expect(err).To(BeNil()) + g.Expect(rsp.Objects).To(HaveLen(2)) + g.Expect(rsp.Objects[0].Name).To(Equal("file.jpg")) + g.Expect(rsp.Objects[0].Url).To(Equal("https://my-space.ams3.example.com/micro/123/file.jpg")) + g.Expect(rsp.Objects[1].Name).To(Equal("file2.jpg")) + g.Expect(rsp.Objects[1].Url).To(Equal("")) } }) @@ -449,8 +486,8 @@ func TestHead(t *testing.T) { objectName string url string visibility string - modified int64 - created int64 + modified string + created string err error head func(input *sthree.HeadObjectInput) (*sthree.HeadObjectOutput, error) }{ @@ -459,21 +496,41 @@ func TestHead(t *testing.T) { objectName: "foo.jpg", visibility: "public", url: "https://my-space.ams3.example.com/micro/123/foo.jpg", - created: 1638547905, - modified: 1638547906, + created: "2009-11-10T23:00:00Z", + modified: "2009-11-10T23:00:00Z", head: func(input *sthree.HeadObjectInput) (*sthree.HeadObjectOutput, error) { g.Expect(*input.Bucket).To(Equal("my-space")) g.Expect(*input.Key).To(Equal("micro/123/foo.jpg")) return &sthree.HeadObjectOutput{ - LastModified: aws.Time(time.Unix(1638547906, 0)), + LastModified: aws.Time(time.Unix(1257894000, 0)), Metadata: map[string]*string{ - mdCreated: aws.String("1638547905"), + mdCreated: aws.String("1257894000"), mdVisibility: aws.String(visibilityPublic), }, }, nil }, }, + { + name: "Simple case private", + objectName: "foo.jpg", + visibility: "private", + url: "", + created: "2009-11-10T23:00:00Z", + modified: "2009-11-10T23:00:00Z", + head: func(input *sthree.HeadObjectInput) (*sthree.HeadObjectOutput, error) { + g.Expect(*input.Bucket).To(Equal("my-space")) + g.Expect(*input.Key).To(Equal("micro/123/foo.jpg")) + + return &sthree.HeadObjectOutput{ + LastModified: aws.Time(time.Unix(1257894000, 0)), + Metadata: map[string]*string{ + mdCreated: aws.String("2009-11-10T23:00:00Z"), + mdVisibility: aws.String("private"), + }, + }, nil + }, + }, { name: "Empty prefix", err: errors.BadRequest("space.Head", "Missing name param"), @@ -487,6 +544,7 @@ func TestHead(t *testing.T) { }, }, } + store.DefaultStore = memory.NewStore() for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { @@ -522,7 +580,7 @@ func TestHead(t *testing.T) { } else { g.Expect(err).To(BeNil()) g.Expect(rsp.Object.Name).To(Equal(tc.objectName)) - g.Expect(rsp.Object.Url).To(Equal("https://my-space.ams3.example.com/micro/123/" + tc.objectName)) + g.Expect(rsp.Object.Url).To(Equal(tc.url)) g.Expect(rsp.Object.Visibility).To(Equal(tc.visibility)) g.Expect(rsp.Object.Created).To(Equal(tc.created)) g.Expect(rsp.Object.Modified).To(Equal(tc.modified)) diff --git a/space/proto/space.pb.go b/space/proto/space.pb.go index 2c7b0ec..b33ed26 100644 --- a/space/proto/space.pb.go +++ b/space/proto/space.pb.go @@ -444,8 +444,10 @@ type ListObject struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // when was this last modified - Modified int64 `protobuf:"varint,2,opt,name=modified,proto3" json:"modified,omitempty"` - Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` + Modified string `protobuf:"bytes,2,opt,name=modified,proto3" json:"modified,omitempty"` + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` + Visibility string `protobuf:"bytes,4,opt,name=visibility,proto3" json:"visibility,omitempty"` + Created string `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"` } func (x *ListObject) Reset() { @@ -487,11 +489,11 @@ func (x *ListObject) GetName() string { return "" } -func (x *ListObject) GetModified() int64 { +func (x *ListObject) GetModified() string { if x != nil { return x.Modified } - return 0 + return "" } func (x *ListObject) GetUrl() string { @@ -501,12 +503,27 @@ func (x *ListObject) GetUrl() string { return "" } +func (x *ListObject) GetVisibility() string { + if x != nil { + return x.Visibility + } + return "" +} + +func (x *ListObject) GetCreated() string { + if x != nil { + return x.Created + } + return "" +} + // Retrieve meta information about an object type HeadRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // name of the object Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -603,9 +620,9 @@ type HeadObject struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // when was this last modified - Modified int64 `protobuf:"varint,2,opt,name=modified,proto3" json:"modified,omitempty"` + Modified string `protobuf:"bytes,2,opt,name=modified,proto3" json:"modified,omitempty"` // when was this created - Created int64 `protobuf:"varint,3,opt,name=created,proto3" json:"created,omitempty"` + 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 @@ -651,18 +668,18 @@ func (x *HeadObject) GetName() string { return "" } -func (x *HeadObject) GetModified() int64 { +func (x *HeadObject) GetModified() string { if x != nil { return x.Modified } - return 0 + return "" } -func (x *HeadObject) GetCreated() int64 { +func (x *HeadObject) GetCreated() string { if x != nil { return x.Created } - return 0 + return "" } func (x *HeadObject) GetVisibility() string { @@ -679,12 +696,13 @@ func (x *HeadObject) GetUrl() string { return "" } -// Read/download the object +// Read an object in storage. Use for private objects. type ReadRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // name of the object Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -732,6 +750,9 @@ type ReadResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // Returns the response as raw data + Object string `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` } func (x *ReadResponse) Reset() { @@ -766,6 +787,13 @@ func (*ReadResponse) Descriptor() ([]byte, []int) { return file_proto_space_proto_rawDescGZIP(), []int{13} } +func (x *ReadResponse) GetObject() string { + if x != nil { + return x.Object + } + return "" +} + var File_proto_space_proto protoreflect.FileDescriptor var file_proto_space_proto_rawDesc = []byte{ @@ -796,52 +824,57 @@ var file_proto_space_proto_rawDesc = []byte{ 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x4e, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 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, 0x03, 0x52, 0x08, 0x6d, 0x6f, 0x64, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x21, 0x0a, 0x0b, 0x48, 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, 0x39, 0x0a, 0x0c, 0x48, 0x65, - 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x48, 0x65, 0x61, 0x64, 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, 0x03, 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, 0x03, 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, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, + 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, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 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, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x22, 0x21, 0x0a, 0x0b, 0x48, 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, 0x39, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, 0x65, + 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x48, 0x65, 0x61, 0x64, 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, 0x22, 0x0e, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 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, 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, + 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, 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, + 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, - 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, + 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, 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, + 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, } var ( diff --git a/space/proto/space.proto b/space/proto/space.proto index fd7c5b4..e7b9957 100644 --- a/space/proto/space.proto +++ b/space/proto/space.proto @@ -68,8 +68,10 @@ message ListResponse { message ListObject { string name = 1; // when was this last modified - int64 modified = 2; + string modified = 2; string url = 3; + string visibility = 4; + string created = 5; } // Retrieve meta information about an object @@ -85,9 +87,9 @@ message HeadResponse { message HeadObject { string name = 1; // when was this last modified - int64 modified = 2; + string modified = 2; // when was this created - int64 created = 3; + string created = 3; // is this public or private string visibility = 4; // URL to access the object if it is public