mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
rewrite thumbnails API
Improved the thumbnails API so that the binary files won't be transported via GRPC. GRPC has a limited message size and isn't very effiefficient with large binary data.
This commit is contained in:
7
changelog/unreleased/thumbnails-api.md
Normal file
7
changelog/unreleased/thumbnails-api.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Enhancement: Improve thumbnails API
|
||||
|
||||
Changed the thumbnails API to no longer transfer images via GRPC.
|
||||
GRPC has a limited message size and isn't very efficient with large binary data.
|
||||
The new API transports the images over HTTP.
|
||||
|
||||
https://github.com/owncloud/ocis/pull/3272
|
||||
@@ -20,6 +20,56 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The file types to which the thumbnail can be encoded to.
|
||||
type ThumbnailType int32
|
||||
|
||||
const (
|
||||
ThumbnailType_PNG ThumbnailType = 0 // Represents PNG type
|
||||
ThumbnailType_JPG ThumbnailType = 1 // Represents JPG type
|
||||
ThumbnailType_GIF ThumbnailType = 2 // Represents GIF type
|
||||
)
|
||||
|
||||
// Enum value maps for ThumbnailType.
|
||||
var (
|
||||
ThumbnailType_name = map[int32]string{
|
||||
0: "PNG",
|
||||
1: "JPG",
|
||||
2: "GIF",
|
||||
}
|
||||
ThumbnailType_value = map[string]int32{
|
||||
"PNG": 0,
|
||||
"JPG": 1,
|
||||
"GIF": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ThumbnailType) Enum() *ThumbnailType {
|
||||
p := new(ThumbnailType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ThumbnailType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ThumbnailType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_ocis_messages_thumbnails_v0_thumbnails_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (ThumbnailType) Type() protoreflect.EnumType {
|
||||
return &file_ocis_messages_thumbnails_v0_thumbnails_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x ThumbnailType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ThumbnailType.Descriptor instead.
|
||||
func (ThumbnailType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_ocis_messages_thumbnails_v0_thumbnails_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type WebdavSource struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -184,12 +234,15 @@ var file_ocis_messages_thumbnails_v0_thumbnails_proto_rawDesc = []byte{
|
||||
0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70,
|
||||
0x61, 0x74, 0x68, 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, 0x42, 0x43, 0x5a, 0x41, 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, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67,
|
||||
0x65, 0x6e, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73,
|
||||
0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2f, 0x76, 0x30, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x2a, 0x0a, 0x0d, 0x54, 0x68, 0x75,
|
||||
0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4e,
|
||||
0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4a, 0x50, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03,
|
||||
0x47, 0x49, 0x46, 0x10, 0x02, 0x42, 0x43, 0x5a, 0x41, 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, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f,
|
||||
0x63, 0x69, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x74, 0x68, 0x75,
|
||||
0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x2f, 0x76, 0x30, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -204,10 +257,12 @@ func file_ocis_messages_thumbnails_v0_thumbnails_proto_rawDescGZIP() []byte {
|
||||
return file_ocis_messages_thumbnails_v0_thumbnails_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_ocis_messages_thumbnails_v0_thumbnails_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_ocis_messages_thumbnails_v0_thumbnails_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_ocis_messages_thumbnails_v0_thumbnails_proto_goTypes = []interface{}{
|
||||
(*WebdavSource)(nil), // 0: ocis.messages.thumbnails.v0.WebdavSource
|
||||
(*CS3Source)(nil), // 1: ocis.messages.thumbnails.v0.CS3Source
|
||||
(ThumbnailType)(0), // 0: ocis.messages.thumbnails.v0.ThumbnailType
|
||||
(*WebdavSource)(nil), // 1: ocis.messages.thumbnails.v0.WebdavSource
|
||||
(*CS3Source)(nil), // 2: ocis.messages.thumbnails.v0.CS3Source
|
||||
}
|
||||
var file_ocis_messages_thumbnails_v0_thumbnails_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
@@ -253,13 +308,14 @@ func file_ocis_messages_thumbnails_v0_thumbnails_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_ocis_messages_thumbnails_v0_thumbnails_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumEnums: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_ocis_messages_thumbnails_v0_thumbnails_proto_goTypes,
|
||||
DependencyIndexes: file_ocis_messages_thumbnails_v0_thumbnails_proto_depIdxs,
|
||||
EnumInfos: file_ocis_messages_thumbnails_v0_thumbnails_proto_enumTypes,
|
||||
MessageInfos: file_ocis_messages_thumbnails_v0_thumbnails_proto_msgTypes,
|
||||
}.Build()
|
||||
File_ocis_messages_thumbnails_v0_thumbnails_proto = out.File
|
||||
|
||||
@@ -22,56 +22,6 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The file types to which the thumbnail can get encoded to.
|
||||
type GetThumbnailRequest_ThumbnailType int32
|
||||
|
||||
const (
|
||||
GetThumbnailRequest_PNG GetThumbnailRequest_ThumbnailType = 0 // Represents PNG type
|
||||
GetThumbnailRequest_JPG GetThumbnailRequest_ThumbnailType = 1 // Represents JPG type
|
||||
GetThumbnailRequest_GIF GetThumbnailRequest_ThumbnailType = 2 // Represents GIF type
|
||||
)
|
||||
|
||||
// Enum value maps for GetThumbnailRequest_ThumbnailType.
|
||||
var (
|
||||
GetThumbnailRequest_ThumbnailType_name = map[int32]string{
|
||||
0: "PNG",
|
||||
1: "JPG",
|
||||
2: "GIF",
|
||||
}
|
||||
GetThumbnailRequest_ThumbnailType_value = map[string]int32{
|
||||
"PNG": 0,
|
||||
"JPG": 1,
|
||||
"GIF": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x GetThumbnailRequest_ThumbnailType) Enum() *GetThumbnailRequest_ThumbnailType {
|
||||
p := new(GetThumbnailRequest_ThumbnailType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x GetThumbnailRequest_ThumbnailType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (GetThumbnailRequest_ThumbnailType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_ocis_services_thumbnails_v0_thumbnails_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (GetThumbnailRequest_ThumbnailType) Type() protoreflect.EnumType {
|
||||
return &file_ocis_services_thumbnails_v0_thumbnails_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x GetThumbnailRequest_ThumbnailType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetThumbnailRequest_ThumbnailType.Descriptor instead.
|
||||
func (GetThumbnailRequest_ThumbnailType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_ocis_services_thumbnails_v0_thumbnails_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
// A request to retrieve a thumbnail
|
||||
type GetThumbnailRequest struct {
|
||||
state protoimpl.MessageState
|
||||
@@ -81,7 +31,7 @@ type GetThumbnailRequest 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.
|
||||
ThumbnailType GetThumbnailRequest_ThumbnailType `protobuf:"varint,2,opt,name=thumbnail_type,json=thumbnailType,proto3,enum=ocis.services.thumbnails.v0.GetThumbnailRequest_ThumbnailType" json:"thumbnail_type,omitempty"`
|
||||
ThumbnailType v0.ThumbnailType `protobuf:"varint,2,opt,name=thumbnail_type,json=thumbnailType,proto3,enum=ocis.messages.thumbnails.v0.ThumbnailType" json:"thumbnail_type,omitempty"`
|
||||
// The width of the thumbnail
|
||||
Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"`
|
||||
// The height of the thumbnail
|
||||
@@ -131,11 +81,11 @@ func (x *GetThumbnailRequest) GetFilepath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetThumbnailRequest) GetThumbnailType() GetThumbnailRequest_ThumbnailType {
|
||||
func (x *GetThumbnailRequest) GetThumbnailType() v0.ThumbnailType {
|
||||
if x != nil {
|
||||
return x.ThumbnailType
|
||||
}
|
||||
return GetThumbnailRequest_PNG
|
||||
return v0.ThumbnailType(0)
|
||||
}
|
||||
|
||||
func (x *GetThumbnailRequest) GetWidth() int32 {
|
||||
@@ -195,10 +145,12 @@ type GetThumbnailResponse struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The thumbnail as a binary
|
||||
Thumbnail []byte `protobuf:"bytes,1,opt,name=thumbnail,proto3" json:"thumbnail,omitempty"`
|
||||
// The endpoint where the thumbnail can be downloaded.
|
||||
DataEndpoint string `protobuf:"bytes,1,opt,name=data_endpoint,json=dataEndpoint,proto3" json:"data_endpoint,omitempty"`
|
||||
// The transfer token to be able to download the thumbnail.
|
||||
TransferToken string `protobuf:"bytes,2,opt,name=transfer_token,json=transferToken,proto3" json:"transfer_token,omitempty"`
|
||||
// The mimetype of the thumbnail
|
||||
Mimetype string `protobuf:"bytes,2,opt,name=mimetype,proto3" json:"mimetype,omitempty"`
|
||||
Mimetype string `protobuf:"bytes,3,opt,name=mimetype,proto3" json:"mimetype,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetThumbnailResponse) Reset() {
|
||||
@@ -233,11 +185,18 @@ func (*GetThumbnailResponse) Descriptor() ([]byte, []int) {
|
||||
return file_ocis_services_thumbnails_v0_thumbnails_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *GetThumbnailResponse) GetThumbnail() []byte {
|
||||
func (x *GetThumbnailResponse) GetDataEndpoint() string {
|
||||
if x != nil {
|
||||
return x.Thumbnail
|
||||
return x.DataEndpoint
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetThumbnailResponse) GetTransferToken() string {
|
||||
if x != nil {
|
||||
return x.TransferToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetThumbnailResponse) GetMimetype() string {
|
||||
@@ -260,70 +219,69 @@ var file_ocis_services_thumbnails_v0_thumbnails_proto_rawDesc = []byte{
|
||||
0x69, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 0x97, 0x03, 0x0a, 0x13, 0x47, 0x65,
|
||||
0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd7, 0x02, 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, 0x65, 0x0a,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x51, 0x0a,
|
||||
0x0e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 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, 0x2e, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69,
|
||||
0x6c, 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, 0x50, 0x0a, 0x0d, 0x77, 0x65, 0x62, 0x64, 0x61, 0x76, 0x5f, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x63, 0x69, 0x73,
|
||||
0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 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, 0x47, 0x0a, 0x0a, 0x63, 0x73, 0x33, 0x5f, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e,
|
||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 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, 0x2a, 0x0a,
|
||||
0x0d, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07,
|
||||
0x0a, 0x03, 0x50, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4a, 0x50, 0x47, 0x10, 0x01,
|
||||
0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x02, 0x42, 0x08, 0x0a, 0x06, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 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, 0x87, 0x01, 0x0a, 0x10, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e,
|
||||
0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0c, 0x47, 0x65,
|
||||
0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x30, 0x2e, 0x6f, 0x63, 0x69,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73,
|
||||
0x2e, 0x76, 0x30, 0x2e, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 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, 0x50,
|
||||
0x0a, 0x0d, 0x77, 0x65, 0x62, 0x64, 0x61, 0x76, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 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, 0x47, 0x0a, 0x0a, 0x63, 0x73, 0x33, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 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, 0x42, 0x08, 0x0a, 0x06, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x22, 0x7e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e,
|
||||
0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x64,
|
||||
0x61, 0x74, 0x61, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66,
|
||||
0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x74,
|
||||
0x79, 0x70, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x10, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69,
|
||||
0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54,
|
||||
0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x30, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 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, 0x31, 0x2e, 0x6f, 0x63, 0x69,
|
||||
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 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, 0x31, 0x2e, 0x6f,
|
||||
0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 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, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
|
||||
0xeb, 0x02, 0x5a, 0x41, 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, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69,
|
||||
0x6c, 0x73, 0x2f, 0x76, 0x30, 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,
|
||||
0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xeb, 0x02,
|
||||
0x5a, 0x41, 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, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73,
|
||||
0x2f, 0x76, 0x30, 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 (
|
||||
@@ -338,21 +296,20 @@ func file_ocis_services_thumbnails_v0_thumbnails_proto_rawDescGZIP() []byte {
|
||||
return file_ocis_services_thumbnails_v0_thumbnails_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_ocis_services_thumbnails_v0_thumbnails_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_ocis_services_thumbnails_v0_thumbnails_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_ocis_services_thumbnails_v0_thumbnails_proto_goTypes = []interface{}{
|
||||
(GetThumbnailRequest_ThumbnailType)(0), // 0: ocis.services.thumbnails.v0.GetThumbnailRequest.ThumbnailType
|
||||
(*GetThumbnailRequest)(nil), // 1: ocis.services.thumbnails.v0.GetThumbnailRequest
|
||||
(*GetThumbnailResponse)(nil), // 2: ocis.services.thumbnails.v0.GetThumbnailResponse
|
||||
(*v0.WebdavSource)(nil), // 3: ocis.messages.thumbnails.v0.WebdavSource
|
||||
(*v0.CS3Source)(nil), // 4: ocis.messages.thumbnails.v0.CS3Source
|
||||
(*GetThumbnailRequest)(nil), // 0: ocis.services.thumbnails.v0.GetThumbnailRequest
|
||||
(*GetThumbnailResponse)(nil), // 1: ocis.services.thumbnails.v0.GetThumbnailResponse
|
||||
(v0.ThumbnailType)(0), // 2: ocis.messages.thumbnails.v0.ThumbnailType
|
||||
(*v0.WebdavSource)(nil), // 3: ocis.messages.thumbnails.v0.WebdavSource
|
||||
(*v0.CS3Source)(nil), // 4: ocis.messages.thumbnails.v0.CS3Source
|
||||
}
|
||||
var file_ocis_services_thumbnails_v0_thumbnails_proto_depIdxs = []int32{
|
||||
0, // 0: ocis.services.thumbnails.v0.GetThumbnailRequest.thumbnail_type:type_name -> ocis.services.thumbnails.v0.GetThumbnailRequest.ThumbnailType
|
||||
2, // 0: ocis.services.thumbnails.v0.GetThumbnailRequest.thumbnail_type:type_name -> ocis.messages.thumbnails.v0.ThumbnailType
|
||||
3, // 1: ocis.services.thumbnails.v0.GetThumbnailRequest.webdav_source:type_name -> ocis.messages.thumbnails.v0.WebdavSource
|
||||
4, // 2: ocis.services.thumbnails.v0.GetThumbnailRequest.cs3_source:type_name -> ocis.messages.thumbnails.v0.CS3Source
|
||||
1, // 3: ocis.services.thumbnails.v0.ThumbnailService.GetThumbnail:input_type -> ocis.services.thumbnails.v0.GetThumbnailRequest
|
||||
2, // 4: ocis.services.thumbnails.v0.ThumbnailService.GetThumbnail:output_type -> ocis.services.thumbnails.v0.GetThumbnailResponse
|
||||
0, // 3: ocis.services.thumbnails.v0.ThumbnailService.GetThumbnail:input_type -> ocis.services.thumbnails.v0.GetThumbnailRequest
|
||||
1, // 4: ocis.services.thumbnails.v0.ThumbnailService.GetThumbnail:output_type -> ocis.services.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
|
||||
@@ -400,14 +357,13 @@ func file_ocis_services_thumbnails_v0_thumbnails_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_ocis_services_thumbnails_v0_thumbnails_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_ocis_services_thumbnails_v0_thumbnails_proto_goTypes,
|
||||
DependencyIndexes: file_ocis_services_thumbnails_v0_thumbnails_proto_depIdxs,
|
||||
EnumInfos: file_ocis_services_thumbnails_v0_thumbnails_proto_enumTypes,
|
||||
MessageInfos: file_ocis_services_thumbnails_v0_thumbnails_proto_msgTypes,
|
||||
}.Build()
|
||||
File_ocis_services_thumbnails_v0_thumbnails_proto = out.File
|
||||
|
||||
@@ -30,16 +30,6 @@
|
||||
],
|
||||
"paths": {},
|
||||
"definitions": {
|
||||
"GetThumbnailRequestThumbnailType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"PNG",
|
||||
"JPG",
|
||||
"GIF"
|
||||
],
|
||||
"default": "PNG",
|
||||
"description": "The file types to which the thumbnail can get encoded to."
|
||||
},
|
||||
"protobufAny": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -81,10 +71,13 @@
|
||||
"v0GetThumbnailResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"thumbnail": {
|
||||
"dataEndpoint": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"title": "The thumbnail as a binary"
|
||||
"description": "The endpoint where the thumbnail can be downloaded."
|
||||
},
|
||||
"transferToken": {
|
||||
"type": "string",
|
||||
"description": "The transfer token to be able to download the thumbnail."
|
||||
},
|
||||
"mimetype": {
|
||||
"type": "string",
|
||||
@@ -93,6 +86,16 @@
|
||||
},
|
||||
"title": "The service response"
|
||||
},
|
||||
"v0ThumbnailType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"PNG",
|
||||
"JPG",
|
||||
"GIF"
|
||||
],
|
||||
"default": "PNG",
|
||||
"description": "The file types to which the thumbnail can be encoded to."
|
||||
},
|
||||
"v0WebdavSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -21,3 +21,10 @@ message CS3Source {
|
||||
string path = 1;
|
||||
string authorization = 2;
|
||||
}
|
||||
|
||||
// The file types to which the thumbnail can be encoded to.
|
||||
enum ThumbnailType {
|
||||
PNG = 0; // Represents PNG type
|
||||
JPG = 1; // Represents JPG type
|
||||
GIF = 2; // Represents GIF type
|
||||
}
|
||||
@@ -41,14 +41,8 @@ service ThumbnailService {
|
||||
message GetThumbnailRequest {
|
||||
// The path to the source image
|
||||
string filepath = 1;
|
||||
// The file types to which the thumbnail can get encoded to.
|
||||
enum ThumbnailType {
|
||||
PNG = 0; // Represents PNG type
|
||||
JPG = 1; // Represents JPG type
|
||||
GIF = 2; // Represents GIF type
|
||||
}
|
||||
// The type to which the thumbnail should get encoded to.
|
||||
ThumbnailType thumbnail_type = 2;
|
||||
ocis.messages.thumbnails.v0.ThumbnailType thumbnail_type = 2;
|
||||
// The width of the thumbnail
|
||||
int32 width = 3;
|
||||
// The height of the thumbnail
|
||||
@@ -61,8 +55,10 @@ message GetThumbnailRequest {
|
||||
|
||||
// The service response
|
||||
message GetThumbnailResponse {
|
||||
// The thumbnail as a binary
|
||||
bytes thumbnail = 1;
|
||||
// The endpoint where the thumbnail can be downloaded.
|
||||
string data_endpoint = 1;
|
||||
// The transfer token to be able to download the thumbnail.
|
||||
string transfer_token = 2;
|
||||
// The mimetype of the thumbnail
|
||||
string mimetype = 2;
|
||||
string mimetype = 3;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/metrics"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/server/debug"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/server/grpc"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/server/http"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/tracing"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -57,9 +58,7 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
grpc.Metrics(metrics),
|
||||
)
|
||||
|
||||
gr.Add(func() error {
|
||||
return service.Run()
|
||||
}, func(_ error) {
|
||||
gr.Add(service.Run, func(_ error) {
|
||||
fmt.Println("shutting down grpc server")
|
||||
cancel()
|
||||
})
|
||||
@@ -79,6 +78,28 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
cancel()
|
||||
})
|
||||
|
||||
httpServer, err := http.Server(
|
||||
http.Logger(logger),
|
||||
http.Context(ctx),
|
||||
http.Config(cfg),
|
||||
http.Metrics(metrics),
|
||||
http.Namespace(cfg.HTTP.Namespace),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Info().
|
||||
Err(err).
|
||||
Str("transport", "http").
|
||||
Msg("Failed to initialize server")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(httpServer.Run, func(_ error) {
|
||||
logger.Info().Str("server", "http").Msg("shutting down server")
|
||||
cancel()
|
||||
})
|
||||
|
||||
return gr.Run()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type Config struct {
|
||||
Debug Debug `ocisConfig:"debug"`
|
||||
|
||||
GRPC GRPC `ocisConfig:"grpc"`
|
||||
HTTP HTTP `ocisConfig:"http"`
|
||||
|
||||
Thumbnail Thumbnail `ocisConfig:"thumbnail"`
|
||||
|
||||
@@ -41,4 +42,6 @@ type Thumbnail struct {
|
||||
CS3AllowInsecure bool `ocisConfig:"cs3_allow_insecure" env:"OCIS_INSECURE;THUMBNAILS_CS3SOURCE_INSECURE"`
|
||||
RevaGateway string `ocisConfig:"reva_gateway" env:"REVA_GATEWAY"` //TODO: use REVA config
|
||||
FontMapFile string `ocisConfig:"font_map_file" env:"THUMBNAILS_TXT_FONTMAP_FILE"`
|
||||
TransferTokenSecret string `ocisConfig:"transfer_token" env:"THUMBNAILS_TRANSFER_TOKEN"`
|
||||
DataEndpoint string `ocisConfig:"data_endpoint" env:"THUMBNAILS_DATA_ENDPOINT"`
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ func DefaultConfig() *Config {
|
||||
Addr: "127.0.0.1:9185",
|
||||
Namespace: "com.owncloud.api",
|
||||
},
|
||||
HTTP: HTTP{
|
||||
Addr: "127.0.0.1:9186",
|
||||
Root: "/thumbnails",
|
||||
Namespace: "com.owncloud.web",
|
||||
},
|
||||
Service: Service{
|
||||
Name: "thumbnails",
|
||||
},
|
||||
@@ -29,6 +34,8 @@ func DefaultConfig() *Config {
|
||||
WebdavAllowInsecure: true,
|
||||
RevaGateway: "127.0.0.1:9142",
|
||||
CS3AllowInsecure: false,
|
||||
TransferTokenSecret: "changemeplease",
|
||||
DataEndpoint: "http://127.0.0.1:9186/thumbnails/data",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
8
thumbnails/pkg/config/http.go
Normal file
8
thumbnails/pkg/config/http.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
// HTTP defines the available http configuration.
|
||||
type HTTP struct {
|
||||
Addr string `ocisConfig:"addr" env:"THUMBNAILS_HTTP_ADDR"`
|
||||
Root string `ocisConfig:"root" env:"THUMBNAILS_HTTP_ROOT"`
|
||||
Namespace string
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
|
||||
"github.com/owncloud/ocis/ocis-pkg/version"
|
||||
thumbnailssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/thumbnails/v0"
|
||||
svc "github.com/owncloud/ocis/thumbnails/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/service/v0/decorators"
|
||||
svc "github.com/owncloud/ocis/thumbnails/pkg/service/grpc/v0"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/service/grpc/v0/decorators"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/imgsource"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/storage"
|
||||
)
|
||||
|
||||
69
thumbnails/pkg/server/http/option.go
Normal file
69
thumbnails/pkg/server/http/option.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/config"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/metrics"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Namespace string
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
Metrics *metrics.Metrics
|
||||
Flags []cli.Flag
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
// Logger provides a function to set the logger option.
|
||||
func Logger(val log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = val
|
||||
}
|
||||
}
|
||||
|
||||
// Context provides a function to set the context option.
|
||||
func Context(val context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = val
|
||||
}
|
||||
}
|
||||
|
||||
// Config provides a function to set the config option.
|
||||
func Config(val *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
|
||||
// Metrics provides a function to set the metrics option.
|
||||
func Metrics(val *metrics.Metrics) Option {
|
||||
return func(o *Options) {
|
||||
o.Metrics = val
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace provides a function to set the Namespace option.
|
||||
func Namespace(val string) Option {
|
||||
return func(o *Options) {
|
||||
o.Namespace = val
|
||||
}
|
||||
}
|
||||
58
thumbnails/pkg/server/http/server.go
Normal file
58
thumbnails/pkg/server/http/server.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
ocismiddleware "github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/ocis-pkg/version"
|
||||
svc "github.com/owncloud/ocis/thumbnails/pkg/service/http/v0"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/storage"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
// Server initializes the http service and server.
|
||||
func Server(opts ...Option) (http.Service, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
service := http.NewService(
|
||||
http.Logger(options.Logger),
|
||||
http.Name(options.Config.Service.Name),
|
||||
http.Version(version.String),
|
||||
http.Namespace(options.Config.HTTP.Namespace),
|
||||
http.Address(options.Config.HTTP.Addr),
|
||||
http.Context(options.Context),
|
||||
)
|
||||
|
||||
handle := svc.NewService(
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(
|
||||
middleware.RealIP,
|
||||
middleware.RequestID,
|
||||
// ocismiddleware.Secure,
|
||||
ocismiddleware.Version(
|
||||
options.Config.Service.Name,
|
||||
version.String,
|
||||
),
|
||||
ocismiddleware.Logger(options.Logger),
|
||||
),
|
||||
svc.ThumbnailStorage(
|
||||
storage.NewFileSystemStorage(
|
||||
options.Config.Thumbnail.FileSystemStorage,
|
||||
options.Logger,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
{
|
||||
handle = svc.NewInstrument(handle, options.Metrics)
|
||||
handle = svc.NewLogging(handle, options.Logger)
|
||||
handle = svc.NewTracing(handle)
|
||||
}
|
||||
|
||||
if err := micro.RegisterHandler(service.Server(), handle); err != nil {
|
||||
return http.Service{}, err
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
||||
@@ -6,15 +6,19 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
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"
|
||||
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
thumbnailsmsg "github.com/owncloud/ocis/protogen/gen/ocis/messages/thumbnails/v0"
|
||||
thumbnailssvc "github.com/owncloud/ocis/protogen/gen/ocis/services/thumbnails/v0"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/preprocessor"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/service/v0/decorators"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/service/grpc/v0/decorators"
|
||||
tjwt "github.com/owncloud/ocis/thumbnails/pkg/service/jwt"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/imgsource"
|
||||
"github.com/pkg/errors"
|
||||
@@ -44,6 +48,8 @@ func NewService(opts ...Option) decorators.DecoratedService {
|
||||
preprocessorOpts: PreprocessorOpts{
|
||||
TxtFontFileMap: options.Config.Thumbnail.FontMapFile,
|
||||
},
|
||||
dataEndpoint: options.Config.Thumbnail.DataEndpoint,
|
||||
transferTokenSecret: options.Config.Thumbnail.TransferTokenSecret,
|
||||
}
|
||||
|
||||
return svc
|
||||
@@ -51,13 +57,15 @@ func NewService(opts ...Option) decorators.DecoratedService {
|
||||
|
||||
// Thumbnail implements the GRPC handler.
|
||||
type Thumbnail struct {
|
||||
serviceID string
|
||||
manager thumbnail.Manager
|
||||
webdavSource imgsource.Source
|
||||
cs3Source imgsource.Source
|
||||
logger log.Logger
|
||||
cs3Client gateway.GatewayAPIClient
|
||||
preprocessorOpts PreprocessorOpts
|
||||
serviceID string
|
||||
dataEndpoint string
|
||||
transferTokenSecret string
|
||||
manager thumbnail.Manager
|
||||
webdavSource imgsource.Source
|
||||
cs3Source imgsource.Source
|
||||
logger log.Logger
|
||||
cs3Client gateway.GatewayAPIClient
|
||||
preprocessorOpts PreprocessorOpts
|
||||
}
|
||||
|
||||
type PreprocessorOpts struct {
|
||||
@@ -66,28 +74,28 @@ type PreprocessorOpts struct {
|
||||
|
||||
// GetThumbnail retrieves a thumbnail for an image
|
||||
func (g Thumbnail) GetThumbnail(ctx context.Context, req *thumbnailssvc.GetThumbnailRequest, rsp *thumbnailssvc.GetThumbnailResponse) error {
|
||||
_, ok := thumbnailssvc.GetThumbnailRequest_ThumbnailType_value[req.ThumbnailType.String()]
|
||||
tType, ok := thumbnailsmsg.ThumbnailType_name[int32(req.ThumbnailType)]
|
||||
if !ok {
|
||||
g.logger.Debug().Str("thumbnail_type", req.ThumbnailType.String()).Msg("unsupported thumbnail type")
|
||||
g.logger.Debug().Str("thumbnail_type", tType).Msg("unsupported thumbnail type")
|
||||
return nil
|
||||
}
|
||||
generator, err := thumbnail.GeneratorForType(req.ThumbnailType.String())
|
||||
generator, err := thumbnail.GeneratorForType(tType)
|
||||
if err != nil {
|
||||
g.logger.Debug().Str("thumbnail_type", req.ThumbnailType.String()).Msg("unsupported thumbnail type")
|
||||
g.logger.Debug().Str("thumbnail_type", tType).Msg("unsupported thumbnail type")
|
||||
return nil
|
||||
}
|
||||
encoder, err := thumbnail.EncoderForType(req.ThumbnailType.String())
|
||||
encoder, err := thumbnail.EncoderForType(tType)
|
||||
if err != nil {
|
||||
g.logger.Debug().Str("thumbnail_type", req.ThumbnailType.String()).Msg("unsupported thumbnail type")
|
||||
g.logger.Debug().Str("thumbnail_type", tType).Msg("unsupported thumbnail type")
|
||||
return nil
|
||||
}
|
||||
|
||||
var thumb []byte
|
||||
var key string
|
||||
switch {
|
||||
case req.GetWebdavSource() != nil:
|
||||
thumb, err = g.handleWebdavSource(ctx, req, generator, encoder)
|
||||
key, err = g.handleWebdavSource(ctx, req, generator, encoder)
|
||||
case req.GetCs3Source() != nil:
|
||||
thumb, err = g.handleCS3Source(ctx, req, generator, encoder)
|
||||
key, err = g.handleCS3Source(ctx, req, generator, encoder)
|
||||
default:
|
||||
g.logger.Error().Msg("no image source provided")
|
||||
return merrors.BadRequest(g.serviceID, "image source is missing")
|
||||
@@ -96,16 +104,36 @@ func (g Thumbnail) GetThumbnail(ctx context.Context, req *thumbnailssvc.GetThumb
|
||||
return err
|
||||
}
|
||||
|
||||
rsp.Thumbnail = thumb
|
||||
claims := tjwt.ThumbnailClaims{
|
||||
Key: key,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Minute)),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
transferToken, err := token.SignedString([]byte(g.transferTokenSecret))
|
||||
if err != nil {
|
||||
g.logger.Error().
|
||||
Err(err).
|
||||
Msg("GetThumbnail: failed to sign token")
|
||||
return merrors.InternalServerError(g.serviceID, "couldn't finish request")
|
||||
}
|
||||
rsp.DataEndpoint = g.dataEndpoint
|
||||
rsp.TransferToken = transferToken
|
||||
rsp.Mimetype = encoder.MimeType()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g Thumbnail) handleCS3Source(ctx context.Context, req *thumbnailssvc.GetThumbnailRequest, generator thumbnail.Generator, encoder thumbnail.Encoder) ([]byte, error) {
|
||||
func (g Thumbnail) handleCS3Source(ctx context.Context,
|
||||
req *thumbnailssvc.GetThumbnailRequest,
|
||||
generator thumbnail.Generator,
|
||||
encoder thumbnail.Encoder) (string, error) {
|
||||
src := req.GetCs3Source()
|
||||
sRes, err := g.stat(src.Path, src.Authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
tr := thumbnail.Request{
|
||||
@@ -115,15 +143,14 @@ func (g Thumbnail) handleCS3Source(ctx context.Context, req *thumbnailssvc.GetTh
|
||||
Checksum: sRes.GetInfo().GetChecksum().GetSum(),
|
||||
}
|
||||
|
||||
thumb, ok := g.manager.Get(tr)
|
||||
if ok {
|
||||
return thumb, nil
|
||||
if key, exists := g.manager.CheckThumbnail(tr); exists {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
ctx = imgsource.ContextSetAuthorization(ctx, src.Authorization)
|
||||
r, err := g.cs3Source.Get(ctx, src.Path)
|
||||
if err != nil {
|
||||
return nil, merrors.InternalServerError(g.serviceID, "could not get image from source: %s", err.Error())
|
||||
return "", merrors.InternalServerError(g.serviceID, "could not get image from source: %s", err.Error())
|
||||
}
|
||||
defer r.Close() // nolint:errcheck
|
||||
ppOpts := map[string]interface{}{
|
||||
@@ -132,20 +159,24 @@ func (g Thumbnail) handleCS3Source(ctx context.Context, req *thumbnailssvc.GetTh
|
||||
pp := preprocessor.ForType(sRes.GetInfo().GetMimeType(), ppOpts)
|
||||
img, err := pp.Convert(r)
|
||||
if img == nil || err != nil {
|
||||
return nil, merrors.InternalServerError(g.serviceID, "could not get image")
|
||||
}
|
||||
if thumb, err = g.manager.Generate(tr, img); err != nil {
|
||||
return nil, err
|
||||
return "", merrors.InternalServerError(g.serviceID, "could not get image")
|
||||
}
|
||||
|
||||
return thumb, nil
|
||||
key, err := g.manager.Generate(tr, img)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.GetThumbnailRequest, generator thumbnail.Generator, encoder thumbnail.Encoder) ([]byte, error) {
|
||||
func (g Thumbnail) handleWebdavSource(ctx context.Context,
|
||||
req *thumbnailssvc.GetThumbnailRequest,
|
||||
generator thumbnail.Generator,
|
||||
encoder thumbnail.Encoder) (string, error) {
|
||||
src := req.GetWebdavSource()
|
||||
imgURL, err := url.Parse(src.Url)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "source url is invalid")
|
||||
return "", errors.Wrap(err, "source url is invalid")
|
||||
}
|
||||
|
||||
var auth, statPath string
|
||||
@@ -173,7 +204,7 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, merrors.InternalServerError(g.serviceID, "could not authenticate: %s", err.Error())
|
||||
return "", merrors.InternalServerError(g.serviceID, "could not authenticate: %s", err.Error())
|
||||
}
|
||||
auth = rsp.Token
|
||||
statPath = path.Join("/public", src.PublicLinkToken, req.Filepath)
|
||||
@@ -183,7 +214,7 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
}
|
||||
sRes, err := g.stat(statPath, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
tr := thumbnail.Request{
|
||||
Resolution: image.Rect(0, 0, int(req.Width), int(req.Height)),
|
||||
@@ -191,9 +222,9 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
Encoder: encoder,
|
||||
Checksum: sRes.GetInfo().GetChecksum().GetSum(),
|
||||
}
|
||||
thumb, ok := g.manager.Get(tr)
|
||||
if ok {
|
||||
return thumb, nil
|
||||
|
||||
if key, exists := g.manager.CheckThumbnail(tr); exists {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
if src.WebdavAuthorization != "" {
|
||||
@@ -202,7 +233,7 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
imgURL.RawQuery = ""
|
||||
r, err := g.webdavSource.Get(ctx, imgURL.String())
|
||||
if err != nil {
|
||||
return nil, merrors.InternalServerError(g.serviceID, "could not get image from source: %s", err.Error())
|
||||
return "", merrors.InternalServerError(g.serviceID, "could not get image from source: %s", err.Error())
|
||||
}
|
||||
defer r.Close() // nolint:errcheck
|
||||
ppOpts := map[string]interface{}{
|
||||
@@ -211,13 +242,14 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
|
||||
pp := preprocessor.ForType(sRes.GetInfo().GetMimeType(), ppOpts)
|
||||
img, err := pp.Convert(r)
|
||||
if img == nil || err != nil {
|
||||
return nil, merrors.InternalServerError(g.serviceID, "could not get image")
|
||||
}
|
||||
if thumb, err = g.manager.Generate(tr, img); err != nil {
|
||||
return nil, err
|
||||
return "", merrors.InternalServerError(g.serviceID, "could not get image")
|
||||
}
|
||||
|
||||
return thumb, nil
|
||||
key, err := g.manager.Generate(tr, img)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (g Thumbnail) stat(path, auth string) (*provider.StatResponse, error) {
|
||||
30
thumbnails/pkg/service/http/v0/instrument.go
Normal file
30
thumbnails/pkg/service/http/v0/instrument.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/metrics"
|
||||
)
|
||||
|
||||
// NewInstrument returns a service that instruments metrics.
|
||||
func NewInstrument(next Service, metrics *metrics.Metrics) Service {
|
||||
return instrument{
|
||||
next: next,
|
||||
metrics: metrics,
|
||||
}
|
||||
}
|
||||
|
||||
type instrument struct {
|
||||
next Service
|
||||
metrics *metrics.Metrics
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (i instrument) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
i.next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetThumbnail implements the Service interface.
|
||||
func (i instrument) GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
i.next.GetThumbnail(w, r)
|
||||
}
|
||||
30
thumbnails/pkg/service/http/v0/logging.go
Normal file
30
thumbnails/pkg/service/http/v0/logging.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
)
|
||||
|
||||
// NewLogging returns a service that logs messages.
|
||||
func NewLogging(next Service, logger log.Logger) Service {
|
||||
return logging{
|
||||
next: next,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
type logging struct {
|
||||
next Service
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (l logging) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
l.next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetThumbnail implements the Service interface.
|
||||
func (l logging) GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
l.next.GetThumbnail(w, r)
|
||||
}
|
||||
59
thumbnails/pkg/service/http/v0/option.go
Normal file
59
thumbnails/pkg/service/http/v0/option.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/config"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/storage"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
Middleware []func(http.Handler) http.Handler
|
||||
ThumbnailStorage storage.Storage
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
// Logger provides a function to set the logger option.
|
||||
func Logger(val log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = val
|
||||
}
|
||||
}
|
||||
|
||||
// Config provides a function to set the config option.
|
||||
func Config(val *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware provides a function to set the middleware option.
|
||||
func Middleware(val ...func(http.Handler) http.Handler) Option {
|
||||
return func(o *Options) {
|
||||
o.Middleware = val
|
||||
}
|
||||
}
|
||||
|
||||
// ThumbnailStorage provides a function to set the ThumbnailStorage option.
|
||||
func ThumbnailStorage(storage storage.Storage) Option {
|
||||
return func(o *Options) {
|
||||
o.ThumbnailStorage = storage
|
||||
}
|
||||
}
|
||||
123
thumbnails/pkg/service/http/v0/service.go
Normal file
123
thumbnails/pkg/service/http/v0/service.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/config"
|
||||
tjwt "github.com/owncloud/ocis/thumbnails/pkg/service/jwt"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
keyContextKey contextKey = "key"
|
||||
)
|
||||
|
||||
// Service defines the extension handlers.
|
||||
type Service interface {
|
||||
ServeHTTP(http.ResponseWriter, *http.Request)
|
||||
GetThumbnail(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
// NewService returns a service implementation for Service.
|
||||
func NewService(opts ...Option) Service {
|
||||
options := newOptions(opts...)
|
||||
|
||||
m := chi.NewMux()
|
||||
m.Use(options.Middleware...)
|
||||
|
||||
logger := options.Logger
|
||||
resolutions, err := thumbnail.ParseResolutions(options.Config.Thumbnail.Resolutions)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("resolutions not configured correctly")
|
||||
}
|
||||
svc := Thumbnails{
|
||||
config: options.Config,
|
||||
mux: m,
|
||||
logger: options.Logger,
|
||||
manager: thumbnail.NewSimpleManager(
|
||||
resolutions,
|
||||
options.ThumbnailStorage,
|
||||
logger,
|
||||
),
|
||||
}
|
||||
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
r.Use(svc.TransferTokenValidator)
|
||||
r.Get("/data", svc.GetThumbnail)
|
||||
})
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// Thumbnails implements the business logic for Service.
|
||||
type Thumbnails struct {
|
||||
config *config.Config
|
||||
logger log.Logger
|
||||
mux *chi.Mux
|
||||
manager thumbnail.Manager
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (s Thumbnails) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetThumbnail implements the Service interface.
|
||||
func (s Thumbnails) GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
key := r.Context().Value(keyContextKey).(string)
|
||||
|
||||
thumbnail, err := s.manager.GetThumbnail(key)
|
||||
if err != nil {
|
||||
s.logger.Error().
|
||||
Err(err).
|
||||
Str("key", key).
|
||||
Msg("could not get the thumbnail")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(thumbnail)))
|
||||
if _, err = w.Write(thumbnail); err != nil {
|
||||
s.logger.Error().
|
||||
Err(err).
|
||||
Str("key", key).
|
||||
Msg("could not write the thumbnail response")
|
||||
}
|
||||
}
|
||||
|
||||
func (s Thumbnails) TransferTokenValidator(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tokenString := r.Header.Get("Transfer-Token")
|
||||
token, err := jwt.ParseWithClaims(tokenString, &tjwt.ThumbnailClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(s.config.Thumbnail.TransferTokenSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error().
|
||||
Err(err).
|
||||
Str("transfer-token", tokenString).
|
||||
Msg("failed to parse transfer token")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*tjwt.ThumbnailClaims); ok && token.Valid {
|
||||
ctx := context.WithValue(r.Context(), keyContextKey, claims.Key)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
})
|
||||
}
|
||||
28
thumbnails/pkg/service/http/v0/tracing.go
Normal file
28
thumbnails/pkg/service/http/v0/tracing.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/middleware"
|
||||
)
|
||||
|
||||
// NewTracing returns a service that instruments traces.
|
||||
func NewTracing(next Service) Service {
|
||||
return tracing{
|
||||
next: next,
|
||||
}
|
||||
}
|
||||
|
||||
type tracing struct {
|
||||
next Service
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (t tracing) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.TraceContext(t.next).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetThumbnail implements the Service interface.
|
||||
func (t tracing) GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
t.next.GetThumbnail(w, r)
|
||||
}
|
||||
8
thumbnails/pkg/service/jwt/jwt.go
Normal file
8
thumbnails/pkg/service/jwt/jwt.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package jwt
|
||||
|
||||
import "github.com/golang-jwt/jwt/v4"
|
||||
|
||||
type ThumbnailClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
Key string `json:"key"`
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,8 +16,8 @@ const (
|
||||
)
|
||||
|
||||
// NewFileSystemStorage creates a new instance of FileSystem
|
||||
func NewFileSystemStorage(cfg config.FileSystemStorage, logger log.Logger) *FileSystem {
|
||||
return &FileSystem{
|
||||
func NewFileSystemStorage(cfg config.FileSystemStorage, logger log.Logger) FileSystem {
|
||||
return FileSystem{
|
||||
root: cfg.RootDirectory,
|
||||
logger: logger,
|
||||
}
|
||||
@@ -27,21 +29,27 @@ type FileSystem struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Get loads the image from the file system.
|
||||
func (s *FileSystem) Get(key string) ([]byte, bool) {
|
||||
func (s FileSystem) Stat(key string) bool {
|
||||
img := filepath.Join(s.root, filesDir, key)
|
||||
if _, err := os.Stat(img); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s FileSystem) Get(key string) ([]byte, error) {
|
||||
img := filepath.Join(s.root, filesDir, key)
|
||||
content, err := os.ReadFile(img)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
s.logger.Debug().Str("err", err.Error()).Str("key", key).Msg("could not load thumbnail from store")
|
||||
}
|
||||
return nil, false
|
||||
return nil, err
|
||||
}
|
||||
return content, true
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// Set writes the image to the file system.
|
||||
func (s *FileSystem) Put(key string, img []byte) error {
|
||||
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 {
|
||||
@@ -71,7 +79,7 @@ func (s *FileSystem) Put(key string, img []byte) error {
|
||||
// e.g. 97/9f/4c8db98f7b82e768ef478d3c8612/500x300.png
|
||||
//
|
||||
// The key also represents the path to the thumbnail in the filesystem under the configured root directory.
|
||||
func (s *FileSystem) BuildKey(r Request) string {
|
||||
func (s FileSystem) BuildKey(r Request) string {
|
||||
checksum := r.Checksum
|
||||
filetype := r.Types[0]
|
||||
filename := strconv.Itoa(r.Resolution.Dx()) + "x" + strconv.Itoa(r.Resolution.Dy()) + "." + filetype
|
||||
|
||||
@@ -17,9 +17,14 @@ type InMemory struct {
|
||||
store map[string][]byte
|
||||
}
|
||||
|
||||
func (s InMemory) Stat(key string) bool {
|
||||
_, exists := s.store[key]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Get loads the thumbnail from memory.
|
||||
func (s InMemory) Get(key string) ([]byte, bool) {
|
||||
return s.store[key], true
|
||||
func (s InMemory) Get(key string) ([]byte, error) {
|
||||
return s.store[key], nil
|
||||
}
|
||||
|
||||
// Set stores the thumbnail in memory.
|
||||
|
||||
@@ -8,18 +8,19 @@ import (
|
||||
type Request struct {
|
||||
// The checksum of the source file
|
||||
// Will be used to determine if a thumbnail exists
|
||||
Checksum string
|
||||
Checksum string
|
||||
// Types provided by the encoder.
|
||||
// Contains the mimetypes of the thumbnail.
|
||||
// In case of jpg/jpeg it will contain both.
|
||||
Types []string
|
||||
Types []string
|
||||
// The resolution of the thumbnail
|
||||
Resolution image.Rectangle
|
||||
}
|
||||
|
||||
// Storage defines the interface for a thumbnail store.
|
||||
type Storage interface {
|
||||
Get(string) ([]byte, bool)
|
||||
Stat(string) bool
|
||||
Get(string) ([]byte, error)
|
||||
Put(string, []byte) error
|
||||
BuildKey(Request) string
|
||||
}
|
||||
|
||||
@@ -5,19 +5,19 @@ import (
|
||||
"image"
|
||||
"image/gif"
|
||||
"mime"
|
||||
"strings"
|
||||
|
||||
"github.com/owncloud/ocis/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/thumbnails/pkg/thumbnail/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
SupportedMimeTypes = [...]string{
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/jpeg",
|
||||
"image/gif",
|
||||
"text/plain",
|
||||
// SupportedMimeTypes contains a all mimetypes which are supported by the thumbnailer.
|
||||
SupportedMimeTypes = map[string]struct{}{
|
||||
"image/png": {},
|
||||
"image/jpg": {},
|
||||
"image/jpeg": {},
|
||||
"image/gif": {},
|
||||
"text/plain": {},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -31,11 +31,14 @@ type Request struct {
|
||||
|
||||
// Manager is responsible for generating thumbnails
|
||||
type Manager interface {
|
||||
// Generate will return a thumbnail for a file
|
||||
Generate(Request, interface{}) ([]byte, error)
|
||||
// Get loads the thumbnail from the storage.
|
||||
// It will return nil if no image is stored for the given context.
|
||||
Get(Request) ([]byte, bool)
|
||||
// Generate creates a thumbnail and stores it.
|
||||
// The function returns a key with which the actual file can be retrieved.
|
||||
Generate(Request, interface{}) (string, error)
|
||||
// CheckThumbnail checks if a thumbnail with the requested attributes exists.
|
||||
// The function will return a status if the file exists and the key to the file.
|
||||
CheckThumbnail(Request) (string, bool)
|
||||
// GetThumbnail will load the thumbnail from the storage and return its content.
|
||||
GetThumbnail(key string) ([]byte, error)
|
||||
}
|
||||
|
||||
// NewSimpleManager creates a new instance of SimpleManager
|
||||
@@ -54,9 +57,7 @@ type SimpleManager struct {
|
||||
resolutions Resolutions
|
||||
}
|
||||
|
||||
// Generate creates a thumbnail and stores it.
|
||||
// The created thumbnail is also being returned.
|
||||
func (s SimpleManager) Generate(r Request, img interface{}) ([]byte, error) {
|
||||
func (s SimpleManager) Generate(r Request, img interface{}) (string, error) {
|
||||
var match image.Rectangle
|
||||
switch m := img.(type) {
|
||||
case *gif.GIF:
|
||||
@@ -67,28 +68,29 @@ func (s SimpleManager) Generate(r Request, img interface{}) ([]byte, error) {
|
||||
|
||||
thumbnail, err := r.Generator.GenerateThumbnail(match, img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
dst := new(bytes.Buffer)
|
||||
err = r.Encoder.Encode(dst, thumbnail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
buf := new(bytes.Buffer)
|
||||
if err := r.Encoder.Encode(buf, thumbnail); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
k := s.storage.BuildKey(mapToStorageRequest(r))
|
||||
err = s.storage.Put(k, dst.Bytes())
|
||||
if err != nil {
|
||||
s.logger.Warn().Err(err).Msg("could not store thumbnail")
|
||||
if err := s.storage.Put(k, buf.Bytes()); err != nil {
|
||||
s.logger.Error().Err(err).Msg("could not store thumbnail")
|
||||
return "", err
|
||||
}
|
||||
return dst.Bytes(), nil
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// Get tries to get the stored thumbnail and return it.
|
||||
// If there is no cached thumbnail it will return nil
|
||||
func (s SimpleManager) Get(r Request) ([]byte, bool) {
|
||||
func (s SimpleManager) CheckThumbnail(r Request) (string, bool) {
|
||||
k := s.storage.BuildKey(mapToStorageRequest(r))
|
||||
return s.storage.Get(k)
|
||||
return k, s.storage.Stat(k)
|
||||
}
|
||||
|
||||
func (s SimpleManager) GetThumbnail(key string) ([]byte, error) {
|
||||
return s.storage.Get(key)
|
||||
}
|
||||
|
||||
func mapToStorageRequest(r Request) storage.Request {
|
||||
@@ -104,10 +106,6 @@ func IsMimeTypeSupported(m string) bool {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, mt := range SupportedMimeTypes {
|
||||
if strings.EqualFold(mt, mimeType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
_, supported := SupportedMimeTypes[mimeType]
|
||||
return supported
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package svc
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -128,12 +129,7 @@ func (g Webdav) SpacesThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(rsp.Thumbnail) == 0 {
|
||||
renderError(w, r, errNotFound(""))
|
||||
return
|
||||
}
|
||||
|
||||
g.mustRender(w, r, newThumbnailResponse(rsp))
|
||||
g.sendThumbnailResponse(rsp, w, r)
|
||||
}
|
||||
|
||||
// Thumbnail implements the Service interface.
|
||||
@@ -186,12 +182,7 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(rsp.Thumbnail) == 0 {
|
||||
renderError(w, r, errNotFound(""))
|
||||
return
|
||||
}
|
||||
|
||||
g.mustRender(w, r, newThumbnailResponse(rsp))
|
||||
g.sendThumbnailResponse(rsp, w, r)
|
||||
}
|
||||
|
||||
func (g Webdav) PublicThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -231,12 +222,7 @@ func (g Webdav) PublicThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(rsp.Thumbnail) == 0 {
|
||||
renderError(w, r, errNotFound(""))
|
||||
return
|
||||
}
|
||||
|
||||
g.mustRender(w, r, newThumbnailResponse(rsp))
|
||||
g.sendThumbnailResponse(rsp, w, r)
|
||||
}
|
||||
|
||||
func (g Webdav) PublicThumbnailHead(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -247,7 +233,7 @@ func (g Webdav) PublicThumbnailHead(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
rsp, err := g.thumbnailsClient.GetThumbnail(r.Context(), &thumbnailssvc.GetThumbnailRequest{
|
||||
_, err = g.thumbnailsClient.GetThumbnail(r.Context(), &thumbnailssvc.GetThumbnailRequest{
|
||||
Filepath: strings.TrimLeft(tr.Filepath, "/"),
|
||||
ThumbnailType: extensionToThumbnailType(strings.TrimLeft(tr.Extension, ".")),
|
||||
Width: tr.Width,
|
||||
@@ -276,28 +262,56 @@ func (g Webdav) PublicThumbnailHead(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(rsp.Thumbnail) == 0 {
|
||||
renderError(w, r, errNotFound(""))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (g Webdav) sendThumbnailResponse(rsp *thumbnailssvc.GetThumbnailResponse, w http.ResponseWriter, r *http.Request) {
|
||||
client := &http.Client{
|
||||
// Timeout: time.Second * 5,
|
||||
}
|
||||
|
||||
dlReq, err := http.NewRequest(http.MethodGet, rsp.DataEndpoint, http.NoBody)
|
||||
if err != nil {
|
||||
renderError(w, r, errInternalError(err.Error()))
|
||||
g.log.Error().Err(err).Msg("could not download thumbnail")
|
||||
return
|
||||
}
|
||||
dlReq.Header.Set("Transfer-Token", rsp.TransferToken)
|
||||
|
||||
dlRsp, err := client.Do(dlReq)
|
||||
if err != nil {
|
||||
renderError(w, r, errInternalError(err.Error()))
|
||||
g.log.Error().Err(err).Msg("could not download thumbnail")
|
||||
return
|
||||
}
|
||||
defer dlRsp.Body.Close()
|
||||
|
||||
if dlRsp.StatusCode != http.StatusOK {
|
||||
g.log.Error().
|
||||
Str("transfer_token", rsp.TransferToken).
|
||||
Str("data_endpoint", rsp.DataEndpoint).
|
||||
Str("response_status", dlRsp.Status).
|
||||
Msg("could not download thumbnail")
|
||||
renderError(w, r, errInternalError("could not download thumbnail"))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func extensionToThumbnailType(ext string) thumbnailssvc.GetThumbnailRequest_ThumbnailType {
|
||||
switch strings.ToUpper(ext) {
|
||||
case "GIF":
|
||||
return thumbnailssvc.GetThumbnailRequest_GIF
|
||||
case "PNG":
|
||||
return thumbnailssvc.GetThumbnailRequest_PNG
|
||||
default:
|
||||
return thumbnailssvc.GetThumbnailRequest_JPG
|
||||
w.Header().Set("Content-Type", rsp.Mimetype)
|
||||
_, err = io.Copy(w, dlRsp.Body)
|
||||
if err != nil {
|
||||
g.log.Error().Err(err).Msg("failed to write thumbnail to response writer")
|
||||
}
|
||||
}
|
||||
|
||||
func (g Webdav) mustRender(w http.ResponseWriter, r *http.Request, renderer render.Renderer) {
|
||||
if err := render.Render(w, r, renderer); err != nil {
|
||||
g.log.Err(err).Msg("failed to write response")
|
||||
func extensionToThumbnailType(ext string) thumbnailsmsg.ThumbnailType {
|
||||
switch strings.ToUpper(ext) {
|
||||
case "GIF":
|
||||
return thumbnailsmsg.ThumbnailType_GIF
|
||||
case "PNG":
|
||||
return thumbnailsmsg.ThumbnailType_PNG
|
||||
default:
|
||||
return thumbnailsmsg.ThumbnailType_JPG
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,25 +351,6 @@ func errNotFound(msg string) *errResponse {
|
||||
return newErrResponse(http.StatusNotFound, msg)
|
||||
}
|
||||
|
||||
type thumbnailResponse struct {
|
||||
contentType string
|
||||
thumbnail []byte
|
||||
}
|
||||
|
||||
func (t *thumbnailResponse) Render(w http.ResponseWriter, _ *http.Request) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", t.contentType)
|
||||
_, err := w.Write(t.thumbnail)
|
||||
return err
|
||||
}
|
||||
|
||||
func newThumbnailResponse(rsp *thumbnailssvc.GetThumbnailResponse) *thumbnailResponse {
|
||||
return &thumbnailResponse{
|
||||
contentType: rsp.Mimetype,
|
||||
thumbnail: rsp.Thumbnail,
|
||||
}
|
||||
}
|
||||
|
||||
func renderError(w http.ResponseWriter, r *http.Request, err *errResponse) {
|
||||
render.Status(r, err.HTTPStatusCode)
|
||||
render.XML(w, r, err)
|
||||
|
||||
Reference in New Issue
Block a user