From dceb96ff9858f95136c8b3bceb1eaddf8d8d0ac0 Mon Sep 17 00:00:00 2001 From: David Christofas Date: Tue, 6 Apr 2021 15:52:30 +0200 Subject: [PATCH] prepare for public link thumbnails - Implement a CS3 image source handler - Use checksum instead of etag for unique check - Simplify storage layout --- thumbnails/pkg/config/config.go | 13 +- thumbnails/pkg/flagset/flagset.go | 14 +- thumbnails/pkg/proto/v0/thumbnails.pb.go | 433 ++++++++++++------ .../pkg/proto/v0/thumbnails.pb.micro.go | 12 +- .../pkg/proto/v0/thumbnails.pb.micro_test.go | 13 +- thumbnails/pkg/proto/v0/thumbnails.pb_test.go | 42 +- thumbnails/pkg/proto/v0/thumbnails.proto | 37 +- thumbnails/pkg/server/grpc/server.go | 14 +- thumbnails/pkg/service/v0/instrument.go | 2 +- thumbnails/pkg/service/v0/logging.go | 2 +- thumbnails/pkg/service/v0/option.go | 15 + thumbnails/pkg/service/v0/service.go | 101 ++-- thumbnails/pkg/service/v0/tracing.go | 5 +- thumbnails/pkg/thumbnail/imgsource/cs3.go | 78 ++++ thumbnails/pkg/thumbnail/imgsource/webdav.go | 17 +- .../pkg/thumbnail/storage/filesystem.go | 122 ++--- thumbnails/pkg/thumbnail/storage/inmemory.go | 19 +- thumbnails/pkg/thumbnail/storage/storage.go | 4 +- thumbnails/pkg/thumbnail/thumbnail.go | 28 +- webdav/pkg/service/v0/service.go | 32 +- 20 files changed, 620 insertions(+), 383 deletions(-) create mode 100644 thumbnails/pkg/thumbnail/imgsource/cs3.go diff --git a/thumbnails/pkg/config/config.go b/thumbnails/pkg/config/config.go index d742f9bfee..d825831c75 100644 --- a/thumbnails/pkg/config/config.go +++ b/thumbnails/pkg/config/config.go @@ -53,12 +53,6 @@ type FileSystemStorage struct { RootDirectory string } -// WebDavSource defines the available webdav source configuration. -type WebDavSource struct { - BaseURL string - Insecure bool -} - // FileSystemSource defines the available filesystem source configuration. type FileSystemSource struct { BasePath string @@ -66,9 +60,10 @@ type FileSystemSource struct { // Thumbnail defines the available thumbnail related configuration. type Thumbnail struct { - Resolutions []string - FileSystemStorage FileSystemStorage - WebDavSource WebDavSource + Resolutions []string + FileSystemStorage FileSystemStorage + WebdavAllowInsecure bool + RevaGateway string } // New initializes a new configuration with or without defaults. diff --git a/thumbnails/pkg/flagset/flagset.go b/thumbnails/pkg/flagset/flagset.go index 73c85c27f3..4d672b03f4 100644 --- a/thumbnails/pkg/flagset/flagset.go +++ b/thumbnails/pkg/flagset/flagset.go @@ -143,18 +143,18 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag { Destination: &cfg.Thumbnail.FileSystemStorage.RootDirectory, }, &cli.StringFlag{ - Name: "webdavsource-baseurl", - Value: flags.OverrideDefaultString(cfg.Thumbnail.WebDavSource.BaseURL, "https://localhost:9200/remote.php/webdav/"), - Usage: "Base url for a webdav api", - EnvVars: []string{"THUMBNAILS_WEBDAVSOURCE_BASEURL"}, - Destination: &cfg.Thumbnail.WebDavSource.BaseURL, + Name: "reva-gateway-addr", + Value: flags.OverrideDefaultString(cfg.Thumbnail.RevaGateway, "localhost:9142"), + Usage: "Reva gateway address", + EnvVars: []string{"THUMBNAILS_REVA_GATEWAY", "PROXY_REVA_GATEWAY_ADDR"}, + Destination: &cfg.Thumbnail.RevaGateway, }, &cli.BoolFlag{ Name: "webdavsource-insecure", - Value: flags.OverrideDefaultBool(cfg.Thumbnail.WebDavSource.Insecure, true), + Value: flags.OverrideDefaultBool(cfg.Thumbnail.WebdavAllowInsecure, true), Usage: "Whether to skip certificate checks", EnvVars: []string{"THUMBNAILS_WEBDAVSOURCE_INSECURE"}, - Destination: &cfg.Thumbnail.WebDavSource.Insecure, + Destination: &cfg.Thumbnail.WebdavAllowInsecure, }, &cli.StringSliceFlag{ Name: "thumbnail-resolution", diff --git a/thumbnails/pkg/proto/v0/thumbnails.pb.go b/thumbnails/pkg/proto/v0/thumbnails.pb.go index 9a491e8680..636eb7a42f 100644 --- a/thumbnails/pkg/proto/v0/thumbnails.pb.go +++ b/thumbnails/pkg/proto/v0/thumbnails.pb.go @@ -21,55 +21,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// The file types to which the thumbnail cna get encoded to. -type GetRequest_FileType int32 +// The file types to which the thumbnail can get encoded to. +type GetThumbnailRequest_FileType int32 const ( - GetRequest_PNG GetRequest_FileType = 0 // Represents PNG type - GetRequest_JPG GetRequest_FileType = 1 // Represents JPG type + GetThumbnailRequest_PNG GetThumbnailRequest_FileType = 0 // Represents PNG type + GetThumbnailRequest_JPG GetThumbnailRequest_FileType = 1 // Represents JPG type ) -// Enum value maps for GetRequest_FileType. +// Enum value maps for GetThumbnailRequest_FileType. var ( - GetRequest_FileType_name = map[int32]string{ + GetThumbnailRequest_FileType_name = map[int32]string{ 0: "PNG", 1: "JPG", } - GetRequest_FileType_value = map[string]int32{ + GetThumbnailRequest_FileType_value = map[string]int32{ "PNG": 0, "JPG": 1, } ) -func (x GetRequest_FileType) Enum() *GetRequest_FileType { - p := new(GetRequest_FileType) +func (x GetThumbnailRequest_FileType) Enum() *GetThumbnailRequest_FileType { + p := new(GetThumbnailRequest_FileType) *p = x return p } -func (x GetRequest_FileType) String() string { +func (x GetThumbnailRequest_FileType) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (GetRequest_FileType) Descriptor() protoreflect.EnumDescriptor { +func (GetThumbnailRequest_FileType) Descriptor() protoreflect.EnumDescriptor { return file_thumbnails_proto_enumTypes[0].Descriptor() } -func (GetRequest_FileType) Type() protoreflect.EnumType { +func (GetThumbnailRequest_FileType) Type() protoreflect.EnumType { return &file_thumbnails_proto_enumTypes[0] } -func (x GetRequest_FileType) Number() protoreflect.EnumNumber { +func (x GetThumbnailRequest_FileType) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use GetRequest_FileType.Descriptor instead. -func (GetRequest_FileType) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use GetThumbnailRequest_FileType.Descriptor instead. +func (GetThumbnailRequest_FileType) EnumDescriptor() ([]byte, []int) { return file_thumbnails_proto_rawDescGZIP(), []int{0, 0} } // A request to retrieve a thumbnail -type GetRequest struct { +type GetThumbnailRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -77,21 +77,19 @@ type GetRequest struct { // The path to the source image Filepath string `protobuf:"bytes,1,opt,name=filepath,proto3" json:"filepath,omitempty"` // The type to which the thumbnail should get encoded to. - Filetype GetRequest_FileType `protobuf:"varint,2,opt,name=filetype,proto3,enum=com.owncloud.ocis.thumbnails.v0.GetRequest_FileType" json:"filetype,omitempty"` - // The etag of the source image - Etag string `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"` + ThumbnailType GetThumbnailRequest_FileType `protobuf:"varint,2,opt,name=thumbnail_type,json=thumbnailType,proto3,enum=com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest_FileType" json:"thumbnail_type,omitempty"` // The width of the thumbnail - Width int32 `protobuf:"varint,4,opt,name=width,proto3" json:"width,omitempty"` + Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` // The height of the thumbnail - Height int32 `protobuf:"varint,5,opt,name=height,proto3" json:"height,omitempty"` - // The authorization token - Authorization string `protobuf:"bytes,6,opt,name=authorization,proto3" json:"authorization,omitempty"` - // The user requesting the resource. - Username string `protobuf:"bytes,7,opt,name=username,proto3" json:"username,omitempty"` + Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` + // Types that are assignable to Source: + // *GetThumbnailRequest_WebdavSource + // *GetThumbnailRequest_Cs3Source + Source isGetThumbnailRequest_Source `protobuf_oneof:"source"` } -func (x *GetRequest) Reset() { - *x = GetRequest{} +func (x *GetThumbnailRequest) Reset() { + *x = GetThumbnailRequest{} if protoimpl.UnsafeEnabled { mi := &file_thumbnails_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -99,13 +97,13 @@ func (x *GetRequest) Reset() { } } -func (x *GetRequest) String() string { +func (x *GetThumbnailRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetRequest) ProtoMessage() {} +func (*GetThumbnailRequest) ProtoMessage() {} -func (x *GetRequest) ProtoReflect() protoreflect.Message { +func (x *GetThumbnailRequest) ProtoReflect() protoreflect.Message { mi := &file_thumbnails_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -117,74 +115,89 @@ func (x *GetRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetRequest.ProtoReflect.Descriptor instead. -func (*GetRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetThumbnailRequest.ProtoReflect.Descriptor instead. +func (*GetThumbnailRequest) Descriptor() ([]byte, []int) { return file_thumbnails_proto_rawDescGZIP(), []int{0} } -func (x *GetRequest) GetFilepath() string { +func (x *GetThumbnailRequest) GetFilepath() string { if x != nil { return x.Filepath } return "" } -func (x *GetRequest) GetFiletype() GetRequest_FileType { +func (x *GetThumbnailRequest) GetThumbnailType() GetThumbnailRequest_FileType { if x != nil { - return x.Filetype + return x.ThumbnailType } - return GetRequest_PNG + return GetThumbnailRequest_PNG } -func (x *GetRequest) GetEtag() string { - if x != nil { - return x.Etag - } - return "" -} - -func (x *GetRequest) GetWidth() int32 { +func (x *GetThumbnailRequest) GetWidth() int32 { if x != nil { return x.Width } return 0 } -func (x *GetRequest) GetHeight() int32 { +func (x *GetThumbnailRequest) GetHeight() int32 { if x != nil { return x.Height } return 0 } -func (x *GetRequest) GetAuthorization() string { - if x != nil { - return x.Authorization +func (m *GetThumbnailRequest) GetSource() isGetThumbnailRequest_Source { + if m != nil { + return m.Source } - return "" + return nil } -func (x *GetRequest) GetUsername() string { - if x != nil { - return x.Username +func (x *GetThumbnailRequest) GetWebdavSource() *WebdavSource { + if x, ok := x.GetSource().(*GetThumbnailRequest_WebdavSource); ok { + return x.WebdavSource } - return "" + return nil } -// The service response -type GetResponse struct { +func (x *GetThumbnailRequest) GetCs3Source() *CS3Source { + if x, ok := x.GetSource().(*GetThumbnailRequest_Cs3Source); ok { + return x.Cs3Source + } + return nil +} + +type isGetThumbnailRequest_Source interface { + isGetThumbnailRequest_Source() +} + +type GetThumbnailRequest_WebdavSource struct { + WebdavSource *WebdavSource `protobuf:"bytes,5,opt,name=webdav_source,json=webdavSource,proto3,oneof"` +} + +type GetThumbnailRequest_Cs3Source struct { + Cs3Source *CS3Source `protobuf:"bytes,6,opt,name=cs3_source,json=cs3Source,proto3,oneof"` +} + +func (*GetThumbnailRequest_WebdavSource) isGetThumbnailRequest_Source() {} + +func (*GetThumbnailRequest_Cs3Source) isGetThumbnailRequest_Source() {} + +type WebdavSource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The thumbnail as a binary - Thumbnail []byte `protobuf:"bytes,1,opt,name=thumbnail,proto3" json:"thumbnail,omitempty"` - // The mimetype of the thumbnail - Mimetype string `protobuf:"bytes,2,opt,name=mimetype,proto3" json:"mimetype,omitempty"` + // REQUIRED. + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + // OPTIONAL. + Authorization string `protobuf:"bytes,2,opt,name=authorization,proto3" json:"authorization,omitempty"` } -func (x *GetResponse) Reset() { - *x = GetResponse{} +func (x *WebdavSource) Reset() { + *x = WebdavSource{} if protoimpl.UnsafeEnabled { mi := &file_thumbnails_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -192,13 +205,13 @@ func (x *GetResponse) Reset() { } } -func (x *GetResponse) String() string { +func (x *WebdavSource) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetResponse) ProtoMessage() {} +func (*WebdavSource) ProtoMessage() {} -func (x *GetResponse) ProtoReflect() protoreflect.Message { +func (x *WebdavSource) ProtoReflect() protoreflect.Message { mi := &file_thumbnails_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -210,19 +223,124 @@ func (x *GetResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetResponse.ProtoReflect.Descriptor instead. -func (*GetResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use WebdavSource.ProtoReflect.Descriptor instead. +func (*WebdavSource) Descriptor() ([]byte, []int) { return file_thumbnails_proto_rawDescGZIP(), []int{1} } -func (x *GetResponse) GetThumbnail() []byte { +func (x *WebdavSource) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *WebdavSource) GetAuthorization() string { + if x != nil { + return x.Authorization + } + return "" +} + +type CS3Source struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *CS3Source) Reset() { + *x = CS3Source{} + if protoimpl.UnsafeEnabled { + mi := &file_thumbnails_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CS3Source) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CS3Source) ProtoMessage() {} + +func (x *CS3Source) ProtoReflect() protoreflect.Message { + mi := &file_thumbnails_proto_msgTypes[2] + 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 CS3Source.ProtoReflect.Descriptor instead. +func (*CS3Source) Descriptor() ([]byte, []int) { + return file_thumbnails_proto_rawDescGZIP(), []int{2} +} + +func (x *CS3Source) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +// The service response +type GetThumbnailResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The thumbnail as a binary + Thumbnail []byte `protobuf:"bytes,1,opt,name=thumbnail,proto3" json:"thumbnail,omitempty"` + // The mimetype of the thumbnail + Mimetype string `protobuf:"bytes,2,opt,name=mimetype,proto3" json:"mimetype,omitempty"` +} + +func (x *GetThumbnailResponse) Reset() { + *x = GetThumbnailResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_thumbnails_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetThumbnailResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetThumbnailResponse) ProtoMessage() {} + +func (x *GetThumbnailResponse) ProtoReflect() protoreflect.Message { + mi := &file_thumbnails_proto_msgTypes[3] + 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 GetThumbnailResponse.ProtoReflect.Descriptor instead. +func (*GetThumbnailResponse) Descriptor() ([]byte, []int) { + return file_thumbnails_proto_rawDescGZIP(), []int{3} +} + +func (x *GetThumbnailResponse) GetThumbnail() []byte { if x != nil { return x.Thumbnail } return nil } -func (x *GetResponse) GetMimetype() string { +func (x *GetThumbnailResponse) GetMimetype() string { if x != nil { return x.Mimetype } @@ -238,60 +356,75 @@ var file_thumbnails_proto_rawDesc = []byte{ 0x2e, 0x76, 0x30, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x02, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x50, - 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, - 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2e, - 0x76, 0x30, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, - 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x65, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x1c, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4a, 0x50, 0x47, - 0x10, 0x01, 0x22, 0x47, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, - 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x32, 0x7d, 0x0a, 0x10, 0x54, - 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x69, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, - 0x2b, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6f, + 0x6f, 0x74, 0x6f, 0x22, 0x90, 0x03, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x64, 0x0a, 0x0e, 0x74, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x3d, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x76, - 0x30, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, + 0x30, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, + 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x54, 0x0a, 0x0d, 0x77, + 0x65, 0x62, 0x64, 0x61, 0x76, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, + 0x73, 0x2e, 0x76, 0x30, 0x2e, 0x57, 0x65, 0x62, 0x64, 0x61, 0x76, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x48, 0x00, 0x52, 0x0c, 0x77, 0x65, 0x62, 0x64, 0x61, 0x76, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x4b, 0x0a, 0x0a, 0x63, 0x73, 0x33, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, + 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x76, 0x30, 0x2e, 0x43, 0x53, 0x33, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x48, 0x00, 0x52, 0x09, 0x63, 0x73, 0x33, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x1c, + 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4e, + 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4a, 0x50, 0x47, 0x10, 0x01, 0x42, 0x08, 0x0a, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x46, 0x0a, 0x0c, 0x57, 0x65, 0x62, 0x64, 0x61, 0x76, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, + 0x0a, 0x09, 0x43, 0x53, 0x33, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, + 0x50, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, + 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, + 0x65, 0x32, 0x8f, 0x01, 0x0a, 0x10, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, + 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x76, 0x30, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, + 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x76, 0x30, 0x2e, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xe0, 0x02, 0x5a, 0x36, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, - 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, - 0x6c, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x30, 0x3b, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x92, 0x41, 0xa4, 0x02, 0x12, 0xb8, 0x01, 0x0a, 0x22, 0x6f, 0x77, - 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x20, - 0x53, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, - 0x22, 0x47, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x47, 0x6d, 0x62, - 0x48, 0x12, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, - 0x63, 0x69, 0x73, 0x1a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x6f, 0x77, 0x6e, - 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x42, 0x0a, 0x0a, 0x41, 0x70, 0x61, - 0x63, 0x68, 0x65, 0x2d, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, - 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, - 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, - 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, - 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x3f, 0x0a, 0x10, - 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, - 0x12, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, - 0x75, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0xe0, 0x02, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, + 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x30, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x92, 0x41, + 0xa4, 0x02, 0x12, 0xb8, 0x01, 0x0a, 0x22, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, + 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x20, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x74, + 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x47, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, + 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x12, 0x20, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, + 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x1a, 0x14, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x63, + 0x6f, 0x6d, 0x2a, 0x42, 0x0a, 0x0a, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x32, 0x2e, 0x30, + 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, + 0x69, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, + 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, 0x01, + 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, + 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x3f, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x12, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x2f, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -307,21 +440,25 @@ func file_thumbnails_proto_rawDescGZIP() []byte { } var file_thumbnails_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_thumbnails_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_thumbnails_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_thumbnails_proto_goTypes = []interface{}{ - (GetRequest_FileType)(0), // 0: com.owncloud.ocis.thumbnails.v0.GetRequest.FileType - (*GetRequest)(nil), // 1: com.owncloud.ocis.thumbnails.v0.GetRequest - (*GetResponse)(nil), // 2: com.owncloud.ocis.thumbnails.v0.GetResponse + (GetThumbnailRequest_FileType)(0), // 0: com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest.FileType + (*GetThumbnailRequest)(nil), // 1: com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest + (*WebdavSource)(nil), // 2: com.owncloud.ocis.thumbnails.v0.WebdavSource + (*CS3Source)(nil), // 3: com.owncloud.ocis.thumbnails.v0.CS3Source + (*GetThumbnailResponse)(nil), // 4: com.owncloud.ocis.thumbnails.v0.GetThumbnailResponse } var file_thumbnails_proto_depIdxs = []int32{ - 0, // 0: com.owncloud.ocis.thumbnails.v0.GetRequest.filetype:type_name -> com.owncloud.ocis.thumbnails.v0.GetRequest.FileType - 1, // 1: com.owncloud.ocis.thumbnails.v0.ThumbnailService.GetThumbnail:input_type -> com.owncloud.ocis.thumbnails.v0.GetRequest - 2, // 2: com.owncloud.ocis.thumbnails.v0.ThumbnailService.GetThumbnail:output_type -> com.owncloud.ocis.thumbnails.v0.GetResponse - 2, // [2:3] is the sub-list for method output_type - 1, // [1:2] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 0, // 0: com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest.thumbnail_type:type_name -> com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest.FileType + 2, // 1: com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest.webdav_source:type_name -> com.owncloud.ocis.thumbnails.v0.WebdavSource + 3, // 2: com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest.cs3_source:type_name -> com.owncloud.ocis.thumbnails.v0.CS3Source + 1, // 3: com.owncloud.ocis.thumbnails.v0.ThumbnailService.GetThumbnail:input_type -> com.owncloud.ocis.thumbnails.v0.GetThumbnailRequest + 4, // 4: com.owncloud.ocis.thumbnails.v0.ThumbnailService.GetThumbnail:output_type -> com.owncloud.ocis.thumbnails.v0.GetThumbnailResponse + 4, // [4:5] is the sub-list for method output_type + 3, // [3:4] 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_thumbnails_proto_init() } @@ -331,7 +468,7 @@ func file_thumbnails_proto_init() { } if !protoimpl.UnsafeEnabled { file_thumbnails_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRequest); i { + switch v := v.(*GetThumbnailRequest); i { case 0: return &v.state case 1: @@ -343,7 +480,31 @@ func file_thumbnails_proto_init() { } } file_thumbnails_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetResponse); i { + switch v := v.(*WebdavSource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_thumbnails_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CS3Source); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_thumbnails_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetThumbnailResponse); i { case 0: return &v.state case 1: @@ -355,13 +516,17 @@ func file_thumbnails_proto_init() { } } } + file_thumbnails_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*GetThumbnailRequest_WebdavSource)(nil), + (*GetThumbnailRequest_Cs3Source)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_thumbnails_proto_rawDesc, NumEnums: 1, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/thumbnails/pkg/proto/v0/thumbnails.pb.micro.go b/thumbnails/pkg/proto/v0/thumbnails.pb.micro.go index 73a086e33c..81f77b00e5 100644 --- a/thumbnails/pkg/proto/v0/thumbnails.pb.micro.go +++ b/thumbnails/pkg/proto/v0/thumbnails.pb.micro.go @@ -44,7 +44,7 @@ func NewThumbnailServiceEndpoints() []*api.Endpoint { type ThumbnailService interface { // Generates the thumbnail and returns it. - GetThumbnail(ctx context.Context, in *GetRequest, opts ...client.CallOption) (*GetResponse, error) + GetThumbnail(ctx context.Context, in *GetThumbnailRequest, opts ...client.CallOption) (*GetThumbnailResponse, error) } type thumbnailService struct { @@ -59,9 +59,9 @@ func NewThumbnailService(name string, c client.Client) ThumbnailService { } } -func (c *thumbnailService) GetThumbnail(ctx context.Context, in *GetRequest, opts ...client.CallOption) (*GetResponse, error) { +func (c *thumbnailService) GetThumbnail(ctx context.Context, in *GetThumbnailRequest, opts ...client.CallOption) (*GetThumbnailResponse, error) { req := c.c.NewRequest(c.name, "ThumbnailService.GetThumbnail", in) - out := new(GetResponse) + out := new(GetThumbnailResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -73,12 +73,12 @@ func (c *thumbnailService) GetThumbnail(ctx context.Context, in *GetRequest, opt type ThumbnailServiceHandler interface { // Generates the thumbnail and returns it. - GetThumbnail(context.Context, *GetRequest, *GetResponse) error + GetThumbnail(context.Context, *GetThumbnailRequest, *GetThumbnailResponse) error } func RegisterThumbnailServiceHandler(s server.Server, hdlr ThumbnailServiceHandler, opts ...server.HandlerOption) error { type thumbnailService interface { - GetThumbnail(ctx context.Context, in *GetRequest, out *GetResponse) error + GetThumbnail(ctx context.Context, in *GetThumbnailRequest, out *GetThumbnailResponse) error } type ThumbnailService struct { thumbnailService @@ -91,6 +91,6 @@ type thumbnailServiceHandler struct { ThumbnailServiceHandler } -func (h *thumbnailServiceHandler) GetThumbnail(ctx context.Context, in *GetRequest, out *GetResponse) error { +func (h *thumbnailServiceHandler) GetThumbnail(ctx context.Context, in *GetThumbnailRequest, out *GetThumbnailResponse) error { return h.ThumbnailServiceHandler.GetThumbnail(ctx, in, out) } diff --git a/thumbnails/pkg/proto/v0/thumbnails.pb.micro_test.go b/thumbnails/pkg/proto/v0/thumbnails.pb.micro_test.go index 4aa72003f3..ef5ce8c3fa 100644 --- a/thumbnails/pkg/proto/v0/thumbnails.pb.micro_test.go +++ b/thumbnails/pkg/proto/v0/thumbnails.pb.micro_test.go @@ -52,10 +52,10 @@ func init() { } func TestGetThumbnailInvalidImage(t *testing.T) { - req := proto.GetRequest{ + req := proto.GetThumbnailRequest{ Filepath: "invalid.png", - Filetype: proto.GetRequest_PNG, - Etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + ThumbnailType: proto.GetThumbnailRequest_PNG, + Checksum: "33a64df551425fcc55e4d42a148795d9f25f89d4", Height: 32, Width: 32, Username: "user1", @@ -68,13 +68,12 @@ func TestGetThumbnailInvalidImage(t *testing.T) { } func TestGetThumbnail(t *testing.T) { - req := proto.GetRequest{ + req := proto.GetThumbnailRequest{ Filepath: "oc.png", - Filetype: proto.GetRequest_PNG, - Etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + ThumbnailType: proto.GetThumbnailRequest_PNG, + Checksum: "33a64df551425fcc55e4d42a148795d9f25f89d4", Height: 32, Width: 32, - Authorization: "Bearer eyJhbGciOiJQUzI1NiIsImtpZCI6IiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwaG9lbml4IiwiZXhwIjoxNTkwNTc1Mzk4LCJqdGkiOiJqUEw5c1A3UUEzY0diYi1yRnhkSjJCWnFPc1BDTDg1ZyIsImlhdCI6MTU5MDU3NDc5OCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6OTIwMCIsInN1YiI6Ilh0U2lfbWl5V1NCLXBrdkdueFBvQzVBNGZsaWgwVUNMZ3ZVN2NMd2ptakNLWDdGWW4ySFdrNnJSQ0V1eTJHNXFBeV95TVFjX0ZLOWFORmhVTXJYMnBRQGtvbm5lY3QiLCJrYy5pc0FjY2Vzc1Rva2VuIjp0cnVlLCJrYy5hdXRob3JpemVkU2NvcGVzIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJlbWFpbCJdLCJrYy5pZGVudGl0eSI6eyJrYy5pLmRuIjoiRWluc3RlaW4iLCJrYy5pLmlkIjoiY249ZWluc3RlaW4sb3U9dXNlcnMsZGM9ZXhhbXBsZSxkYz1vcmciLCJrYy5pLnVuIjoiZWluc3RlaW4ifSwia2MucHJvdmlkZXIiOiJpZGVudGlmaWVyLWxkYXAifQ.FSDe4vzwYpHbNfckBON5EI-01MS_dYFxenddqfJPzjlAEMEH2FFn2xQHCsxhC7wSxivhjV7Z5eRoNUR606keA64Tjs8pJBNECSptBMmE_xfAlc6X5IFILgDnR5bBu6Z2hhu-dVj72Hcyvo_X__OeWekYu7oyoXW41Mw3ayiUAwjCAzV3WPOAJ_r0zbW68_m29BgH3BoSxaF6lmjStIIAIyw7IBZ2QXb_FvGouknmfeWlGL9lkFPGL_dYKwjWieG947nY4Kg8IvHByEbw-xlY3L2EdA7Q8ZMbqdX7GzjtEIVYvCT4-TxWRcmB3SmO-Z8CVq27NHlKm3aZ0k2PS8Ga1w", Username: "user1", } client := service.Client() diff --git a/thumbnails/pkg/proto/v0/thumbnails.pb_test.go b/thumbnails/pkg/proto/v0/thumbnails.pb_test.go index 59a79ae932..2ebe9baea5 100644 --- a/thumbnails/pkg/proto/v0/thumbnails.pb_test.go +++ b/thumbnails/pkg/proto/v0/thumbnails.pb_test.go @@ -10,19 +10,19 @@ import ( type TestRequest struct { testDataName string filepath string - filetype proto.GetRequest_FileType + filetype proto.GetThumbnailRequest_FileType etag string width int32 height int32 authorization string - expected proto.GetRequest + expected proto.GetThumbnailRequest } type TestResponse struct { testDataName string img []byte mimetype string - expected proto.GetResponse + expected proto.GetThumbnailResponse } func TestRequestString(t *testing.T) { @@ -31,64 +31,60 @@ func TestRequestString(t *testing.T) { { "ASCII", "Foo.jpg", - proto.GetRequest_JPG, + proto.GetThumbnailRequest_JPG, "33a64df551425fcc55e4d42a148795d9f25f89d4", 24, 24, "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", - proto.GetRequest{ + proto.GetThumbnailRequest{ Filepath: "Foo.jpg", - Filetype: proto.GetRequest_JPG, - Etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + ThumbnailType: proto.GetThumbnailRequest_JPG, + Checksum: "33a64df551425fcc55e4d42a148795d9f25f89d4", Width: 24, Height: 24, - Authorization: "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", }, }, { "UTF", "मिलन.jpg", - proto.GetRequest_JPG, + proto.GetThumbnailRequest_JPG, "33a64df551425fcc55e4d42a148795d9f25f89d4", 24, 24, "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", - proto.GetRequest{ + proto.GetThumbnailRequest{ Filepath: "\340\244\256\340\244\277\340\244\262\340\244\250.jpg", - Filetype: proto.GetRequest_JPG, - Etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + ThumbnailType: proto.GetThumbnailRequest_JPG, + Checksum: "33a64df551425fcc55e4d42a148795d9f25f89d4", Width: 24, Height: 24, - Authorization: "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", }, }, { "PNG", "Foo.png", - proto.GetRequest_PNG, + proto.GetThumbnailRequest_PNG, "33a64df551425fcc55e4d42a148795d9f25f89d4", 24, 24, "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", - proto.GetRequest{ + proto.GetThumbnailRequest{ Filepath: "Foo.png", - Etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + Checksum: "33a64df551425fcc55e4d42a148795d9f25f89d4", Width: 24, Height: 24, - Authorization: "Basic SGVXaG9SZWFkc1RoaXM6SXNTdHVwaWQK", }, }, } for _, testCase := range tests { t.Run(testCase.testDataName, func(t *testing.T) { - req := proto.GetRequest{ + req := proto.GetThumbnailRequest{ Filepath: testCase.filepath, - Filetype: testCase.filetype, - Etag: testCase.etag, + ThumbnailType: testCase.filetype, + Checksum: testCase.etag, Height: testCase.height, Width: testCase.width, - Authorization: testCase.authorization, } assert.Equal(t, testCase.expected.String(), req.String()) }) @@ -101,7 +97,7 @@ func TestResponseString(t *testing.T) { "ASCII", []byte("image data"), "image/png", - proto.GetResponse{ + proto.GetThumbnailResponse{ Thumbnail: []byte("image data"), Mimetype: "image/png", }, @@ -110,7 +106,7 @@ func TestResponseString(t *testing.T) { for _, testCase := range tests { t.Run(testCase.testDataName, func(t *testing.T) { - response := proto.GetResponse{ + response := proto.GetThumbnailResponse{ Thumbnail: testCase.img, Mimetype: testCase.mimetype, } diff --git a/thumbnails/pkg/proto/v0/thumbnails.proto b/thumbnails/pkg/proto/v0/thumbnails.proto index 34072d4619..21a77d9c55 100644 --- a/thumbnails/pkg/proto/v0/thumbnails.proto +++ b/thumbnails/pkg/proto/v0/thumbnails.proto @@ -33,36 +33,45 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // A Service for handling thumbnail generation service ThumbnailService { // Generates the thumbnail and returns it. - rpc GetThumbnail(GetRequest) returns (GetResponse); + rpc GetThumbnail(GetThumbnailRequest) returns (GetThumbnailResponse); } // A request to retrieve a thumbnail -message GetRequest { +message GetThumbnailRequest { // The path to the source image string filepath = 1; - // The file types to which the thumbnail cna get encoded to. + // The file types to which the thumbnail can get encoded to. enum FileType { PNG = 0; // Represents PNG type JPG = 1; // Represents JPG type } // The type to which the thumbnail should get encoded to. - FileType filetype = 2; - // The etag of the source image - string etag = 3; + FileType thumbnail_type = 2; // The width of the thumbnail - int32 width = 4; + int32 width = 3; // The height of the thumbnail - int32 height = 5; - // The authorization token - string authorization = 6; - // The user requesting the resource. - string username = 7; + int32 height = 4; + oneof source { + WebdavSource webdav_source = 5; + CS3Source cs3_source = 6; + } +} + +message WebdavSource { + // REQUIRED. + string url = 1; + // OPTIONAL. + string authorization = 2; +} + +message CS3Source { + string path = 1; } // The service response -message GetResponse { +message GetThumbnailResponse { // The thumbnail as a binary bytes thumbnail = 1; // The mimetype of the thumbnail string mimetype = 2; -} \ No newline at end of file +} diff --git a/thumbnails/pkg/server/grpc/server.go b/thumbnails/pkg/server/grpc/server.go index b09a01be91..c436445c7d 100644 --- a/thumbnails/pkg/server/grpc/server.go +++ b/thumbnails/pkg/server/grpc/server.go @@ -1,6 +1,7 @@ package grpc import ( + "github.com/cs3org/reva/pkg/rgrpc/todo/pool" "github.com/owncloud/ocis/ocis-pkg/service/grpc" "github.com/owncloud/ocis/thumbnails/pkg/proto/v0" svc "github.com/owncloud/ocis/thumbnails/pkg/service/v0" @@ -23,19 +24,26 @@ func NewService(opts ...Option) grpc.Service { grpc.Flags(options.Flags...), grpc.Version(options.Config.Server.Version), ) - + tconf := options.Config.Thumbnail + gc, err := pool.GetGatewayServiceClient(tconf.RevaGateway) + if err != nil { + options.Logger.Error().Err(err).Msg("could not get gateway client") + return grpc.Service{} + } var thumbnail proto.ThumbnailServiceHandler { thumbnail = svc.NewService( svc.Config(options.Config), svc.Logger(options.Logger), - svc.ThumbnailSource(imgsource.NewWebDavSource(options.Config.Thumbnail.WebDavSource)), + svc.ThumbnailSource(imgsource.NewWebDavSource(tconf)), svc.ThumbnailStorage( storage.NewFileSystemStorage( - options.Config.Thumbnail.FileSystemStorage, + tconf.FileSystemStorage, options.Logger, ), ), + svc.CS3Source(imgsource.NewCS3Source(gc)), + svc.CS3Client(gc), ) thumbnail = svc.NewInstrument(thumbnail, options.Metrics) thumbnail = svc.NewLogging(thumbnail, options.Logger) diff --git a/thumbnails/pkg/service/v0/instrument.go b/thumbnails/pkg/service/v0/instrument.go index a06f865680..1c3e77824e 100644 --- a/thumbnails/pkg/service/v0/instrument.go +++ b/thumbnails/pkg/service/v0/instrument.go @@ -22,7 +22,7 @@ type instrument struct { } // GetThumbnail implements the ThumbnailServiceHandler interface. -func (i instrument) GetThumbnail(ctx context.Context, req *v0proto.GetRequest, rsp *v0proto.GetResponse) error { +func (i instrument) GetThumbnail(ctx context.Context, req *v0proto.GetThumbnailRequest, rsp *v0proto.GetThumbnailResponse) error { timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) { us := v * 1000_000 i.metrics.Latency.WithLabelValues().Observe(us) diff --git a/thumbnails/pkg/service/v0/logging.go b/thumbnails/pkg/service/v0/logging.go index dbe6d69001..69f74d133d 100644 --- a/thumbnails/pkg/service/v0/logging.go +++ b/thumbnails/pkg/service/v0/logging.go @@ -22,7 +22,7 @@ type logging struct { } // GetThumbnail implements the ThumbnailServiceHandler interface. -func (l logging) GetThumbnail(ctx context.Context, req *v0proto.GetRequest, rsp *v0proto.GetResponse) error { +func (l logging) GetThumbnail(ctx context.Context, req *v0proto.GetThumbnailRequest, rsp *v0proto.GetThumbnailResponse) error { start := time.Now() err := l.next.GetThumbnail(ctx, req, rsp) diff --git a/thumbnails/pkg/service/v0/option.go b/thumbnails/pkg/service/v0/option.go index ac12ff69ed..06b8013b55 100644 --- a/thumbnails/pkg/service/v0/option.go +++ b/thumbnails/pkg/service/v0/option.go @@ -1,6 +1,7 @@ package svc import ( + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" "net/http" "github.com/owncloud/ocis/ocis-pkg/log" @@ -19,6 +20,8 @@ type Options struct { Middleware []func(http.Handler) http.Handler ThumbnailStorage storage.Storage ImageSource imgsource.Source + CS3Source imgsource.Source + CS3Client gateway.GatewayAPIClient } // newOptions initializes the available default options. @@ -66,3 +69,15 @@ func ThumbnailSource(val imgsource.Source) Option { o.ImageSource = val } } + +func CS3Source(val imgsource.Source) Option { + return func(o *Options) { + o.CS3Source = val + } +} + +func CS3Client(c gateway.GatewayAPIClient) Option { + return func(o *Options) { + o.CS3Client = c + } +} diff --git a/thumbnails/pkg/service/v0/service.go b/thumbnails/pkg/service/v0/service.go index 6392b6ee6b..3de2a82d85 100644 --- a/thumbnails/pkg/service/v0/service.go +++ b/thumbnails/pkg/service/v0/service.go @@ -2,13 +2,17 @@ package svc import ( "context" - "image" - merrors "github.com/asim/go-micro/v3/errors" + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/pkg/token" "github.com/owncloud/ocis/ocis-pkg/log" v0proto "github.com/owncloud/ocis/thumbnails/pkg/proto/v0" "github.com/owncloud/ocis/thumbnails/pkg/thumbnail" "github.com/owncloud/ocis/thumbnails/pkg/thumbnail/imgsource" + "google.golang.org/grpc/metadata" + "image" ) // NewService returns a service implementation for Service. @@ -26,8 +30,10 @@ func NewService(opts ...Option) v0proto.ThumbnailServiceHandler { options.ThumbnailStorage, logger, ), - source: options.ImageSource, - logger: logger, + webdavSource: options.ImageSource, + cs3Source: options.CS3Source, + logger: logger, + cs3Client: options.CS3Client, } return svc @@ -35,57 +41,94 @@ func NewService(opts ...Option) v0proto.ThumbnailServiceHandler { // Thumbnail implements the GRPC handler. type Thumbnail struct { - serviceID string - manager thumbnail.Manager - source imgsource.Source - logger log.Logger + serviceID string + manager thumbnail.Manager + webdavSource imgsource.Source + cs3Source imgsource.Source + logger log.Logger + cs3Client gateway.GatewayAPIClient } // GetThumbnail retrieves a thumbnail for an image -func (g Thumbnail) GetThumbnail(ctx context.Context, req *v0proto.GetRequest, rsp *v0proto.GetResponse) error { - encoder := thumbnail.EncoderForType(req.Filetype.String()) - if encoder == nil { - g.logger.Debug().Str("filetype", req.Filetype.String()).Msg("unsupported filetype") +func (g Thumbnail) GetThumbnail(ctx context.Context, req *v0proto.GetThumbnailRequest, rsp *v0proto.GetThumbnailResponse) error { + _, ok := v0proto.GetThumbnailRequest_FileType_value[req.ThumbnailType.String()] + if !ok { + g.logger.Debug().Str("filetype", req.ThumbnailType.String()).Msg("unsupported filetype") return nil } - - auth := req.Authorization - if auth == "" { - return merrors.BadRequest(g.serviceID, "authorization is missing") + encoder := thumbnail.EncoderForType(req.ThumbnailType.String()) + if encoder == nil { + g.logger.Debug().Str("filetype", req.ThumbnailType.String()).Msg("unsupported filetype") + return nil } - username := req.Username - if username == "" { - return merrors.BadRequest(g.serviceID, "username missing in request") + sReq := &provider.StatRequest{ + Ref: &provider.Reference{ + Spec: &provider.Reference_Path{Path: "/home/" + req.Filepath}, + }, + } + + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return merrors.Unauthorized(g.serviceID, "authorization is missing") + } + auth, ok := md[token.TokenHeader] + if !ok { + return merrors.Unauthorized(g.serviceID, "authorization is missing") + } + + ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, auth[0]) + sRes, err := g.cs3Client.Stat(ctx, sReq) + if err != nil { + g.logger.Error().Err(err).Msg("could stat file") + return merrors.InternalServerError(g.serviceID, "could not stat file: %s", err.Error()) + } + + if sRes.Status.Code != rpc.Code_CODE_OK { + g.logger.Error().Err(err).Msg("could not create Request") + return merrors.InternalServerError(g.serviceID, "could not stat file: %s", err.Error()) } tr := thumbnail.Request{ Resolution: image.Rect(0, 0, int(req.Width), int(req.Height)), Encoder: encoder, - ETag: req.Etag, - Username: username, + ETag: sRes.GetInfo().GetChecksum().GetSum(), } - thumbnail := g.manager.GetStored(tr) - if thumbnail != nil { - rsp.Thumbnail = thumbnail + thumb, ok := g.manager.Get(tr) + if ok { + rsp.Thumbnail = thumb rsp.Mimetype = tr.Encoder.MimeType() return nil } - sCtx := imgsource.ContextSetAuthorization(ctx, auth) - img, err := g.source.Get(sCtx, req.Filepath) + var img image.Image + switch { + case req.GetWebdavSource() != nil: + src := req.GetWebdavSource() + src.GetAuthorization() + + sCtx := imgsource.ContextSetAuthorization(ctx, src.GetAuthorization()) + img, err = g.webdavSource.Get(sCtx, src.GetUrl()) + case req.GetCs3Source() != nil: + src := req.GetCs3Source() + + sCtx := imgsource.ContextSetAuthorization(ctx, auth[0]) + img, err = g.cs3Source.Get(sCtx, src.Path) + default: + g.logger.Error().Msg("no image source provided") + return merrors.BadRequest(g.serviceID, "image source is missing") + } if err != nil { return merrors.InternalServerError(g.serviceID, "could not get image from source: %v", err.Error()) } if img == nil { return merrors.InternalServerError(g.serviceID, "could not get image from source") } - thumbnail, err = g.manager.Get(tr, img) - if err != nil { + if thumb, err = g.manager.Generate(tr, img); err != nil { return err } - rsp.Thumbnail = thumbnail + rsp.Thumbnail = thumb rsp.Mimetype = tr.Encoder.MimeType() return nil } diff --git a/thumbnails/pkg/service/v0/tracing.go b/thumbnails/pkg/service/v0/tracing.go index c56767126e..8f4ffd2718 100644 --- a/thumbnails/pkg/service/v0/tracing.go +++ b/thumbnails/pkg/service/v0/tracing.go @@ -19,14 +19,13 @@ type tracing struct { } // GetThumbnail implements the ThumbnailServiceHandler interface. -func (t tracing) GetThumbnail(ctx context.Context, req *v0proto.GetRequest, rsp *v0proto.GetResponse) error { +func (t tracing) GetThumbnail(ctx context.Context, req *v0proto.GetThumbnailRequest, rsp *v0proto.GetThumbnailResponse) error { ctx, span := trace.StartSpan(ctx, "Thumbnails.GetThumbnail") defer span.End() span.Annotate([]trace.Attribute{ trace.StringAttribute("filepath", req.Filepath), - trace.StringAttribute("filetype", req.Filetype.String()), - trace.StringAttribute("etag", req.Etag), + trace.StringAttribute("thumbnail_type", req.ThumbnailType.String()), trace.Int64Attribute("width", int64(req.Width)), trace.Int64Attribute("height", int64(req.Height)), }, "Execute Thumbnails.GetThumbnail handler") diff --git a/thumbnails/pkg/thumbnail/imgsource/cs3.go b/thumbnails/pkg/thumbnail/imgsource/cs3.go new file mode 100644 index 0000000000..1c5c0bed34 --- /dev/null +++ b/thumbnails/pkg/thumbnail/imgsource/cs3.go @@ -0,0 +1,78 @@ +package imgsource + +import ( + "context" + "crypto/tls" + "fmt" + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/pkg/rhttp" + "github.com/cs3org/reva/pkg/token" + "github.com/pkg/errors" + "google.golang.org/grpc/metadata" + "image" + "net/http" +) + +type CS3 struct { + client gateway.GatewayAPIClient +} + +func NewCS3Source(c gateway.GatewayAPIClient) CS3 { + return CS3{ + client: c, + } +} + +func (s CS3) Get(ctx context.Context, path string) (image.Image, error) { + auth, _ := ContextGetAuthorization(ctx) + ctx = metadata.AppendToOutgoingContext(context.Background(), token.TokenHeader, auth) + rsp, err := s.client.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{ + Ref: &provider.Reference{ + Spec: &provider.Reference_Path{ + Path: path, + }, + } , + }) + + if err != nil { + return nil, err + } + + if rsp.Status.Code != rpc.Code_CODE_OK { + return nil, fmt.Errorf("could not load image: %s", rsp.Status.Message) + } + var ep, tk string + for _, p := range rsp.Protocols { + if p.Protocol == "simple" { + ep, tk = p.DownloadEndpoint, p.Token + } + } + + httpReq, err := rhttp.NewRequest(ctx, "GET", ep, nil) + if err != nil { + return nil, err + } + httpReq.Header.Set(token.TokenHeader, auth) + httpReq.Header.Set("X-REVA-TRANSFER", tk) + + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec + client := &http.Client{} + + resp, err := client.Do(httpReq) + if err != nil { + return nil, err + } + defer resp.Body.Close() //nolint:errcheck + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("could not get the image \"%s\". Request returned with statuscode %d ", path, resp.StatusCode) + } + + img, _, err := image.Decode(resp.Body) + if err != nil { + return nil, errors.Wrapf(err, `could not decode the image "%s"`, path) + } + return img, nil +} diff --git a/thumbnails/pkg/thumbnail/imgsource/webdav.go b/thumbnails/pkg/thumbnail/imgsource/webdav.go index 99d24c072d..7c0caa50c4 100644 --- a/thumbnails/pkg/thumbnail/imgsource/webdav.go +++ b/thumbnails/pkg/thumbnail/imgsource/webdav.go @@ -4,37 +4,30 @@ import ( "context" "crypto/tls" "fmt" + "github.com/owncloud/ocis/thumbnails/pkg/config" + "github.com/pkg/errors" "image" _ "image/gif" // Import the gif package so that image.Decode can understand gifs _ "image/jpeg" // Import the jpeg package so that image.Decode can understand jpegs _ "image/png" // Import the png package so that image.Decode can understand pngs "net/http" - "net/url" - "path" - - "github.com/owncloud/ocis/thumbnails/pkg/config" - "github.com/pkg/errors" ) // NewWebDavSource creates a new webdav instance. -func NewWebDavSource(cfg config.WebDavSource) WebDav { +func NewWebDavSource(cfg config.Thumbnail) WebDav { return WebDav{ - baseURL: cfg.BaseURL, - insecure: cfg.Insecure, + insecure: cfg.WebdavAllowInsecure, } } // WebDav implements the Source interface for webdav services type WebDav struct { - baseURL string insecure bool } // Get downloads the file from a webdav service func (s WebDav) Get(ctx context.Context, file string) (image.Image, error) { - u, _ := url.Parse(s.baseURL) - u.Path = path.Join(u.Path, file) - req, err := http.NewRequest(http.MethodGet, u.String(), nil) + req, err := http.NewRequest(http.MethodGet, file, nil) if err != nil { return nil, errors.Wrapf(err, `could not get the image "%s"`, file) } diff --git a/thumbnails/pkg/thumbnail/storage/filesystem.go b/thumbnails/pkg/thumbnail/storage/filesystem.go index 10cc05fc15..d1754a4d30 100644 --- a/thumbnails/pkg/thumbnail/storage/filesystem.go +++ b/thumbnails/pkg/thumbnail/storage/filesystem.go @@ -1,26 +1,20 @@ package storage import ( - "crypto/sha256" - "encoding/hex" - "io/ioutil" + "github.com/owncloud/ocis/ocis-pkg/log" + "github.com/owncloud/ocis/thumbnails/pkg/config" + "github.com/pkg/errors" "os" "path/filepath" "strconv" "strings" - "sync" - - "github.com/owncloud/ocis/ocis-pkg/log" - "github.com/owncloud/ocis/thumbnails/pkg/config" - "github.com/pkg/errors" ) const ( - usersDir = "users" filesDir = "files" ) -// NewFileSystemStorage creates a new instanz of FileSystem +// NewFileSystemStorage creates a new instance of FileSystem func NewFileSystemStorage(cfg config.FileSystemStorage, logger log.Logger) *FileSystem { return &FileSystem{ root: cfg.RootDirectory, @@ -32,32 +26,42 @@ func NewFileSystemStorage(cfg config.FileSystemStorage, logger log.Logger) *File type FileSystem struct { root string logger log.Logger - mux sync.Mutex } // Get loads the image from the file system. -func (s *FileSystem) Get(username string, key string) []byte { - userDir := s.userDir(username) - img := filepath.Join(userDir, key) - content, err := ioutil.ReadFile(img) +func (s *FileSystem) Get(key string) ([]byte, bool) { + img := filepath.Join(s.root, filesDir, key) + content, err := os.ReadFile(img) if err != nil { - s.logger.Debug().Str("err", err.Error()).Str("key", key).Msg("could not load thumbnail from store") - return nil + if !os.IsNotExist(err) { + s.logger.Debug().Str("err", err.Error()).Str("key", key).Msg("could not load thumbnail from store") + } + return nil, false } - return content + return content, true } // Set writes the image to the file system. -func (s *FileSystem) Set(username string, key string, img []byte) error { - _, err := s.storeImage(key, img) - if err != nil { - return errors.Wrap(err, "could not store image") +func (s *FileSystem) Put(key string, img []byte) error { + imgPath := filepath.Join(s.root, filesDir, key) + dir := filepath.Dir(imgPath) + if err := os.MkdirAll(dir, 0700); err != nil { + return errors.Wrapf(err, "error while creating directory %s", dir) } - userDir, err := s.createUserDir(username) - if err != nil { - return err + + if _, err := os.Stat(imgPath); os.IsNotExist(err) { + f, err := os.Create(imgPath) + if err != nil { + return errors.Wrapf(err, "could not create file \"%s\"", key) + } + defer f.Close() + + if _, err = f.Write(img); err != nil { + return errors.Wrapf(err, "could not write to file \"%s\"", key) + } } - return s.linkImageToUserDir(key, userDir) + + return nil } // BuildKey generate the unique key for a thumbnail. @@ -80,69 +84,3 @@ func (s *FileSystem) rootDir(key string) string { p := strings.Split(key, string(os.PathSeparator)) return p[0] } - -func (s *FileSystem) storeImage(key string, img []byte) (string, error) { - s.mux.Lock() - defer s.mux.Unlock() - imgPath := filepath.Join(s.root, filesDir, key) - dir := filepath.Dir(imgPath) - if err := os.MkdirAll(dir, 0700); err != nil { - return "", errors.Wrapf(err, "error while creating directory %s", dir) - } - - if _, err := os.Stat(imgPath); os.IsNotExist(err) { - f, err := os.Create(imgPath) - if err != nil { - return "", errors.Wrapf(err, "could not create file \"%s\"", key) - } - defer f.Close() - - _, err = f.Write(img) - if err != nil { - return "", errors.Wrapf(err, "could not write to file \"%s\"", key) - } - } - - return imgPath, nil -} - -// userDir returns the path to the user directory. -// The username is hashed before appending it on the path to prevent bugs caused by invalid folder names. -// Also the hash is then splitted up in three parts that results in a path which looks as follows: -// /users/<3 characters>/<3 characters>/<48 characters>/ -// This will balance the folders in setups with many users. -func (s *FileSystem) userDir(username string) string { - - hash := sha256.New224() - if _, err := hash.Write([]byte(username)); err != nil { - s.logger.Fatal().Err(err).Msg("failed to create hash") - } - unHash := hex.EncodeToString(hash.Sum(nil)) // 224 Bits or 224 / 4 = 56 characters. - - return filepath.Join(s.root, usersDir, unHash[:3], unHash[3:6], unHash[6:]) -} - -func (s *FileSystem) createUserDir(username string) (string, error) { - userDir := s.userDir(username) - if err := os.MkdirAll(userDir, 0700); err != nil { - return "", errors.Wrapf(err, "could not create userDir: %s", userDir) - } - - return userDir, nil -} - -// linkImageToUserDir links the stored images to the user directory. -// The goal is to minimize disk usage by linking to the images if they already exist and avoid file duplication. -func (s *FileSystem) linkImageToUserDir(key string, userDir string) error { - imgRootDir := s.rootDir(key) - - s.mux.Lock() - defer s.mux.Unlock() - err := os.Symlink(filepath.Join(s.root, filesDir, imgRootDir), filepath.Join(userDir, imgRootDir)) - if err != nil { - if !os.IsExist(err) { - return errors.Wrap(err, "could not link image to userdir") - } - } - return nil -} diff --git a/thumbnails/pkg/thumbnail/storage/inmemory.go b/thumbnails/pkg/thumbnail/storage/inmemory.go index 90afe95abd..74e5c3a9e0 100644 --- a/thumbnails/pkg/thumbnail/storage/inmemory.go +++ b/thumbnails/pkg/thumbnail/storage/inmemory.go @@ -7,31 +7,24 @@ import ( // NewInMemoryStorage creates a new InMemory instance. func NewInMemoryStorage() InMemory { return InMemory{ - store: make(map[string]map[string][]byte), + store: make(map[string][]byte), } } // InMemory represents an in memory storage for thumbnails // Can be used during development type InMemory struct { - store map[string]map[string][]byte + store map[string][]byte } // Get loads the thumbnail from memory. -func (s InMemory) Get(username string, key string) []byte { - userImages := s.store[username] - if userImages == nil { - return nil - } - return s.store[username][key] +func (s InMemory) Get(key string) ([]byte, bool) { + return s.store[key], true } // Set stores the thumbnail in memory. -func (s InMemory) Set(username string, key string, thumbnail []byte) error { - if _, ok := s.store[username]; !ok { - s.store[username] = make(map[string][]byte) - } - s.store[username][key] = thumbnail +func (s InMemory) Put(key string, thumbnail []byte) error { + s.store[key] = thumbnail return nil } diff --git a/thumbnails/pkg/thumbnail/storage/storage.go b/thumbnails/pkg/thumbnail/storage/storage.go index 1ec71cc761..ae01a0c6f5 100644 --- a/thumbnails/pkg/thumbnail/storage/storage.go +++ b/thumbnails/pkg/thumbnail/storage/storage.go @@ -13,7 +13,7 @@ type Request struct { // Storage defines the interface for a thumbnail store. type Storage interface { - Get(string, string) []byte - Set(string, string, []byte) error + Get(string) ([]byte, bool) + Put(string, []byte) error BuildKey(Request) string } diff --git a/thumbnails/pkg/thumbnail/thumbnail.go b/thumbnails/pkg/thumbnail/thumbnail.go index 1f12d4f56b..0cffa1eb03 100644 --- a/thumbnails/pkg/thumbnail/thumbnail.go +++ b/thumbnails/pkg/thumbnail/thumbnail.go @@ -2,11 +2,10 @@ package thumbnail import ( "bytes" - "image" - "github.com/owncloud/ocis/ocis-pkg/log" "github.com/owncloud/ocis/thumbnails/pkg/thumbnail/storage" "golang.org/x/image/draw" + "image" ) // Request bundles information needed to generate a thumbnail for afile @@ -14,16 +13,15 @@ type Request struct { Resolution image.Rectangle Encoder Encoder ETag string - Username string } // Manager is responsible for generating thumbnails type Manager interface { // Get will return a thumbnail for a file - Get(Request, image.Image) ([]byte, error) + Generate(Request, image.Image) ([]byte, error) // GetStored loads the thumbnail from the storage. // It will return nil if no image is stored for the given context. - GetStored(Request) []byte + Get(Request) ([]byte, bool) } // NewSimpleManager creates a new instance of SimpleManager @@ -43,31 +41,29 @@ type SimpleManager struct { } // Get implements the Get Method of Manager -func (s SimpleManager) Get(r Request, img image.Image) ([]byte, error) { +func (s SimpleManager) Generate(r Request, img image.Image) ([]byte, error) { match := s.resolutions.ClosestMatch(r.Resolution, img.Bounds()) thumbnail := s.generate(match, img) - key := s.storage.BuildKey(mapToStorageRequest(r)) - - buf := new(bytes.Buffer) - err := r.Encoder.Encode(buf, thumbnail) + dst := new(bytes.Buffer) + err := r.Encoder.Encode(dst, thumbnail) if err != nil { return nil, err } - bytes := buf.Bytes() - err = s.storage.Set(r.Username, key, bytes) + + key := s.storage.BuildKey(mapToStorageRequest(r)) + err = s.storage.Put(key, dst.Bytes()) if err != nil { s.logger.Warn().Err(err).Msg("could not store thumbnail") } - return bytes, nil + return dst.Bytes(), nil } // GetStored tries to get the stored thumbnail and return it. // If there is no cached thumbnail it will return nil -func (s SimpleManager) GetStored(r Request) []byte { +func (s SimpleManager) Get(r Request) ([]byte, bool) { key := s.storage.BuildKey(mapToStorageRequest(r)) - stored := s.storage.Get(r.Username, key) - return stored + return s.storage.Get(key) } func (s SimpleManager) generate(r image.Rectangle, img image.Image) image.Image { diff --git a/webdav/pkg/service/v0/service.go b/webdav/pkg/service/v0/service.go index 854c777c1c..7aa10cb320 100644 --- a/webdav/pkg/service/v0/service.go +++ b/webdav/pkg/service/v0/service.go @@ -1,6 +1,8 @@ package svc import ( + "github.com/asim/go-micro/v3/metadata" + "github.com/cs3org/reva/pkg/token" "io" "net/http" "strings" @@ -35,6 +37,7 @@ func NewService(opts ...Option) Service { m.Route(options.Config.HTTP.Root, func(r chi.Router) { r.Get("/remote.php/dav/files/{user}/*", svc.Thumbnail) + r.Get("/remote.php/dav/public-files/{token}/*", svc.Thumbnail) }) return svc @@ -62,15 +65,22 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) { return } + t := r.Header.Get("X-Access-Token") + md := make(metadata.Metadata) + md.Set(token.TokenHeader, t) + ctx := metadata.NewContext(r.Context(), md) + c := thumbnails.NewThumbnailService("com.owncloud.api.thumbnails", grpc.DefaultClient) - rsp, err := c.GetThumbnail(r.Context(), &thumbnails.GetRequest{ + rsp, err := c.GetThumbnail(ctx, &thumbnails.GetThumbnailRequest{ Filepath: strings.TrimLeft(tr.Filepath, "/"), - Filetype: extensionToFiletype(strings.TrimLeft(tr.Extension, ".")), - Etag: tr.Etag, + ThumbnailType: extensionToFiletype(strings.TrimLeft(tr.Extension, ".")), Width: int32(tr.Width), Height: int32(tr.Height), - Authorization: tr.Authorization, - Username: tr.Username, + Source: &thumbnails.GetThumbnailRequest_Cs3Source{ + Cs3Source: &thumbnails.CS3Source{ + Path: "/home" + tr.Filepath, + }, + }, }) if err != nil { g.log.Error().Err(err).Msg("could not get thumbnail") @@ -89,17 +99,17 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) { mustWrite(g.log, w, rsp.Thumbnail) } -func extensionToFiletype(ext string) thumbnails.GetRequest_FileType { +func extensionToFiletype(ext string) thumbnails.GetThumbnailRequest_FileType { ext = strings.ToUpper(ext) switch ext { case "JPG", "PNG": - val := thumbnails.GetRequest_FileType_value[ext] - return thumbnails.GetRequest_FileType(val) + val := thumbnails.GetThumbnailRequest_FileType_value[ext] + return thumbnails.GetThumbnailRequest_FileType(val) case "JPEG", "GIF": - val := thumbnails.GetRequest_FileType_value["JPG"] - return thumbnails.GetRequest_FileType(val) + val := thumbnails.GetThumbnailRequest_FileType_value["JPG"] + return thumbnails.GetThumbnailRequest_FileType(val) default: - return thumbnails.GetRequest_FileType(-1) + return thumbnails.GetThumbnailRequest_FileType(-1) } }