diff --git a/shortener/api/v1/proto/shortener/shortener.proto b/shortener/api/v1/proto/shortener/shortener.proto index 39880d3..f47b145 100644 --- a/shortener/api/v1/proto/shortener/shortener.proto +++ b/shortener/api/v1/proto/shortener/shortener.proto @@ -33,3 +33,8 @@ message UpdateVisitorCountMessage { string short_url=1; } +message UpdateShortenerMessage { + string id =1; + string full_url=2; +} + diff --git a/shortener/cmd/v1/example.env b/shortener/cmd/v1/example.env index 177af63..ef3622f 100644 --- a/shortener/cmd/v1/example.env +++ b/shortener/cmd/v1/example.env @@ -16,6 +16,7 @@ REDIS_TTL=5 AMQP_SERVER_URL=amqp://guest:guest@amqp:5672/ AMQP_QUEUE_CREATE_SHORTENER=create-shortener-queue AMQP_QUEUE_UPDATE_VISITOR_COUNT=update-visitor-count-queue +AMQP_QUEUE_UPDATE_SHORTENER=update-shortener-queue GRPC_PORT=9091 diff --git a/shortener/cmd/v1/main.go b/shortener/cmd/v1/main.go index bf3f366..76abeba 100644 --- a/shortener/cmd/v1/main.go +++ b/shortener/cmd/v1/main.go @@ -144,7 +144,7 @@ func main() { // Make a channel to receive messages into infinite loop. forever := make(chan bool) - queues := []string{app.Config.RabbitMQ.QueueCreateShortener, app.Config.RabbitMQ.QueueUpdateVisitor} + queues := []string{app.Config.RabbitMQ.QueueCreateShortener, app.Config.RabbitMQ.QueueUpdateVisitor, app.Config.RabbitMQ.QueueUpdateShortener} for _, q := range queues { go infrastructure.ConsumeMessages(app, q) diff --git a/shortener/internal/v1/application/app.go b/shortener/internal/v1/application/app.go index 1e5ea62..956e187 100644 --- a/shortener/internal/v1/application/app.go +++ b/shortener/internal/v1/application/app.go @@ -89,7 +89,7 @@ func SetupApplication(ctx context.Context) (*App, error) { return app, err } - queues := []string{app.Config.RabbitMQ.QueueCreateShortener, app.Config.RabbitMQ.QueueUpdateVisitor} + queues := []string{app.Config.RabbitMQ.QueueCreateShortener, app.Config.RabbitMQ.QueueUpdateVisitor, app.Config.RabbitMQ.QueueUpdateShortener} for _, q := range queues { _, err = amqpClient.QueueDeclare( diff --git a/shortener/internal/v1/config/config.go b/shortener/internal/v1/config/config.go index 84f9c9a..b466d03 100644 --- a/shortener/internal/v1/config/config.go +++ b/shortener/internal/v1/config/config.go @@ -41,6 +41,7 @@ type ( ConnURL string QueueCreateShortener string QueueUpdateVisitor string + QueueUpdateShortener string } Tracer struct { @@ -75,6 +76,7 @@ func loadConfiguration() *Configuration { ConnURL: helper.GetEnvString("AMQP_SERVER_URL"), QueueCreateShortener: helper.GetEnvString("AMQP_QUEUE_CREATE_SHORTENER"), QueueUpdateVisitor: helper.GetEnvString("AMQP_QUEUE_UPDATE_VISITOR_COUNT"), + QueueUpdateShortener: helper.GetEnvString("AMQP_QUEUE_UPDATE_SHORTENER"), }, Tracer: &Tracer{ JaegerURL: helper.GetEnvString("JAEGER_URL"), diff --git a/shortener/internal/v1/controller/short.go b/shortener/internal/v1/controller/short.go index dab846a..09080e3 100644 --- a/shortener/internal/v1/controller/short.go +++ b/shortener/internal/v1/controller/short.go @@ -29,6 +29,7 @@ type ( // rabbitmq ProcessCreateShortUser(ctx context.Context, msg *shortenerpb.CreateShortenerMessage) error ProcessUpdateVisitorCount(ctx context.Context, msg *shortenerpb.UpdateVisitorCountMessage) error + ProcessUpdateShortUser(ctx context.Context, msg *shortenerpb.UpdateShortenerMessage) error } // ShortControllerImpl is an app short struct that consists of all the dependencies needed for short controller @@ -150,3 +151,21 @@ func (sc *ShortControllerImpl) ProcessUpdateVisitorCount(ctx context.Context, ms return nil } + +func (sc *ShortControllerImpl) ProcessUpdateShortUser(ctx context.Context, msg *shortenerpb.UpdateShortenerMessage) error { + tr := sc.Tracer.Tracer("Shortener-ProcessUpdateShortUser Controller") + _, span := tr.Start(sc.Context, "Start ProcessUpdateShortUser") + defer span.End() + + req := &model.UpdateShortRequest{ + ID: msg.GetId(), + FullURL: msg.GetFullUrl(), + } + + err := sc.ShortSvc.UpdateShort(ctx, req) + if err != nil { + return model.NewError(model.Internal, err.Error()) + } + + return nil +} diff --git a/shortener/internal/v1/infrastructure/rabbitmq.go b/shortener/internal/v1/infrastructure/rabbitmq.go index 7ea9a04..668ec38 100644 --- a/shortener/internal/v1/infrastructure/rabbitmq.go +++ b/shortener/internal/v1/infrastructure/rabbitmq.go @@ -63,7 +63,22 @@ func ConsumeMessages(app *application.App, queueName string) { } app.Logger.Info(fmt.Sprintf("[%s] Success Process Message :", queueName), req) + case app.Config.RabbitMQ.QueueUpdateShortener: + req := &shortenerpb.UpdateShortenerMessage{} + err := proto.Unmarshal(msg.Body, req) + if err != nil { + app.Logger.Error("Unmarshal proto UpdateShortenerMessage ERROR, ", err) + } + + app.Logger.Info(fmt.Sprintf("[%s] Success Consume Message :", queueName), req) + + err = dep.ShortController.ProcessUpdateShortUser(app.Context, req) + if err != nil { + app.Logger.Error("ProcessUpdateShortUser ERROR, ", err) + } + + app.Logger.Info(fmt.Sprintf("[%s] Success Process Message :", queueName), req) } } }() diff --git a/shortener/internal/v1/model/short.go b/shortener/internal/v1/model/short.go index 3221e73..1adc8b3 100644 --- a/shortener/internal/v1/model/short.go +++ b/shortener/internal/v1/model/short.go @@ -30,4 +30,9 @@ type ( UpdateVisitorRequest struct { ShortURL string `json:"short_url"` } + + UpdateShortRequest struct { + ID string `json:"id"` + FullURL string `json:"full_url"` + } ) diff --git a/shortener/internal/v1/repository/short.go b/shortener/internal/v1/repository/short.go index fca6a82..7ef7f08 100644 --- a/shortener/internal/v1/repository/short.go +++ b/shortener/internal/v1/repository/short.go @@ -12,6 +12,7 @@ import ( "github.com/sirupsen/logrus" "github.com/streadway/amqp" "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/otel/sdk/trace" @@ -28,6 +29,7 @@ type ( SetFullURLByKey(ctx context.Context, shortURL string, fullURL string, duration time.Duration) error PublishUpdateVisitorCount(ctx context.Context, req *model.UpdateVisitorRequest) error UpdateVisitorByShortURL(ctx context.Context, req *model.UpdateVisitorRequest, lastVisitedCount int64) error + UpdateFullURLByID(ctx context.Context, req *model.UpdateShortRequest) error } // ShortRepositoryImpl is an app short struct that consists of all the dependencies needed for short repository @@ -212,6 +214,29 @@ func (sr *ShortRepositoryImpl) UpdateVisitorByShortURL(ctx context.Context, req return nil } +func (sr *ShortRepositoryImpl) UpdateFullURLByID(ctx context.Context, req *model.UpdateShortRequest) error { + tr := sr.Tracer.Tracer("Shortener-UpdateFullURLByID Repository") + ctx, span := tr.Start(ctx, "Start UpdateFullURLByID") + defer span.End() + + objShortID, err := primitive.ObjectIDFromHex(req.ID) + if err != nil { + sr.Logger.Error("ShortRepositoryImpl.UpdateFullURLByID primitive.ObjectIDFromHex ERROR, ", err) + return err + } + + _, err = sr.DB.Collection(sr.Config.Database.ShortenersCollection).UpdateOne(ctx, + bson.D{{Key: "_id", Value: objShortID}}, bson.M{ + "$set": bson.D{{Key: "full_url", Value: req.FullURL}, {Key: "updated_at", Value: time.Now()}}, + }) + if err != nil { + sr.Logger.Error("ShortRepositoryImpl.UpdateFullURLByID UpdateOne ERROR, ", err) + return err + } + + return nil +} + func (sr *ShortRepositoryImpl) prepareProtoPublishUpdateVisitorCountMessage(req *model.UpdateVisitorRequest) *shortenerpb.UpdateVisitorCountMessage { return &shortenerpb.UpdateVisitorCountMessage{ ShortUrl: req.ShortURL, diff --git a/shortener/internal/v1/service/short.go b/shortener/internal/v1/service/short.go index 32ccb12..39b5ac7 100644 --- a/shortener/internal/v1/service/short.go +++ b/shortener/internal/v1/service/short.go @@ -20,6 +20,7 @@ type ( CreateShort(ctx context.Context, req *model.CreateShortRequest) error ClickShort(shortURL string) (*model.ClickShortResponse, error) UpdateVisitorShort(ctx context.Context, req *model.UpdateVisitorRequest) error + UpdateShort(ctx context.Context, req *model.UpdateShortRequest) error } // ShortServiceImpl is an app short struct that consists of all the dependencies needed for short repository @@ -143,6 +144,18 @@ func (ss *ShortServiceImpl) UpdateVisitorShort(ctx context.Context, req *model.U return nil } +func (ss *ShortServiceImpl) UpdateShort(ctx context.Context, req *model.UpdateShortRequest) error { + tr := ss.Tracer.Tracer("Shortener-UpdateShort Service") + ctx, span := tr.Start(ctx, "Start UpdateShort") + defer span.End() + + if _, err := url.ParseRequestURI(req.FullURL); err != nil { + return model.NewError(model.Validation, err.Error()) + } + + return ss.ShortRepo.UpdateFullURLByID(ctx, req) +} + func (ss *ShortServiceImpl) validateCreateShort(req *model.CreateShortRequest) error { if _, err := url.ParseRequestURI(req.FullURL); err != nil { return model.NewError(model.Validation, err.Error()) diff --git a/shortener/pkg/api/v1/proto/shortener/shortener.pb.go b/shortener/pkg/api/v1/proto/shortener/shortener.pb.go index 7f49d60..56ac910 100644 --- a/shortener/pkg/api/v1/proto/shortener/shortener.pb.go +++ b/shortener/pkg/api/v1/proto/shortener/shortener.pb.go @@ -295,6 +295,61 @@ func (x *UpdateVisitorCountMessage) GetShortUrl() string { return "" } +type UpdateShortenerMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + FullUrl string `protobuf:"bytes,2,opt,name=full_url,json=fullUrl,proto3" json:"full_url,omitempty"` +} + +func (x *UpdateShortenerMessage) Reset() { + *x = UpdateShortenerMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_api_v1_proto_shortener_shortener_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateShortenerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateShortenerMessage) ProtoMessage() {} + +func (x *UpdateShortenerMessage) ProtoReflect() protoreflect.Message { + mi := &file_api_v1_proto_shortener_shortener_proto_msgTypes[5] + 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 UpdateShortenerMessage.ProtoReflect.Descriptor instead. +func (*UpdateShortenerMessage) Descriptor() ([]byte, []int) { + return file_api_v1_proto_shortener_shortener_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdateShortenerMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateShortenerMessage) GetFullUrl() string { + if x != nil { + return x.FullUrl + } + return "" +} + var File_api_v1_proto_shortener_shortener_proto protoreflect.FileDescriptor var file_api_v1_proto_shortener_shortener_proto_rawDesc = []byte{ @@ -328,21 +383,26 @@ var file_api_v1_proto_shortener_shortener_proto_rawDesc = []byte{ 0x65, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x72, - 0x6c, 0x32, 0x8b, 0x01, 0x0a, 0x10, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x42, 0x79, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x12, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, - 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x55, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x69, - 0x63, 0x6b, 0x48, 0x44, 0x2f, 0x73, 0x69, 0x6e, 0x67, 0x6b, 0x61, 0x74, 0x69, 0x6e, 0x2d, 0x72, - 0x65, 0x76, 0x61, 0x6d, 0x70, 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x2f, - 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3b, 0x73, 0x68, 0x6f, 0x72, 0x74, - 0x65, 0x6e, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x22, 0x43, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x66, + 0x75, 0x6c, 0x6c, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, + 0x75, 0x6c, 0x6c, 0x55, 0x72, 0x6c, 0x32, 0x8b, 0x01, 0x0a, 0x10, 0x53, 0x68, 0x6f, 0x72, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x18, 0x47, + 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x42, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x50, 0x69, 0x63, 0x6b, 0x48, 0x44, 0x2f, 0x73, 0x69, 0x6e, 0x67, 0x6b, 0x61, + 0x74, 0x69, 0x6e, 0x2d, 0x72, 0x65, 0x76, 0x61, 0x6d, 0x70, 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x3b, + 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -357,13 +417,14 @@ func file_api_v1_proto_shortener_shortener_proto_rawDescGZIP() []byte { return file_api_v1_proto_shortener_shortener_proto_rawDescData } -var file_api_v1_proto_shortener_shortener_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_api_v1_proto_shortener_shortener_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_api_v1_proto_shortener_shortener_proto_goTypes = []interface{}{ (*Shortener)(nil), // 0: api.v1.proto.shortener.Shortener (*ListShortenerRequest)(nil), // 1: api.v1.proto.shortener.ListShortenerRequest (*ListShortenerResponse)(nil), // 2: api.v1.proto.shortener.ListShortenerResponse (*CreateShortenerMessage)(nil), // 3: api.v1.proto.shortener.CreateShortenerMessage (*UpdateVisitorCountMessage)(nil), // 4: api.v1.proto.shortener.UpdateVisitorCountMessage + (*UpdateShortenerMessage)(nil), // 5: api.v1.proto.shortener.UpdateShortenerMessage } var file_api_v1_proto_shortener_shortener_proto_depIdxs = []int32{ 0, // 0: api.v1.proto.shortener.ListShortenerResponse.shorteners:type_name -> api.v1.proto.shortener.Shortener @@ -442,6 +503,18 @@ func file_api_v1_proto_shortener_shortener_proto_init() { return nil } } + file_api_v1_proto_shortener_shortener_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateShortenerMessage); 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{ @@ -449,7 +522,7 @@ func file_api_v1_proto_shortener_shortener_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_v1_proto_shortener_shortener_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, },