From 1ad11d7e08920e18fb45c3caf7d0b888e4851a91 Mon Sep 17 00:00:00 2001 From: Ron Rise Date: Sun, 17 Nov 2024 11:07:26 -0500 Subject: [PATCH] Added grpc web service --- Dockerfile | 6 +- Taskfile.yaml | 7 + generator/format.go | 5 +- go.mod | 23 ++-- go.sum | 46 ++++--- grpc/imgurl.pb.go | 306 +++++++++++++++++++++++++++++++++++++++++ grpc/imgurl.proto | 24 ++++ grpc/imgurl_grpc.pb.go | 121 ++++++++++++++++ grpc/server.go | 41 ++++++ main.go | 41 +++++- 10 files changed, 590 insertions(+), 30 deletions(-) create mode 100644 Taskfile.yaml create mode 100644 grpc/imgurl.pb.go create mode 100644 grpc/imgurl.proto create mode 100644 grpc/imgurl_grpc.pb.go create mode 100644 grpc/server.go diff --git a/Dockerfile b/Dockerfile index 9ef93c2..4587dba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM siteworxpro/golang:latest AS build +FROM siteworxpro/golang:1.23.3 AS build WORKDIR /app @@ -12,10 +12,10 @@ RUN go mod tidy && go build -o imgproxy . FROM alpine AS runtime -EXPOSE 8080 +EXPOSE 9000 WORKDIR /app COPY --from=build /app/imgproxy /app/imgproxy -ENTRYPOINT ["/app/imgproxy", "server"] \ No newline at end of file +ENTRYPOINT ["/app/imgproxy", "grpc"] \ No newline at end of file diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..8b9ddfa --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,7 @@ +version: '3' + +tasks: + proto-build: + cmds: + - protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative grpc/imgurl.proto + silent: true \ No newline at end of file diff --git a/generator/format.go b/generator/format.go index 5fd7d9b..b3d2837 100644 --- a/generator/format.go +++ b/generator/format.go @@ -18,7 +18,8 @@ const ( ) func (g *Generator) StringToFormat(string string) (Format, error) { - switch strings.ToLower(string) { + s := strings.ToLower(string) + switch s { case "jpg": return JPG, nil case "jpeg": @@ -33,6 +34,8 @@ func (g *Generator) StringToFormat(string string) (Format, error) { return GIF, nil case "ico": return ICO, nil + case "def": + case "default": case "": return DEF, nil } diff --git a/go.mod b/go.mod index 0f6d0e9..f721222 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,30 @@ module github.com/siteworxpro/img-proxy-url-generator -go 1.22.5 +go 1.23.3 require ( - github.com/aws/aws-sdk-go v1.54.19 - github.com/bigkevmcd/go-configparser v0.0.0-20240624060122-ccd05f93a9d2 - github.com/charmbracelet/lipgloss v0.13.0 - github.com/urfave/cli/v2 v2.27.2 + github.com/aws/aws-sdk-go v1.55.5 + github.com/bigkevmcd/go-configparser v0.0.0-20240808124832-fc81059ea0bd + github.com/charmbracelet/lipgloss v1.0.0 + github.com/urfave/cli/v2 v2.27.5 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.2 ) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/charmbracelet/x/ansi v0.4.5 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - golang.org/x/sys v0.22.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect ) diff --git a/go.sum b/go.sum index 668797c..e5f8efe 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,21 @@ -github.com/aws/aws-sdk-go v1.54.19 h1:tyWV+07jagrNiCcGRzRhdtVjQs7Vy41NwsuOcl0IbVI= -github.com/aws/aws-sdk-go v1.54.19/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/bigkevmcd/go-configparser v0.0.0-20240624060122-ccd05f93a9d2 h1:2qnRmzKO1fVs2UOqyt6tRMpVB8FrOnx8IG8C2lK0cjU= -github.com/bigkevmcd/go-configparser v0.0.0-20240624060122-ccd05f93a9d2/go.mod h1:vzEQfW+A1T+AMJmTIX+SXNLNECHOM7GEinHhw0IjykI= -github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= -github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/bigkevmcd/go-configparser v0.0.0-20240808124832-fc81059ea0bd h1:MsTk4yo6KVYdulsDscuH4AwiZN1CyuCJAg59EWE7HPQ= +github.com/bigkevmcd/go-configparser v0.0.0-20240808124832-fc81059ea0bd/go.mod h1:vzEQfW+A1T+AMJmTIX+SXNLNECHOM7GEinHhw0IjykI= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -24,8 +28,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -36,13 +40,23 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/grpc/imgurl.pb.go b/grpc/imgurl.pb.go new file mode 100644 index 0000000..df66add --- /dev/null +++ b/grpc/imgurl.pb.go @@ -0,0 +1,306 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.1 +// protoc v5.28.3 +// source: grpc/imgurl.proto + +package grpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Format int32 + +const ( + Format_JPG Format = 1 + Format_PNG Format = 2 + Format_BMP Format = 3 + Format_WEBP Format = 4 + Format_GIF Format = 5 + Format_ICO Format = 6 +) + +// Enum value maps for Format. +var ( + Format_name = map[int32]string{ + 1: "JPG", + 2: "PNG", + 3: "BMP", + 4: "WEBP", + 5: "GIF", + 6: "ICO", + } + Format_value = map[string]int32{ + "JPG": 1, + "PNG": 2, + "BMP": 3, + "WEBP": 4, + "GIF": 5, + "ICO": 6, + } +) + +func (x Format) Enum() *Format { + p := new(Format) + *p = x + return p +} + +func (x Format) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Format) Descriptor() protoreflect.EnumDescriptor { + return file_grpc_imgurl_proto_enumTypes[0].Descriptor() +} + +func (Format) Type() protoreflect.EnumType { + return &file_grpc_imgurl_proto_enumTypes[0] +} + +func (x Format) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *Format) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = Format(num) + return nil +} + +// Deprecated: Use Format.Descriptor instead. +func (Format) EnumDescriptor() ([]byte, []int) { + return file_grpc_imgurl_proto_rawDescGZIP(), []int{0} +} + +type UrlRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Image *string `protobuf:"bytes,1,req,name=image" json:"image,omitempty"` + Params []string `protobuf:"bytes,2,rep,name=params" json:"params,omitempty"` + Format *Format `protobuf:"varint,3,opt,name=format,enum=Format" json:"format,omitempty"` +} + +func (x *UrlRequest) Reset() { + *x = UrlRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_imgurl_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UrlRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UrlRequest) ProtoMessage() {} + +func (x *UrlRequest) ProtoReflect() protoreflect.Message { + mi := &file_grpc_imgurl_proto_msgTypes[0] + 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 UrlRequest.ProtoReflect.Descriptor instead. +func (*UrlRequest) Descriptor() ([]byte, []int) { + return file_grpc_imgurl_proto_rawDescGZIP(), []int{0} +} + +func (x *UrlRequest) GetImage() string { + if x != nil && x.Image != nil { + return *x.Image + } + return "" +} + +func (x *UrlRequest) GetParams() []string { + if x != nil { + return x.Params + } + return nil +} + +func (x *UrlRequest) GetFormat() Format { + if x != nil && x.Format != nil { + return *x.Format + } + return Format_JPG +} + +type UrlResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url *string `protobuf:"bytes,1,req,name=url" json:"url,omitempty"` +} + +func (x *UrlResponse) Reset() { + *x = UrlResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_imgurl_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UrlResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UrlResponse) ProtoMessage() {} + +func (x *UrlResponse) ProtoReflect() protoreflect.Message { + mi := &file_grpc_imgurl_proto_msgTypes[1] + 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 UrlResponse.ProtoReflect.Descriptor instead. +func (*UrlResponse) Descriptor() ([]byte, []int) { + return file_grpc_imgurl_proto_rawDescGZIP(), []int{1} +} + +func (x *UrlResponse) GetUrl() string { + if x != nil && x.Url != nil { + return *x.Url + } + return "" +} + +var File_grpc_imgurl_proto protoreflect.FileDescriptor + +var file_grpc_imgurl_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x69, 0x6d, 0x67, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x5b, 0x0a, 0x0a, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, + 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, + 0x1f, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x07, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x22, 0x1f, 0x0a, 0x0b, 0x55, 0x72, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, + 0x6c, 0x2a, 0x3f, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x07, 0x0a, 0x03, 0x4a, + 0x50, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x07, 0x0a, + 0x03, 0x42, 0x4d, 0x50, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x42, 0x50, 0x10, 0x04, + 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x43, 0x4f, + 0x10, 0x06, 0x32, 0x34, 0x0a, 0x09, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, + 0x27, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x2e, 0x55, 0x72, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x55, 0x72, 0x6c, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x74, 0x65, 0x77, 0x6f, 0x72, 0x78, 0x70, + 0x72, 0x6f, 0x2f, 0x69, 0x6d, 0x67, 0x2d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x75, 0x72, 0x6c, + 0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x67, 0x72, 0x70, 0x63, +} + +var ( + file_grpc_imgurl_proto_rawDescOnce sync.Once + file_grpc_imgurl_proto_rawDescData = file_grpc_imgurl_proto_rawDesc +) + +func file_grpc_imgurl_proto_rawDescGZIP() []byte { + file_grpc_imgurl_proto_rawDescOnce.Do(func() { + file_grpc_imgurl_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_imgurl_proto_rawDescData) + }) + return file_grpc_imgurl_proto_rawDescData +} + +var file_grpc_imgurl_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_grpc_imgurl_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_grpc_imgurl_proto_goTypes = []interface{}{ + (Format)(0), // 0: Format + (*UrlRequest)(nil), // 1: UrlRequest + (*UrlResponse)(nil), // 2: UrlResponse +} +var file_grpc_imgurl_proto_depIdxs = []int32{ + 0, // 0: UrlRequest.format:type_name -> Format + 1, // 1: Generator.Generate:input_type -> UrlRequest + 2, // 2: Generator.Generate:output_type -> UrlResponse + 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 +} + +func init() { file_grpc_imgurl_proto_init() } +func file_grpc_imgurl_proto_init() { + if File_grpc_imgurl_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_grpc_imgurl_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UrlRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_imgurl_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UrlResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_imgurl_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_grpc_imgurl_proto_goTypes, + DependencyIndexes: file_grpc_imgurl_proto_depIdxs, + EnumInfos: file_grpc_imgurl_proto_enumTypes, + MessageInfos: file_grpc_imgurl_proto_msgTypes, + }.Build() + File_grpc_imgurl_proto = out.File + file_grpc_imgurl_proto_rawDesc = nil + file_grpc_imgurl_proto_goTypes = nil + file_grpc_imgurl_proto_depIdxs = nil +} diff --git a/grpc/imgurl.proto b/grpc/imgurl.proto new file mode 100644 index 0000000..06a52f5 --- /dev/null +++ b/grpc/imgurl.proto @@ -0,0 +1,24 @@ +option go_package = "github.com/siteworxpro/img-proxy-url-generator/grpc"; + +message UrlRequest { + required string image = 1; + repeated string params = 2; + optional Format format = 3; +} + +enum Format { + JPG = 1; + PNG = 2; + BMP = 3; + WEBP = 4; + GIF = 5; + ICO = 6; +} + +message UrlResponse { + required string url = 1; +} + +service Generator { + rpc Generate (UrlRequest) returns (UrlResponse) {} +} \ No newline at end of file diff --git a/grpc/imgurl_grpc.pb.go b/grpc/imgurl_grpc.pb.go new file mode 100644 index 0000000..3a7d413 --- /dev/null +++ b/grpc/imgurl_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: grpc/imgurl.proto + +package grpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Generator_Generate_FullMethodName = "/Generator/Generate" +) + +// GeneratorClient is the client API for Generator service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GeneratorClient interface { + Generate(ctx context.Context, in *UrlRequest, opts ...grpc.CallOption) (*UrlResponse, error) +} + +type generatorClient struct { + cc grpc.ClientConnInterface +} + +func NewGeneratorClient(cc grpc.ClientConnInterface) GeneratorClient { + return &generatorClient{cc} +} + +func (c *generatorClient) Generate(ctx context.Context, in *UrlRequest, opts ...grpc.CallOption) (*UrlResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UrlResponse) + err := c.cc.Invoke(ctx, Generator_Generate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GeneratorServer is the server API for Generator service. +// All implementations must embed UnimplementedGeneratorServer +// for forward compatibility. +type GeneratorServer interface { + Generate(context.Context, *UrlRequest) (*UrlResponse, error) + mustEmbedUnimplementedGeneratorServer() +} + +// UnimplementedGeneratorServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedGeneratorServer struct{} + +func (UnimplementedGeneratorServer) Generate(context.Context, *UrlRequest) (*UrlResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Generate not implemented") +} +func (UnimplementedGeneratorServer) mustEmbedUnimplementedGeneratorServer() {} +func (UnimplementedGeneratorServer) testEmbeddedByValue() {} + +// UnsafeGeneratorServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GeneratorServer will +// result in compilation errors. +type UnsafeGeneratorServer interface { + mustEmbedUnimplementedGeneratorServer() +} + +func RegisterGeneratorServer(s grpc.ServiceRegistrar, srv GeneratorServer) { + // If the following call pancis, it indicates UnimplementedGeneratorServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Generator_ServiceDesc, srv) +} + +func _Generator_Generate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UrlRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GeneratorServer).Generate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Generator_Generate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GeneratorServer).Generate(ctx, req.(*UrlRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Generator_ServiceDesc is the grpc.ServiceDesc for Generator service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Generator_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "Generator", + HandlerType: (*GeneratorServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Generate", + Handler: _Generator_Generate_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "grpc/imgurl.proto", +} diff --git a/grpc/server.go b/grpc/server.go new file mode 100644 index 0000000..9d201d5 --- /dev/null +++ b/grpc/server.go @@ -0,0 +1,41 @@ +package grpc + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/siteworxpro/img-proxy-url-generator/generator" + "log" + "strings" +) + +type GeneratorService struct { + UnimplementedGeneratorServer + imgGenerator *generator.Generator +} + +func NewService(imgGenerator *generator.Generator) *GeneratorService { + return &GeneratorService{imgGenerator: imgGenerator} +} + +func (s *GeneratorService) Generate(c context.Context, r *UrlRequest) (*UrlResponse, error) { + + var err error + format := generator.DEF + + if r.Format != nil { + format, err = s.imgGenerator.StringToFormat(r.Format.String()) + if err != nil { + return nil, err + } + } + + url, err := s.imgGenerator.GenerateUrl(*r.Image, r.Params, format) + if err != nil { + return nil, err + } + + log.Println(fmt.Sprintf("%s - [%s] - (%s)", *r.Image, strings.Join(r.Params, ","), url)) + + return &UrlResponse{Url: aws.String(url)}, nil +} diff --git a/main.go b/main.go index 3b9aa6d..9385cf7 100644 --- a/main.go +++ b/main.go @@ -6,10 +6,13 @@ import ( "github.com/bigkevmcd/go-configparser" "github.com/siteworxpro/img-proxy-url-generator/aws" "github.com/siteworxpro/img-proxy-url-generator/generator" + proto "github.com/siteworxpro/img-proxy-url-generator/grpc" "github.com/siteworxpro/img-proxy-url-generator/printer" "github.com/urfave/cli/v2" + "google.golang.org/grpc" "html/template" "log" + "net" "net/http" "os" "strings" @@ -62,12 +65,48 @@ func main() { commands = append(commands, &cli.Command{ Name: "server", - Usage: "Start a webserver for s3 file browsing", + Usage: "Start a webserver for s3 file browsing and the web service", Action: func(c *cli.Context) error { return startServer(c, pr) }, }) + commands = append(commands, &cli.Command{ + Name: "grpc", + Usage: "Start a grpc service", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "port", + Aliases: []string{"p"}, + Usage: "Port to listen on", + Required: false, + Value: 9000, + }, + }, + Action: func(c *cli.Context) error { + err := initGenerator(c.String("config")) + + if err != nil { + return err + } + + s := grpc.NewServer() + addr := fmt.Sprintf(":%d", c.Int("port")) + println("listening on", addr) + lis, err := net.Listen("tcp", addr) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + proto.RegisterGeneratorServer(s, proto.NewService(imgGenerator)) + err = s.Serve(lis) + if err != nil { + log.Fatalf("failed to serve: %v", err) + } + + return nil + }, + }) + commands = append(commands, &cli.Command{ Name: "decrypt", Usage: "decrypt an image url contents",