diff --git a/constant/biz/comment.go b/constant/biz/comment.go new file mode 100644 index 0000000..f1aa24a --- /dev/null +++ b/constant/biz/comment.go @@ -0,0 +1,22 @@ +package biz + +import httpStatus "github.com/cloudwego/hertz/pkg/protocol/consts" + +const ( + InvalidCommentActionType = 400001 + VideoNotFound = 400002 + ActorIDNotMatch = 403001 + UnableToCreateComment = 500001 + UnableToDeleteComment = 500002 + UnableToQueryVideo = 500003 + UnableToQueryComment = 500004 + UnableToQueryUser = 500005 +) + +var ( + UnauthorizedError = GWError{HTTPStatusCode: httpStatus.StatusUnauthorized, StatusCode: 400003, StatusMsg: "Unauthorized"} + + BadRequestError = GWError{HTTPStatusCode: httpStatus.StatusBadRequest, StatusCode: 400004, StatusMsg: "Bad request"} + + InternalServerError = GWError{HTTPStatusCode: httpStatus.StatusInternalServerError, StatusCode: 500006, StatusMsg: "Internal server error"} +) diff --git a/constant/biz/response.go b/constant/biz/response.go index 11bbb76..c26cfb3 100644 --- a/constant/biz/response.go +++ b/constant/biz/response.go @@ -8,5 +8,6 @@ var ( OkStatusMsg = "OK" BadRequestStatusMsg = "Unable to finish request, please check your parameters. If you think this is a bug, please contact us." + ForbiddenStatusMsg = "You are not allowed to access this resource." InternalServerErrorStatusMsg = "The server had an error while processing your request. Sorry about that!" ) diff --git a/constant/config/service.go b/constant/config/service.go index 9e862cb..e047410 100644 --- a/constant/config/service.go +++ b/constant/config/service.go @@ -14,3 +14,6 @@ const FeedServiceAddr = ":40129" const UserServiceName = "toktik-user" const UserServiceAddr = ":40130" + +const CommentServiceName = "toktik-comment-api" +const CommentServiceAddr = ":40131" diff --git a/idl/comment.proto b/idl/comment.proto new file mode 100644 index 0000000..320eabc --- /dev/null +++ b/idl/comment.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; +package douyin.comment; +option go_package = "douyin/comment"; + +import "user.proto"; + +message Comment { + uint32 id = 1; + user.User user = 2; + string content = 3; + string create_date = 4; +} + +enum ActionCommentType { + ACTION_COMMENT_TYPE_UNSPECIFIED = 0; // Only for protobuf compatibility + ACTION_COMMENT_TYPE_ADD = 1; + ACTION_COMMENT_TYPE_DELETE = 2; +} + +message ActionCommentRequest { + uint32 actor_id = 1; + uint32 video_id = 2; + ActionCommentType action_type = 3; + oneof action { + string comment_text = 4; + uint32 comment_id = 5; + } +} + +message ActionCommentResponse { + uint32 status_code = 1; + optional string status_msg = 2; + optional Comment comment = 3; +} + + +message ListCommentRequest { + uint32 actor_id = 1; + uint32 video_id = 2; +} + +message ListCommentResponse { + uint32 status_code = 1; + optional string status_msg = 2; + repeated Comment comment_list = 3; +} + + +service CommentService { + rpc ActionComment(ActionCommentRequest) returns (ActionCommentResponse); + rpc ListComment(ListCommentRequest) returns (ListCommentResponse); +} diff --git a/kitex_gen/douyin/comment/comment.pb.fast.go b/kitex_gen/douyin/comment/comment.pb.fast.go new file mode 100644 index 0000000..d6c128b --- /dev/null +++ b/kitex_gen/douyin/comment/comment.pb.fast.go @@ -0,0 +1,699 @@ +// Code generated by Fastpb v0.0.2. DO NOT EDIT. + +package comment + +import ( + fmt "fmt" + fastpb "github.com/cloudwego/fastpb" + user "toktik/kitex_gen/douyin/user" +) + +var ( + _ = fmt.Errorf + _ = fastpb.Skip +) + +func (x *Comment) FastRead(buf []byte, _type int8, number int32) (offset int, err error) { + switch number { + case 1: + offset, err = x.fastReadField1(buf, _type) + if err != nil { + goto ReadFieldError + } + case 2: + offset, err = x.fastReadField2(buf, _type) + if err != nil { + goto ReadFieldError + } + case 3: + offset, err = x.fastReadField3(buf, _type) + if err != nil { + goto ReadFieldError + } + case 4: + offset, err = x.fastReadField4(buf, _type) + if err != nil { + goto ReadFieldError + } + default: + offset, err = fastpb.Skip(buf, _type, number) + if err != nil { + goto SkipFieldError + } + } + return offset, nil +SkipFieldError: + return offset, fmt.Errorf("%T cannot parse invalid wire-format data, error: %s", x, err) +ReadFieldError: + return offset, fmt.Errorf("%T read field %d '%s' error: %s", x, number, fieldIDToName_Comment[number], err) +} + +func (x *Comment) fastReadField1(buf []byte, _type int8) (offset int, err error) { + x.Id, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *Comment) fastReadField2(buf []byte, _type int8) (offset int, err error) { + var v user.User + offset, err = fastpb.ReadMessage(buf, _type, &v) + if err != nil { + return offset, err + } + x.User = &v + return offset, nil +} + +func (x *Comment) fastReadField3(buf []byte, _type int8) (offset int, err error) { + x.Content, offset, err = fastpb.ReadString(buf, _type) + return offset, err +} + +func (x *Comment) fastReadField4(buf []byte, _type int8) (offset int, err error) { + x.CreateDate, offset, err = fastpb.ReadString(buf, _type) + return offset, err +} + +func (x *ActionCommentRequest) FastRead(buf []byte, _type int8, number int32) (offset int, err error) { + switch number { + case 1: + offset, err = x.fastReadField1(buf, _type) + if err != nil { + goto ReadFieldError + } + case 2: + offset, err = x.fastReadField2(buf, _type) + if err != nil { + goto ReadFieldError + } + case 3: + offset, err = x.fastReadField3(buf, _type) + if err != nil { + goto ReadFieldError + } + case 4: + offset, err = x.fastReadField4(buf, _type) + if err != nil { + goto ReadFieldError + } + case 5: + offset, err = x.fastReadField5(buf, _type) + if err != nil { + goto ReadFieldError + } + default: + offset, err = fastpb.Skip(buf, _type, number) + if err != nil { + goto SkipFieldError + } + } + return offset, nil +SkipFieldError: + return offset, fmt.Errorf("%T cannot parse invalid wire-format data, error: %s", x, err) +ReadFieldError: + return offset, fmt.Errorf("%T read field %d '%s' error: %s", x, number, fieldIDToName_ActionCommentRequest[number], err) +} + +func (x *ActionCommentRequest) fastReadField1(buf []byte, _type int8) (offset int, err error) { + x.ActorId, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ActionCommentRequest) fastReadField2(buf []byte, _type int8) (offset int, err error) { + x.VideoId, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ActionCommentRequest) fastReadField3(buf []byte, _type int8) (offset int, err error) { + var v int32 + v, offset, err = fastpb.ReadInt32(buf, _type) + if err != nil { + return offset, err + } + x.ActionType = ActionCommentType(v) + return offset, nil +} + +func (x *ActionCommentRequest) fastReadField4(buf []byte, _type int8) (offset int, err error) { + var ov ActionCommentRequest_CommentText + x.Action = &ov + ov.CommentText, offset, err = fastpb.ReadString(buf, _type) + return offset, err +} + +func (x *ActionCommentRequest) fastReadField5(buf []byte, _type int8) (offset int, err error) { + var ov ActionCommentRequest_CommentId + x.Action = &ov + ov.CommentId, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ActionCommentResponse) FastRead(buf []byte, _type int8, number int32) (offset int, err error) { + switch number { + case 1: + offset, err = x.fastReadField1(buf, _type) + if err != nil { + goto ReadFieldError + } + case 2: + offset, err = x.fastReadField2(buf, _type) + if err != nil { + goto ReadFieldError + } + case 3: + offset, err = x.fastReadField3(buf, _type) + if err != nil { + goto ReadFieldError + } + default: + offset, err = fastpb.Skip(buf, _type, number) + if err != nil { + goto SkipFieldError + } + } + return offset, nil +SkipFieldError: + return offset, fmt.Errorf("%T cannot parse invalid wire-format data, error: %s", x, err) +ReadFieldError: + return offset, fmt.Errorf("%T read field %d '%s' error: %s", x, number, fieldIDToName_ActionCommentResponse[number], err) +} + +func (x *ActionCommentResponse) fastReadField1(buf []byte, _type int8) (offset int, err error) { + x.StatusCode, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ActionCommentResponse) fastReadField2(buf []byte, _type int8) (offset int, err error) { + tmp, offset, err := fastpb.ReadString(buf, _type) + x.StatusMsg = &tmp + return offset, err +} + +func (x *ActionCommentResponse) fastReadField3(buf []byte, _type int8) (offset int, err error) { + var v Comment + offset, err = fastpb.ReadMessage(buf, _type, &v) + if err != nil { + return offset, err + } + x.Comment = &v + return offset, nil +} + +func (x *ListCommentRequest) FastRead(buf []byte, _type int8, number int32) (offset int, err error) { + switch number { + case 1: + offset, err = x.fastReadField1(buf, _type) + if err != nil { + goto ReadFieldError + } + case 2: + offset, err = x.fastReadField2(buf, _type) + if err != nil { + goto ReadFieldError + } + default: + offset, err = fastpb.Skip(buf, _type, number) + if err != nil { + goto SkipFieldError + } + } + return offset, nil +SkipFieldError: + return offset, fmt.Errorf("%T cannot parse invalid wire-format data, error: %s", x, err) +ReadFieldError: + return offset, fmt.Errorf("%T read field %d '%s' error: %s", x, number, fieldIDToName_ListCommentRequest[number], err) +} + +func (x *ListCommentRequest) fastReadField1(buf []byte, _type int8) (offset int, err error) { + x.ActorId, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ListCommentRequest) fastReadField2(buf []byte, _type int8) (offset int, err error) { + x.VideoId, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ListCommentResponse) FastRead(buf []byte, _type int8, number int32) (offset int, err error) { + switch number { + case 1: + offset, err = x.fastReadField1(buf, _type) + if err != nil { + goto ReadFieldError + } + case 2: + offset, err = x.fastReadField2(buf, _type) + if err != nil { + goto ReadFieldError + } + case 3: + offset, err = x.fastReadField3(buf, _type) + if err != nil { + goto ReadFieldError + } + default: + offset, err = fastpb.Skip(buf, _type, number) + if err != nil { + goto SkipFieldError + } + } + return offset, nil +SkipFieldError: + return offset, fmt.Errorf("%T cannot parse invalid wire-format data, error: %s", x, err) +ReadFieldError: + return offset, fmt.Errorf("%T read field %d '%s' error: %s", x, number, fieldIDToName_ListCommentResponse[number], err) +} + +func (x *ListCommentResponse) fastReadField1(buf []byte, _type int8) (offset int, err error) { + x.StatusCode, offset, err = fastpb.ReadUint32(buf, _type) + return offset, err +} + +func (x *ListCommentResponse) fastReadField2(buf []byte, _type int8) (offset int, err error) { + tmp, offset, err := fastpb.ReadString(buf, _type) + x.StatusMsg = &tmp + return offset, err +} + +func (x *ListCommentResponse) fastReadField3(buf []byte, _type int8) (offset int, err error) { + var v Comment + offset, err = fastpb.ReadMessage(buf, _type, &v) + if err != nil { + return offset, err + } + x.CommentList = append(x.CommentList, &v) + return offset, nil +} + +func (x *Comment) FastWrite(buf []byte) (offset int) { + if x == nil { + return offset + } + offset += x.fastWriteField1(buf[offset:]) + offset += x.fastWriteField2(buf[offset:]) + offset += x.fastWriteField3(buf[offset:]) + offset += x.fastWriteField4(buf[offset:]) + return offset +} + +func (x *Comment) fastWriteField1(buf []byte) (offset int) { + if x.Id == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 1, x.Id) + return offset +} + +func (x *Comment) fastWriteField2(buf []byte) (offset int) { + if x.User == nil { + return offset + } + offset += fastpb.WriteMessage(buf[offset:], 2, x.User) + return offset +} + +func (x *Comment) fastWriteField3(buf []byte) (offset int) { + if x.Content == "" { + return offset + } + offset += fastpb.WriteString(buf[offset:], 3, x.Content) + return offset +} + +func (x *Comment) fastWriteField4(buf []byte) (offset int) { + if x.CreateDate == "" { + return offset + } + offset += fastpb.WriteString(buf[offset:], 4, x.CreateDate) + return offset +} + +func (x *ActionCommentRequest) FastWrite(buf []byte) (offset int) { + if x == nil { + return offset + } + offset += x.fastWriteField1(buf[offset:]) + offset += x.fastWriteField2(buf[offset:]) + offset += x.fastWriteField3(buf[offset:]) + offset += x.fastWriteField4(buf[offset:]) + offset += x.fastWriteField5(buf[offset:]) + return offset +} + +func (x *ActionCommentRequest) fastWriteField1(buf []byte) (offset int) { + if x.ActorId == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 1, x.ActorId) + return offset +} + +func (x *ActionCommentRequest) fastWriteField2(buf []byte) (offset int) { + if x.VideoId == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 2, x.VideoId) + return offset +} + +func (x *ActionCommentRequest) fastWriteField3(buf []byte) (offset int) { + if x.ActionType == 0 { + return offset + } + offset += fastpb.WriteInt32(buf[offset:], 3, int32(x.ActionType)) + return offset +} + +func (x *ActionCommentRequest) fastWriteField4(buf []byte) (offset int) { + if x.GetCommentText() == "" { + return offset + } + offset += fastpb.WriteString(buf[offset:], 4, x.GetCommentText()) + return offset +} + +func (x *ActionCommentRequest) fastWriteField5(buf []byte) (offset int) { + if x.GetCommentId() == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 5, x.GetCommentId()) + return offset +} + +func (x *ActionCommentResponse) FastWrite(buf []byte) (offset int) { + if x == nil { + return offset + } + offset += x.fastWriteField1(buf[offset:]) + offset += x.fastWriteField2(buf[offset:]) + offset += x.fastWriteField3(buf[offset:]) + return offset +} + +func (x *ActionCommentResponse) fastWriteField1(buf []byte) (offset int) { + if x.StatusCode == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 1, x.StatusCode) + return offset +} + +func (x *ActionCommentResponse) fastWriteField2(buf []byte) (offset int) { + if x.StatusMsg == nil { + return offset + } + offset += fastpb.WriteString(buf[offset:], 2, *x.StatusMsg) + return offset +} + +func (x *ActionCommentResponse) fastWriteField3(buf []byte) (offset int) { + if x.Comment == nil { + return offset + } + offset += fastpb.WriteMessage(buf[offset:], 3, x.Comment) + return offset +} + +func (x *ListCommentRequest) FastWrite(buf []byte) (offset int) { + if x == nil { + return offset + } + offset += x.fastWriteField1(buf[offset:]) + offset += x.fastWriteField2(buf[offset:]) + return offset +} + +func (x *ListCommentRequest) fastWriteField1(buf []byte) (offset int) { + if x.ActorId == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 1, x.ActorId) + return offset +} + +func (x *ListCommentRequest) fastWriteField2(buf []byte) (offset int) { + if x.VideoId == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 2, x.VideoId) + return offset +} + +func (x *ListCommentResponse) FastWrite(buf []byte) (offset int) { + if x == nil { + return offset + } + offset += x.fastWriteField1(buf[offset:]) + offset += x.fastWriteField2(buf[offset:]) + offset += x.fastWriteField3(buf[offset:]) + return offset +} + +func (x *ListCommentResponse) fastWriteField1(buf []byte) (offset int) { + if x.StatusCode == 0 { + return offset + } + offset += fastpb.WriteUint32(buf[offset:], 1, x.StatusCode) + return offset +} + +func (x *ListCommentResponse) fastWriteField2(buf []byte) (offset int) { + if x.StatusMsg == nil { + return offset + } + offset += fastpb.WriteString(buf[offset:], 2, *x.StatusMsg) + return offset +} + +func (x *ListCommentResponse) fastWriteField3(buf []byte) (offset int) { + if x.CommentList == nil { + return offset + } + for i := range x.CommentList { + offset += fastpb.WriteMessage(buf[offset:], 3, x.CommentList[i]) + } + return offset +} + +func (x *Comment) Size() (n int) { + if x == nil { + return n + } + n += x.sizeField1() + n += x.sizeField2() + n += x.sizeField3() + n += x.sizeField4() + return n +} + +func (x *Comment) sizeField1() (n int) { + if x.Id == 0 { + return n + } + n += fastpb.SizeUint32(1, x.Id) + return n +} + +func (x *Comment) sizeField2() (n int) { + if x.User == nil { + return n + } + n += fastpb.SizeMessage(2, x.User) + return n +} + +func (x *Comment) sizeField3() (n int) { + if x.Content == "" { + return n + } + n += fastpb.SizeString(3, x.Content) + return n +} + +func (x *Comment) sizeField4() (n int) { + if x.CreateDate == "" { + return n + } + n += fastpb.SizeString(4, x.CreateDate) + return n +} + +func (x *ActionCommentRequest) Size() (n int) { + if x == nil { + return n + } + n += x.sizeField1() + n += x.sizeField2() + n += x.sizeField3() + n += x.sizeField4() + n += x.sizeField5() + return n +} + +func (x *ActionCommentRequest) sizeField1() (n int) { + if x.ActorId == 0 { + return n + } + n += fastpb.SizeUint32(1, x.ActorId) + return n +} + +func (x *ActionCommentRequest) sizeField2() (n int) { + if x.VideoId == 0 { + return n + } + n += fastpb.SizeUint32(2, x.VideoId) + return n +} + +func (x *ActionCommentRequest) sizeField3() (n int) { + if x.ActionType == 0 { + return n + } + n += fastpb.SizeInt32(3, int32(x.ActionType)) + return n +} + +func (x *ActionCommentRequest) sizeField4() (n int) { + if x.GetCommentText() == "" { + return n + } + n += fastpb.SizeString(4, x.GetCommentText()) + return n +} + +func (x *ActionCommentRequest) sizeField5() (n int) { + if x.GetCommentId() == 0 { + return n + } + n += fastpb.SizeUint32(5, x.GetCommentId()) + return n +} + +func (x *ActionCommentResponse) Size() (n int) { + if x == nil { + return n + } + n += x.sizeField1() + n += x.sizeField2() + n += x.sizeField3() + return n +} + +func (x *ActionCommentResponse) sizeField1() (n int) { + if x.StatusCode == 0 { + return n + } + n += fastpb.SizeUint32(1, x.StatusCode) + return n +} + +func (x *ActionCommentResponse) sizeField2() (n int) { + if x.StatusMsg == nil { + return n + } + n += fastpb.SizeString(2, *x.StatusMsg) + return n +} + +func (x *ActionCommentResponse) sizeField3() (n int) { + if x.Comment == nil { + return n + } + n += fastpb.SizeMessage(3, x.Comment) + return n +} + +func (x *ListCommentRequest) Size() (n int) { + if x == nil { + return n + } + n += x.sizeField1() + n += x.sizeField2() + return n +} + +func (x *ListCommentRequest) sizeField1() (n int) { + if x.ActorId == 0 { + return n + } + n += fastpb.SizeUint32(1, x.ActorId) + return n +} + +func (x *ListCommentRequest) sizeField2() (n int) { + if x.VideoId == 0 { + return n + } + n += fastpb.SizeUint32(2, x.VideoId) + return n +} + +func (x *ListCommentResponse) Size() (n int) { + if x == nil { + return n + } + n += x.sizeField1() + n += x.sizeField2() + n += x.sizeField3() + return n +} + +func (x *ListCommentResponse) sizeField1() (n int) { + if x.StatusCode == 0 { + return n + } + n += fastpb.SizeUint32(1, x.StatusCode) + return n +} + +func (x *ListCommentResponse) sizeField2() (n int) { + if x.StatusMsg == nil { + return n + } + n += fastpb.SizeString(2, *x.StatusMsg) + return n +} + +func (x *ListCommentResponse) sizeField3() (n int) { + if x.CommentList == nil { + return n + } + for i := range x.CommentList { + n += fastpb.SizeMessage(3, x.CommentList[i]) + } + return n +} + +var fieldIDToName_Comment = map[int32]string{ + 1: "Id", + 2: "User", + 3: "Content", + 4: "CreateDate", +} + +var fieldIDToName_ActionCommentRequest = map[int32]string{ + 1: "ActorId", + 2: "VideoId", + 3: "ActionType", + 4: "CommentText", + 5: "CommentId", +} + +var fieldIDToName_ActionCommentResponse = map[int32]string{ + 1: "StatusCode", + 2: "StatusMsg", + 3: "Comment", +} + +var fieldIDToName_ListCommentRequest = map[int32]string{ + 1: "ActorId", + 2: "VideoId", +} + +var fieldIDToName_ListCommentResponse = map[int32]string{ + 1: "StatusCode", + 2: "StatusMsg", + 3: "CommentList", +} + +var _ = user.File_user_proto diff --git a/kitex_gen/douyin/comment/comment.pb.go b/kitex_gen/douyin/comment/comment.pb.go new file mode 100644 index 0000000..e8c210f --- /dev/null +++ b/kitex_gen/douyin/comment/comment.pb.go @@ -0,0 +1,650 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: comment.proto + +package comment + +import ( + context "context" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + user "toktik/kitex_gen/douyin/user" +) + +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 ActionCommentType int32 + +const ( + ActionCommentType_ACTION_COMMENT_TYPE_UNSPECIFIED ActionCommentType = 0 // Only for protobuf compatibility + ActionCommentType_ACTION_COMMENT_TYPE_ADD ActionCommentType = 1 + ActionCommentType_ACTION_COMMENT_TYPE_DELETE ActionCommentType = 2 +) + +// Enum value maps for ActionCommentType. +var ( + ActionCommentType_name = map[int32]string{ + 0: "ACTION_COMMENT_TYPE_UNSPECIFIED", + 1: "ACTION_COMMENT_TYPE_ADD", + 2: "ACTION_COMMENT_TYPE_DELETE", + } + ActionCommentType_value = map[string]int32{ + "ACTION_COMMENT_TYPE_UNSPECIFIED": 0, + "ACTION_COMMENT_TYPE_ADD": 1, + "ACTION_COMMENT_TYPE_DELETE": 2, + } +) + +func (x ActionCommentType) Enum() *ActionCommentType { + p := new(ActionCommentType) + *p = x + return p +} + +func (x ActionCommentType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ActionCommentType) Descriptor() protoreflect.EnumDescriptor { + return file_comment_proto_enumTypes[0].Descriptor() +} + +func (ActionCommentType) Type() protoreflect.EnumType { + return &file_comment_proto_enumTypes[0] +} + +func (x ActionCommentType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ActionCommentType.Descriptor instead. +func (ActionCommentType) EnumDescriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{0} +} + +type Comment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + User *user.User `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + CreateDate string `protobuf:"bytes,4,opt,name=create_date,json=createDate,proto3" json:"create_date,omitempty"` +} + +func (x *Comment) Reset() { + *x = Comment{} + if protoimpl.UnsafeEnabled { + mi := &file_comment_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Comment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Comment) ProtoMessage() {} + +func (x *Comment) ProtoReflect() protoreflect.Message { + mi := &file_comment_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 Comment.ProtoReflect.Descriptor instead. +func (*Comment) Descriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{0} +} + +func (x *Comment) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Comment) GetUser() *user.User { + if x != nil { + return x.User + } + return nil +} + +func (x *Comment) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Comment) GetCreateDate() string { + if x != nil { + return x.CreateDate + } + return "" +} + +type ActionCommentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActorId uint32 `protobuf:"varint,1,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"` + VideoId uint32 `protobuf:"varint,2,opt,name=video_id,json=videoId,proto3" json:"video_id,omitempty"` + ActionType ActionCommentType `protobuf:"varint,3,opt,name=action_type,json=actionType,proto3,enum=douyin.comment.ActionCommentType" json:"action_type,omitempty"` + // Types that are assignable to Action: + // + // *ActionCommentRequest_CommentText + // *ActionCommentRequest_CommentId + Action isActionCommentRequest_Action `protobuf_oneof:"action"` +} + +func (x *ActionCommentRequest) Reset() { + *x = ActionCommentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_comment_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ActionCommentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActionCommentRequest) ProtoMessage() {} + +func (x *ActionCommentRequest) ProtoReflect() protoreflect.Message { + mi := &file_comment_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 ActionCommentRequest.ProtoReflect.Descriptor instead. +func (*ActionCommentRequest) Descriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{1} +} + +func (x *ActionCommentRequest) GetActorId() uint32 { + if x != nil { + return x.ActorId + } + return 0 +} + +func (x *ActionCommentRequest) GetVideoId() uint32 { + if x != nil { + return x.VideoId + } + return 0 +} + +func (x *ActionCommentRequest) GetActionType() ActionCommentType { + if x != nil { + return x.ActionType + } + return ActionCommentType_ACTION_COMMENT_TYPE_UNSPECIFIED +} + +func (m *ActionCommentRequest) GetAction() isActionCommentRequest_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *ActionCommentRequest) GetCommentText() string { + if x, ok := x.GetAction().(*ActionCommentRequest_CommentText); ok { + return x.CommentText + } + return "" +} + +func (x *ActionCommentRequest) GetCommentId() uint32 { + if x, ok := x.GetAction().(*ActionCommentRequest_CommentId); ok { + return x.CommentId + } + return 0 +} + +type isActionCommentRequest_Action interface { + isActionCommentRequest_Action() +} + +type ActionCommentRequest_CommentText struct { + CommentText string `protobuf:"bytes,4,opt,name=comment_text,json=commentText,proto3,oneof"` +} + +type ActionCommentRequest_CommentId struct { + CommentId uint32 `protobuf:"varint,5,opt,name=comment_id,json=commentId,proto3,oneof"` +} + +func (*ActionCommentRequest_CommentText) isActionCommentRequest_Action() {} + +func (*ActionCommentRequest_CommentId) isActionCommentRequest_Action() {} + +type ActionCommentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatusCode uint32 `protobuf:"varint,1,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + StatusMsg *string `protobuf:"bytes,2,opt,name=status_msg,json=statusMsg,proto3,oneof" json:"status_msg,omitempty"` + Comment *Comment `protobuf:"bytes,3,opt,name=comment,proto3,oneof" json:"comment,omitempty"` +} + +func (x *ActionCommentResponse) Reset() { + *x = ActionCommentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_comment_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ActionCommentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActionCommentResponse) ProtoMessage() {} + +func (x *ActionCommentResponse) ProtoReflect() protoreflect.Message { + mi := &file_comment_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActionCommentResponse.ProtoReflect.Descriptor instead. +func (*ActionCommentResponse) Descriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{2} +} + +func (x *ActionCommentResponse) GetStatusCode() uint32 { + if x != nil { + return x.StatusCode + } + return 0 +} + +func (x *ActionCommentResponse) GetStatusMsg() string { + if x != nil && x.StatusMsg != nil { + return *x.StatusMsg + } + return "" +} + +func (x *ActionCommentResponse) GetComment() *Comment { + if x != nil { + return x.Comment + } + return nil +} + +type ListCommentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActorId uint32 `protobuf:"varint,1,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"` + VideoId uint32 `protobuf:"varint,2,opt,name=video_id,json=videoId,proto3" json:"video_id,omitempty"` +} + +func (x *ListCommentRequest) Reset() { + *x = ListCommentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_comment_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListCommentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCommentRequest) ProtoMessage() {} + +func (x *ListCommentRequest) ProtoReflect() protoreflect.Message { + mi := &file_comment_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCommentRequest.ProtoReflect.Descriptor instead. +func (*ListCommentRequest) Descriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{3} +} + +func (x *ListCommentRequest) GetActorId() uint32 { + if x != nil { + return x.ActorId + } + return 0 +} + +func (x *ListCommentRequest) GetVideoId() uint32 { + if x != nil { + return x.VideoId + } + return 0 +} + +type ListCommentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatusCode uint32 `protobuf:"varint,1,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + StatusMsg *string `protobuf:"bytes,2,opt,name=status_msg,json=statusMsg,proto3,oneof" json:"status_msg,omitempty"` + CommentList []*Comment `protobuf:"bytes,3,rep,name=comment_list,json=commentList,proto3" json:"comment_list,omitempty"` +} + +func (x *ListCommentResponse) Reset() { + *x = ListCommentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_comment_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListCommentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCommentResponse) ProtoMessage() {} + +func (x *ListCommentResponse) ProtoReflect() protoreflect.Message { + mi := &file_comment_proto_msgTypes[4] + 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 ListCommentResponse.ProtoReflect.Descriptor instead. +func (*ListCommentResponse) Descriptor() ([]byte, []int) { + return file_comment_proto_rawDescGZIP(), []int{4} +} + +func (x *ListCommentResponse) GetStatusCode() uint32 { + if x != nil { + return x.StatusCode + } + return 0 +} + +func (x *ListCommentResponse) GetStatusMsg() string { + if x != nil && x.StatusMsg != nil { + return *x.StatusMsg + } + return "" +} + +func (x *ListCommentResponse) GetCommentList() []*Comment { + if x != nil { + return x.CommentList + } + return nil +} + +var File_comment_proto protoreflect.FileDescriptor + +var file_comment_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0e, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x1a, + 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, 0x07, 0x43, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x14, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x76, 0x69, 0x64, 0x65, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x76, 0x69, 0x64, 0x65, 0x6f, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x64, + 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x65, 0x78, 0x74, + 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xaf, 0x01, 0x0a, 0x15, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x4d, 0x73, 0x67, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, 0x6f, + 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x01, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x88, + 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x73, + 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x4a, 0x0a, + 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x49, 0x64, 0x22, 0xa5, 0x01, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x73, 0x67, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x4d, 0x73, 0x67, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x64, + 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, + 0x73, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x6d, 0x73, + 0x67, 0x2a, 0x75, 0x0a, 0x11, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x41, + 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x43, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x32, 0xc6, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x2e, 0x64, + 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0b, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x64, 0x6f, 0x75, 0x79, 0x69, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x64, + 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x74, 0x6f, 0x6b, 0x74, 0x69, 0x6b, 0x2f, 0x6b, 0x69, 0x74, 0x65, + 0x78, 0x5f, 0x67, 0x65, 0x6e, 0x2f, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_comment_proto_rawDescOnce sync.Once + file_comment_proto_rawDescData = file_comment_proto_rawDesc +) + +func file_comment_proto_rawDescGZIP() []byte { + file_comment_proto_rawDescOnce.Do(func() { + file_comment_proto_rawDescData = protoimpl.X.CompressGZIP(file_comment_proto_rawDescData) + }) + return file_comment_proto_rawDescData +} + +var file_comment_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_comment_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_comment_proto_goTypes = []interface{}{ + (ActionCommentType)(0), // 0: douyin.comment.ActionCommentType + (*Comment)(nil), // 1: douyin.comment.Comment + (*ActionCommentRequest)(nil), // 2: douyin.comment.ActionCommentRequest + (*ActionCommentResponse)(nil), // 3: douyin.comment.ActionCommentResponse + (*ListCommentRequest)(nil), // 4: douyin.comment.ListCommentRequest + (*ListCommentResponse)(nil), // 5: douyin.comment.ListCommentResponse + (*user.User)(nil), // 6: douyin.user.User +} +var file_comment_proto_depIdxs = []int32{ + 6, // 0: douyin.comment.Comment.user:type_name -> douyin.user.User + 0, // 1: douyin.comment.ActionCommentRequest.action_type:type_name -> douyin.comment.ActionCommentType + 1, // 2: douyin.comment.ActionCommentResponse.comment:type_name -> douyin.comment.Comment + 1, // 3: douyin.comment.ListCommentResponse.comment_list:type_name -> douyin.comment.Comment + 2, // 4: douyin.comment.CommentService.ActionComment:input_type -> douyin.comment.ActionCommentRequest + 4, // 5: douyin.comment.CommentService.ListComment:input_type -> douyin.comment.ListCommentRequest + 3, // 6: douyin.comment.CommentService.ActionComment:output_type -> douyin.comment.ActionCommentResponse + 5, // 7: douyin.comment.CommentService.ListComment:output_type -> douyin.comment.ListCommentResponse + 6, // [6:8] is the sub-list for method output_type + 4, // [4:6] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_comment_proto_init() } +func file_comment_proto_init() { + if File_comment_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_comment_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Comment); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_comment_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ActionCommentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_comment_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ActionCommentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_comment_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListCommentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_comment_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListCommentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_comment_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*ActionCommentRequest_CommentText)(nil), + (*ActionCommentRequest_CommentId)(nil), + } + file_comment_proto_msgTypes[2].OneofWrappers = []interface{}{} + file_comment_proto_msgTypes[4].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_comment_proto_rawDesc, + NumEnums: 1, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_comment_proto_goTypes, + DependencyIndexes: file_comment_proto_depIdxs, + EnumInfos: file_comment_proto_enumTypes, + MessageInfos: file_comment_proto_msgTypes, + }.Build() + File_comment_proto = out.File + file_comment_proto_rawDesc = nil + file_comment_proto_goTypes = nil + file_comment_proto_depIdxs = nil +} + +var _ context.Context + +// Code generated by Kitex v0.4.4. DO NOT EDIT. + +type CommentService interface { + ActionComment(ctx context.Context, req *ActionCommentRequest) (res *ActionCommentResponse, err error) + ListComment(ctx context.Context, req *ListCommentRequest) (res *ListCommentResponse, err error) +} diff --git a/kitex_gen/douyin/comment/commentservice/client.go b/kitex_gen/douyin/comment/commentservice/client.go new file mode 100644 index 0000000..754eb12 --- /dev/null +++ b/kitex_gen/douyin/comment/commentservice/client.go @@ -0,0 +1,55 @@ +// Code generated by Kitex v0.4.4. DO NOT EDIT. + +package commentservice + +import ( + "context" + client "github.com/cloudwego/kitex/client" + callopt "github.com/cloudwego/kitex/client/callopt" + comment "toktik/kitex_gen/douyin/comment" +) + +// Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. +type Client interface { + ActionComment(ctx context.Context, Req *comment.ActionCommentRequest, callOptions ...callopt.Option) (r *comment.ActionCommentResponse, err error) + ListComment(ctx context.Context, Req *comment.ListCommentRequest, callOptions ...callopt.Option) (r *comment.ListCommentResponse, err error) +} + +// NewClient creates a client for the service defined in IDL. +func NewClient(destService string, opts ...client.Option) (Client, error) { + var options []client.Option + options = append(options, client.WithDestService(destService)) + + options = append(options, opts...) + + kc, err := client.NewClient(serviceInfo(), options...) + if err != nil { + return nil, err + } + return &kCommentServiceClient{ + kClient: newServiceClient(kc), + }, nil +} + +// MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. +func MustNewClient(destService string, opts ...client.Option) Client { + kc, err := NewClient(destService, opts...) + if err != nil { + panic(err) + } + return kc +} + +type kCommentServiceClient struct { + *kClient +} + +func (p *kCommentServiceClient) ActionComment(ctx context.Context, Req *comment.ActionCommentRequest, callOptions ...callopt.Option) (r *comment.ActionCommentResponse, err error) { + ctx = client.NewCtxWithCallOptions(ctx, callOptions) + return p.kClient.ActionComment(ctx, Req) +} + +func (p *kCommentServiceClient) ListComment(ctx context.Context, Req *comment.ListCommentRequest, callOptions ...callopt.Option) (r *comment.ListCommentResponse, err error) { + ctx = client.NewCtxWithCallOptions(ctx, callOptions) + return p.kClient.ListComment(ctx, Req) +} diff --git a/kitex_gen/douyin/comment/commentservice/commentservice.go b/kitex_gen/douyin/comment/commentservice/commentservice.go new file mode 100644 index 0000000..f023405 --- /dev/null +++ b/kitex_gen/douyin/comment/commentservice/commentservice.go @@ -0,0 +1,360 @@ +// Code generated by Kitex v0.4.4. DO NOT EDIT. + +package commentservice + +import ( + "context" + "fmt" + client "github.com/cloudwego/kitex/client" + kitex "github.com/cloudwego/kitex/pkg/serviceinfo" + streaming "github.com/cloudwego/kitex/pkg/streaming" + proto "google.golang.org/protobuf/proto" + comment "toktik/kitex_gen/douyin/comment" +) + +func serviceInfo() *kitex.ServiceInfo { + return commentServiceServiceInfo +} + +var commentServiceServiceInfo = NewServiceInfo() + +func NewServiceInfo() *kitex.ServiceInfo { + serviceName := "CommentService" + handlerType := (*comment.CommentService)(nil) + methods := map[string]kitex.MethodInfo{ + "ActionComment": kitex.NewMethodInfo(actionCommentHandler, newActionCommentArgs, newActionCommentResult, false), + "ListComment": kitex.NewMethodInfo(listCommentHandler, newListCommentArgs, newListCommentResult, false), + } + extra := map[string]interface{}{ + "PackageName": "douyin.comment", + } + svcInfo := &kitex.ServiceInfo{ + ServiceName: serviceName, + HandlerType: handlerType, + Methods: methods, + PayloadCodec: kitex.Protobuf, + KiteXGenVersion: "v0.4.4", + Extra: extra, + } + return svcInfo +} + +func actionCommentHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { + switch s := arg.(type) { + case *streaming.Args: + st := s.Stream + req := new(comment.ActionCommentRequest) + if err := st.RecvMsg(req); err != nil { + return err + } + resp, err := handler.(comment.CommentService).ActionComment(ctx, req) + if err != nil { + return err + } + if err := st.SendMsg(resp); err != nil { + return err + } + case *ActionCommentArgs: + success, err := handler.(comment.CommentService).ActionComment(ctx, s.Req) + if err != nil { + return err + } + realResult := result.(*ActionCommentResult) + realResult.Success = success + } + return nil +} +func newActionCommentArgs() interface{} { + return &ActionCommentArgs{} +} + +func newActionCommentResult() interface{} { + return &ActionCommentResult{} +} + +type ActionCommentArgs struct { + Req *comment.ActionCommentRequest +} + +func (p *ActionCommentArgs) FastRead(buf []byte, _type int8, number int32) (n int, err error) { + if !p.IsSetReq() { + p.Req = new(comment.ActionCommentRequest) + } + return p.Req.FastRead(buf, _type, number) +} + +func (p *ActionCommentArgs) FastWrite(buf []byte) (n int) { + if !p.IsSetReq() { + return 0 + } + return p.Req.FastWrite(buf) +} + +func (p *ActionCommentArgs) Size() (n int) { + if !p.IsSetReq() { + return 0 + } + return p.Req.Size() +} + +func (p *ActionCommentArgs) Marshal(out []byte) ([]byte, error) { + if !p.IsSetReq() { + return out, fmt.Errorf("No req in ActionCommentArgs") + } + return proto.Marshal(p.Req) +} + +func (p *ActionCommentArgs) Unmarshal(in []byte) error { + msg := new(comment.ActionCommentRequest) + if err := proto.Unmarshal(in, msg); err != nil { + return err + } + p.Req = msg + return nil +} + +var ActionCommentArgs_Req_DEFAULT *comment.ActionCommentRequest + +func (p *ActionCommentArgs) GetReq() *comment.ActionCommentRequest { + if !p.IsSetReq() { + return ActionCommentArgs_Req_DEFAULT + } + return p.Req +} + +func (p *ActionCommentArgs) IsSetReq() bool { + return p.Req != nil +} + +type ActionCommentResult struct { + Success *comment.ActionCommentResponse +} + +var ActionCommentResult_Success_DEFAULT *comment.ActionCommentResponse + +func (p *ActionCommentResult) FastRead(buf []byte, _type int8, number int32) (n int, err error) { + if !p.IsSetSuccess() { + p.Success = new(comment.ActionCommentResponse) + } + return p.Success.FastRead(buf, _type, number) +} + +func (p *ActionCommentResult) FastWrite(buf []byte) (n int) { + if !p.IsSetSuccess() { + return 0 + } + return p.Success.FastWrite(buf) +} + +func (p *ActionCommentResult) Size() (n int) { + if !p.IsSetSuccess() { + return 0 + } + return p.Success.Size() +} + +func (p *ActionCommentResult) Marshal(out []byte) ([]byte, error) { + if !p.IsSetSuccess() { + return out, fmt.Errorf("No req in ActionCommentResult") + } + return proto.Marshal(p.Success) +} + +func (p *ActionCommentResult) Unmarshal(in []byte) error { + msg := new(comment.ActionCommentResponse) + if err := proto.Unmarshal(in, msg); err != nil { + return err + } + p.Success = msg + return nil +} + +func (p *ActionCommentResult) GetSuccess() *comment.ActionCommentResponse { + if !p.IsSetSuccess() { + return ActionCommentResult_Success_DEFAULT + } + return p.Success +} + +func (p *ActionCommentResult) SetSuccess(x interface{}) { + p.Success = x.(*comment.ActionCommentResponse) +} + +func (p *ActionCommentResult) IsSetSuccess() bool { + return p.Success != nil +} + +func listCommentHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { + switch s := arg.(type) { + case *streaming.Args: + st := s.Stream + req := new(comment.ListCommentRequest) + if err := st.RecvMsg(req); err != nil { + return err + } + resp, err := handler.(comment.CommentService).ListComment(ctx, req) + if err != nil { + return err + } + if err := st.SendMsg(resp); err != nil { + return err + } + case *ListCommentArgs: + success, err := handler.(comment.CommentService).ListComment(ctx, s.Req) + if err != nil { + return err + } + realResult := result.(*ListCommentResult) + realResult.Success = success + } + return nil +} +func newListCommentArgs() interface{} { + return &ListCommentArgs{} +} + +func newListCommentResult() interface{} { + return &ListCommentResult{} +} + +type ListCommentArgs struct { + Req *comment.ListCommentRequest +} + +func (p *ListCommentArgs) FastRead(buf []byte, _type int8, number int32) (n int, err error) { + if !p.IsSetReq() { + p.Req = new(comment.ListCommentRequest) + } + return p.Req.FastRead(buf, _type, number) +} + +func (p *ListCommentArgs) FastWrite(buf []byte) (n int) { + if !p.IsSetReq() { + return 0 + } + return p.Req.FastWrite(buf) +} + +func (p *ListCommentArgs) Size() (n int) { + if !p.IsSetReq() { + return 0 + } + return p.Req.Size() +} + +func (p *ListCommentArgs) Marshal(out []byte) ([]byte, error) { + if !p.IsSetReq() { + return out, fmt.Errorf("No req in ListCommentArgs") + } + return proto.Marshal(p.Req) +} + +func (p *ListCommentArgs) Unmarshal(in []byte) error { + msg := new(comment.ListCommentRequest) + if err := proto.Unmarshal(in, msg); err != nil { + return err + } + p.Req = msg + return nil +} + +var ListCommentArgs_Req_DEFAULT *comment.ListCommentRequest + +func (p *ListCommentArgs) GetReq() *comment.ListCommentRequest { + if !p.IsSetReq() { + return ListCommentArgs_Req_DEFAULT + } + return p.Req +} + +func (p *ListCommentArgs) IsSetReq() bool { + return p.Req != nil +} + +type ListCommentResult struct { + Success *comment.ListCommentResponse +} + +var ListCommentResult_Success_DEFAULT *comment.ListCommentResponse + +func (p *ListCommentResult) FastRead(buf []byte, _type int8, number int32) (n int, err error) { + if !p.IsSetSuccess() { + p.Success = new(comment.ListCommentResponse) + } + return p.Success.FastRead(buf, _type, number) +} + +func (p *ListCommentResult) FastWrite(buf []byte) (n int) { + if !p.IsSetSuccess() { + return 0 + } + return p.Success.FastWrite(buf) +} + +func (p *ListCommentResult) Size() (n int) { + if !p.IsSetSuccess() { + return 0 + } + return p.Success.Size() +} + +func (p *ListCommentResult) Marshal(out []byte) ([]byte, error) { + if !p.IsSetSuccess() { + return out, fmt.Errorf("No req in ListCommentResult") + } + return proto.Marshal(p.Success) +} + +func (p *ListCommentResult) Unmarshal(in []byte) error { + msg := new(comment.ListCommentResponse) + if err := proto.Unmarshal(in, msg); err != nil { + return err + } + p.Success = msg + return nil +} + +func (p *ListCommentResult) GetSuccess() *comment.ListCommentResponse { + if !p.IsSetSuccess() { + return ListCommentResult_Success_DEFAULT + } + return p.Success +} + +func (p *ListCommentResult) SetSuccess(x interface{}) { + p.Success = x.(*comment.ListCommentResponse) +} + +func (p *ListCommentResult) IsSetSuccess() bool { + return p.Success != nil +} + +type kClient struct { + c client.Client +} + +func newServiceClient(c client.Client) *kClient { + return &kClient{ + c: c, + } +} + +func (p *kClient) ActionComment(ctx context.Context, Req *comment.ActionCommentRequest) (r *comment.ActionCommentResponse, err error) { + var _args ActionCommentArgs + _args.Req = Req + var _result ActionCommentResult + if err = p.c.Call(ctx, "ActionComment", &_args, &_result); err != nil { + return + } + return _result.GetSuccess(), nil +} + +func (p *kClient) ListComment(ctx context.Context, Req *comment.ListCommentRequest) (r *comment.ListCommentResponse, err error) { + var _args ListCommentArgs + _args.Req = Req + var _result ListCommentResult + if err = p.c.Call(ctx, "ListComment", &_args, &_result); err != nil { + return + } + return _result.GetSuccess(), nil +} diff --git a/kitex_gen/douyin/comment/commentservice/invoker.go b/kitex_gen/douyin/comment/commentservice/invoker.go new file mode 100644 index 0000000..9b32635 --- /dev/null +++ b/kitex_gen/douyin/comment/commentservice/invoker.go @@ -0,0 +1,24 @@ +// Code generated by Kitex v0.4.4. DO NOT EDIT. + +package commentservice + +import ( + server "github.com/cloudwego/kitex/server" + comment "toktik/kitex_gen/douyin/comment" +) + +// NewInvoker creates a server.Invoker with the given handler and options. +func NewInvoker(handler comment.CommentService, opts ...server.Option) server.Invoker { + var options []server.Option + + options = append(options, opts...) + + s := server.NewInvoker(options...) + if err := s.RegisterService(serviceInfo(), handler); err != nil { + panic(err) + } + if err := s.Init(); err != nil { + panic(err) + } + return s +} diff --git a/kitex_gen/douyin/comment/commentservice/server.go b/kitex_gen/douyin/comment/commentservice/server.go new file mode 100644 index 0000000..af484b2 --- /dev/null +++ b/kitex_gen/douyin/comment/commentservice/server.go @@ -0,0 +1,20 @@ +// Code generated by Kitex v0.4.4. DO NOT EDIT. +package commentservice + +import ( + server "github.com/cloudwego/kitex/server" + comment "toktik/kitex_gen/douyin/comment" +) + +// NewServer creates a server.Server with the given handler and options. +func NewServer(handler comment.CommentService, opts ...server.Option) server.Server { + var options []server.Option + + options = append(options, opts...) + + svr := server.NewServer(options...) + if err := svr.RegisterService(serviceInfo(), handler); err != nil { + panic(err) + } + return svr +} diff --git a/manifests-dev/deployment-toktik-comment-api.yaml b/manifests-dev/deployment-toktik-comment-api.yaml new file mode 100644 index 0000000..d893baa --- /dev/null +++ b/manifests-dev/deployment-toktik-comment-api.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + sidecar.jaegertracing.io/inject: 'true' + labels: + app: toktik-comment-api + name: toktik-comment-api + namespace: toktik-service-bundle +spec: + selector: + matchLabels: + name: toktik-comment-api + template: + metadata: + labels: + app: toktik-comment-api + branch: dev + version: ${BUILD_NUMBER}-${CI_COMMIT_ID} + name: toktik-comment-api + dream-app: toktik-comment-api + dream-unit: toktik-comment-api + spec: + imagePullSecrets: + - name: regcred + containers: + - image: ${IMAGE} + imagePullPolicy: IfNotPresent + name: toktik-comment-api + command: + - /bin/bash + args: + - bootstrap-comment.sh + envFrom: + - configMapRef: + name: env-config + - configMapRef: + name: config + ports: + - name: grpc-40131 + containerPort: 40131 + protocol: TCP + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 100m + memory: 8Mi + terminationGracePeriodSeconds: 30 diff --git a/manifests-dev/service-toktik-comment-api.yaml b/manifests-dev/service-toktik-comment-api.yaml new file mode 100644 index 0000000..7ee6cff --- /dev/null +++ b/manifests-dev/service-toktik-comment-api.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: toktik-comment-api + name: toktik-comment-api + namespace: toktik-service-bundle +spec: + ports: + - name: grpc + port: 40131 + protocol: TCP + targetPort: 40131 + selector: + name: toktik-comment-api + branch: dev + type: ClusterIP diff --git a/repo/comments.gen.go b/repo/comments.gen.go new file mode 100644 index 0000000..eef36a4 --- /dev/null +++ b/repo/comments.gen.go @@ -0,0 +1,434 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package repo + +import ( + "context" + "strings" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "toktik/repo/model" +) + +func newComment(db *gorm.DB, opts ...gen.DOOption) comment { + _comment := comment{} + + _comment.commentDo.UseDB(db, opts...) + _comment.commentDo.UseModel(&model.Comment{}) + + tableName := _comment.commentDo.TableName() + _comment.ALL = field.NewAsterisk(tableName) + _comment.ID = field.NewUint32(tableName, "id") + _comment.CreatedAt = field.NewTime(tableName, "created_at") + _comment.UpdatedAt = field.NewTime(tableName, "updated_at") + _comment.DeletedAt = field.NewField(tableName, "deleted_at") + _comment.CommentId = field.NewUint32(tableName, "comment_id") + _comment.VideoId = field.NewUint32(tableName, "video_id") + _comment.UserId = field.NewUint32(tableName, "user_id") + _comment.Content = field.NewString(tableName, "content") + + _comment.fillFieldMap() + + return _comment +} + +type comment struct { + commentDo + + ALL field.Asterisk + ID field.Uint32 + CreatedAt field.Time + UpdatedAt field.Time + DeletedAt field.Field + CommentId field.Uint32 + VideoId field.Uint32 + UserId field.Uint32 + Content field.String + + fieldMap map[string]field.Expr +} + +func (c comment) Table(newTableName string) *comment { + c.commentDo.UseTable(newTableName) + return c.updateTableName(newTableName) +} + +func (c comment) As(alias string) *comment { + c.commentDo.DO = *(c.commentDo.As(alias).(*gen.DO)) + return c.updateTableName(alias) +} + +func (c *comment) updateTableName(table string) *comment { + c.ALL = field.NewAsterisk(table) + c.ID = field.NewUint32(table, "id") + c.CreatedAt = field.NewTime(table, "created_at") + c.UpdatedAt = field.NewTime(table, "updated_at") + c.DeletedAt = field.NewField(table, "deleted_at") + c.CommentId = field.NewUint32(table, "comment_id") + c.VideoId = field.NewUint32(table, "video_id") + c.UserId = field.NewUint32(table, "user_id") + c.Content = field.NewString(table, "content") + + c.fillFieldMap() + + return c +} + +func (c *comment) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := c.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (c *comment) fillFieldMap() { + c.fieldMap = make(map[string]field.Expr, 8) + c.fieldMap["id"] = c.ID + c.fieldMap["created_at"] = c.CreatedAt + c.fieldMap["updated_at"] = c.UpdatedAt + c.fieldMap["deleted_at"] = c.DeletedAt + c.fieldMap["comment_id"] = c.CommentId + c.fieldMap["video_id"] = c.VideoId + c.fieldMap["user_id"] = c.UserId + c.fieldMap["content"] = c.Content +} + +func (c comment) clone(db *gorm.DB) comment { + c.commentDo.ReplaceConnPool(db.Statement.ConnPool) + return c +} + +func (c comment) replaceDB(db *gorm.DB) comment { + c.commentDo.ReplaceDB(db) + return c +} + +type commentDo struct{ gen.DO } + +type ICommentDo interface { + gen.SubQuery + Debug() ICommentDo + WithContext(ctx context.Context) ICommentDo + WithResult(fc func(tx gen.Dao)) gen.ResultInfo + ReplaceDB(db *gorm.DB) + ReadDB() ICommentDo + WriteDB() ICommentDo + As(alias string) gen.Dao + Session(config *gorm.Session) ICommentDo + Columns(cols ...field.Expr) gen.Columns + Clauses(conds ...clause.Expression) ICommentDo + Not(conds ...gen.Condition) ICommentDo + Or(conds ...gen.Condition) ICommentDo + Select(conds ...field.Expr) ICommentDo + Where(conds ...gen.Condition) ICommentDo + Order(conds ...field.Expr) ICommentDo + Distinct(cols ...field.Expr) ICommentDo + Omit(cols ...field.Expr) ICommentDo + Join(table schema.Tabler, on ...field.Expr) ICommentDo + LeftJoin(table schema.Tabler, on ...field.Expr) ICommentDo + RightJoin(table schema.Tabler, on ...field.Expr) ICommentDo + Group(cols ...field.Expr) ICommentDo + Having(conds ...gen.Condition) ICommentDo + Limit(limit int) ICommentDo + Offset(offset int) ICommentDo + Count() (count int64, err error) + Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentDo + Unscoped() ICommentDo + Create(values ...*model.Comment) error + CreateInBatches(values []*model.Comment, batchSize int) error + Save(values ...*model.Comment) error + First() (*model.Comment, error) + Take() (*model.Comment, error) + Last() (*model.Comment, error) + Find() ([]*model.Comment, error) + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Comment, err error) + FindInBatches(result *[]*model.Comment, batchSize int, fc func(tx gen.Dao, batch int) error) error + Pluck(column field.Expr, dest interface{}) error + Delete(...*model.Comment) (info gen.ResultInfo, err error) + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + Updates(value interface{}) (info gen.ResultInfo, err error) + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + UpdateColumns(value interface{}) (info gen.ResultInfo, err error) + UpdateFrom(q gen.SubQuery) gen.Dao + Attrs(attrs ...field.AssignExpr) ICommentDo + Assign(attrs ...field.AssignExpr) ICommentDo + Joins(fields ...field.RelationField) ICommentDo + Preload(fields ...field.RelationField) ICommentDo + FirstOrInit() (*model.Comment, error) + FirstOrCreate() (*model.Comment, error) + FindByPage(offset int, limit int) (result []*model.Comment, count int64, err error) + ScanByPage(result interface{}, offset int, limit int) (count int64, err error) + Scan(result interface{}) (err error) + Returning(value interface{}, columns ...string) ICommentDo + UnderlyingDB() *gorm.DB + schema.Tabler + + FilterWithNameAndRole(name string, role string) (result []model.Comment, err error) +} + +// SELECT * FROM @@table WHERE name = @name{{if role !=""}} AND role = @role{{end}} +func (c commentDo) FilterWithNameAndRole(name string, role string) (result []model.Comment, err error) { + var params []interface{} + + var generateSQL strings.Builder + params = append(params, name) + generateSQL.WriteString("SELECT * FROM comments WHERE name = ? ") + if role != "" { + params = append(params, role) + generateSQL.WriteString("AND role = ? ") + } + + var executeSQL *gorm.DB + executeSQL = c.UnderlyingDB().Raw(generateSQL.String(), params...).Find(&result) // ignore_security_alert + err = executeSQL.Error + + return +} + +func (c commentDo) Debug() ICommentDo { + return c.withDO(c.DO.Debug()) +} + +func (c commentDo) WithContext(ctx context.Context) ICommentDo { + return c.withDO(c.DO.WithContext(ctx)) +} + +func (c commentDo) ReadDB() ICommentDo { + return c.Clauses(dbresolver.Read) +} + +func (c commentDo) WriteDB() ICommentDo { + return c.Clauses(dbresolver.Write) +} + +func (c commentDo) Session(config *gorm.Session) ICommentDo { + return c.withDO(c.DO.Session(config)) +} + +func (c commentDo) Clauses(conds ...clause.Expression) ICommentDo { + return c.withDO(c.DO.Clauses(conds...)) +} + +func (c commentDo) Returning(value interface{}, columns ...string) ICommentDo { + return c.withDO(c.DO.Returning(value, columns...)) +} + +func (c commentDo) Not(conds ...gen.Condition) ICommentDo { + return c.withDO(c.DO.Not(conds...)) +} + +func (c commentDo) Or(conds ...gen.Condition) ICommentDo { + return c.withDO(c.DO.Or(conds...)) +} + +func (c commentDo) Select(conds ...field.Expr) ICommentDo { + return c.withDO(c.DO.Select(conds...)) +} + +func (c commentDo) Where(conds ...gen.Condition) ICommentDo { + return c.withDO(c.DO.Where(conds...)) +} + +func (c commentDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) ICommentDo { + return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB())) +} + +func (c commentDo) Order(conds ...field.Expr) ICommentDo { + return c.withDO(c.DO.Order(conds...)) +} + +func (c commentDo) Distinct(cols ...field.Expr) ICommentDo { + return c.withDO(c.DO.Distinct(cols...)) +} + +func (c commentDo) Omit(cols ...field.Expr) ICommentDo { + return c.withDO(c.DO.Omit(cols...)) +} + +func (c commentDo) Join(table schema.Tabler, on ...field.Expr) ICommentDo { + return c.withDO(c.DO.Join(table, on...)) +} + +func (c commentDo) LeftJoin(table schema.Tabler, on ...field.Expr) ICommentDo { + return c.withDO(c.DO.LeftJoin(table, on...)) +} + +func (c commentDo) RightJoin(table schema.Tabler, on ...field.Expr) ICommentDo { + return c.withDO(c.DO.RightJoin(table, on...)) +} + +func (c commentDo) Group(cols ...field.Expr) ICommentDo { + return c.withDO(c.DO.Group(cols...)) +} + +func (c commentDo) Having(conds ...gen.Condition) ICommentDo { + return c.withDO(c.DO.Having(conds...)) +} + +func (c commentDo) Limit(limit int) ICommentDo { + return c.withDO(c.DO.Limit(limit)) +} + +func (c commentDo) Offset(offset int) ICommentDo { + return c.withDO(c.DO.Offset(offset)) +} + +func (c commentDo) Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentDo { + return c.withDO(c.DO.Scopes(funcs...)) +} + +func (c commentDo) Unscoped() ICommentDo { + return c.withDO(c.DO.Unscoped()) +} + +func (c commentDo) Create(values ...*model.Comment) error { + if len(values) == 0 { + return nil + } + return c.DO.Create(values) +} + +func (c commentDo) CreateInBatches(values []*model.Comment, batchSize int) error { + return c.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (c commentDo) Save(values ...*model.Comment) error { + if len(values) == 0 { + return nil + } + return c.DO.Save(values) +} + +func (c commentDo) First() (*model.Comment, error) { + if result, err := c.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Comment), nil + } +} + +func (c commentDo) Take() (*model.Comment, error) { + if result, err := c.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Comment), nil + } +} + +func (c commentDo) Last() (*model.Comment, error) { + if result, err := c.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Comment), nil + } +} + +func (c commentDo) Find() ([]*model.Comment, error) { + result, err := c.DO.Find() + return result.([]*model.Comment), err +} + +func (c commentDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Comment, err error) { + buf := make([]*model.Comment, 0, batchSize) + err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (c commentDo) FindInBatches(result *[]*model.Comment, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return c.DO.FindInBatches(result, batchSize, fc) +} + +func (c commentDo) Attrs(attrs ...field.AssignExpr) ICommentDo { + return c.withDO(c.DO.Attrs(attrs...)) +} + +func (c commentDo) Assign(attrs ...field.AssignExpr) ICommentDo { + return c.withDO(c.DO.Assign(attrs...)) +} + +func (c commentDo) Joins(fields ...field.RelationField) ICommentDo { + for _, _f := range fields { + c = *c.withDO(c.DO.Joins(_f)) + } + return &c +} + +func (c commentDo) Preload(fields ...field.RelationField) ICommentDo { + for _, _f := range fields { + c = *c.withDO(c.DO.Preload(_f)) + } + return &c +} + +func (c commentDo) FirstOrInit() (*model.Comment, error) { + if result, err := c.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Comment), nil + } +} + +func (c commentDo) FirstOrCreate() (*model.Comment, error) { + if result, err := c.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Comment), nil + } +} + +func (c commentDo) FindByPage(offset int, limit int) (result []*model.Comment, count int64, err error) { + result, err = c.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = c.Offset(-1).Limit(-1).Count() + return +} + +func (c commentDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = c.Count() + if err != nil { + return + } + + err = c.Offset(offset).Limit(limit).Scan(result) + return +} + +func (c commentDo) Scan(result interface{}) (err error) { + return c.DO.Scan(result) +} + +func (c commentDo) Delete(models ...*model.Comment) (result gen.ResultInfo, err error) { + return c.DO.Delete(models) +} + +func (c *commentDo) withDO(do gen.Dao) *commentDo { + c.DO = *do.(*gen.DO) + return c +} diff --git a/repo/gen.go b/repo/gen.go index acc6141..24bc1bc 100644 --- a/repo/gen.go +++ b/repo/gen.go @@ -17,6 +17,7 @@ import ( var ( Q = new(Query) + Comment *comment User *user UserToken *userToken Video *video @@ -24,6 +25,7 @@ var ( func SetDefault(db *gorm.DB, opts ...gen.DOOption) { *Q = *Use(db, opts...) + Comment = &Q.Comment User = &Q.User UserToken = &Q.UserToken Video = &Q.Video @@ -32,6 +34,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) { func Use(db *gorm.DB, opts ...gen.DOOption) *Query { return &Query{ db: db, + Comment: newComment(db, opts...), User: newUser(db, opts...), UserToken: newUserToken(db, opts...), Video: newVideo(db, opts...), @@ -41,6 +44,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query { type Query struct { db *gorm.DB + Comment comment User user UserToken userToken Video video @@ -51,6 +55,7 @@ func (q *Query) Available() bool { return q.db != nil } func (q *Query) clone(db *gorm.DB) *Query { return &Query{ db: db, + Comment: q.Comment.clone(db), User: q.User.clone(db), UserToken: q.UserToken.clone(db), Video: q.Video.clone(db), @@ -68,6 +73,7 @@ func (q *Query) WriteDB() *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query { return &Query{ db: db, + Comment: q.Comment.replaceDB(db), User: q.User.replaceDB(db), UserToken: q.UserToken.replaceDB(db), Video: q.Video.replaceDB(db), @@ -75,6 +81,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query { } type queryCtx struct { + Comment ICommentDo User IUserDo UserToken IUserTokenDo Video IVideoDo @@ -82,6 +89,7 @@ type queryCtx struct { func (q *Query) WithContext(ctx context.Context) *queryCtx { return &queryCtx{ + Comment: q.Comment.WithContext(ctx), User: q.User.WithContext(ctx), UserToken: q.UserToken.WithContext(ctx), Video: q.Video.WithContext(ctx), diff --git a/repo/gen/gormGen.go b/repo/gen/gormGen.go index 85457e1..4de324b 100644 --- a/repo/gen/gormGen.go +++ b/repo/gen/gormGen.go @@ -25,10 +25,10 @@ func main() { g.UseDB(gormdb) // reuse your gorm db // Generate basic type-safe DAO API for struct `model.User` following conventions - g.ApplyBasic(auth.UserToken{}, model.Video{}, model.User{}, model.Video{}) + g.ApplyBasic(auth.UserToken{}, model.Video{}, model.User{}, model.Video{}, model.Comment{}) // Generate Type Safe API with Dynamic SQL defined on Querier interface - g.ApplyInterface(func(Querier) {}, auth.UserToken{}, model.Video{}, model.User{}) + g.ApplyInterface(func(Querier) {}, auth.UserToken{}, model.Video{}, model.User{}, model.Comment{}) // Generate the code g.Execute() diff --git a/repo/model/comment.go b/repo/model/comment.go new file mode 100644 index 0000000..95322f8 --- /dev/null +++ b/repo/model/comment.go @@ -0,0 +1,10 @@ +package model + +// Comment 评论表 /* +type Comment struct { + Model + CommentId uint32 `json:"comment_id" column:"comment_id"` + VideoId uint32 `json:"video_id" column:"video_id"` + UserId uint32 `json:"user_id" column:"user_id"` + Content string `json:"content" column:"content"` +} diff --git a/service/comment/build.sh b/service/comment/build.sh new file mode 100644 index 0000000..da7bb5f --- /dev/null +++ b/service/comment/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +RUN_NAME="comment" + +mkdir -p output/bin +cp script/* output/ +chmod +x output/bootstrap.sh + +if [ "$IS_SYSTEM_TEST_ENV" != "1" ]; then + go build -o output/bin/${RUN_NAME} +else + go test -c -covermode=set -o output/bin/${RUN_NAME} -coverpkg=./... +fi + diff --git a/service/comment/handler.go b/service/comment/handler.go new file mode 100644 index 0000000..271f1c2 --- /dev/null +++ b/service/comment/handler.go @@ -0,0 +1,309 @@ +package main + +import ( + "context" + "github.com/cloudwego/kitex/client" + consul "github.com/kitex-contrib/registry-consul" + "github.com/sirupsen/logrus" + "log" + "time" + "toktik/constant/biz" + "toktik/constant/config" + "toktik/kitex_gen/douyin/comment" + "toktik/kitex_gen/douyin/user" + "toktik/kitex_gen/douyin/user/userservice" + "toktik/logging" + gen "toktik/repo" + "toktik/repo/model" +) + +var UserClient userservice.Client + +func init() { + r, err := consul.NewConsulResolver(config.EnvConfig.CONSUL_ADDR) + if err != nil { + log.Fatal(err) + } + UserClient, err = userservice.NewClient(config.UserServiceName, client.WithResolver(r)) + if err != nil { + log.Fatal(err) + } +} + +// CommentServiceImpl implements the last service interface defined in the IDL. +type CommentServiceImpl struct{} + +// ActionComment implements the CommentServiceImpl interface. +func (s *CommentServiceImpl) ActionComment(ctx context.Context, req *comment.ActionCommentRequest) (resp *comment.ActionCommentResponse, err error) { + logger := logging.Logger.WithFields(logrus.Fields{ + "user_id": req.ActorId, + "video_id": req.VideoId, + "action_type": req.ActionType, + "comment_text": req.GetCommentText(), + "comment_id": req.GetCommentId(), + "time": time.Now(), + "function": "ActionComment", + }) + logger.Debugf("Process start") + + var pCommentText string + var pCommentID uint32 + switch req.ActionType { + case comment.ActionCommentType_ACTION_COMMENT_TYPE_ADD: + pCommentText = req.GetCommentText() + case comment.ActionCommentType_ACTION_COMMENT_TYPE_DELETE: + pCommentID = req.GetCommentId() + case comment.ActionCommentType_ACTION_COMMENT_TYPE_UNSPECIFIED: + fallthrough + default: + logger.WithFields(logrus.Fields{ + "time": time.Now(), + }).Warnf("invalid action type") + return &comment.ActionCommentResponse{ + StatusCode: biz.InvalidCommentActionType, + StatusMsg: &biz.BadRequestStatusMsg, + }, nil + } + + // Video check: check if the qVideo exists || check if creator is the same as actor + qVideo := gen.Q.Video + pVideo, err := qVideo.WithContext(ctx). + Where(qVideo.ID.Eq(req.VideoId)). + First() + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Warnf("video query error") + return &comment.ActionCommentResponse{ + StatusCode: biz.UnableToQueryVideo, + StatusMsg: &biz.InternalServerErrorStatusMsg, + }, nil + } + if pVideo == nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + }).Warnf("video not found") + return &comment.ActionCommentResponse{ + StatusCode: biz.VideoNotFound, + StatusMsg: &biz.BadRequestStatusMsg, + }, nil + } + + userResponse, err := UserClient.GetUser(ctx, &user.UserRequest{ + UserId: req.ActorId, + ActorId: req.ActorId, + }) + + if err != nil || userResponse.StatusCode != biz.OkStatusCode { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Warnf("user service error") + return &comment.ActionCommentResponse{ + StatusCode: biz.UnableToQueryUser, + StatusMsg: &biz.InternalServerErrorStatusMsg, + }, nil + } + + pUser := userResponse.User + + switch req.ActionType { + case comment.ActionCommentType_ACTION_COMMENT_TYPE_ADD: + resp, err = addComment(ctx, logger, pUser, pVideo.ID, pCommentText) + case comment.ActionCommentType_ACTION_COMMENT_TYPE_DELETE: + resp, err = deleteComment(ctx, logger, pUser, pVideo.ID, pCommentID) + } + if err != nil { + return resp, err + } + + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "response": resp, + }).Debug("all process done, ready to launch response") + + return resp, err +} + +func addComment(ctx context.Context, logger *logrus.Entry, pUser *user.User, pVideoID uint32, pCommentText string) (resp *comment.ActionCommentResponse, err error) { + count, err := gen.Q.Comment.WithContext(ctx).Count() + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("failed to query db entry") + resp = &comment.ActionCommentResponse{ + StatusCode: biz.UnableToQueryComment, + StatusMsg: &biz.InternalServerErrorStatusMsg, + } + return + } + + rComment := model.Comment{ + VideoId: pVideoID, + CommentId: uint32(count + 1), + UserId: pUser.Id, + Content: pCommentText, + } + + err = gen.Q.Comment.WithContext(ctx).Create(&rComment) + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("failed to create db entry") + resp = &comment.ActionCommentResponse{ + StatusCode: biz.UnableToCreateComment, + StatusMsg: &biz.InternalServerErrorStatusMsg, + } + return + } + resp = &comment.ActionCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + Comment: &comment.Comment{ + Id: rComment.CommentId, + User: pUser, + Content: rComment.Content, + CreateDate: rComment.CreatedAt.Format("01-02"), + }, + } + return +} + +func deleteComment(ctx context.Context, logger *logrus.Entry, pUser *user.User, videoID uint32, commentID uint32) (resp *comment.ActionCommentResponse, err error) { + qComment := gen.Q.Comment + + rComment, err := qComment.WithContext(ctx). + Where(qComment.VideoId.Eq(videoID), qComment.CommentId.Eq(commentID)). + First() + + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("failed to query db entry") + resp = &comment.ActionCommentResponse{ + StatusCode: biz.UnableToQueryComment, + StatusMsg: &biz.InternalServerErrorStatusMsg, + } + return + } + + if rComment.UserId != pUser.Id { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + }).Debug("comment creator and actor not match") + return &comment.ActionCommentResponse{ + StatusCode: biz.ActorIDNotMatch, + StatusMsg: &biz.ForbiddenStatusMsg, + }, nil + } + + _, err = qComment.WithContext(ctx). + Where(qComment.ID.Eq(rComment.ID)). + Delete() + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("failed to delete db entry") + resp = &comment.ActionCommentResponse{ + StatusCode: biz.UnableToDeleteComment, + StatusMsg: &biz.InternalServerErrorStatusMsg, + } + return + } + resp = &comment.ActionCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + Comment: nil, + } + return +} + +// ListComment implements the CommentServiceImpl interface. +func (s *CommentServiceImpl) ListComment(ctx context.Context, req *comment.ListCommentRequest) (resp *comment.ListCommentResponse, err error) { + logger := logging.Logger.WithFields(logrus.Fields{ + "user_id": req.ActorId, + "video_id": req.VideoId, + "time": time.Now(), + "function": "ListComment", + }) + logger.Debug("Process start") + + qVideo := gen.Q.Video + pVideo, err := qVideo.WithContext(ctx). + Where(qVideo.ID.Eq(req.VideoId)). + First() + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("video query error") + return &comment.ListCommentResponse{ + StatusCode: biz.UnableToQueryVideo, + StatusMsg: &biz.InternalServerErrorStatusMsg, + }, nil + } + if pVideo == nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + }).Debug("video not found") + return &comment.ListCommentResponse{ + StatusCode: biz.VideoNotFound, + StatusMsg: &biz.BadRequestStatusMsg, + }, nil + } + + qComment := gen.Q.Comment + pCommentList, err := qComment.WithContext(ctx). + Where(qComment.VideoId.Eq(pVideo.ID)). + Order(qComment.CreatedAt.Desc()). + Find() + + if err != nil { + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "err": err, + }).Debug("comment query error") + return &comment.ListCommentResponse{ + StatusCode: biz.UnableToQueryComment, + StatusMsg: &biz.InternalServerErrorStatusMsg, + }, nil + } + + rCommentList := make([]*comment.Comment, 0, len(pCommentList)) + for _, pComment := range pCommentList { + userResponse, err := UserClient.GetUser(ctx, &user.UserRequest{ + UserId: req.ActorId, + ActorId: req.ActorId, + }) + + if err != nil || userResponse.StatusCode != biz.OkStatusCode { + logger.WithFields(logrus.Fields{ + "pComment": pComment, + "err": err, + "time": time.Now(), + }).Debug("unable to get user info") + } + + rCommentList = append(rCommentList, &comment.Comment{ + Id: pComment.CommentId, + User: userResponse.User, + Content: pComment.Content, + CreateDate: pComment.CreatedAt.Format("01-02"), + }) + } + + logger.WithFields(logrus.Fields{ + "time": time.Now(), + "response": resp, + }).Debug("all process done, ready to launch response") + return &comment.ListCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + CommentList: rCommentList, + }, nil +} diff --git a/service/comment/handler_test.go b/service/comment/handler_test.go new file mode 100644 index 0000000..87bcef2 --- /dev/null +++ b/service/comment/handler_test.go @@ -0,0 +1,252 @@ +package main + +import ( + "context" + "github.com/DATA-DOG/go-sqlmock" + "github.com/cloudwego/kitex/client/callopt" + "reflect" + "regexp" + "testing" + "time" + "toktik/constant/biz" + "toktik/kitex_gen/douyin/comment" + "toktik/kitex_gen/douyin/user" + "toktik/repo/model" + "toktik/test/mock" +) + +var ( + testComment = &model.Comment{ + Model: model.Model{ + CreatedAt: time.Now(), + }, + CommentId: 1, + VideoId: 1, + UserId: mockUser.Id, + Content: "test comment", + } +) + +var ( + mockUser = user.User{Id: 65535} + mockVideo = model.Video{ + Model: model.Model{ + ID: 1, + CreatedAt: time.Now(), + }, + UserId: mockUser.Id, + Title: "test video", + FileName: "test.mp4", + CoverName: "test.jpg", + } +) + +func TestCommentServiceImpl_ActionComment_Add(t *testing.T) { + var addSuccessArg = struct { + ctx context.Context + req *comment.ActionCommentRequest + }{ctx: context.Background(), req: &comment.ActionCommentRequest{ + ActorId: mockUser.Id, + VideoId: mockVideo.ID, + ActionType: comment.ActionCommentType_ACTION_COMMENT_TYPE_ADD, + Action: &comment.ActionCommentRequest_CommentText{CommentText: testComment.Content}, + }} + var addSuccessResp = &comment.ActionCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + Comment: &comment.Comment{ + Id: testComment.CommentId, + User: &mockUser, + Content: testComment.Content, + CreateDate: testComment.CreatedAt.Format("01-02"), + }, + } + + UserClient = MockUserClient{} + + videoRows := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "user_id", "title", "file_name", "cover_name"}) + videoRows.AddRow(mockVideo.ID, mockVideo.CreatedAt, mockVideo.UpdatedAt, mockVideo.DeletedAt, mockVideo.UserId, mockVideo.Title, mockVideo.FileName, mockVideo.CoverName) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "videos" WHERE "videos"."id" = $1 AND "videos"."deleted_at" IS NULL ORDER BY "videos"."id" LIMIT 1`)). + WillReturnRows(videoRows) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "comments" WHERE "comments"."deleted_at" IS NULL`)). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + + mock.DBMock.ExpectBegin() + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`INSERT INTO "comments" ("created_at","updated_at","deleted_at","comment_id","video_id","user_id","content") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`)). + WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(testComment.CommentId)) + mock.DBMock.ExpectCommit() + + type args struct { + ctx context.Context + req *comment.ActionCommentRequest + } + tests := []struct { + name string + args args + wantResp *comment.ActionCommentResponse + wantErr bool + }{ + {name: "Add Comment", args: addSuccessArg, wantResp: addSuccessResp}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &CommentServiceImpl{} + gotResp, err := s.ActionComment(tt.args.ctx, tt.args.req) + if (err != nil) != tt.wantErr { + t.Errorf("ActionComment(Add) error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ActionComment(Add) gotResp %v, want %v", gotResp, tt.wantResp) + } + }) + } +} + +func TestCommentServiceImpl_ActionComment_Delete(t *testing.T) { + var deleteSuccessArg = struct { + ctx context.Context + req *comment.ActionCommentRequest + }{ctx: context.Background(), req: &comment.ActionCommentRequest{ + ActorId: mockUser.Id, + VideoId: mockVideo.ID, + ActionType: comment.ActionCommentType_ACTION_COMMENT_TYPE_DELETE, + Action: &comment.ActionCommentRequest_CommentId{CommentId: testComment.CommentId}, + }} + var deletedSuccessResp = &comment.ActionCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + Comment: nil, + } + + UserClient = MockUserClient{} + + videoRows := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "user_id", "title", "file_name", "cover_name"}) + videoRows.AddRow(mockVideo.ID, mockVideo.CreatedAt, mockVideo.UpdatedAt, mockVideo.DeletedAt, mockVideo.UserId, mockVideo.Title, mockVideo.FileName, mockVideo.CoverName) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "videos" WHERE "videos"."id" = $1 AND "videos"."deleted_at" IS NULL ORDER BY "videos"."id" LIMIT 1`)). + WillReturnRows(videoRows) + + commentRows := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "comment_id", "video_id", "user_id", "content"}) + commentRows.AddRow(testComment.ID, testComment.CreatedAt, testComment.UpdatedAt, testComment.DeletedAt, testComment.CommentId, testComment.VideoId, testComment.UserId, testComment.Content) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "comments" WHERE "comments"."video_id" = $1 AND "comments"."comment_id" = $2 AND "comments"."deleted_at" IS NULL ORDER BY "comments"."id" LIMIT 1`)). + WillReturnRows(commentRows) + + mock.DBMock.ExpectBegin() + mock.DBMock. + ExpectExec(regexp.QuoteMeta(`UPDATE "comments" SET "deleted_at"=$1 WHERE "comments"."id" = $2 AND "comments"."deleted_at" IS NULL`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + mock.DBMock.ExpectCommit() + + type args struct { + ctx context.Context + req *comment.ActionCommentRequest + } + tests := []struct { + name string + args args + wantResp *comment.ActionCommentResponse + wantErr bool + }{ + {name: "Delete Comment", args: deleteSuccessArg, wantResp: deletedSuccessResp}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &CommentServiceImpl{} + gotResp, err := s.ActionComment(tt.args.ctx, tt.args.req) + if (err != nil) != tt.wantErr { + t.Errorf("ActionComment(Delete) error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ActionComment(Delete) gotResp %v, want %v", gotResp, tt.wantResp) + } + }) + } +} + +func TestCommentServiceImpl_ListComment(t *testing.T) { + var successArg = struct { + ctx context.Context + req *comment.ListCommentRequest + }{ctx: context.Background(), req: &comment.ListCommentRequest{ + ActorId: mockUser.Id, + VideoId: mockVideo.ID, + }} + + comments := make([]*comment.Comment, 0) + comments = append(comments, &comment.Comment{ + Id: testComment.CommentId, + User: &user.User{ + Id: mockUser.Id, + Name: mockUser.Name, + FollowCount: mockUser.FollowCount, + FollowerCount: mockUser.FollowerCount, + IsFollow: mockUser.IsFollow, + }, + Content: testComment.Content, + CreateDate: testComment.CreatedAt.Format("01-02"), + }) + var successResp = &comment.ListCommentResponse{ + StatusCode: biz.OkStatusCode, + StatusMsg: &biz.OkStatusMsg, + CommentList: comments, + } + + UserClient = MockUserClient{} + + videoRows := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "user_id", "title", "file_name", "cover_name"}) + videoRows.AddRow(mockVideo.ID, mockVideo.CreatedAt, mockVideo.UpdatedAt, mockVideo.DeletedAt, mockVideo.UserId, mockVideo.Title, mockVideo.FileName, mockVideo.CoverName) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "videos" WHERE "videos"."id" = $1 AND "videos"."deleted_at" IS NULL ORDER BY "videos"."id" LIMIT 1`)). + WillReturnRows(videoRows) + + commentRows := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "deleted_at", "comment_id", "video_id", "user_id", "content"}) + commentRows.AddRow(testComment.ID, testComment.CreatedAt, testComment.UpdatedAt, testComment.DeletedAt, testComment.CommentId, testComment.VideoId, testComment.UserId, testComment.Content) + + mock.DBMock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "comments" WHERE "comments"."video_id" = $1 AND "comments"."deleted_at" IS NULL ORDER BY "comments"."created_at" DESC`)). + WillReturnRows(commentRows) + + type args struct { + ctx context.Context + req *comment.ListCommentRequest + } + tests := []struct { + name string + args args + wantResp *comment.ListCommentResponse + wantErr bool + }{ + {name: "List Comment", args: successArg, wantResp: successResp}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &CommentServiceImpl{} + gotResp, err := s.ListComment(tt.args.ctx, tt.args.req) + if (err != nil) != tt.wantErr { + t.Errorf("ListComment() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotResp, tt.wantResp) { + t.Errorf("ListComment() gotResp %v, want %v", gotResp, tt.wantResp) + } + }) + } +} + +type MockUserClient struct { +} + +func (m MockUserClient) GetUser(ctx context.Context, Req *user.UserRequest, callOptions ...callopt.Option) (r *user.UserResponse, err error) { + return &user.UserResponse{StatusCode: biz.OkStatusCode, User: &mockUser}, nil +} diff --git a/service/comment/kitex.yaml b/service/comment/kitex.yaml new file mode 100644 index 0000000..554d0f7 --- /dev/null +++ b/service/comment/kitex.yaml @@ -0,0 +1,4 @@ +kitexinfo: + ServiceName: 'comment' + ToolVersion: 'v0.4.4' + diff --git a/service/comment/main.go b/service/comment/main.go new file mode 100644 index 0000000..6c90ca6 --- /dev/null +++ b/service/comment/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "github.com/cloudwego/kitex/pkg/rpcinfo" + "github.com/cloudwego/kitex/server" + consul "github.com/kitex-contrib/registry-consul" + "log" + "net" + "toktik/constant/config" + comment "toktik/kitex_gen/douyin/comment/commentservice" +) + +func main() { + var err error + + r, err := consul.NewConsulRegister(config.EnvConfig.CONSUL_ADDR) + if err != nil { + log.Fatal(err) + } + + addr, err := net.ResolveTCPAddr("tcp", config.CommentServiceAddr) + if err != nil { + panic(err) + } + + srv := comment.NewServer( + new(CommentServiceImpl), + server.WithServiceAddr(addr), + server.WithRegistry(r), + server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ + ServiceName: config.CommentServiceName, + }), + ) + + err = srv.Run() + + if err != nil { + log.Fatal(err) + } +} diff --git a/service/comment/script/bootstrap.sh b/service/comment/script/bootstrap.sh new file mode 100644 index 0000000..e940a23 --- /dev/null +++ b/service/comment/script/bootstrap.sh @@ -0,0 +1,22 @@ +#! /usr/bin/env bash +CURDIR=$(cd $(dirname $0); pwd) + +if [ "X$1" != "X" ]; then + RUNTIME_ROOT=$1 +else + RUNTIME_ROOT=${CURDIR} +fi + +export KITEX_RUNTIME_ROOT=$RUNTIME_ROOT +export KITEX_LOG_DIR="$RUNTIME_ROOT/log" + +if [ ! -d "$KITEX_LOG_DIR/app" ]; then + mkdir -p "$KITEX_LOG_DIR/app" +fi + +if [ ! -d "$KITEX_LOG_DIR/rpc" ]; then + mkdir -p "$KITEX_LOG_DIR/rpc" +fi + +exec "$CURDIR/bin/comment" + diff --git a/service/web/comment/handler.go b/service/web/comment/handler.go new file mode 100644 index 0000000..79832bd --- /dev/null +++ b/service/web/comment/handler.go @@ -0,0 +1,167 @@ +package comment + +import ( + "context" + "errors" + "fmt" + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/cloudwego/kitex/client" + consul "github.com/kitex-contrib/registry-consul" + "github.com/sirupsen/logrus" + "log" + "strconv" + "time" + "toktik/constant/biz" + "toktik/constant/config" + "toktik/kitex_gen/douyin/comment" + "toktik/kitex_gen/douyin/comment/commentservice" + "toktik/logging" +) + +var commentClient commentservice.Client + +func init() { + r, err := consul.NewConsulResolver(config.EnvConfig.CONSUL_ADDR) + if err != nil { + log.Fatal(err) + } + commentClient, err = commentservice.NewClient(config.CommentServiceName, client.WithResolver(r)) + if err != nil { + log.Fatal(err) + } +} + +func Action(ctx context.Context, c *app.RequestContext) { + methodFields := logrus.Fields{ + "time": time.Now(), + "method": "CommentAction", + } + logger := logging.Logger.WithFields(methodFields) + logger.Debugf("Process start") + + actorId := c.GetUint32("user_id") + videoId, videoIdExists := c.GetQuery("video_id") + actionType, actionTypeExists := c.GetQuery("action_type") + commentText := c.Query("comment_text") + commentId := c.Query("comment_id") + + if actorId == 0 { + biz.UnauthorizedError.WithFields(&methodFields).LaunchError(c) + return + } + + if !videoIdExists || !actionTypeExists { + biz.BadRequestError.WithFields(&methodFields).LaunchError(c) + return + } + + pVideoId, err := strconv.ParseUint(videoId, 10, 32) + pActionType, err := strconv.ParseInt(actionType, 10, 32) + pCommentId, err := strconv.ParseUint(commentId, 10, 32) + + if err != nil { + biz.BadRequestError.WithFields(&methodFields).WithCause(err).LaunchError(c) + return + } + + var rActionType = comment.ActionCommentType(pActionType) + + var ( + rErr error + ) + + switch rActionType { + case comment.ActionCommentType_ACTION_COMMENT_TYPE_ADD: + resp, err := commentClient.ActionComment(ctx, &comment.ActionCommentRequest{ + ActorId: actorId, + VideoId: uint32(pVideoId), + ActionType: rActionType, + Action: &comment.ActionCommentRequest_CommentText{CommentText: commentText}, + }) + if err != nil { + rErr = err + break + } + logger.WithFields(logrus.Fields{ + "response": resp, + }).Debugf("add comment success") + c.JSON( + consts.StatusOK, + resp, + ) + return + case comment.ActionCommentType_ACTION_COMMENT_TYPE_DELETE: + resp, err := commentClient.ActionComment(ctx, &comment.ActionCommentRequest{ + ActorId: actorId, + VideoId: uint32(pVideoId), + ActionType: rActionType, + Action: &comment.ActionCommentRequest_CommentId{CommentId: uint32(pCommentId)}, + }) + if err != nil { + rErr = err + break + } + logger.WithFields(logrus.Fields{ + "response": resp, + }).Debugf("delete comment success") + c.JSON( + consts.StatusOK, + resp, + ) + return + case comment.ActionCommentType_ACTION_COMMENT_TYPE_UNSPECIFIED: + fallthrough + default: + rErr = errors.New(fmt.Sprintf("invalid action type: %d", rActionType)) + } + + if rErr != nil { + biz.InternalServerError.WithCause(rErr).WithFields(&methodFields).LaunchError(c) + return + } +} + +func List(ctx context.Context, c *app.RequestContext) { + methodFields := logrus.Fields{ + "time": time.Now(), + "method": "CommentList", + } + logger := logging.Logger.WithFields(methodFields) + logger.Debugf("Process start") + + actorId := c.GetUint32("user_id") + videoId, videoIdExists := c.GetQuery("video_id") + + if actorId == 0 { + biz.UnauthorizedError.WithFields(&methodFields).LaunchError(c) + return + } + + if !videoIdExists { + biz.BadRequestError.WithFields(&methodFields).LaunchError(c) + return + } + + pVideoId, err := strconv.ParseUint(videoId, 10, 32) + + if err != nil { + biz.BadRequestError.WithFields(&methodFields).WithCause(err).LaunchError(c) + return + } + + resp, err := commentClient.ListComment(ctx, &comment.ListCommentRequest{ + ActorId: actorId, + VideoId: uint32(pVideoId), + }) + + if err != nil { + biz.InternalServerError.WithCause(err).WithFields(&methodFields).LaunchError(c) + return + } + + c.JSON( + consts.StatusOK, + resp, + ) +} diff --git a/service/web/main.go b/service/web/main.go index b126982..89e400d 100644 --- a/service/web/main.go +++ b/service/web/main.go @@ -3,6 +3,7 @@ package main import ( "toktik/constant/config" "toktik/service/web/auth" + "toktik/service/web/comment" "toktik/service/web/feed" "toktik/service/web/mw" "toktik/service/web/publish" @@ -47,8 +48,8 @@ func main() { // comment service commentGroup := douyin.Group("/comment") - commentGroup.POST("/action") - commentGroup.GET("/list") + commentGroup.POST("/action/", comment.Action) + commentGroup.GET("/list/", comment.List) // relation service relationGroup := douyin.Group("/relation")