├── .github ├── auto_assign.yml └── workflows │ ├── codecov.yml │ └── lint.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── comment │ └── Dockerfile ├── favorite │ └── Dockerfile ├── follow │ └── Dockerfile ├── gateway │ └── Dockerfile ├── message │ └── Dockerfile ├── minio-client │ └── Dockerfile ├── mq │ └── Dockerfile ├── mysql-gen │ └── gen.go ├── user │ └── Dockerfile └── video │ └── Dockerfile ├── common ├── checkpwd │ ├── checkPwd.go │ └── checkPwd_test.go ├── globalkey │ ├── constantKey.go │ └── redisCacheKey.go ├── help │ ├── sensitiveWords │ │ ├── sensitiveWords.go │ │ └── sensitiveWoredsFilter.go │ └── token │ │ ├── common.go │ │ ├── genToken.go │ │ └── parseToken.go ├── messageTypes │ └── message.go ├── model │ ├── GenModel │ │ └── createModel.sh │ ├── commentModel │ │ ├── commentmodel.go │ │ ├── commentmodel_gen.go │ │ └── vars.go │ ├── favoriteModel │ │ ├── favoritemodel.go │ │ ├── favoritemodel_gen.go │ │ └── vars.go │ ├── followModel │ │ ├── followmodel.go │ │ ├── followmodel_gen.go │ │ ├── followmodel_method.go │ │ └── vars.go │ ├── genmodel │ │ └── readme.md │ ├── messageModel │ │ ├── messagemodel.go │ │ ├── messagemodel_gen.go │ │ └── vars.go │ ├── userModel │ │ ├── usermodel.go │ │ ├── usermodel_gen.go │ │ └── vars.go │ └── videoModel │ │ ├── vars.go │ │ ├── videomodel.go │ │ ├── videomodel_gen.go │ │ └── videomodel_method.go └── xerr │ ├── errCode.go │ ├── errMsg.go │ └── errors.go ├── deployment ├── cluster │ └── douyin-cluster.yaml ├── comment │ └── comment.yaml ├── dashboard │ ├── README.md │ ├── cluster_role_binding.yaml │ └── service_account.yaml ├── favorite │ └── favorite.yaml ├── follow │ └── follow.yaml ├── gateway │ └── gateway.yaml ├── message │ └── message.yaml ├── minio-client │ └── minio-client.yaml ├── minio │ └── minio.yaml ├── mq │ └── mq.yaml ├── mysql │ ├── mysql-deploy.yaml │ └── mysql-scheme.yaml ├── nfs │ ├── README.md │ ├── nfs-deploy.yaml │ └── nfs-pvx.yaml ├── user │ └── user.yaml └── video │ └── video.yaml ├── docs ├── Setup.md └── design │ ├── CodingRules.md │ ├── Structure.drawio │ └── design.md ├── go.mod ├── go.sum ├── pkg ├── comment │ ├── etc │ │ └── usercomment.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── getvideocommentlogic.go │ │ │ └── updatecommentstatuslogic.go │ │ ├── server │ │ │ └── usercommentserver.go │ │ └── svc │ │ │ └── servicecontext.go │ ├── readme.md │ ├── userCommentPb │ │ ├── GenPb │ │ │ ├── UserComment.proto │ │ │ └── build.sh │ │ ├── UserComment.pb.go │ │ └── UserComment_grpc.pb.go │ ├── usercomment.go │ └── usercomment │ │ └── usercomment.go ├── constant │ └── mysql.go ├── favorite │ ├── etc │ │ └── userOptService.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── checkIsFavoriteLogic.go │ │ │ ├── getUserFavoriteLogic.go │ │ │ └── updateFavoriteStatusLogic.go │ │ ├── server │ │ │ └── userOptServiceServer.go │ │ └── svc │ │ │ └── serviceContext.go │ ├── userOptPb │ │ ├── GenPb │ │ │ ├── UserOptService.proto │ │ │ └── build.sh │ │ ├── UserOptService.pb.go │ │ └── UserOptService_grpc.pb.go │ ├── userOptService.go │ └── useroptservice │ │ └── userOptService.go ├── follow │ ├── etc │ │ └── follow.yaml │ ├── follow.go │ ├── followservice │ │ └── followservice.go │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── checkisfollowlogic.go │ │ │ ├── followlogic.go │ │ │ ├── getfollowerlistlogic.go │ │ │ ├── getfollowlistlogic.go │ │ │ └── getfriendlistlogic.go │ │ ├── server │ │ │ └── followserviceserver.go │ │ └── svc │ │ │ └── servicecontext.go │ ├── proto │ │ └── follow.proto │ └── types │ │ └── follow │ │ ├── follow.pb.go │ │ └── follow_grpc.pb.go ├── gateway │ ├── api.go │ ├── api │ │ ├── build.sh │ │ ├── message.api │ │ ├── user.api │ │ ├── userOpt.api │ │ └── video.api │ ├── etc │ │ └── user-api.yaml │ └── internal │ │ ├── config │ │ └── config.go │ │ ├── handler │ │ ├── feed │ │ │ └── feedVideoListHandler.go │ │ ├── message │ │ │ ├── messageHandler.go │ │ │ └── messagelistHandler.go │ │ ├── publish │ │ │ ├── getPublishVideoListHandler.go │ │ │ └── publishVideoHandler.go │ │ ├── routes.go │ │ ├── user │ │ │ ├── userInfoHandler.go │ │ │ ├── userLoginHandler.go │ │ │ └── userRegisterHandler.go │ │ └── userOpt │ │ │ ├── commentOptHandler.go │ │ │ ├── favoriteOptHandler.go │ │ │ ├── followOptHandler.go │ │ │ ├── getCommentListHandler.go │ │ │ ├── getFavoriteListHandler.go │ │ │ ├── getFollowListHandler.go │ │ │ ├── getFollowerListHandler.go │ │ │ └── getFriendListHandler.go │ │ ├── logic │ │ ├── feed │ │ │ └── feedVideoListLogic.go │ │ ├── message │ │ │ ├── messageLogic.go │ │ │ └── messagelistLogic.go │ │ ├── publish │ │ │ ├── getPublishVideoListLogic.go │ │ │ └── publishVideoLogic.go │ │ ├── user │ │ │ ├── userInfoLogic.go │ │ │ ├── userLoginLogic.go │ │ │ └── userRegisterLogic.go │ │ └── userOpt │ │ │ ├── commentoptlogic.go │ │ │ ├── favoriteOptLogic.go │ │ │ ├── followOptLogic.go │ │ │ ├── getFavoriteListLogic.go │ │ │ ├── getFollowListLogic.go │ │ │ ├── getFollowerListLogic.go │ │ │ ├── getFriendListLogic.go │ │ │ └── getcommentlistlogic.go │ │ ├── middleware │ │ ├── authjwtMiddleware.go │ │ └── isloginMiddleware.go │ │ ├── svc │ │ └── serviceContext.go │ │ └── types │ │ └── types.go ├── kafka │ ├── docs.go │ ├── manager.go │ └── operator.go ├── logger │ └── log.go ├── message │ ├── etc │ │ └── userMessage.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── getMessageListLogic.go │ │ │ └── sendMessageLogic.go │ │ ├── server │ │ │ └── userMessageServer.go │ │ └── svc │ │ │ └── serviceContext.go │ ├── userMessage.go │ ├── userMessagePb │ │ ├── GenPb │ │ │ ├── UserMessage.proto │ │ │ └── build.sh │ │ ├── UserMessage.pb.go │ │ └── UserMessage_grpc.pb.go │ └── usermessage │ │ └── userMessage.go ├── minio-client │ ├── etc │ │ └── minioclient.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── uploadfilelogic.go │ │ │ └── utils.go │ │ ├── server │ │ │ └── minioclientserver.go │ │ └── svc │ │ │ └── servicecontext.go │ ├── minioclient.go │ ├── minioclient │ │ └── minioclient.go │ ├── proto │ │ └── minio-client.proto │ └── types │ │ └── minio-client │ │ ├── minio-client.pb.go │ │ └── minio-client_grpc.pb.go ├── mq │ ├── etc │ │ └── mq.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── listen │ │ │ ├── kqMqs.go │ │ │ └── listen.go │ │ ├── mqs │ │ │ └── kq │ │ │ │ ├── userCommentUpdate.go │ │ │ │ ├── userFavoriteUpdate.go │ │ │ │ └── userFollowUpdate.go │ │ └── svc │ │ │ └── serviceContext.go │ └── mq.go ├── sql │ ├── 01_test.go │ ├── README.md │ ├── dal │ │ ├── dal.go │ │ ├── method.go │ │ ├── model │ │ │ ├── chat.gen.go │ │ │ ├── comment.gen.go │ │ │ ├── favorite.gen.go │ │ │ ├── follow.gen.go │ │ │ ├── user.gen.go │ │ │ └── video.gen.go │ │ ├── query │ │ │ ├── chat.gen.go │ │ │ ├── comment.gen.go │ │ │ ├── favorite.gen.go │ │ │ ├── follow.gen.go │ │ │ ├── gen.go │ │ │ ├── user.gen.go │ │ │ └── video.gen.go │ │ └── user_test.go │ ├── pack │ │ ├── conn.go │ │ └── query.go │ └── schema.sql ├── user │ ├── etc │ │ └── userService.yaml │ ├── internal │ │ ├── config │ │ │ └── config.go │ │ ├── logic │ │ │ ├── infoLogic.go │ │ │ ├── loginLogic.go │ │ │ └── registerLogic.go │ │ ├── server │ │ │ └── userServiceServer.go │ │ └── svc │ │ │ └── serviceContext.go │ ├── user.go │ ├── userInfoPb │ │ ├── GenPb │ │ │ ├── UserService.proto │ │ │ └── build.sh │ │ ├── UserService.pb.go │ │ └── UserService_grpc.pb.go │ └── userservice │ │ └── userService.go └── video │ ├── etc │ └── video.yaml │ ├── internal │ ├── config │ │ └── config.go │ ├── logic │ │ ├── changevideocommentlogic.go │ │ ├── getallvideobyuseridlogic.go │ │ ├── getvideologic.go │ │ └── publishvideologic.go │ ├── server │ │ └── videoserviceserver.go │ └── svc │ │ └── servicecontext.go │ ├── proto │ └── video.proto │ ├── types │ └── video │ │ ├── video.pb.go │ │ └── video_grpc.pb.go │ ├── video.go │ └── videoservice │ └── videoservice.go └── proto ├── READEME.md ├── comment_action.proto ├── comment_list.proto ├── favorite_action.proto ├── favorite_list.proto ├── feed.proto ├── message_action.proto ├── message_chat.proto ├── publish_action.proto ├── publish_list.proto ├── relation_action.proto ├── relation_follow_list.proto ├── relation_follower_list.proto ├── relation_friend_list.proto ├── user.proto ├── user_login.proto └── user_register.proto /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # Set to true to add reviewers to pull requests 2 | addReviewers: true 3 | 4 | # Set to true to add assignees to pull requests 5 | addAssignees: true 6 | 7 | # A list of reviewers to be added to pull requests (GitHub user name) 8 | reviewers: 9 | - Vacant2333 10 | 11 | # A list of keywords to be skipped the process that add reviewers if pull requests include it 12 | skipKeywords: 13 | - wip 14 | 15 | # A number of reviewers added to the pull request 16 | # Set 0 to add all the reviewers (default: 0) 17 | numberOfReviewers: 0 18 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | name: golangci-codecov 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 2 16 | - uses: actions/setup-go@v2 17 | with: 18 | go-version: '1.18' 19 | - name: Run coverage 20 | run: go test -race -coverprofile=coverage.txt -covermode=atomic ./... 21 | - name: Upload coverage to Codecov 22 | uses: codecov/codecov-action@v3 -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - master 8 | - main 9 | pull_request: 10 | permissions: 11 | contents: read 12 | # Optional: allow read access to pull request. Use with `only-new-issues` option. 13 | # pull-requests: read 14 | jobs: 15 | golangci: 16 | name: lint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/setup-go@v3 20 | with: 21 | go-version: 1.19 22 | - uses: actions/checkout@v3 23 | - name: golangci-lint 24 | uses: golangci/golangci-lint-action@v3 25 | with: 26 | # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version 27 | version: latest 28 | args: --timeout=10m 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | /deployment/dashboard/token.txt 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Vacant 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ByteDance douyin project 2 | 3 | [Docs](https://github.com/Vacant2333/douyin/blob/main/docs/) 4 | 5 | [Structure](https://github.com/Vacant2333/douyin/blob/main/docs/design/Structure.drawio) -------------------------------------------------------------------------------- /cmd/comment/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/comment/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/usercomment /usr/local/go/src/douyin/pkg/comment/usercomment.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/usercomment /app/usercomment 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./usercomment", "-f", "etc/usercomment.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/favorite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/favorite/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/favorite /usr/local/go/src/douyin/pkg/favorite/userOptService.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/favorite /app/favorite 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./favorite", "-f", "etc/userOptService.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/follow/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/follow/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/follow /usr/local/go/src/douyin/pkg/follow/follow.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/follow /app/follow 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./follow", "-f", "etc/follow.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/gateway/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/gateway /usr/local/go/src/douyin/pkg/gateway/api.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/gateway /app/gateway 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./gateway", "-f", "etc/user-api.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/message/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/message/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/message /usr/local/go/src/douyin/pkg/message/userMessage.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/message /app/message 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./message", "-f", "etc/userMessage.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/minio-client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/minio-client/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/minioclient /usr/local/go/src/douyin/pkg/minio-client/minioclient.go 12 | 13 | FROM minidocks/ffmpeg 14 | WORKDIR /app 15 | COPY --from=builder /app/minioclient /app/minioclient 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./minioclient", "-f", "etc/minioclient.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/mq/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/mq/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/mq /usr/local/go/src/douyin/pkg/mq/mq.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/mq /app/mq 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./mq", "-f", "etc/mq.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/user/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/user/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/user /usr/local/go/src/douyin/pkg/user/user.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/user /app/user 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./user", "-f", "etc/userService.yaml"] 18 | -------------------------------------------------------------------------------- /cmd/video/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest AS builder 2 | ENV CGO_ENABLED 0 3 | ENV GOPROXY https://goproxy.cn,direct 4 | WORKDIR /build 5 | ADD go.mod . 6 | ADD go.sum . 7 | RUN go mod download 8 | COPY pkg /usr/local/go/src/douyin/pkg 9 | COPY common /usr/local/go/src/douyin/common 10 | COPY pkg/video/etc /app/etc 11 | RUN go build -ldflags="-s -w" -o /app/video /usr/local/go/src/douyin/pkg/video/video.go 12 | 13 | FROM gcr.io/distroless/static-debian11:latest 14 | WORKDIR /app 15 | COPY --from=builder /app/video /app/video 16 | COPY --from=builder /app/etc /app/etc 17 | CMD ["./video", "-f", "etc/video.yaml"] 18 | -------------------------------------------------------------------------------- /common/checkpwd/checkPwd.go: -------------------------------------------------------------------------------- 1 | package checkpwd 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | // 密码强度必须为字⺟⼤⼩写+数字+符号,9位以上 9 | func CheckPassword(ps string) error { 10 | if len(ps) < 9 { 11 | return fmt.Errorf("password len is < 9") 12 | } 13 | num := `[0-9]{1}` 14 | a_z := `[a-z]{1}` 15 | A_Z := `[A-Z]{1}` 16 | symbol := `[!@#~$%^&*()+|_]{1}` 17 | if b, err := regexp.MatchString(num, ps); !b || err != nil { 18 | return fmt.Errorf("password need num :%v", err) 19 | } 20 | if b, err := regexp.MatchString(a_z, ps); !b || err != nil { 21 | return fmt.Errorf("password need a_z :%v", err) 22 | } 23 | if b, err := regexp.MatchString(A_Z, ps); !b || err != nil { 24 | return fmt.Errorf("password need A_Z :%v", err) 25 | } 26 | if b, err := regexp.MatchString(symbol, ps); !b || err != nil { 27 | return fmt.Errorf("password need symbol :%v", err) 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /common/checkpwd/checkPwd_test.go: -------------------------------------------------------------------------------- 1 | package checkpwd 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestCheckPassword(t *testing.T) { // 测试函数名必须以Test开头,必须接收一个*testing.T类型参数 9 | got := CheckPassword("@2019") // 程序输出的结果 10 | fmt.Printf("result:%v\n", got) 11 | } 12 | -------------------------------------------------------------------------------- /common/globalkey/constantKey.go: -------------------------------------------------------------------------------- 1 | package globalkey 2 | 3 | // 软删除只是在数据库表中添加量该字段 4 | 5 | var DelStateNo int64 = 0 //未删除 6 | var DelStateYes int64 = 1 //已删除 7 | -------------------------------------------------------------------------------- /common/globalkey/redisCacheKey.go: -------------------------------------------------------------------------------- 1 | package globalkey 2 | 3 | // 存放的是api记录点赞和关注放在redis的key与valTpl 4 | 5 | const FavoriteSetKey = "FavoriteKey" 6 | const FavoriteSetValTpl = "Favorite&Video&Id:%d" 7 | 8 | const FollowSetKey = "FollowKey" 9 | const FollowSetValTpl = "Follow&Follow&Id:%d" 10 | 11 | const ExistDataValTpl = "%d:%d" 12 | -------------------------------------------------------------------------------- /common/help/sensitiveWords/sensitiveWords.go: -------------------------------------------------------------------------------- 1 | package sensitiveWords 2 | 3 | var SensitiveWords = []string{ 4 | "共产专制", 5 | "共产王朝", 6 | "裆中央", 7 | "土共", 8 | "土g", 9 | "共狗", 10 | "g匪", 11 | "共匪", 12 | "仇共", 13 | "共产党腐败", 14 | "共产党专制", 15 | "共产党的报应", 16 | "共产党的末日", 17 | "共产党专制", 18 | "communistparty", 19 | "症腐", 20 | "政腐", 21 | "政付", 22 | "正府", 23 | "政俯", 24 | "政f", 25 | "zhengfu", 26 | "政zhi", 27 | "挡中央", 28 | "档中央", 29 | "中国zf", 30 | "中央zf", 31 | "国wu院", 32 | "中华帝国", 33 | "gong和", 34 | "大陆官方", 35 | "北京政权", 36 | "艹你", 37 | "死全家", 38 | "全家不得好死", 39 | "cao你", 40 | "草你妈", 41 | "日你妈", 42 | "JB", 43 | "本屌", 44 | "齐B短裙", 45 | "法克鱿", 46 | "傻逼", 47 | "绿茶婊", 48 | "你妈的", 49 | "表砸", 50 | "屌爆了", 51 | "买了个婊", 52 | "已撸", 53 | "吉跋猫", 54 | "妈蛋", 55 | "碧池", 56 | "淫家", 57 | "法轮功", 58 | "伪火", 59 | "退党", 60 | "超越红墙", 61 | "逢8必灾", 62 | "逢八必灾", 63 | "逢9必乱", 64 | "逢九必乱", 65 | "甲睾酮", 66 | "adrenaline", 67 | "erythropoietin", 68 | "地奈德", 69 | "莫达非尼", 70 | "氯噻嗪", 71 | "苯巴比妥", 72 | "促性腺激素", 73 | "泼尼松", 74 | "麻黄草", 75 | "雄烯二醇", 76 | "地塞米松", 77 | "tamoxifen", 78 | "strychnine", 79 | "androst", 80 | "新型毒品", 81 | "杜冷丁", 82 | "兴奋剂", 83 | "mdma", 84 | "海洛因", 85 | "海luo因", 86 | "heroin", 87 | "diamorphine", 88 | "diacetylmorphine", 89 | "鸦片", 90 | "阿芙蓉", 91 | "咖啡因", 92 | "cocain", 93 | "三唑仑", 94 | "美沙酮", 95 | "麻古", 96 | "k粉", 97 | "凯他敏", 98 | "ketamine", 99 | "冰毒", 100 | "苯丙胺", 101 | "cannabis", 102 | "大麻", 103 | "爱他死", 104 | "氯胺酮", 105 | "benzodiazepines", 106 | "甲基安非他明", 107 | "安非他命", 108 | "吗啡", 109 | "社会主义灭亡", 110 | "打倒中国", 111 | "打倒共产党", 112 | "打倒共产主义", 113 | "64惨案", 114 | "64时期", 115 | "64运动", 116 | "4事件", 117 | "四事件", 118 | "北京风波", 119 | "操逼", 120 | "操黑", 121 | "操烂", 122 | "肏你", 123 | "肏死", 124 | "插逼", 125 | "插进", 126 | "插你", 127 | "插我", 128 | "插阴", 129 | "潮吹", 130 | "潮喷", 131 | "成人dv", 132 | "成人电影", 133 | "成人论坛", 134 | "成人小说", 135 | "成人电", 136 | "成人电影", 137 | "成人卡通", 138 | "成人聊", 139 | "成人片", 140 | "成人视", 141 | "成人图", 142 | "成人文", 143 | "成人小", 144 | "成人电影", 145 | "成人论坛", 146 | "成人色情", 147 | "成人网站", 148 | "成人文学", 149 | "成人小说", 150 | "艳情小说", 151 | "成人游戏", 152 | "黄片", 153 | "几吧", 154 | "鸡吧", 155 | "鸡巴", 156 | "鸡奸", 157 | "寂寞男", 158 | "寂寞女", 159 | "妓女", 160 | "激情", 161 | "集体淫", 162 | "奸情", 163 | "叫床", 164 | "脚交", 165 | } 166 | -------------------------------------------------------------------------------- /common/help/sensitiveWords/sensitiveWoredsFilter.go: -------------------------------------------------------------------------------- 1 | package sensitiveWords 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stringx" 5 | ) 6 | 7 | func SensitiveWordsFliter(sensitiveWords []string, context string, replaceMask rune) string { 8 | //敏感词过滤 9 | filter := stringx.NewTrie(sensitiveWords, stringx.WithMask(replaceMask)) // 默认替换为* 10 | safe, _, _ := filter.Filter(context) 11 | return safe 12 | } 13 | -------------------------------------------------------------------------------- /common/help/token/common.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "github.com/golang-jwt/jwt/v4" 4 | 5 | type Claims struct { 6 | UserId int64 `json:"user_id"` 7 | ExpireAt int64 `json:"expire_at"` 8 | Else jwt.MapClaims 9 | jwt.RegisteredClaims 10 | } 11 | 12 | type CurrentUserId string 13 | 14 | const ( 15 | AccessSecret = "pedagoguing" 16 | AccessExpire = 86400 17 | ) 18 | -------------------------------------------------------------------------------- /common/help/token/genToken.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import ( 4 | "github.com/golang-jwt/jwt/v4" 5 | "time" 6 | ) 7 | 8 | type GenToken struct{} 9 | 10 | func (g *GenToken) GenToken(iat time.Time, userId int64, payloads map[string]interface{}) (string, error) { 11 | claims := Claims{ 12 | UserId: userId, 13 | ExpireAt: iat.Add(time.Second * AccessExpire).Unix(), 14 | RegisteredClaims: jwt.RegisteredClaims{ 15 | Issuer: "pedagoguing", 16 | }, 17 | } 18 | for k, v := range payloads { 19 | claims.Else[k] = v 20 | } 21 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 22 | return token.SignedString([]byte(AccessSecret)) 23 | } 24 | -------------------------------------------------------------------------------- /common/help/token/parseToken.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "github.com/golang-jwt/jwt/v4" 4 | 5 | type ParseToken struct{} 6 | 7 | func (*ParseToken) ParseToken(tokenString string) (*Claims, error) { 8 | // 解码token 9 | tokenClaims, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { 10 | return []byte(AccessSecret), nil 11 | }) 12 | // 如果不为空,解码成功 13 | if tokenClaims != nil { 14 | // 断言转换 15 | if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid { 16 | return claims, nil 17 | } 18 | } 19 | return nil, err 20 | } 21 | -------------------------------------------------------------------------------- /common/messageTypes/message.go: -------------------------------------------------------------------------------- 1 | package messageTypes 2 | 3 | const ( 4 | ActionADD int64 = 1 5 | ActionCancel int64 = 2 6 | ActionErr int64 = -99 7 | ) 8 | 9 | // UserCommentOptMessage 评论 / 删除评论 10 | type UserCommentOptMessage struct { 11 | VideoId int64 `json:"video_id"` 12 | CommentId int64 `json:"comment_id"` 13 | UserId int64 `json:"user_id"` 14 | ActionType int64 `json:"action_type"` 15 | CommentText string `json:"comment_text,omitempty"` 16 | CreateDate string `json:"create_date,omitempty"` 17 | } 18 | 19 | // UserFavoriteOptMessage 点赞 / 取消点赞 20 | type UserFavoriteOptMessage struct { 21 | ActionType int64 `json:"action_type"` 22 | VideoId int64 `json:"video_id"` 23 | UserId int64 `json:"user_id"` 24 | } 25 | 26 | // UserFollowOptMessage 关注 / 取消关注 27 | type UserFollowOptMessage struct { 28 | ActionType int64 `json:"action_type"` 29 | ToUserId int64 `json:"to_user_id"` 30 | UserId int64 `json:"user_id"` 31 | } 32 | -------------------------------------------------------------------------------- /common/model/GenModel/createModel.sh: -------------------------------------------------------------------------------- 1 | # 生成comment表模型 2 | goctl model mysql datasource -url="root:2019xzcdg@tcp(120.25.202.230:3306)/tiktok" -table="comment" -c -dir="../../model" --home=../../../../../tpl/1.3.5 -------------------------------------------------------------------------------- /common/model/commentModel/commentmodel.go: -------------------------------------------------------------------------------- 1 | package commentModel 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/core/stores/sqlx" 6 | ) 7 | 8 | var _ CommentModel = (*customCommentModel)(nil) 9 | 10 | type ( 11 | // CommentModel is an interface to be customized, add more methods here, 12 | // and implement the added methods in customCommentModel. 13 | CommentModel interface { 14 | commentModel 15 | } 16 | 17 | customCommentModel struct { 18 | *defaultCommentModel 19 | } 20 | ) 21 | 22 | // NewCommentModel returns a model for the database table. 23 | func NewCommentModel(conn sqlx.SqlConn, c cache.CacheConf) CommentModel { 24 | return &customCommentModel{ 25 | defaultCommentModel: newCommentModel(conn, c), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/model/commentModel/vars.go: -------------------------------------------------------------------------------- 1 | package commentModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/favoriteModel/favoritemodel.go: -------------------------------------------------------------------------------- 1 | package favoriteModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var _ FavoriteModel = (*customFavoriteModel)(nil) 6 | 7 | type ( 8 | // FavoriteModel is an interface to be customized, add more methods here, 9 | // and implement the added methods in customFavoriteModel. 10 | FavoriteModel interface { 11 | favoriteModel 12 | } 13 | 14 | customFavoriteModel struct { 15 | *defaultFavoriteModel 16 | } 17 | ) 18 | 19 | // NewFavoriteModel returns a model for the database table. 20 | func NewFavoriteModel(conn sqlx.SqlConn) FavoriteModel { 21 | return &customFavoriteModel{ 22 | defaultFavoriteModel: newFavoriteModel(conn), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/model/favoriteModel/vars.go: -------------------------------------------------------------------------------- 1 | package favoriteModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/followModel/followmodel.go: -------------------------------------------------------------------------------- 1 | package followModel 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/core/stores/sqlx" 6 | ) 7 | 8 | var _ FollowModel = (*customFollowModel)(nil) 9 | 10 | type ( 11 | // FollowModel is an interface to be customized, add more methods here, 12 | // and implement the added methods in customFollowModel. 13 | FollowModel interface { 14 | followModel 15 | } 16 | 17 | customFollowModel struct { 18 | *defaultFollowModel 19 | } 20 | ) 21 | 22 | // NewFollowModel returns a model for the database table. 23 | func NewFollowModel(conn sqlx.SqlConn, c cache.CacheConf) FollowModel { 24 | return &customFollowModel{ 25 | defaultFollowModel: newFollowModel(conn, c), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/model/followModel/vars.go: -------------------------------------------------------------------------------- 1 | package followModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/genmodel/readme.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | cd ../ 3 | goctl model mysql datasource -url="root:123456@tcp(127.0.0.1:3306)/tiktok" -table="video" -dir="./videoModel" -c 4 | goctl model mysql datasource -url="root:123456@tcp(127.0.0.1:3306)/tiktok" -table="follow" -dir="./followModel" -c 5 | ``` -------------------------------------------------------------------------------- /common/model/messageModel/messagemodel.go: -------------------------------------------------------------------------------- 1 | package messageModel 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/core/stores/sqlx" 6 | ) 7 | 8 | var _ MessageModel = (*customMessageModel)(nil) 9 | 10 | type ( 11 | // MessageModel is an interface to be customized, add more methods here, 12 | // and implement the added methods in customMessageModel. 13 | MessageModel interface { 14 | messageModel 15 | } 16 | 17 | customMessageModel struct { 18 | *defaultMessageModel 19 | } 20 | ) 21 | 22 | // NewMessageModel returns a model for the database table. 23 | func NewMessageModel(conn sqlx.SqlConn, c cache.CacheConf) MessageModel { 24 | return &customMessageModel{ 25 | defaultMessageModel: newMessageModel(conn, c), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/model/messageModel/vars.go: -------------------------------------------------------------------------------- 1 | package messageModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/userModel/usermodel.go: -------------------------------------------------------------------------------- 1 | package userModel 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/core/stores/sqlx" 6 | ) 7 | 8 | var _ UserModel = (*customUserModel)(nil) 9 | 10 | type ( 11 | // UserModel is an interface to be customized, add more methods here, 12 | // and implement the added methods in customUserModel. 13 | UserModel interface { 14 | userModel 15 | } 16 | 17 | customUserModel struct { 18 | *defaultUserModel 19 | } 20 | ) 21 | 22 | // NewUserModel returns a model for the database table. 23 | func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel { 24 | return &customUserModel{ 25 | defaultUserModel: newUserModel(conn, c), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/model/userModel/vars.go: -------------------------------------------------------------------------------- 1 | package userModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/videoModel/vars.go: -------------------------------------------------------------------------------- 1 | package videoModel 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /common/model/videoModel/videomodel.go: -------------------------------------------------------------------------------- 1 | package videoModel 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/core/stores/sqlx" 6 | ) 7 | 8 | var _ VideoModel = (*customVideoModel)(nil) 9 | 10 | type ( 11 | // VideoModel is an interface to be customized, add more methods here, 12 | // and implement the added methods in customVideoModel. 13 | VideoModel interface { 14 | videoModel 15 | } 16 | 17 | customVideoModel struct { 18 | *defaultVideoModel 19 | } 20 | ) 21 | 22 | // NewVideoModel returns a model for the database table. 23 | func NewVideoModel(conn sqlx.SqlConn, c cache.CacheConf) VideoModel { 24 | return &customVideoModel{ 25 | defaultVideoModel: newVideoModel(conn, c), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/model/videoModel/videomodel_method.go: -------------------------------------------------------------------------------- 1 | package videoModel 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | "github.com/zeromicro/go-zero/core/stores/sqlc" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | func (m *defaultVideoModel) FindManyByTime(ctx context.Context, time int64, num int64) ([]*Video, error) { 12 | var resp []*Video 13 | query := fmt.Sprintf("select %s from %s where `removed` = 0 and `time` > ? limit ?", videoRows, m.table) 14 | err := m.QueryRowsNoCacheCtx(ctx, &resp, query, time, num) 15 | 16 | switch err { 17 | case nil: 18 | return resp, nil 19 | case sqlc.ErrNotFound: 20 | return nil, ErrNotFound 21 | default: 22 | return nil, err 23 | } 24 | } 25 | 26 | func (m *defaultVideoModel) FindAllByUserId(ctx context.Context, userId int64) ([]*Video, error) { 27 | var resp []*Video 28 | query := fmt.Sprintf("select %s from %s where `removed` = 0 and `author_id` = ?", videoRows, m.table) 29 | err := m.QueryRowsNoCacheCtx(ctx, &resp, query, userId) 30 | 31 | switch err { 32 | case nil: 33 | return resp, nil 34 | case sqlc.ErrNotFound: 35 | return nil, ErrNotFound 36 | default: 37 | return nil, err 38 | } 39 | } 40 | 41 | func (m *defaultVideoModel) UpdateCount(ctx context.Context, videoId int64, filed string, actionType int64) error { 42 | var query string 43 | if actionType == 1 { 44 | query = fmt.Sprintf("update %s set %s = %s + 1 where `id` = ?", m.table, filed, filed) 45 | } else { 46 | query = fmt.Sprintf("update %s set %s = %s - 1 where `id` = ?", m.table, filed, filed) 47 | } 48 | tiktokVideoIdKey := fmt.Sprintf("%s%v", cacheTiktokVideoIdPrefix, videoId) 49 | _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { 50 | return conn.ExecCtx(ctx, query, videoId) 51 | }, tiktokVideoIdKey) 52 | if err != nil { 53 | return err 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /common/xerr/errCode.go: -------------------------------------------------------------------------------- 1 | package xerr 2 | 3 | // 通用错误码成功返回 4 | const ( 5 | OK int64 = 0 6 | ERR int64 = 1 7 | ) 8 | 9 | // 全局错误码 10 | const ( 11 | SERVER_COMMON_ERROR int64 = 100001 12 | REUQEST_PARAM_ERROR int64 = 100002 13 | TOKEN_EXPIRE_ERROR int64 = 100003 14 | TOKEN_GENERATE_ERROR int64 = 100004 15 | DB_ERROR int64 = 100005 16 | DB_UPDATE_AFFECTED_ZERO_ERROR int64 = 100006 17 | SECRET_ERROR int64 = 100007 18 | ) 19 | -------------------------------------------------------------------------------- /common/xerr/errMsg.go: -------------------------------------------------------------------------------- 1 | package xerr 2 | 3 | var message map[int64]string 4 | 5 | func init() { 6 | message = make(map[int64]string) 7 | message[OK] = "SUCCESS" 8 | message[REUQEST_PARAM_ERROR] = "参数错误" 9 | message[TOKEN_EXPIRE_ERROR] = "token失效,请重新登陆" 10 | message[TOKEN_GENERATE_ERROR] = "生成token失败" 11 | message[DB_ERROR] = "数据库繁忙,请稍后再试" 12 | message[SECRET_ERROR] = "密码错误" 13 | } 14 | 15 | func MapErrMsg(errcode int64) string { 16 | if msg, ok := message[errcode]; ok { 17 | return msg 18 | } else { 19 | return "服务器开小差啦,稍后再来试一试" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/xerr/errors.go: -------------------------------------------------------------------------------- 1 | package xerr 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | /** 8 | 常用通用固定错误 9 | */ 10 | 11 | type CodeError struct { 12 | errCode int64 13 | errMsg string 14 | } 15 | 16 | // GetErrCode 返回给前端的错误码 17 | func (e *CodeError) GetErrCode() int64 { 18 | return e.errCode 19 | } 20 | 21 | // GetErrMsg 返回给前端显示端错误信息 22 | func (e *CodeError) GetErrMsg() string { 23 | return e.errMsg 24 | } 25 | 26 | func (e *CodeError) Error() string { 27 | return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg) 28 | } 29 | 30 | func NewErrCode(errCode int64) *CodeError { 31 | return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)} 32 | } 33 | 34 | func NewErrMsg(errMsg string) *CodeError { 35 | return &CodeError{errCode: SERVER_COMMON_ERROR, errMsg: errMsg} 36 | } 37 | -------------------------------------------------------------------------------- /deployment/cluster/douyin-cluster.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | name: douyin 4 | nodes: 5 | - role: control-plane 6 | - role: worker 7 | - role: worker 8 | - role: worker 9 | -------------------------------------------------------------------------------- /deployment/comment/comment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: comment 6 | name: comment 7 | namespace: comment 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: comment 13 | template: 14 | metadata: 15 | labels: 16 | app: comment 17 | spec: 18 | containers: 19 | - name: comment 20 | image: douyin/comment:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/dashboard/README.md: -------------------------------------------------------------------------------- 1 | # kubernets dashboard 2 | 3 | ## Install Kubernetes-Dashboard 4 | 5 | ```bash 6 | # Add dashboard repo to your helm 7 | helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/ 8 | # Create dashboard namespace 9 | kubectl create ns dashboard 10 | # Install dashboard to the last namespace 11 | helm install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard -n dashboard 12 | # Apply role and account config file 13 | kubectl apply -f cluster_role_binding.yaml 14 | kubectl apply -f service_account.yaml 15 | # Get the login token 16 | kubectl -n dashboard create token admin-user > token.txt 17 | ``` 18 | 19 | ## Visit Kubernetes-Dashboard 20 | 21 | ```bash 22 | export POD_NAME=$(kubectl get pods \ 23 | -n dashboard \ 24 | -l "app.kubernetes.io/name=kubernetes-dashboard,app.kubernetes.io/instance=kubernetes-dashboard" \ 25 | -o jsonpath="{.items[0].metadata.name}") 26 | echo Visit the dashboard https://127.0.0.1:8443/ by your token: 27 | cat token.txt 28 | kubectl -n dashboard port-forward $POD_NAME 8443:8443 29 | ``` 30 | -------------------------------------------------------------------------------- /deployment/dashboard/cluster_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: admin-user 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: cluster-admin 9 | subjects: 10 | - kind: ServiceAccount 11 | name: admin-user 12 | namespace: dashboard -------------------------------------------------------------------------------- /deployment/dashboard/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: admin-user 5 | namespace: dashboard -------------------------------------------------------------------------------- /deployment/favorite/favorite.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: favorite 6 | name: favorite 7 | namespace: favorite 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: favorite 13 | template: 14 | metadata: 15 | labels: 16 | app: favorite 17 | spec: 18 | containers: 19 | - name: favorite 20 | image: douyin/favorite:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/follow/follow.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: follow 6 | name: follow 7 | namespace: follow 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: follow 13 | template: 14 | metadata: 15 | labels: 16 | app: follow 17 | spec: 18 | containers: 19 | - name: follow 20 | image: douyin/follow:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/gateway/gateway.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: gateway 6 | name: gateway 7 | namespace: gateway 8 | spec: 9 | ports: 10 | - port: 8888 11 | protocol: TCP 12 | targetPort: 8888 13 | selector: 14 | app: gateway 15 | type: LoadBalancer 16 | --- 17 | apiVersion: apps/v1 18 | kind: Deployment 19 | metadata: 20 | labels: 21 | app: gateway 22 | name: gateway 23 | namespace: gateway 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: gateway 29 | template: 30 | metadata: 31 | labels: 32 | app: gateway 33 | spec: 34 | containers: 35 | - name: gateway 36 | image: douyin/gateway:nightly 37 | imagePullPolicy: Never 38 | ports: 39 | - containerPort: 8888 40 | -------------------------------------------------------------------------------- /deployment/message/message.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: message 6 | name: message 7 | namespace: message 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: message 13 | template: 14 | metadata: 15 | labels: 16 | app: message 17 | spec: 18 | containers: 19 | - name: message 20 | image: douyin/message:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/minio-client/minio-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: minio-client 6 | name: minio-client 7 | namespace: minio-client 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: minio-client 13 | template: 14 | metadata: 15 | labels: 16 | app: minio-client 17 | spec: 18 | containers: 19 | - name: minio-client 20 | image: douyin/minio-client:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/minio/minio.yaml: -------------------------------------------------------------------------------- 1 | rootUser: "douyin" 2 | rootPassword: "douyin_pass" 3 | replicas: 2 4 | persistence: 5 | size: 10Gi 6 | resources: 7 | requests: 8 | memory: 1Gi 9 | buckets: 10 | - name: douyin 11 | policy: public 12 | -------------------------------------------------------------------------------- /deployment/mq/mq.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: mq 6 | name: mq 7 | namespace: mq 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: mq 13 | template: 14 | metadata: 15 | labels: 16 | app: mq 17 | spec: 18 | containers: 19 | - name: mq 20 | image: douyin/mq:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/mysql/mysql-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: service-mysql 5 | labels: 6 | app: mysql 7 | spec: 8 | ports: 9 | - name: mysql 10 | port: 3306 11 | targetPort: 3306 12 | selector: 13 | app: mysql 14 | type: ClusterIP 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: mysql 20 | spec: 21 | selector: 22 | matchLabels: 23 | app: mysql 24 | strategy: 25 | type: Recreate 26 | template: 27 | metadata: 28 | labels: 29 | app: mysql 30 | spec: 31 | containers: 32 | - name: mysql 33 | image: mysql 34 | env: 35 | - name: MYSQL_ROOT_PASSWORD 36 | value: root 37 | - name: MYSQL_USER 38 | value: titok 39 | - name: MYSQL_PASSWORD 40 | value: titok 41 | ports: 42 | - name: mysql 43 | containerPort: 3306 44 | volumeMounts: 45 | - name: mysql-pv 46 | mountPath: /var/lib/mysql 47 | - name: mysql-initdb 48 | mountPath: /var/lib/mysql 49 | command: 50 | - bash 51 | - "-c" 52 | - | 53 | /entrypoint.sh mysqld & 54 | sleep 30 55 | mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE USER 'titok'@'%' IDENTIFIED BY 'titok';" 56 | mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "GRANT ALL PRIVILEGES ON *.* TO 'titok'@'%';" 57 | mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "FLUSH PRIVILEGES;" 58 | mysql -u root -p${MYSQL_ROOT_PASSWORD} < /var/lib/mysql/schema.sql 59 | volumes: 60 | - name: mysql-pv 61 | persistentVolumeClaim: 62 | claimName: nfs-pvc 63 | - name: mysql-initdb 64 | configMap: 65 | name: mysql-scheme 66 | -------------------------------------------------------------------------------- /deployment/nfs/README.md: -------------------------------------------------------------------------------- 1 | # NFS 2 | 3 | ## Why nfs? 4 | 5 | When your pods down... All datas will disappear from there. 6 | Just because you store you all data in this instace rather than presistence volume. 7 | 8 | So we need a `NFS`, a file system for distributed systems... with no more explaination. 9 | 10 | - It can provide the `volume` for backend 11 | - Presistent storage 12 | - Accesss from different `namespcae` or `pods 13 | 14 | 15 | ## nfs-client-provisioner 16 | 17 | >nfs-client-provisioner 是一个Kubernetes的简易NFS的外部provisioner,本身不提供NFS,需要现有的NFS服务器提供存储 18 | >- PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上) 19 | >- PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上) 20 | -------------------------------------------------------------------------------- /deployment/nfs/nfs-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nfs-server 5 | spec: 6 | ports: 7 | - name: nfs 8 | port: 2049 9 | protocol: TCP 10 | - name: mountd 11 | port: 20048 12 | protocol: TCP 13 | - name: rpcbind 14 | port: 111 15 | protocol: TCP 16 | selector: 17 | app: nfs-server 18 | type: ClusterIP 19 | --- 20 | apiVersion: apps/v1 21 | kind: StatefulSet 22 | metadata: 23 | name: nfs-server 24 | spec: 25 | serviceName: "nfs-server" 26 | replicas: 1 27 | selector: 28 | matchLabels: 29 | app: nfs-server 30 | template: 31 | metadata: 32 | labels: 33 | app: nfs-server 34 | spec: 35 | containers: 36 | - name: nfs-server 37 | image: quay.io/kubernetes_incubator/nfs-server:1.0 38 | ports: 39 | - name: nfs 40 | containerPort: 2049 41 | protocol: TCP 42 | - name: mountd 43 | containerPort: 20048 44 | protocol: TCP 45 | - name: rpcbind 46 | containerPort: 111 47 | protocol: TCP 48 | securityContext: 49 | privileged: true 50 | volumeMounts: 51 | - name: nfs-pv 52 | mountPath: /nfsdata 53 | volumes: 54 | - name: nfs-pv 55 | persistentVolumeClaim: 56 | claimName: nfs-pvc 57 | -------------------------------------------------------------------------------- /deployment/nfs/nfs-pvx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: nfs-pv 5 | spec: 6 | capacity: 7 | storage: 2Gi 8 | accessModes: 9 | - ReadWriteMany 10 | nfs: 11 | server: nfs-server 12 | path: "/" 13 | --- 14 | apiVersion: v1 15 | kind: PersistentVolumeClaim 16 | metadata: 17 | name: nfs-pvc 18 | spec: 19 | accessModes: 20 | - ReadWriteMany 21 | resources: 22 | requests: 23 | storage: 2Gi 24 | storageClassName: standard 25 | -------------------------------------------------------------------------------- /deployment/user/user.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: user 6 | name: user 7 | namespace: user 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: user 13 | template: 14 | metadata: 15 | labels: 16 | app: user 17 | spec: 18 | containers: 19 | - name: user 20 | image: douyin/user:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /deployment/video/video.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: video 6 | name: video 7 | namespace: video 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: video 13 | template: 14 | metadata: 15 | labels: 16 | app: video 17 | spec: 18 | containers: 19 | - name: video 20 | image: douyin/video:nightly 21 | imagePullPolicy: Never 22 | -------------------------------------------------------------------------------- /docs/Setup.md: -------------------------------------------------------------------------------- 1 | # Deploy this project 2 | 3 | ## 1. Install dependencies 4 | If you use Windows, we recommend that you install dependent software in the virtual machine. 5 | - [Docker](https://www.docker.com/) 6 | - [Kind](https://kind.sigs.k8s.io/) 7 | - [Kubectl](https://kubernetes.io/docs/tasks/tools/) 8 | - [Helm](https://helm.sh/docs/intro/install/) 9 | - [Make](https://www.gnu.org/software/make/#download) 10 | 11 | ## 2. Install the cluster and components 12 | Run this commands in root direction. 13 | #### Install Cluster 14 | ```bash 15 | make install-cluster 16 | ``` 17 | 18 | #### Install components which you need 19 | ```bash 20 | make install-minio install-etcd install-kafka install-redis 21 | ``` 22 | 23 | ## Install the microservices 24 | ```bash 25 | make install-minio-client install-user install-comment install-mq install-favorite install-video install-message install-follow install-gateway 26 | ``` 27 | 28 | ## Optional components 29 | - [Kubernetes-Dashboard](https://github.com/Vacant2333/douyin/blob/main/deployment/dashboard/README.md) 30 | -------------------------------------------------------------------------------- /docs/design/CodingRules.md: -------------------------------------------------------------------------------- 1 | ## Coding rules 2 | 3 | #### Coding 4 | 5 | Annotations like this one: 6 | 7 | ```go 8 | // The number of videos 9 | var num int64 10 | ``` 11 | 12 | #### Designing 13 | 14 | RPC Port:`30001`
15 | API Port:`30002`
16 | Dockerfile builder image: `golang:latest`
17 | Dockerfile running image: `gcr.io/distroless/static-debian11:latest`
18 | -------------------------------------------------------------------------------- /pkg/comment/etc/usercomment.yaml: -------------------------------------------------------------------------------- 1 | Name: usercomment.rpc 2 | ListenOn: 0.0.0.0:8083 3 | Mode: dev 4 | Etcd: 5 | Hosts: 6 | - etcd.etcd.svc.cluster.local:2379 7 | Key: usercomment.rpc 8 | DB: 9 | DataSource: douyin:Z4eEXbWWCApby8dE@tcp(bt.vacant.zone:3306)/douyin?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai 10 | CacheConf: 11 | - Host: redis-master.redis.svc.cluster.local:6379 12 | Pass: redispwd123 13 | VideoRPC: 14 | Etcd: 15 | Hosts: 16 | - etcd.etcd.svc.cluster.local:2379 17 | Key: video.rpc 18 | -------------------------------------------------------------------------------- /pkg/comment/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | ) 7 | 8 | type Config struct { 9 | zrpc.RpcServerConf 10 | DB struct { 11 | DataSource string 12 | } 13 | CacheConf cache.CacheConf 14 | VideoRPC zrpc.RpcClientConf 15 | } 16 | -------------------------------------------------------------------------------- /pkg/comment/internal/logic/getvideocommentlogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/comment/internal/svc" 6 | "douyin/pkg/comment/userCommentPb" 7 | "fmt" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | ) 10 | 11 | type GetVideoCommentLogic struct { 12 | ctx context.Context 13 | svcCtx *svc.ServiceContext 14 | logx.Logger 15 | } 16 | 17 | func NewGetVideoCommentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetVideoCommentLogic { 18 | return &GetVideoCommentLogic{ 19 | ctx: ctx, 20 | svcCtx: svcCtx, 21 | Logger: logx.WithContext(ctx), 22 | } 23 | } 24 | 25 | // GetVideoComment -----------------------userCommentList----------------------- 26 | func (l *GetVideoCommentLogic) GetVideoComment(in *userCommentPb.GetVideoCommentReq) (*userCommentPb.GetVideoCommentReqResp, error) { 27 | fmt.Printf(":::::::::::::::::::::::::::::::::::::::::::::::") 28 | allCommentInfoData, err := l.svcCtx.UserCommentModel.FindAll(l.ctx, in.VideoId) 29 | 30 | if err != nil { 31 | logx.Errorf("GetCommentList------->SELECT err : %s", err.Error()) 32 | return &userCommentPb.GetVideoCommentReqResp{}, err 33 | } 34 | 35 | var commentList []*userCommentPb.Comment 36 | for _, v := range allCommentInfoData { 37 | var comment userCommentPb.Comment 38 | comment.CommentId = v.Id 39 | comment.Content = v.Content 40 | comment.CreateDate = v.CreateTime.String() 41 | comment.UserId = v.UserId 42 | 43 | commentList = append(commentList, &comment) 44 | } 45 | 46 | return &userCommentPb.GetVideoCommentReqResp{ 47 | CommentList: commentList, 48 | }, nil 49 | } 50 | -------------------------------------------------------------------------------- /pkg/comment/internal/server/usercommentserver.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: UserComment.proto 3 | 4 | package server 5 | 6 | import ( 7 | "context" 8 | logic2 "douyin/pkg/comment/internal/logic" 9 | "douyin/pkg/comment/internal/svc" 10 | userCommentPb2 "douyin/pkg/comment/userCommentPb" 11 | ) 12 | 13 | type UserCommentServer struct { 14 | svcCtx *svc.ServiceContext 15 | userCommentPb2.UnimplementedUserCommentServer 16 | } 17 | 18 | func NewUserCommentServer(svcCtx *svc.ServiceContext) *UserCommentServer { 19 | return &UserCommentServer{ 20 | svcCtx: svcCtx, 21 | } 22 | } 23 | 24 | // -----------------------userCommentStatus----------------------- 25 | func (s *UserCommentServer) UpdateCommentStatus(ctx context.Context, in *userCommentPb2.UpdateCommentStatusReq) (*userCommentPb2.UpdateCommentStatusResp, error) { 26 | l := logic2.NewUpdateCommentStatusLogic(ctx, s.svcCtx) 27 | return l.UpdateCommentStatus(in) 28 | } 29 | 30 | // -----------------------userCommentList----------------------- 31 | func (s *UserCommentServer) GetVideoComment(ctx context.Context, in *userCommentPb2.GetVideoCommentReq) (*userCommentPb2.GetVideoCommentReqResp, error) { 32 | l := logic2.NewGetVideoCommentLogic(ctx, s.svcCtx) 33 | return l.GetVideoComment(in) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/comment/internal/svc/servicecontext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/common/model/commentModel" 5 | "douyin/pkg/comment/internal/config" 6 | "douyin/pkg/video/videoservice" 7 | "github.com/zeromicro/go-zero/core/stores/sqlx" 8 | "github.com/zeromicro/go-zero/zrpc" 9 | ) 10 | 11 | type ServiceContext struct { 12 | Config config.Config 13 | UserCommentModel commentModel.CommentModel 14 | VideoRPC videoservice.VideoService 15 | } 16 | 17 | func NewServiceContext(c config.Config) *ServiceContext { 18 | return &ServiceContext{ 19 | Config: c, 20 | UserCommentModel: commentModel.NewCommentModel(sqlx.NewMysql(c.DB.DataSource), c.CacheConf), 21 | VideoRPC: videoservice.NewVideoService(zrpc.MustNewClient(c.VideoRPC)), 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pkg/comment/readme.md: -------------------------------------------------------------------------------- 1 | goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="*" -dir="./model" goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="*" -dir="./model" 2 | 3 | kubectl apply -f auth.yaml 4 | 5 | kubectl get sa -n douyin-comment 6 | 7 | goctl docker -go .\usercomment.go . 8 | 9 | docker build -t douyin-comment-api:v1 . 10 | 11 | kind create cluster --image kindest/node:v1.25.3 --config deployment/cluster/douyin-cluster.yaml 12 | 13 | 14 | # 创建命名空间 15 | kubectl create namespace douyin-comment 16 | 17 | kind create cluster --config deployment/cluster/douyin-cluster.yaml 18 | 19 | goctl kube deploy -replicas 2 -requestCpu 200 -requestMem 50 -limitCpu 300 -limitMem 100 -name comment-rpc-svc -namespace douyin-comment -i 20 | mage douyin-comment-rpc:v1 -o douyin-comment-rpc.yaml -port 8081 --serviceAccount find-endpoints 21 | 22 | goctl kube deploy -nodePort 32010 -replicas 2 -requestCpu 200 -requestMem 50 -limitCpu 300 -limitMem 100 -name douyin-api-svc -namespace do 23 | uyin-comment -image douyin-comment-api:v1 -o douyin-comment-api.yaml -port 8888 --serviceAccount find-endpoints 24 | 25 | 26 | kubectl apply -f .\douyin-comment-rpc.yaml 27 | kubectl apply -f .\douyin-comment-api.yaml 28 | 29 | kind load docker-image douyin-comment-rpc:v1 --name douyin 30 | kind load docker-image douyin-comment-api:v1 --name douyin 31 | 32 | 33 | -------------------------------------------------------------------------------- /pkg/comment/userCommentPb/GenPb/UserComment.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package ="./userCommentPb"; 4 | 5 | package pb; 6 | 7 | // ------------------------------------ 8 | // Messages 9 | // ------------------------------------ 10 | 11 | // 用户对视频评论 12 | message UpdateCommentStatusReq { 13 | int64 videoId = 1; //videoId 14 | int64 userId = 2; //userId 15 | int64 commentId = 3; //commentId 16 | string Content = 4; 17 | int64 actionType = 5; //评论 取消评论 18 | } 19 | 20 | message UpdateCommentStatusResp { 21 | int64 commentId = 3; //commentId 22 | } 23 | 24 | // 获得视频的评论列表 25 | message GetVideoCommentReq { 26 | int64 videoId = 1; //video_id 27 | } 28 | message Comment { 29 | int64 commentId = 1; 30 | int64 userId = 2; 31 | string content = 3; 32 | string createDate = 4; 33 | } 34 | 35 | message GetVideoCommentReqResp { 36 | repeated Comment commentList = 1;//comment_list 37 | } 38 | 39 | // ------------------------------------ 40 | // Rpc Func 41 | // ------------------------------------ 42 | 43 | service UserComment{ 44 | //-----------------------userCommentStatus----------------------- 45 | rpc UpdateCommentStatus(UpdateCommentStatusReq) returns (UpdateCommentStatusResp); 46 | //-----------------------userCommentList----------------------- 47 | rpc GetVideoComment(GetVideoCommentReq) returns (GetVideoCommentReqResp); 48 | } 49 | -------------------------------------------------------------------------------- /pkg/comment/userCommentPb/GenPb/build.sh: -------------------------------------------------------------------------------- 1 | goctl rpc protoc UserCommentService.proto --go_out=../../ --go-grpc_out=../../ --zrpc_out=../../ --style=goZero --home=../../../../tpl 2 | # 当有多个proto文件时 需要先生成其他的文件 再生成主要的pb文件 3 | 4 | 5 | goctl rpc protoc UserComment.proto --go_out=../../ --go-grpc_out=../../ --zrpc_out=../../ 6 | -------------------------------------------------------------------------------- /pkg/comment/usercomment.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/comment/internal/config" 5 | "douyin/pkg/comment/internal/server" 6 | "douyin/pkg/comment/internal/svc" 7 | "douyin/pkg/comment/userCommentPb" 8 | "flag" 9 | "fmt" 10 | 11 | "github.com/zeromicro/go-zero/core/conf" 12 | "github.com/zeromicro/go-zero/core/service" 13 | "github.com/zeromicro/go-zero/zrpc" 14 | "google.golang.org/grpc" 15 | "google.golang.org/grpc/reflection" 16 | ) 17 | 18 | var configFile = flag.String("f", "etc/usercomment.yaml", "the config file") 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | var c config.Config 24 | conf.MustLoad(*configFile, &c) 25 | ctx := svc.NewServiceContext(c) 26 | 27 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { 28 | userCommentPb.RegisterUserCommentServer(grpcServer, server.NewUserCommentServer(ctx)) 29 | 30 | if c.Mode == service.DevMode || c.Mode == service.TestMode { 31 | reflection.Register(grpcServer) 32 | } 33 | }) 34 | defer s.Stop() 35 | 36 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) 37 | s.Start() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/comment/usercomment/usercomment.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: UserComment.proto 3 | 4 | package usercomment 5 | 6 | import ( 7 | "context" 8 | userCommentPb2 "douyin/pkg/comment/userCommentPb" 9 | 10 | "github.com/zeromicro/go-zero/zrpc" 11 | "google.golang.org/grpc" 12 | ) 13 | 14 | type ( 15 | Comment = userCommentPb2.Comment 16 | GetVideoCommentReq = userCommentPb2.GetVideoCommentReq 17 | GetVideoCommentReqResp = userCommentPb2.GetVideoCommentReqResp 18 | UpdateCommentStatusReq = userCommentPb2.UpdateCommentStatusReq 19 | UpdateCommentStatusResp = userCommentPb2.UpdateCommentStatusResp 20 | 21 | UserComment interface { 22 | // -----------------------userCommentStatus----------------------- 23 | UpdateCommentStatus(ctx context.Context, in *UpdateCommentStatusReq, opts ...grpc.CallOption) (*UpdateCommentStatusResp, error) 24 | // -----------------------userCommentList----------------------- 25 | GetVideoComment(ctx context.Context, in *GetVideoCommentReq, opts ...grpc.CallOption) (*GetVideoCommentReqResp, error) 26 | } 27 | 28 | defaultUserComment struct { 29 | cli zrpc.Client 30 | } 31 | ) 32 | 33 | func NewUserComment(cli zrpc.Client) UserComment { 34 | return &defaultUserComment{ 35 | cli: cli, 36 | } 37 | } 38 | 39 | // -----------------------userCommentStatus----------------------- 40 | func (m *defaultUserComment) UpdateCommentStatus(ctx context.Context, in *UpdateCommentStatusReq, opts ...grpc.CallOption) (*UpdateCommentStatusResp, error) { 41 | client := userCommentPb2.NewUserCommentClient(m.cli.Conn()) 42 | return client.UpdateCommentStatus(ctx, in, opts...) 43 | } 44 | 45 | // -----------------------userCommentList----------------------- 46 | func (m *defaultUserComment) GetVideoComment(ctx context.Context, in *GetVideoCommentReq, opts ...grpc.CallOption) (*GetVideoCommentReqResp, error) { 47 | client := userCommentPb2.NewUserCommentClient(m.cli.Conn()) 48 | return client.GetVideoComment(ctx, in, opts...) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/constant/mysql.go: -------------------------------------------------------------------------------- 1 | package constantx 2 | 3 | const ( 4 | MYSQL_Dsn string = "titok:titok@tcp(127.0.0.1:3306)/titok?charset=utf8mb4&parseTime=True&loc=Local" 5 | ) 6 | 7 | // config 8 | const ( 9 | MYSQL_SkipDefaultTransaction bool = true // close default tx 10 | MYSQL_PrepareStmt bool = true // cache precompile sentence 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/favorite/etc/userOptService.yaml: -------------------------------------------------------------------------------- 1 | Name: useropt.rpc 2 | ListenOn: 0.0.0.0:8081 3 | Mode: dev 4 | Etcd: 5 | Hosts: 6 | - etcd.etcd.svc.cluster.local:2379 7 | Key: useropt.rpc 8 | DB: 9 | DataSource: douyin:Z4eEXbWWCApby8dE@tcp(bt.vacant.zone:3306)/douyin?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai 10 | CacheRedis: 11 | - Host: redis-master.redis.svc.cluster.local:6379 12 | Pass: redispwd123 13 | VideoRPC: 14 | Etcd: 15 | Hosts: 16 | - etcd.etcd.svc.cluster.local:2379 17 | Key: video.rpc 18 | -------------------------------------------------------------------------------- /pkg/favorite/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | ) 7 | 8 | type Config struct { 9 | zrpc.RpcServerConf 10 | 11 | DB struct { 12 | DataSource string 13 | } 14 | CacheRedis cache.CacheConf 15 | VideoRPC zrpc.RpcClientConf 16 | } 17 | -------------------------------------------------------------------------------- /pkg/favorite/internal/logic/checkIsFavoriteLogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/logger" 6 | 7 | "douyin/pkg/favorite/internal/svc" 8 | "douyin/pkg/favorite/userOptPb" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type CheckIsFavoriteLogic struct { 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | logx.Logger 17 | } 18 | 19 | func NewCheckIsFavoriteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckIsFavoriteLogic { 20 | return &CheckIsFavoriteLogic{ 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | Logger: logx.WithContext(ctx), 24 | } 25 | } 26 | 27 | func (l *CheckIsFavoriteLogic) CheckIsFavorite(in *userOptPb.CheckIsFavoriteReq) (*userOptPb.CheckIsFavoriteResp, error) { 28 | result, err := l.svcCtx.UserFavoriteModel.CheckIsFavorite(l.ctx, in.UserId, in.VideoId) 29 | if err != nil { 30 | logger.Error("CheckIsFavorite查询错误", err) 31 | return nil, err 32 | } 33 | return &userOptPb.CheckIsFavoriteResp{IsFavorite: result}, nil 34 | } 35 | -------------------------------------------------------------------------------- /pkg/favorite/internal/logic/getUserFavoriteLogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/favorite/internal/svc" 6 | "douyin/pkg/favorite/userOptPb" 7 | "fmt" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type GetUserFavoriteLogic struct { 13 | ctx context.Context 14 | svcCtx *svc.ServiceContext 15 | logx.Logger 16 | } 17 | 18 | func NewGetUserFavoriteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserFavoriteLogic { 19 | return &GetUserFavoriteLogic{ 20 | ctx: ctx, 21 | svcCtx: svcCtx, 22 | Logger: logx.WithContext(ctx), 23 | } 24 | } 25 | 26 | // -----------------------userFavoriteList----------------------- 27 | func (l *GetUserFavoriteLogic) GetUserFavorite(in *userOptPb.GetUserFavoriteReq) (*userOptPb.GetUserFavoriteResp, error) { 28 | fmt.Printf("GetVideoFavorite-------------->") 29 | 30 | allFavoriteInfoData, err := l.svcCtx.UserFavoriteModel.FindAll(l.ctx, in.UserId) 31 | if err != nil { 32 | logx.Errorf("GetFavoriteList------->SELECT err : %s", err.Error()) 33 | return &userOptPb.GetUserFavoriteResp{}, err 34 | } 35 | var favoriteList []*userOptPb.Favorite 36 | for _, v := range allFavoriteInfoData { 37 | var favorite userOptPb.Favorite 38 | videoInfoData, err := l.svcCtx.UserVideoModel.FindOne(l.ctx, v.VideoId) 39 | if err != nil { 40 | logx.Errorf("GetFavoriteList------->SELECT err : %s", err.Error()) 41 | return &userOptPb.GetUserFavoriteResp{}, err 42 | } 43 | favorite.UserId = v.UserId 44 | favorite.PlayUrl = videoInfoData.PlayUrl 45 | favorite.Title = videoInfoData.Title 46 | favorite.VideoId = videoInfoData.Id 47 | favorite.CoverUrl = videoInfoData.CoverUrl 48 | favorite.AuthorId = videoInfoData.AuthorId 49 | 50 | favoriteList = append(favoriteList, &favorite) 51 | } 52 | return &userOptPb.GetUserFavoriteResp{ 53 | FavoriteList: favoriteList, 54 | }, nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/favorite/internal/server/userOptServiceServer.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: UserOptService.proto 3 | 4 | package server 5 | 6 | import ( 7 | "context" 8 | logic2 "douyin/pkg/favorite/internal/logic" 9 | "douyin/pkg/favorite/internal/svc" 10 | userOptPb2 "douyin/pkg/favorite/userOptPb" 11 | ) 12 | 13 | type UserOptServiceServer struct { 14 | svcCtx *svc.ServiceContext 15 | userOptPb2.UnimplementedUserOptServiceServer 16 | } 17 | 18 | func NewUserOptServiceServer(svcCtx *svc.ServiceContext) *UserOptServiceServer { 19 | return &UserOptServiceServer{ 20 | svcCtx: svcCtx, 21 | } 22 | } 23 | 24 | // -----------------------userFavoriteList----------------------- 25 | func (s *UserOptServiceServer) GetUserFavorite(ctx context.Context, in *userOptPb2.GetUserFavoriteReq) (*userOptPb2.GetUserFavoriteResp, error) { 26 | l := logic2.NewGetUserFavoriteLogic(ctx, s.svcCtx) 27 | return l.GetUserFavorite(in) 28 | } 29 | 30 | func (s *UserOptServiceServer) UpdateFavoriteStatus(ctx context.Context, in *userOptPb2.UpdateFavoriteStatusReq) (*userOptPb2.UpdateFavoriteStatusResp, error) { 31 | l := logic2.NewUpdateFavoriteStatusLogic(ctx, s.svcCtx) 32 | return l.UpdateFavoriteStatus(in) 33 | } 34 | 35 | func (s *UserOptServiceServer) CheckIsFavorite(ctx context.Context, in *userOptPb2.CheckIsFavoriteReq) (*userOptPb2.CheckIsFavoriteResp, error) { 36 | l := logic2.NewCheckIsFavoriteLogic(ctx, s.svcCtx) 37 | return l.CheckIsFavorite(in) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/favorite/internal/svc/serviceContext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/common/model/favoriteModel" 5 | "douyin/common/model/videoModel" 6 | "douyin/pkg/favorite/internal/config" 7 | "github.com/zeromicro/go-zero/core/stores/sqlx" 8 | ) 9 | 10 | type ServiceContext struct { 11 | Config config.Config 12 | UserFavoriteModel favoriteModel.FavoriteModel 13 | UserVideoModel videoModel.VideoModel 14 | VideoModel videoModel.VideoModel 15 | } 16 | 17 | func NewServiceContext(c config.Config) *ServiceContext { 18 | return &ServiceContext{ 19 | Config: c, 20 | UserFavoriteModel: favoriteModel.NewFavoriteModel(sqlx.NewMysql(c.DB.DataSource)), 21 | UserVideoModel: videoModel.NewVideoModel(sqlx.NewMysql(c.DB.DataSource), c.CacheRedis), 22 | VideoModel: videoModel.NewVideoModel(sqlx.NewMysql(c.DB.DataSource), c.CacheRedis), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/favorite/userOptPb/GenPb/UserOptService.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package ="./userOptPb"; 4 | 5 | package pb; 6 | 7 | // ------------------------------------ 8 | // Messages 9 | // ------------------------------------ 10 | 11 | //--------------------------------userFavoriteList-------------------------------- 12 | 13 | // 用户给视频点赞 14 | message UpdateFavoriteStatusReq { 15 | int64 videoId = 1; //videoId 16 | int64 userId = 2; //userId 17 | int64 actionType = 3; //点赞 18 | } 19 | 20 | message UpdateFavoriteStatusResp { 21 | } 22 | 23 | // 获得用户和视频的点赞关系 24 | message GetUserFavoriteReq { 25 | int64 userId = 1; //userId 26 | } 27 | 28 | message Favorite{ 29 | int64 videoId = 1;//videoId 30 | string play_url = 2; 31 | string cover_url = 3; 32 | string title = 4; 33 | int64 author_id = 5; 34 | int64 user_id=6; 35 | } 36 | 37 | message GetUserFavoriteResp { 38 | repeated Favorite FavoriteList = 1; //userFavoriteList 39 | 40 | } 41 | 42 | message CheckIsFavoriteReq { 43 | int64 userId=1; 44 | int64 videoId=2; 45 | } 46 | 47 | message CheckIsFavoriteResp { 48 | bool isFavorite=1; 49 | } 50 | 51 | // ------------------------------------ 52 | // Rpc Func 53 | // ------------------------------------ 54 | 55 | service UserOptService{ 56 | //-----------------------userFavoriteList----------------------- 57 | rpc GetUserFavorite(GetUserFavoriteReq) returns (GetUserFavoriteResp); 58 | rpc UpdateFavoriteStatus(UpdateFavoriteStatusReq) returns (UpdateFavoriteStatusResp); 59 | rpc CheckIsFavorite(CheckIsFavoriteReq) returns (CheckIsFavoriteResp); 60 | } 61 | -------------------------------------------------------------------------------- /pkg/favorite/userOptPb/GenPb/build.sh: -------------------------------------------------------------------------------- 1 | goctl rpc protoc UserOptService.proto --go_out=../../ --go-grpc_out=../../ --zrpc_out=../../ --style=goZero --home=../../../../tpl 2 | # 当有多个proto文件时 需要先生成其他的文件 再生成主要的pb文件 -------------------------------------------------------------------------------- /pkg/favorite/userOptService.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/favorite/internal/config" 5 | "douyin/pkg/favorite/internal/server" 6 | "douyin/pkg/favorite/internal/svc" 7 | "douyin/pkg/favorite/userOptPb" 8 | "flag" 9 | "fmt" 10 | 11 | "github.com/zeromicro/go-zero/core/conf" 12 | "github.com/zeromicro/go-zero/core/service" 13 | "github.com/zeromicro/go-zero/zrpc" 14 | "google.golang.org/grpc" 15 | "google.golang.org/grpc/reflection" 16 | ) 17 | 18 | var configFile = flag.String("f", "etc/userOptService.yaml", "the config file") 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | var c config.Config 24 | conf.MustLoad(*configFile, &c) 25 | ctx := svc.NewServiceContext(c) 26 | 27 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { 28 | userOptPb.RegisterUserOptServiceServer(grpcServer, server.NewUserOptServiceServer(ctx)) 29 | 30 | if c.Mode == service.DevMode || c.Mode == service.TestMode { 31 | reflection.Register(grpcServer) 32 | } 33 | }) 34 | defer s.Stop() 35 | 36 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) 37 | s.Start() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/favorite/useroptservice/userOptService.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: UserOptService.proto 3 | 4 | package useroptservice 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/favorite/userOptPb" 10 | 11 | "github.com/zeromicro/go-zero/zrpc" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | type ( 16 | CheckIsFavoriteReq = userOptPb.CheckIsFavoriteReq 17 | CheckIsFavoriteResp = userOptPb.CheckIsFavoriteResp 18 | Favorite = userOptPb.Favorite 19 | GetUserFavoriteReq = userOptPb.GetUserFavoriteReq 20 | GetUserFavoriteResp = userOptPb.GetUserFavoriteResp 21 | UpdateFavoriteStatusReq = userOptPb.UpdateFavoriteStatusReq 22 | UpdateFavoriteStatusResp = userOptPb.UpdateFavoriteStatusResp 23 | 24 | UserOptService interface { 25 | // -----------------------userFavoriteList----------------------- 26 | GetUserFavorite(ctx context.Context, in *GetUserFavoriteReq, opts ...grpc.CallOption) (*GetUserFavoriteResp, error) 27 | UpdateFavoriteStatus(ctx context.Context, in *UpdateFavoriteStatusReq, opts ...grpc.CallOption) (*UpdateFavoriteStatusResp, error) 28 | CheckIsFavorite(ctx context.Context, in *CheckIsFavoriteReq, opts ...grpc.CallOption) (*CheckIsFavoriteResp, error) 29 | } 30 | 31 | defaultUserOptService struct { 32 | cli zrpc.Client 33 | } 34 | ) 35 | 36 | func NewUserOptService(cli zrpc.Client) UserOptService { 37 | return &defaultUserOptService{ 38 | cli: cli, 39 | } 40 | } 41 | 42 | // -----------------------userFavoriteList----------------------- 43 | func (m *defaultUserOptService) GetUserFavorite(ctx context.Context, in *GetUserFavoriteReq, opts ...grpc.CallOption) (*GetUserFavoriteResp, error) { 44 | client := userOptPb.NewUserOptServiceClient(m.cli.Conn()) 45 | return client.GetUserFavorite(ctx, in, opts...) 46 | } 47 | 48 | func (m *defaultUserOptService) UpdateFavoriteStatus(ctx context.Context, in *UpdateFavoriteStatusReq, opts ...grpc.CallOption) (*UpdateFavoriteStatusResp, error) { 49 | client := userOptPb.NewUserOptServiceClient(m.cli.Conn()) 50 | return client.UpdateFavoriteStatus(ctx, in, opts...) 51 | } 52 | 53 | func (m *defaultUserOptService) CheckIsFavorite(ctx context.Context, in *CheckIsFavoriteReq, opts ...grpc.CallOption) (*CheckIsFavoriteResp, error) { 54 | client := userOptPb.NewUserOptServiceClient(m.cli.Conn()) 55 | return client.CheckIsFavorite(ctx, in, opts...) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/follow/etc/follow.yaml: -------------------------------------------------------------------------------- 1 | Name: follow.rpc 2 | ListenOn: 0.0.0.0:8082 3 | Etcd: 4 | Hosts: 5 | - etcd.etcd.svc.cluster.local:2379 6 | Key: follow.rpc 7 | Mysql: 8 | DataSource: douyin:Z4eEXbWWCApby8dE@tcp(bt.vacant.zone:3306)/douyin?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai 9 | CacheRedis: 10 | - Host: redis-master.redis.svc.cluster.local:6379 11 | Pass: redispwd123 12 | UserRPC: 13 | Etcd: 14 | Hosts: 15 | - etcd.etcd.svc.cluster.local:2379 16 | Key: user.rpc 17 | -------------------------------------------------------------------------------- /pkg/follow/follow.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/follow/internal/config" 5 | "douyin/pkg/follow/internal/server" 6 | "douyin/pkg/follow/internal/svc" 7 | "douyin/pkg/follow/types/follow" 8 | "flag" 9 | "fmt" 10 | 11 | "github.com/zeromicro/go-zero/core/conf" 12 | "github.com/zeromicro/go-zero/core/service" 13 | "github.com/zeromicro/go-zero/zrpc" 14 | "google.golang.org/grpc" 15 | "google.golang.org/grpc/reflection" 16 | ) 17 | 18 | var configFile = flag.String("f", "etc/follow.yaml", "the config file") 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | var c config.Config 24 | conf.MustLoad(*configFile, &c) 25 | ctx := svc.NewServiceContext(c) 26 | 27 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { 28 | follow.RegisterFollowServiceServer(grpcServer, server.NewFollowServiceServer(ctx)) 29 | 30 | if c.Mode == service.DevMode || c.Mode == service.TestMode { 31 | reflection.Register(grpcServer) 32 | } 33 | }) 34 | defer s.Stop() 35 | 36 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) 37 | s.Start() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/follow/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | ) 7 | 8 | type Config struct { 9 | zrpc.RpcServerConf 10 | UserRPC zrpc.RpcClientConf 11 | Mysql struct { 12 | DataSource string 13 | } 14 | CacheRedis cache.CacheConf 15 | } 16 | -------------------------------------------------------------------------------- /pkg/follow/internal/logic/checkisfollowlogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | 6 | "douyin/pkg/follow/internal/svc" 7 | "douyin/pkg/follow/types/follow" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type CheckIsFollowLogic struct { 13 | ctx context.Context 14 | svcCtx *svc.ServiceContext 15 | logx.Logger 16 | } 17 | 18 | func NewCheckIsFollowLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckIsFollowLogic { 19 | return &CheckIsFollowLogic{ 20 | ctx: ctx, 21 | svcCtx: svcCtx, 22 | Logger: logx.WithContext(ctx), 23 | } 24 | } 25 | 26 | func (l *CheckIsFollowLogic) CheckIsFollow(in *follow.CheckIsFollowReq) (*follow.CheckIsFollowResp, error) { 27 | isFollow, err := l.svcCtx.FollowModel.CheckIsFollow(l.ctx, in.UserId, in.FunId) 28 | if err != nil { 29 | logx.Errorf("query is follow failed: %v", err.Error()) 30 | return nil, err 31 | } 32 | return &follow.CheckIsFollowResp{ 33 | StatusCode: 0, 34 | StatusMsg: "success", 35 | IsFollow: isFollow, 36 | }, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/follow/internal/logic/followlogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "douyin/common/model/followModel" 7 | "douyin/pkg/follow/internal/svc" 8 | "douyin/pkg/follow/types/follow" 9 | "douyin/pkg/logger" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type FollowLogic struct { 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | logx.Logger 17 | } 18 | 19 | func NewFollowLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FollowLogic { 20 | return &FollowLogic{ 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | Logger: logx.WithContext(ctx), 24 | } 25 | } 26 | 27 | func (l *FollowLogic) Follow(in *follow.FollowReq) (*follow.FollowResp, error) { 28 | followId, _ := l.svcCtx.FollowModel.FindIfExist(l.ctx, in.ToUserId, in.UserId) 29 | 30 | if followId != 0 { 31 | var removed int64 32 | if in.ActionType == 2 { 33 | removed = 1 34 | } 35 | // 查询到了followId,调用update更新 36 | newFollowModel := &followModel.Follow{ 37 | Id: followId, 38 | Removed: removed, 39 | } 40 | err := l.svcCtx.FollowModel.Update(l.ctx, newFollowModel) 41 | if err != nil { 42 | logger.Errorf("follow option failed: %v", err.Error()) 43 | return &follow.FollowResp{ 44 | StatusCode: -1, 45 | StatusMsg: "follow option failed", 46 | }, err 47 | } 48 | } else { 49 | // 未查询到相关数据,直接insert 50 | if in.ActionType == 1 { 51 | newFollowModel := &followModel.Follow{ 52 | UserId: sql.NullInt64{ 53 | Int64: in.ToUserId, 54 | Valid: true, 55 | }, 56 | FunId: in.UserId, 57 | } 58 | _, err := l.svcCtx.FollowModel.Insert(l.ctx, newFollowModel) 59 | if err != nil { 60 | return &follow.FollowResp{ 61 | StatusCode: -1, 62 | StatusMsg: "follow option failed", 63 | }, err 64 | } 65 | } 66 | } 67 | 68 | return &follow.FollowResp{ 69 | StatusCode: 0, 70 | StatusMsg: "success", 71 | }, nil 72 | } 73 | -------------------------------------------------------------------------------- /pkg/follow/internal/logic/getfollowlistlogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/follow/internal/svc" 6 | "douyin/pkg/follow/types/follow" 7 | "douyin/pkg/user/userservice" 8 | "sync" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type GetFollowListLogic struct { 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | logx.Logger 17 | } 18 | 19 | func NewGetFollowListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowListLogic { 20 | return &GetFollowListLogic{ 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | Logger: logx.WithContext(ctx), 24 | } 25 | } 26 | 27 | func (l *GetFollowListLogic) GetFollowList(in *follow.GetFollowListReq) (*follow.GetFollowListResp, error) { 28 | queryFollow, err := l.svcCtx.FollowModel.FindAllByFunId(l.ctx, in.UserId) 29 | if err != nil { 30 | logx.Errorf("get follow list failed: %v", err.Error()) 31 | return &follow.GetFollowListResp{ 32 | StatusCode: -1, 33 | StatusMsg: "get follow list failed", 34 | }, err 35 | } 36 | follows := make([]*follow.User, len(queryFollow)) 37 | var wg sync.WaitGroup 38 | for index, v := range queryFollow { 39 | wg.Add(1) 40 | query := v 41 | i := index 42 | go func() { 43 | queryFollows, err := l.svcCtx.UserPRC.Info(l.ctx, &userservice.UserInfoReq{ 44 | UserId: query.UserId.Int64, 45 | }) 46 | if err != nil { 47 | logx.Errorf("in follow model get user info failed: %v", err.Error()) 48 | return 49 | } 50 | follows[i] = &follow.User{} 51 | follows[i].Id = queryFollows.User.UserId 52 | follows[i].Name = queryFollows.User.UserName 53 | follows[i].FollowCount = queryFollows.User.FollowCount 54 | follows[i].FollowerCount = queryFollows.User.FollowerCount 55 | follows[i].IsFollow = true 56 | follows[i].Avatar = queryFollows.User.Avatar 57 | follows[i].BackgroundImage = queryFollows.User.BackgroundImage 58 | follows[i].Signature = queryFollows.User.Signature 59 | follows[i].TotalFavorited = queryFollows.User.TotalFavorited 60 | follows[i].WorkCount = queryFollows.User.WorkCount 61 | follows[i].FavoriteCount = queryFollows.User.FavoriteCount 62 | defer wg.Done() 63 | }() 64 | } 65 | wg.Wait() 66 | return &follow.GetFollowListResp{ 67 | StatusCode: 0, 68 | UserList: follows, 69 | }, nil 70 | } 71 | -------------------------------------------------------------------------------- /pkg/follow/internal/server/followserviceserver.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: follow.proto 3 | 4 | package server 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/follow/internal/logic" 10 | "douyin/pkg/follow/internal/svc" 11 | "douyin/pkg/follow/types/follow" 12 | ) 13 | 14 | type FollowServiceServer struct { 15 | svcCtx *svc.ServiceContext 16 | follow.UnimplementedFollowServiceServer 17 | } 18 | 19 | func NewFollowServiceServer(svcCtx *svc.ServiceContext) *FollowServiceServer { 20 | return &FollowServiceServer{ 21 | svcCtx: svcCtx, 22 | } 23 | } 24 | 25 | func (s *FollowServiceServer) Follow(ctx context.Context, in *follow.FollowReq) (*follow.FollowResp, error) { 26 | l := logic.NewFollowLogic(ctx, s.svcCtx) 27 | return l.Follow(in) 28 | } 29 | 30 | func (s *FollowServiceServer) GetFollowList(ctx context.Context, in *follow.GetFollowListReq) (*follow.GetFollowListResp, error) { 31 | l := logic.NewGetFollowListLogic(ctx, s.svcCtx) 32 | return l.GetFollowList(in) 33 | } 34 | 35 | func (s *FollowServiceServer) GetFollowerList(ctx context.Context, in *follow.GetFollowerListReq) (*follow.GetFollowerListResp, error) { 36 | l := logic.NewGetFollowerListLogic(ctx, s.svcCtx) 37 | return l.GetFollowerList(in) 38 | } 39 | 40 | func (s *FollowServiceServer) GetFriendList(ctx context.Context, in *follow.GetFriendListReq) (*follow.GetFriendListResp, error) { 41 | l := logic.NewGetFriendListLogic(ctx, s.svcCtx) 42 | return l.GetFriendList(in) 43 | } 44 | 45 | func (s *FollowServiceServer) CheckIsFollow(ctx context.Context, in *follow.CheckIsFollowReq) (*follow.CheckIsFollowResp, error) { 46 | l := logic.NewCheckIsFollowLogic(ctx, s.svcCtx) 47 | return l.CheckIsFollow(in) 48 | } 49 | -------------------------------------------------------------------------------- /pkg/follow/internal/svc/servicecontext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/common/model/followModel" 5 | "douyin/pkg/follow/internal/config" 6 | "douyin/pkg/user/userservice" 7 | "github.com/zeromicro/go-zero/core/stores/sqlx" 8 | "github.com/zeromicro/go-zero/zrpc" 9 | ) 10 | 11 | type ServiceContext struct { 12 | Config config.Config 13 | FollowModel followModel.FollowModel 14 | UserPRC userservice.UserService 15 | } 16 | 17 | func NewServiceContext(c config.Config) *ServiceContext { 18 | conn := sqlx.NewMysql(c.Mysql.DataSource) 19 | return &ServiceContext{ 20 | Config: c, 21 | FollowModel: followModel.NewFollowModel(conn, c.CacheRedis), 22 | UserPRC: userservice.NewUserService(zrpc.MustNewClient(c.UserRPC)), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/gateway/api.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/config" 5 | "douyin/pkg/gateway/internal/handler" 6 | "douyin/pkg/gateway/internal/svc" 7 | "flag" 8 | "fmt" 9 | 10 | "github.com/zeromicro/go-zero/core/conf" 11 | "github.com/zeromicro/go-zero/rest" 12 | ) 13 | 14 | var configFile = flag.String("f", "etc/user-api.yaml", "the config file") 15 | 16 | func main() { 17 | flag.Parse() 18 | 19 | var c config.Config 20 | 21 | conf.MustLoad(*configFile, &c) 22 | 23 | server := rest.MustNewServer(c.RestConf) 24 | defer server.Stop() 25 | 26 | ctx := svc.NewServiceContext(c) 27 | handler.RegisterHandlers(server, ctx) 28 | 29 | fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) 30 | server.Start() 31 | } 32 | -------------------------------------------------------------------------------- /pkg/gateway/api/build.sh: -------------------------------------------------------------------------------- 1 | # 通过goctl生成脚手架 --home 是你的模板(如果未对goctl的模板进行修改就不写,我这里修改了一些模板) 2 | # userOpt.api中 import了多个api文件 所以最后只需要这一个文件 3 | goctl api go -api userOpt.api -dir ../ --style=goZero --home=../../../tpl -------------------------------------------------------------------------------- /pkg/gateway/api/message.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | import "user.api" 4 | 5 | type MessageReq { 6 | Token string `form:"token"` 7 | ToUserId int64 `form:"to_user_id"` 8 | ActionType int64 `form:"action_type"` 9 | Content string `form:"content"` 10 | } 11 | 12 | type MessageRes { 13 | Code int64 `json:"status_code"` 14 | Msg string `json:"status_msg,omitempty"` 15 | } 16 | type MessageListReq { 17 | UserId int64 `form:"user_id"` 18 | Token string `form:"token"` 19 | } 20 | 21 | type MessageListRes { 22 | Status 23 | MessageList []*Message `json:"message_list,omitempty"` 24 | } 25 | 26 | type Message { 27 | Id int64 `json:"id"` 28 | ToUserId int64 `json:"to_user_id"` 29 | FromUserId int64 `json:"from_user_id"` 30 | Content string `json:"content"` 31 | CreateTime string `json:"create_time"` 32 | } 33 | 34 | @server( 35 | group : message 36 | prefix : /douyin 37 | middleware: AuthJWT 38 | ) 39 | 40 | service user-api { 41 | @doc "发送消息" 42 | @handler Message 43 | post /message/action (MessageReq) returns (MessageRes) 44 | 45 | @doc "聊天记录" 46 | @handler MessageList 47 | get /message/chat (MessageListReq) returns (MessageListRes) 48 | } -------------------------------------------------------------------------------- /pkg/gateway/api/user.api: -------------------------------------------------------------------------------- 1 | // api语法版本 2 | syntax = "v1" 3 | 4 | info( 5 | author: "babysite" 6 | date: "2023-02-18" 7 | ) 8 | // common 返回 9 | type Status { 10 | Code int64 `json:"status_code"` 11 | Msg string `json:"status_msg,omitempty"` 12 | } 13 | 14 | // common 请求 15 | type UserReq { 16 | UserName string `form:"username"` 17 | Password string `form:"password"` 18 | } 19 | 20 | type IdWithTokenReq { 21 | UserId int64 `form:"user_id"` 22 | Token string `form:"token"` 23 | } 24 | 25 | type IdWithTokenRes { 26 | UserId int64 `json:"user_id,omitempty"` 27 | Token string `json:"token,omitempty"` 28 | } 29 | 30 | // 每个成员的tag只能绑定一种 json,form,path header 31 | // 注册 32 | type ( 33 | UserRegisterReq { 34 | UserReq 35 | } 36 | UserRegisterRes { 37 | Status 38 | IdWithTokenRes 39 | } 40 | ) 41 | 42 | // 登录 43 | type ( 44 | UserLoginReq { 45 | UserReq 46 | } 47 | UserLoginRes { 48 | Status 49 | IdWithTokenRes 50 | } 51 | ) 52 | 53 | // 用户信息 54 | type User { 55 | UserId int64 `json:"id"` 56 | UserName string `json:"name"` 57 | FollowCount int64 `json:"follow_count"` 58 | FollowerCount int64 `json:"follower_count"` 59 | IsFollow bool `json:"is_follow"` 60 | Avatar string `json:"avatar"` 61 | BackgroundImage string `json:"background_image"` 62 | Signature string `json:"signature"` 63 | TotalFavorited int64 `json:"total_favorited"` 64 | WorkCount int64 `json:"work_count"` 65 | FavoriteCount int64 `json:"favorite_count"` 66 | } 67 | 68 | type ( 69 | UserInfoReq { 70 | IdWithTokenReq 71 | } 72 | UserInfoRes { 73 | Status 74 | User *User `json:"user,omitempty"` 75 | } 76 | ) 77 | @server ( 78 | group : user 79 | prefix : /douyin/user 80 | ) 81 | service user-api { 82 | @doc "用户注册" 83 | @handler UserRegister 84 | post /register (UserRegisterReq) returns (UserRegisterRes) 85 | @doc "用户登录" 86 | @handler UserLogin 87 | post /login (UserLoginReq) returns (UserLoginRes) 88 | } 89 | 90 | @server ( 91 | group : user 92 | prefix : /douyin/user 93 | middleware: AuthJWT 94 | ) 95 | service user-api { 96 | @doc "用户信息" 97 | @handler UserInfo 98 | get / (UserInfoReq) returns (UserInfoRes) 99 | } -------------------------------------------------------------------------------- /pkg/gateway/api/video.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info( 4 | title: "video" 5 | author: "babysite" 6 | ) 7 | 8 | import "user.api" 9 | 10 | type PubVideoReq { 11 | Token string `form:"token"` 12 | Data []byte `form:"data"` 13 | Title string `form:"title"` 14 | } 15 | 16 | type PubVideoRes { 17 | Status 18 | } 19 | 20 | type GetPubVideoListReq { 21 | Token string `form:"token"` 22 | UserId int64 `form:"user_id"` 23 | } 24 | 25 | type PubVideo { 26 | Id int64 `json:"id"` 27 | User User `json:"author"` 28 | PlayURL string `json:"play_url"` 29 | CoverURL string `json:"cover_url"` 30 | FavoriteCount int `json:"favorite_count"` 31 | CommentCount int `json:"comment_count"` 32 | IsFavorite bool `json:"is_favorite"` 33 | Title string `json:"title"` 34 | } 35 | 36 | type GetPubVideoListRes { 37 | Status 38 | VideoPubList []*PubVideo `json:"video_list,omitempty"` 39 | } 40 | 41 | @server( 42 | group: publish 43 | prefix: /douyin/publish 44 | middleware: AuthJWT 45 | ) 46 | service user-api { 47 | @doc "发布视频" 48 | @handler PublishVideo 49 | post /action (PubVideoReq) returns (PubVideoRes) 50 | 51 | @doc "获取发布视频列表" 52 | @handler GetPublishVideoList 53 | get /list (GetPubVideoListReq) returns (GetPubVideoListRes) 54 | } 55 | 56 | type FeedVideoListReq { 57 | Token string `form:"token,optional"` 58 | LastTime int64 `form:"last_time,optional"` 59 | } 60 | 61 | type FeedVideoListRes { 62 | Status 63 | NextTime int64 `json:"next_time,omitempty"` 64 | VideoList []*PubVideo `json:"video_list,omitempty"` 65 | } 66 | 67 | @server( 68 | group: feed 69 | prefix: /douyin/feed 70 | ) 71 | service user-api { 72 | @doc "获取视频流" 73 | @handler FeedVideoList 74 | get / (FeedVideoListReq) returns (FeedVideoListRes) 75 | } -------------------------------------------------------------------------------- /pkg/gateway/etc/user-api.yaml: -------------------------------------------------------------------------------- 1 | Name: user-api 2 | Host: 0.0.0.0 3 | Port: 8888 4 | MaxBytes: 8388608 5 | Timeout: 30000 6 | UserCommentRpc: 7 | Etcd: 8 | Hosts: 9 | - etcd.etcd.svc.cluster.local:2379 10 | Key: usercomment.rpc 11 | UserRpc: 12 | Etcd: 13 | Hosts: 14 | - etcd.etcd.svc.cluster.local:2379 15 | Key: user.rpc 16 | UserFavoriteRpc: 17 | Etcd: 18 | Hosts: 19 | - etcd.etcd.svc.cluster.local:2379 20 | Key: useropt.rpc 21 | VideoRPC: 22 | Etcd: 23 | Hosts: 24 | - etcd.etcd.svc.cluster.local:2379 25 | Key: video.rpc 26 | MessageRpc: 27 | Etcd: 28 | Hosts: 29 | - etcd.etcd.svc.cluster.local:2379 30 | Key: usermessage.rpc 31 | UserCommentOptServiceConf: 32 | Name: UserCommentOptService 33 | Brokers: 34 | - kafka.kafka.svc.cluster.local:9092 35 | Group: UserCommentOptService-group 36 | Topic: UserCommentOptService-topic 37 | Offset: first 38 | Consumers: 1 39 | Processors: 1 40 | UserFollowOptServiceConf: 41 | Name: UserCommentOptService 42 | Brokers: 43 | - kafka.kafka.svc.cluster.local:9092 44 | Group: UserFollowOptService-group 45 | Topic: UserFollowOptService-topic 46 | Offset: first 47 | Consumers: 1 48 | Processors: 1 49 | UserFavoriteOptServiceConf: 50 | Name: UserFavoriteOptService 51 | Brokers: 52 | - kafka.kafka.svc.cluster.local:9092 53 | Group: UserFavoriteOptService-group 54 | Topic: UserFavoriteOptService-topic 55 | Offset: first 56 | Consumers: 1 57 | Processors: 1 58 | FollowRpc: 59 | Etcd: 60 | Hosts: 61 | - etcd.etcd.svc.cluster.local:2379 62 | Key: follow.rpc 63 | -------------------------------------------------------------------------------- /pkg/gateway/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-queue/kq" 5 | "github.com/zeromicro/go-zero/rest" 6 | "github.com/zeromicro/go-zero/zrpc" 7 | ) 8 | 9 | type Config struct { 10 | rest.RestConf 11 | // rpc 12 | UserFavoriteRpc zrpc.RpcClientConf 13 | UserRpc zrpc.RpcClientConf 14 | UserCommentRpc zrpc.RpcClientConf 15 | VideoRPC zrpc.RpcClientConf 16 | FollowRPC zrpc.RpcClientConf 17 | MessageRpc zrpc.RpcClientConf 18 | // kq 19 | UserCommentOptServiceConf kq.KqConf 20 | UserFavoriteOptServiceConf kq.KqConf 21 | UserFollowOptServiceConf kq.KqConf 22 | } 23 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/feed/feedVideoListHandler.go: -------------------------------------------------------------------------------- 1 | package feed 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/feed" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func FeedVideoListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FeedVideoListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := feed.NewFeedVideoListLogic(r.Context(), svcCtx) 21 | resp, err := l.FeedVideoList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/message/messageHandler.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "net/http" 5 | 6 | "douyin/pkg/gateway/internal/logic/message" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func MessageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.MessageReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := message.NewMessageLogic(r.Context(), svcCtx) 21 | resp, err := l.Message(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/message/messagelistHandler.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "net/http" 5 | 6 | "douyin/pkg/gateway/internal/logic/message" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func MessageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.MessageListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := message.NewMessageListLogin(r.Context(), svcCtx) 21 | resp, err := l.MessageList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/publish/getPublishVideoListHandler.go: -------------------------------------------------------------------------------- 1 | package publish 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/publish" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func GetPublishVideoListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.GetPubVideoListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := publish.NewGetPublishVideoListLogic(r.Context(), svcCtx) 21 | resp, err := l.GetPublishVideoList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/publish/publishVideoHandler.go: -------------------------------------------------------------------------------- 1 | package publish 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/publish" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "errors" 8 | "io" 9 | "net/http" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func PublishVideoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.PubVideoReq 17 | 18 | if !r.Form.Has("title") || !r.Form.Has("token") || r.MultipartForm.File == nil || r.MultipartForm.File["data"] == nil { 19 | httpx.ErrorCtx(r.Context(), w, errors.New("missing parameter title,token or file")) 20 | return 21 | } 22 | req.Token = r.Form.Get("token") 23 | req.Title = r.Form.Get("title") 24 | 25 | file, err := r.MultipartForm.File["data"][0].Open() 26 | if err != nil { 27 | httpx.ErrorCtx(r.Context(), w, err) 28 | return 29 | } 30 | req.Data, err = io.ReadAll(file) 31 | if err != nil { 32 | httpx.ErrorCtx(r.Context(), w, err) 33 | return 34 | } 35 | 36 | l := publish.NewPublishVideoLogic(r.Context(), svcCtx) 37 | resp, err := l.PublishVideo(&req) 38 | if err != nil { 39 | httpx.ErrorCtx(r.Context(), w, err) 40 | } else { 41 | httpx.OkJsonCtx(r.Context(), w, resp) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/user/userInfoHandler.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/user" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func UserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.UserInfoReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := user.NewUserInfoLogic(r.Context(), svcCtx) 21 | resp, err := l.UserInfo(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/user/userLoginHandler.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/user" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func UserLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.UserLoginReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := user.NewUserLoginLogic(r.Context(), svcCtx) 21 | resp, err := l.UserLogin(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/user/userRegisterHandler.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/user" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func UserRegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.UserRegisterReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := user.NewUserRegisterLogic(r.Context(), svcCtx) 21 | resp, err := l.UserRegister(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/commentOptHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func CommentOptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.CommentOptReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewCommentOptLogic(r.Context(), svcCtx) 21 | resp, err := l.CommentOpt(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/favoriteOptHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func FavoriteOptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FavoriteOptReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewFavoriteOptLogic(r.Context(), svcCtx) 21 | resp, err := l.FavoriteOpt(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/followOptHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func FollowOptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FollowOptReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewFollowOptLogic(r.Context(), svcCtx) 21 | resp, err := l.FollowOpt(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/getCommentListHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "fmt" 8 | "net/http" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetCommentListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | var req types.CommentListReq 16 | if err := httpx.Parse(r, &req); err != nil { 17 | httpx.ErrorCtx(r.Context(), w, err) 18 | return 19 | } 20 | 21 | l := userOpt.NewGetCommentListLogic(r.Context(), svcCtx) 22 | resp, err := l.GetCommentList(&req) 23 | fmt.Println("list", resp.CommentList, resp) 24 | if err != nil { 25 | httpx.ErrorCtx(r.Context(), w, err) 26 | } else { 27 | httpx.OkJsonCtx(r.Context(), w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/getFavoriteListHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func GetFavoriteListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FavoriteListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewGetFavoriteListLogic(r.Context(), svcCtx) 21 | resp, err := l.GetFavoriteList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/getFollowListHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func GetFollowListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FollowListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewGetFollowListLogic(r.Context(), svcCtx) 21 | resp, err := l.GetFollowList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/getFollowerListHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "douyin/pkg/gateway/internal/logic/userOpt" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func GetFollowerListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FollowerListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewGetFollowerListLogic(r.Context(), svcCtx) 21 | resp, err := l.GetFollowerList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/handler/userOpt/getFriendListHandler.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "net/http" 5 | 6 | "douyin/pkg/gateway/internal/logic/userOpt" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func GetFriendListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | var req types.FriendListReq 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.ErrorCtx(r.Context(), w, err) 17 | return 18 | } 19 | 20 | l := userOpt.NewGetFriendListLogic(r.Context(), svcCtx) 21 | resp, err := l.GetFriendList(&req) 22 | if err != nil { 23 | httpx.ErrorCtx(r.Context(), w, err) 24 | } else { 25 | httpx.OkJsonCtx(r.Context(), w, resp) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/feed/feedVideoListLogic.go: -------------------------------------------------------------------------------- 1 | package feed 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/gateway/internal/svc" 7 | "douyin/pkg/gateway/internal/types" 8 | "douyin/pkg/video/types/video" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type FeedVideoListLogic struct { 13 | logx.Logger 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | } 17 | 18 | func NewFeedVideoListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FeedVideoListLogic { 19 | return &FeedVideoListLogic{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | } 24 | } 25 | 26 | func (l *FeedVideoListLogic) FeedVideoList(req *types.FeedVideoListReq) (resp *types.FeedVideoListRes, err error) { 27 | videosResp, err := l.svcCtx.VideoRPC.GetVideo(l.ctx, &video.GetVideoReq{ 28 | LatestTime: req.LastTime, 29 | Token: req.Token, 30 | }) 31 | if err != nil { 32 | logx.Errorf("get videos failed: %v", err.Error()) 33 | return &types.FeedVideoListRes{ 34 | Status: types.Status{ 35 | Code: xerr.ERR, 36 | Msg: "get videos failed", 37 | }, 38 | }, err 39 | } 40 | videos := make([]*types.PubVideo, len(videosResp.VideoList)) 41 | for i, v := range videosResp.VideoList { 42 | videos[i] = &types.PubVideo{} 43 | videos[i].Id = v.Id 44 | videos[i].User = types.User{ 45 | UserId: v.Author.Id, 46 | UserName: v.Author.Name, 47 | FollowCount: v.Author.FollowCount, 48 | FollowerCount: v.Author.FollowerCount, 49 | IsFollow: v.Author.IsFollow, 50 | Avatar: v.Author.Avatar, 51 | BackgroundImage: v.Author.BackgroundImage, 52 | Signature: v.Author.Signature, 53 | TotalFavorited: v.Author.TotalFavorited, 54 | WorkCount: v.Author.WorkCount, 55 | FavoriteCount: v.Author.FavoriteCount, 56 | } 57 | videos[i].PlayURL = v.PlayUrl 58 | videos[i].CoverURL = v.CoverUrl 59 | videos[i].FavoriteCount = int(v.FavoriteCount) 60 | videos[i].CommentCount = int(v.CommentCount) 61 | videos[i].IsFavorite = v.IsFavorite 62 | videos[i].Title = v.Title 63 | } 64 | return &types.FeedVideoListRes{ 65 | Status: types.Status{ 66 | Code: xerr.OK, 67 | }, 68 | NextTime: videosResp.NextTime, 69 | VideoList: videos, 70 | }, nil 71 | } 72 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/message/messageLogic.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "context" 5 | "douyin/common/help/sensitiveWords" 6 | "douyin/pkg/message/userMessagePb" 7 | 8 | "douyin/pkg/gateway/internal/svc" 9 | "douyin/pkg/gateway/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type MessageLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewMessageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MessageLogic { 21 | return &MessageLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *MessageLogic) Message(req *types.MessageReq) (resp *types.MessageRes, err error) { 29 | req.Content = sensitiveWords.SensitiveWordsFliter(sensitiveWords.SensitiveWords, req.Content, '?') 30 | SendMessageRPC, err := l.svcCtx.MessageRpc.SendMessage(l.ctx, &userMessagePb.MessageReq{ 31 | ToUserId: req.ToUserId, 32 | Content: req.Content, 33 | Token: req.Token, 34 | ActionType: req.ActionType, 35 | }) 36 | 37 | if err != nil { 38 | logx.Errorf("SendMessage->SendMessageRpc err : %v , val : %s , message:%+v", err) 39 | return &types.MessageRes{ 40 | Code: 1, 41 | Msg: "send message to SendMessageRPC err", 42 | }, err 43 | } 44 | return &types.MessageRes{ 45 | Code: 0, 46 | Msg: SendMessageRPC.Msg, 47 | }, nil 48 | } 49 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/message/messagelistLogic.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/gateway/internal/svc" 6 | "douyin/pkg/gateway/internal/types" 7 | "douyin/pkg/message/userMessagePb" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | ) 10 | 11 | type MessagelistLogic struct { 12 | logx.Logger 13 | ctx context.Context 14 | svcCtx *svc.ServiceContext 15 | } 16 | 17 | func NewMessageListLogin(ctx context.Context, svcCtx *svc.ServiceContext) *MessagelistLogic { 18 | return &MessagelistLogic{ 19 | Logger: logx.WithContext(ctx), 20 | ctx: ctx, 21 | svcCtx: svcCtx, 22 | } 23 | } 24 | 25 | func (l *MessagelistLogic) MessageList(req *types.MessageListReq) (resp *types.MessageListRes, err error) { 26 | GetMessagelistRPC, err := l.svcCtx.MessageRpc.GetMessageList(l.ctx, &userMessagePb.MessageListReq{ 27 | UserId: req.ToUserId, 28 | Token: req.Token, 29 | PreTime: req.PreMsgTime, 30 | }) 31 | if err != nil { 32 | logx.Errorf("GetMessagelist->GetMessagelistRpc err : %v , val : %s , message:%+v", err) 33 | return &types.MessageListRes{ 34 | Status: types.Status{Code: 1, Msg: err.Error()}, 35 | MessageList: nil, 36 | }, err 37 | } 38 | MessageList := make([]*types.Message, len(GetMessagelistRPC.MessageList)) 39 | 40 | for i, v := range GetMessagelistRPC.MessageList { 41 | message := &types.Message{} 42 | message.Id = v.Id 43 | message.Content = v.Content 44 | message.CreateTime = v.CreateTime 45 | message.FromUserId = v.FromUserId 46 | message.ToUserId = v.ToUserId 47 | MessageList[i] = message 48 | } 49 | return &types.MessageListRes{ 50 | Status: types.Status{Code: 0}, 51 | MessageList: MessageList, 52 | }, nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/publish/getPublishVideoListLogic.go: -------------------------------------------------------------------------------- 1 | package publish 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/gateway/internal/svc" 7 | "douyin/pkg/gateway/internal/types" 8 | "douyin/pkg/video/types/video" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type GetPublishVideoListLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewGetPublishVideoListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPublishVideoListLogic { 20 | return &GetPublishVideoListLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *GetPublishVideoListLogic) GetPublishVideoList(req *types.GetPubVideoListReq) (resp *types.GetPubVideoListRes, err error) { 28 | videosResp, err := l.svcCtx.VideoRPC.GetAllVideoByUserId(l.ctx, &video.GetAllVideoByUserIdReq{ 29 | Token: req.Token, 30 | UserId: req.UserId, 31 | }) 32 | if err != nil { 33 | logx.Errorf("get videos by userID failed: %v", err.Error()) 34 | return &types.GetPubVideoListRes{ 35 | Status: types.Status{ 36 | Code: xerr.ERR, 37 | Msg: "get videos failed", 38 | }, 39 | }, err 40 | } 41 | videos := make([]*types.PubVideo, len(videosResp.VideoList)) 42 | for i, v := range videosResp.VideoList { 43 | videos[i] = &types.PubVideo{} 44 | videos[i].Id = v.Id 45 | videos[i].User = types.User{ 46 | UserId: v.Author.Id, 47 | UserName: v.Author.Name, 48 | FollowCount: v.Author.FollowCount, 49 | FollowerCount: v.Author.FollowerCount, 50 | IsFollow: v.Author.IsFollow, 51 | Avatar: v.Author.Avatar, 52 | BackgroundImage: v.Author.BackgroundImage, 53 | Signature: v.Author.Signature, 54 | TotalFavorited: v.Author.TotalFavorited, 55 | WorkCount: v.Author.WorkCount, 56 | FavoriteCount: v.Author.FavoriteCount, 57 | } 58 | videos[i].PlayURL = v.PlayUrl 59 | videos[i].CoverURL = v.CoverUrl 60 | videos[i].FavoriteCount = int(v.FavoriteCount) 61 | videos[i].CommentCount = int(v.CommentCount) 62 | videos[i].IsFavorite = v.IsFavorite 63 | videos[i].Title = v.Title 64 | } 65 | return &types.GetPubVideoListRes{ 66 | Status: types.Status{ 67 | Code: xerr.OK, 68 | }, 69 | VideoPubList: videos, 70 | }, nil 71 | } 72 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/publish/publishVideoLogic.go: -------------------------------------------------------------------------------- 1 | package publish 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/gateway/internal/svc" 7 | "douyin/pkg/gateway/internal/types" 8 | "douyin/pkg/video/types/video" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type PublishVideoLogic struct { 13 | logx.Logger 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | } 17 | 18 | func NewPublishVideoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PublishVideoLogic { 19 | return &PublishVideoLogic{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | } 24 | } 25 | 26 | func (l *PublishVideoLogic) PublishVideo(req *types.PubVideoReq) (resp *types.PubVideoRes, err error) { 27 | pubResp, err := l.svcCtx.VideoRPC.PublishVideo(l.ctx, &video.PublishVideoReq{ 28 | Token: req.Token, 29 | Data: req.Data, 30 | Title: req.Title, 31 | }) 32 | if err != nil { 33 | logx.Errorf("publish video failed: %v", err.Error()) 34 | return &types.PubVideoRes{ 35 | Status: types.Status{ 36 | Code: xerr.ERR, 37 | Msg: "get videos failed", 38 | }, 39 | }, err 40 | } 41 | return &types.PubVideoRes{ 42 | Status: types.Status{ 43 | Code: int64(pubResp.StatusCode), 44 | Msg: pubResp.StatusMsg, 45 | }, 46 | }, nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/user/userInfoLogic.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/gateway/internal/svc" 7 | "douyin/pkg/gateway/internal/types" 8 | "douyin/pkg/user/userservice" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type UserInfoLogic struct { 13 | logx.Logger 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | } 17 | 18 | func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic { 19 | return &UserInfoLogic{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | } 24 | } 25 | 26 | func (l *UserInfoLogic) UserInfo(req *types.UserInfoReq) (resp *types.UserInfoRes, err error) { 27 | info, err := l.svcCtx.UserRpc.Info(l.ctx, &userservice.UserInfoReq{ 28 | UserId: req.UserId, 29 | }) 30 | if err != nil { 31 | logx.Errorf("get user info failed: %v", err.Error()) 32 | return &types.UserInfoRes{ 33 | Status: types.Status{ 34 | Code: xerr.ERR, 35 | Msg: "get user info failed", 36 | }, 37 | }, nil 38 | } 39 | 40 | return &types.UserInfoRes{ 41 | Status: types.Status{ 42 | Code: xerr.OK, 43 | }, 44 | User: &types.User{ 45 | UserId: info.User.UserId, 46 | UserName: info.User.UserName, 47 | FollowCount: info.User.FollowCount, 48 | FollowerCount: info.User.FollowerCount, 49 | IsFollow: false, 50 | Avatar: info.User.Avatar, 51 | BackgroundImage: info.User.BackgroundImage, 52 | Signature: info.User.Signature, 53 | TotalFavorited: info.User.TotalFavorited, 54 | WorkCount: info.User.WorkCount, 55 | FavoriteCount: info.User.FavoriteCount, 56 | }, 57 | }, nil 58 | 59 | } 60 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/user/userLoginLogic.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/gateway/internal/svc" 7 | "douyin/pkg/gateway/internal/types" 8 | "douyin/pkg/user/userservice" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type UserLoginLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewUserLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLoginLogic { 20 | return &UserLoginLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *UserLoginLogic) UserLogin(req *types.UserLoginReq) (resp *types.UserLoginRes, err error) { 28 | res, err := l.svcCtx.UserRpc.Login(l.ctx, &userservice.LoginReq{ 29 | UserName: req.UserName, 30 | Password: req.Password, 31 | }) 32 | if err != nil { 33 | logx.Errorf("login failed: %v", err.Error()) 34 | return &types.UserLoginRes{ 35 | Status: types.Status{ 36 | Code: xerr.ERR, 37 | Msg: "login failed", 38 | }, 39 | }, nil 40 | } 41 | 42 | return &types.UserLoginRes{ 43 | Status: types.Status{ 44 | Code: xerr.OK, 45 | }, 46 | IdWithTokenRes: types.IdWithTokenRes{ 47 | UserId: res.UserId, 48 | Token: res.Token, 49 | }, 50 | }, nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/user/userRegisterLogic.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "context" 5 | "douyin/common/checkpwd" 6 | "douyin/common/xerr" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | "douyin/pkg/user/userservice" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type UserRegisterLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewUserRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRegisterLogic { 20 | return &UserRegisterLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterReq) (resp *types.UserRegisterRes, err error) { 28 | err = checkpwd.CheckPassword(req.Password) 29 | if err != nil { 30 | return &types.UserRegisterRes{ 31 | Status: types.Status{ 32 | Code: xerr.REUQEST_PARAM_ERROR, 33 | Msg: "Password strength must be the word write + number + symbol, more than 9 digits", 34 | }, 35 | }, nil 36 | } 37 | 38 | res, err := l.svcCtx.UserRpc.Register(l.ctx, &userservice.RegisterReq{ 39 | UserName: req.UserName, 40 | Password: req.Password, 41 | }) 42 | if err != nil { 43 | logx.Errorf("register failed: %s", err.Error()) 44 | return &types.UserRegisterRes{ 45 | Status: types.Status{ 46 | Code: xerr.SECRET_ERROR, 47 | Msg: "register failed" + err.Error(), 48 | }, 49 | }, nil 50 | } 51 | 52 | return &types.UserRegisterRes{ 53 | Status: types.Status{ 54 | Code: xerr.OK, 55 | }, 56 | IdWithTokenRes: types.IdWithTokenRes{ 57 | UserId: res.UserId, 58 | Token: res.Token, 59 | }, 60 | }, nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/userOpt/favoriteOptLogic.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "context" 5 | myToken "douyin/common/help/token" 6 | "douyin/common/messageTypes" 7 | "douyin/common/xerr" 8 | "douyin/pkg/gateway/internal/svc" 9 | "douyin/pkg/gateway/internal/types" 10 | "encoding/json" 11 | "github.com/jinzhu/copier" 12 | "github.com/pkg/errors" 13 | 14 | "github.com/zeromicro/go-zero/core/logx" 15 | ) 16 | 17 | type FavoriteOptLogic struct { 18 | logx.Logger 19 | ctx context.Context 20 | svcCtx *svc.ServiceContext 21 | } 22 | 23 | func NewFavoriteOptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FavoriteOptLogic { 24 | return &FavoriteOptLogic{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, 28 | } 29 | } 30 | 31 | func (l *FavoriteOptLogic) FavoriteOpt(req *types.FavoriteOptReq) (resp *types.FavoriteOptRes, err error) { 32 | var msgTemp messageTypes.UserFavoriteOptMessage 33 | _ = copier.Copy(&msgTemp, req) 34 | 35 | msgTemp.UserId = l.ctx.Value(myToken.CurrentUserId("CurrentUserId")).(int64) 36 | 37 | // 序列化 38 | msg, err := json.Marshal(msgTemp) 39 | if err != nil { 40 | logx.Errorf("FavoriteOpt json.Marshal err : %s", err.Error()) 41 | return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), " json.Marshal err") 42 | } 43 | 44 | // 向消息队列发送消息 45 | err = l.svcCtx.FavoriteOptMsgProducer.Push(string(msg)) 46 | if err != nil { 47 | logx.Errorf("FavoriteOpt msgProducer.Push err : %s", err.Error()) 48 | return &types.FavoriteOptRes{ 49 | Status: types.Status{ 50 | Code: xerr.ERR, 51 | Msg: "send message to FavoriteOptMsgConsumer err", 52 | }, 53 | }, nil 54 | } 55 | if req.ActionType == 1 { 56 | return &types.FavoriteOptRes{ 57 | Status: types.Status{ 58 | Code: xerr.OK, 59 | Msg: "user favorite success", 60 | }, 61 | }, nil 62 | } 63 | if req.ActionType == 2 { 64 | return &types.FavoriteOptRes{ 65 | Status: types.Status{ 66 | Code: xerr.OK, 67 | Msg: "user cancel favorite success", 68 | }, 69 | }, nil 70 | } 71 | return nil, nil 72 | } 73 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/userOpt/followOptLogic.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "context" 5 | myToken "douyin/common/help/token" 6 | "douyin/common/messageTypes" 7 | "douyin/common/xerr" 8 | "douyin/pkg/gateway/internal/svc" 9 | "douyin/pkg/gateway/internal/types" 10 | "encoding/json" 11 | "github.com/jinzhu/copier" 12 | "github.com/pkg/errors" 13 | 14 | "github.com/zeromicro/go-zero/core/logx" 15 | ) 16 | 17 | type FollowOptLogic struct { 18 | logx.Logger 19 | ctx context.Context 20 | svcCtx *svc.ServiceContext 21 | } 22 | 23 | func NewFollowOptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FollowOptLogic { 24 | return &FollowOptLogic{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, 28 | } 29 | } 30 | 31 | func (l *FollowOptLogic) FollowOpt(req *types.FollowOptReq) (resp *types.FollowOptRes, err error) { 32 | var followTemp messageTypes.UserFollowOptMessage 33 | _ = copier.Copy(&followTemp, req) 34 | 35 | followTemp.UserId = l.ctx.Value(myToken.CurrentUserId("CurrentUserId")).(int64) 36 | followTemp.ToUserId = req.FollowId 37 | followTemp.ActionType = req.ActionType 38 | // 序列化 39 | msg, err := json.Marshal(followTemp) 40 | if err != nil { 41 | logx.Errorf("FollowOpt json.Marshal err : %s", err.Error()) 42 | return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), " json.Marshal err") 43 | } 44 | // 向消息队列发送消息 45 | err = l.svcCtx.FollowOptMsgProducer.Push(string(msg)) 46 | if err != nil { 47 | logx.Errorf("FollowOpt msgProducer.Push err : %s", err.Error()) 48 | return &types.FollowOptRes{ 49 | Status: types.Status{ 50 | Code: xerr.ERR, 51 | Msg: "send message to FollowOptMsgConsumer err", 52 | }, 53 | }, nil 54 | } 55 | if req.ActionType == 1 { 56 | return &types.FollowOptRes{ 57 | Status: types.Status{ 58 | Code: xerr.OK, 59 | Msg: "user follow success", 60 | }, 61 | }, nil 62 | } 63 | if req.ActionType == 2 { 64 | return &types.FollowOptRes{ 65 | Status: types.Status{ 66 | Code: xerr.OK, 67 | Msg: "user cancel follow success", 68 | }, 69 | }, nil 70 | } 71 | return nil, nil 72 | } 73 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/userOpt/getFollowListLogic.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type GetFollowListLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewGetFollowListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowListLogic { 20 | return &GetFollowListLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *GetFollowListLogic) GetFollowList(req *types.FollowListReq) (resp *types.FollowListRes, err error) { 28 | result, err := l.svcCtx.FollowRPC.GetFollowList(l.ctx, &followservice.GetFollowListReq{ 29 | Token: req.Token, 30 | UserId: req.UserId, 31 | }) 32 | if err != nil { 33 | logx.Errorf("UserFollowList->followRpc err : %v , val : %s , message:%+v", err) 34 | return &types.FollowListRes{ 35 | Status: types.Status{ 36 | Code: xerr.ERR, 37 | Msg: "send message to followRpc err", 38 | }, 39 | }, nil 40 | } 41 | userList := make([]*types.User, len(result.UserList)) 42 | for i, v := range result.UserList { 43 | userList[i] = &types.User{} 44 | userList[i].UserId = v.Id 45 | userList[i].UserName = v.Name 46 | userList[i].FollowCount = v.FollowCount 47 | userList[i].FollowerCount = v.FollowerCount 48 | userList[i].IsFollow = v.IsFollow 49 | userList[i].Avatar = v.Avatar 50 | userList[i].BackgroundImage = v.BackgroundImage 51 | userList[i].Signature = v.Signature 52 | userList[i].TotalFavorited = v.TotalFavorited 53 | userList[i].WorkCount = v.WorkCount 54 | userList[i].FavoriteCount = v.FavoriteCount 55 | } 56 | return &types.FollowListRes{ 57 | Status: types.Status{ 58 | Code: xerr.OK, 59 | Msg: "Get favorite list success", 60 | }, 61 | UserFollowlist: userList, 62 | }, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/userOpt/getFollowerListLogic.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "context" 5 | "douyin/common/xerr" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/gateway/internal/svc" 8 | "douyin/pkg/gateway/internal/types" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type GetFollowerListLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewGetFollowerListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowerListLogic { 20 | return &GetFollowerListLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *GetFollowerListLogic) GetFollowerList(req *types.FollowerListReq) (resp *types.FollowerListRes, err error) { 28 | result, err := l.svcCtx.FollowRPC.GetFollowerList(l.ctx, &followservice.GetFollowerListReq{ 29 | Token: req.Token, 30 | UserId: req.UserId, 31 | }) 32 | if err != nil { 33 | logx.Errorf("UserFollowerList->followerRpc err : %v , val : %s , message:%+v", err) 34 | return &types.FollowerListRes{ 35 | Status: types.Status{ 36 | Code: xerr.ERR, 37 | Msg: "send message to followRpc err", 38 | }, 39 | }, nil 40 | } 41 | userList := make([]*types.User, len(result.UserList)) 42 | for i, v := range result.UserList { 43 | userList[i] = &types.User{} 44 | userList[i].UserId = v.Id 45 | userList[i].UserName = v.Name 46 | userList[i].FollowCount = v.FollowCount 47 | userList[i].FollowerCount = v.FollowerCount 48 | userList[i].IsFollow = v.IsFollow 49 | userList[i].Avatar = v.Avatar 50 | userList[i].BackgroundImage = v.BackgroundImage 51 | userList[i].Signature = v.Signature 52 | userList[i].TotalFavorited = v.TotalFavorited 53 | userList[i].WorkCount = v.WorkCount 54 | userList[i].FavoriteCount = v.FavoriteCount 55 | } 56 | return &types.FollowerListRes{ 57 | Status: types.Status{ 58 | Code: xerr.OK, 59 | Msg: "Get favorite list success", 60 | }, 61 | UserFollowerlist: userList, 62 | }, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/gateway/internal/logic/userOpt/getFriendListLogic.go: -------------------------------------------------------------------------------- 1 | package userOpt 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/follow/followservice" 6 | "douyin/pkg/logger" 7 | "sync" 8 | 9 | "douyin/pkg/gateway/internal/svc" 10 | "douyin/pkg/gateway/internal/types" 11 | 12 | "github.com/zeromicro/go-zero/core/logx" 13 | ) 14 | 15 | type GetFriendListLogic struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | } 20 | 21 | func NewGetFriendListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFriendListLogic { 22 | return &GetFriendListLogic{ 23 | Logger: logx.WithContext(ctx), 24 | ctx: ctx, 25 | svcCtx: svcCtx, 26 | } 27 | } 28 | 29 | func (l *GetFriendListLogic) GetFriendList(req *types.FriendListReq) (resp *types.FriendListRes, err error) { 30 | friendRes, err := l.svcCtx.FollowRPC.GetFriendList(l.ctx, &followservice.GetFriendListReq{ 31 | UserId: req.UserId, 32 | Token: req.Token, 33 | }) 34 | if err != nil { 35 | logger.Error("GetFriendList RPC failed %s", err.Error()) 36 | return &types.FriendListRes{ 37 | Status: types.Status{ 38 | Code: -1, 39 | Msg: "get friend list failed", 40 | }, 41 | }, err 42 | } 43 | userList := make([]*types.FriendUser, len(friendRes.UserList)) 44 | var wg sync.WaitGroup 45 | for index, queryUser := range friendRes.UserList { 46 | i := index 47 | user := queryUser 48 | wg.Add(1) 49 | go func() { 50 | userList[i] = &types.FriendUser{} 51 | userList[i].Message = *user.Message 52 | userList[i].MsgType = user.MsgType 53 | userList[i].UserId = user.Id 54 | userList[i].UserName = user.Name 55 | userList[i].FollowCount = user.FollowCount 56 | userList[i].FollowerCount = user.FollowerCount 57 | userList[i].IsFollow = user.IsFollow 58 | userList[i].Avatar = user.Avatar 59 | userList[i].BackgroundImage = user.BackgroundImage 60 | userList[i].Signature = user.Signature 61 | userList[i].TotalFavorited = user.TotalFavorited 62 | userList[i].WorkCount = user.WorkCount 63 | userList[i].FavoriteCount = user.FavoriteCount 64 | defer wg.Done() 65 | }() 66 | } 67 | wg.Wait() 68 | return &types.FriendListRes{ 69 | Status: types.Status{ 70 | Code: 0, 71 | Msg: "success", 72 | }, 73 | UserFriendlist: userList, 74 | }, nil 75 | } 76 | -------------------------------------------------------------------------------- /pkg/gateway/internal/middleware/authjwtMiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | myToken "douyin/common/help/token" 6 | "douyin/common/xerr" 7 | "douyin/pkg/gateway/internal/types" 8 | "encoding/json" 9 | "net/http" 10 | "time" 11 | ) 12 | 13 | type AuthJWTMiddleware struct { 14 | } 15 | 16 | func NewAuthJWTMiddleware() *AuthJWTMiddleware { 17 | return &AuthJWTMiddleware{} 18 | } 19 | 20 | func (m *AuthJWTMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 21 | return func(w http.ResponseWriter, r *http.Request) { 22 | status := new(types.Status) 23 | token := r.FormValue("token") 24 | 25 | if token == "" { 26 | status.Code = xerr.REUQEST_PARAM_ERROR 27 | status.Msg = "no token" 28 | res, _ := json.Marshal(status) 29 | _, _ = w.Write(res) 30 | return 31 | } 32 | // 解析token 判断是否有效 33 | var parseClaims myToken.ParseToken 34 | claims, err := parseClaims.ParseToken(token) 35 | if err != nil { 36 | status.Code = xerr.REUQEST_PARAM_ERROR 37 | status.Msg = "param error " + err.Error() 38 | res, _ := json.Marshal(status) 39 | _, _ = w.Write(res) 40 | return 41 | } 42 | 43 | // 过期时间点 小于当前时间 表示过期 44 | if claims.ExpireAt < time.Now().Unix() { 45 | status.Code = xerr.REUQEST_PARAM_ERROR 46 | status.Msg = "please login again" 47 | res, _ := json.Marshal(status) 48 | _, _ = w.Write(res) 49 | return 50 | } 51 | r = r.Clone(context.WithValue(r.Context(), myToken.CurrentUserId("CurrentUserId"), claims.UserId)) 52 | 53 | next(w, r) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/gateway/internal/middleware/isloginMiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | myToken "douyin/common/help/token" 6 | "douyin/common/xerr" 7 | "douyin/pkg/gateway/internal/types" 8 | "encoding/json" 9 | "net/http" 10 | "time" 11 | ) 12 | 13 | type IsLoginMiddleware struct { 14 | } 15 | 16 | func NewIsLoginMiddleware() *IsLoginMiddleware { 17 | return &IsLoginMiddleware{} 18 | } 19 | 20 | func (m *IsLoginMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 21 | return func(w http.ResponseWriter, r *http.Request) { 22 | status := new(types.Status) 23 | token := r.FormValue("token") 24 | if token != "" { 25 | // 解析token 判断是否有效 26 | var parseClaims myToken.ParseToken 27 | claims, err := parseClaims.ParseToken(token) 28 | if err != nil { 29 | status.Code = xerr.REUQEST_PARAM_ERROR 30 | status.Msg = "param error " + err.Error() 31 | res, _ := json.Marshal(status) 32 | _, _ = w.Write(res) 33 | return 34 | } 35 | 36 | // 过期时间点 小于当前时间 表示过期 37 | if claims.ExpireAt < time.Now().Unix() { 38 | status.Code = xerr.REUQEST_PARAM_ERROR 39 | status.Msg = "please login again" 40 | res, _ := json.Marshal(status) 41 | _, _ = w.Write(res) 42 | return 43 | } 44 | 45 | r = r.Clone(context.WithValue(r.Context(), myToken.CurrentUserId("LoginUserId"), claims.UserId)) 46 | 47 | // 把r传递给下一个handler 48 | next(w, r) 49 | } else { 50 | next(w, r) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pkg/gateway/internal/svc/serviceContext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/pkg/comment/usercomment" 5 | "douyin/pkg/favorite/useroptservice" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/gateway/internal/config" 8 | "douyin/pkg/gateway/internal/middleware" 9 | "douyin/pkg/message/usermessage" 10 | "douyin/pkg/user/userservice" 11 | "douyin/pkg/video/videoservice" 12 | "github.com/zeromicro/go-queue/kq" 13 | "github.com/zeromicro/go-zero/rest" 14 | "github.com/zeromicro/go-zero/zrpc" 15 | ) 16 | 17 | type ServiceContext struct { 18 | Config config.Config 19 | 20 | UserRpc userservice.UserService 21 | UserCommentRpc usercomment.UserComment 22 | UserFavoriteRpc useroptservice.UserOptService 23 | VideoRPC videoservice.VideoService 24 | FollowRPC followservice.FollowService 25 | MessageRpc usermessage.UserMessage 26 | 27 | CommentOptMsgProducer *kq.Pusher 28 | FavoriteOptMsgProducer *kq.Pusher 29 | FollowOptMsgProducer *kq.Pusher 30 | 31 | AuthJWT rest.Middleware 32 | IsLogin rest.Middleware 33 | } 34 | 35 | func NewServiceContext(c config.Config) *ServiceContext { 36 | return &ServiceContext{ 37 | Config: c, 38 | AuthJWT: middleware.NewAuthJWTMiddleware().Handle, 39 | IsLogin: middleware.NewIsLoginMiddleware().Handle, 40 | 41 | UserRpc: userservice.NewUserService(zrpc.MustNewClient(c.UserRpc)), 42 | UserCommentRpc: usercomment.NewUserComment(zrpc.MustNewClient(c.UserCommentRpc)), 43 | FollowRPC: followservice.NewFollowService(zrpc.MustNewClient(c.FollowRPC)), 44 | FavoriteOptMsgProducer: kq.NewPusher(c.UserFavoriteOptServiceConf.Brokers, c.UserFavoriteOptServiceConf.Topic), 45 | MessageRpc: usermessage.NewUserMessage(zrpc.MustNewClient(c.MessageRpc)), 46 | UserFavoriteRpc: useroptservice.NewUserOptService(zrpc.MustNewClient(c.UserFavoriteRpc)), 47 | VideoRPC: videoservice.NewVideoService(zrpc.MustNewClient(c.VideoRPC)), 48 | CommentOptMsgProducer: kq.NewPusher(c.UserCommentOptServiceConf.Brokers, c.UserCommentOptServiceConf.Topic), 49 | FollowOptMsgProducer: kq.NewPusher(c.UserFollowOptServiceConf.Brokers, c.UserFollowOptServiceConf.Topic), 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkg/kafka/docs.go: -------------------------------------------------------------------------------- 1 | package kafkax 2 | 3 | /* 4 | Autor: godot42 5 | Date: 2023-2-7 07:31:32 6 | Descripe: 7 | A packing of kafka-go 8 | */ 9 | -------------------------------------------------------------------------------- /pkg/kafka/manager.go: -------------------------------------------------------------------------------- 1 | package kafkax 2 | 3 | import "github.com/segmentio/kafka-go" 4 | 5 | type Manager struct { 6 | reader *kafka.Reader 7 | writer *kafka.Writer 8 | operator 9 | } 10 | 11 | func New() *Manager { 12 | return nil 13 | } 14 | 15 | func (m *Manager) GetWriter() (*kafka.Writer, error) { 16 | m.reader = kafka.NewReader(kafka.ReaderConfig{}) 17 | return nil, nil 18 | } 19 | 20 | func (m *Manager) GetReader() (*kafka.Reader, error) { 21 | m.writer = kafka.NewWriter(kafka.WriterConfig{}) 22 | return nil, nil 23 | } 24 | -------------------------------------------------------------------------------- /pkg/kafka/operator.go: -------------------------------------------------------------------------------- 1 | package kafkax 2 | 3 | import ( 4 | "github.com/segmentio/kafka-go" 5 | ) 6 | 7 | // TODO: define and implent 8 | type operator interface { 9 | writerOnce(topic, broker string, msg interface{}) 10 | readOnce() 11 | CreateTopics() 12 | Pull() 13 | Push() 14 | PrintTopics(broker string) error 15 | } 16 | 17 | func (m *Manager) PrintTopics(broker string) error { 18 | 19 | conn, err := kafka.Dial("tcp", broker) 20 | if err != nil { 21 | return err 22 | } 23 | defer conn.Close() 24 | 25 | partitions, err := conn.ReadPartitions() 26 | if err != nil { 27 | return err 28 | } 29 | 30 | mp := map[string]struct{}{} 31 | 32 | for _, p := range partitions { 33 | mp[p.Topic] = struct{}{} 34 | } 35 | 36 | for k := range mp { 37 | println(k) 38 | } 39 | 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/logger/log.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "sync" 6 | ) 7 | 8 | var zlog *zap.SugaredLogger 9 | var once sync.Once 10 | 11 | func init() { 12 | once.Do(func() { 13 | zlog = NewLogger() 14 | zlog = zlog.WithOptions(zap.AddCallerSkip(1)) 15 | }) 16 | } 17 | 18 | func NewLogger() *zap.SugaredLogger { 19 | // Todo: Production level 20 | level := zap.NewAtomicLevel() 21 | level.SetLevel(zap.DebugLevel) 22 | 23 | cfg := zap.NewProductionConfig() 24 | cfg.Level = level 25 | logger := zap.Must(cfg.Build()) 26 | sugaredLogger := logger.Sugar() 27 | return sugaredLogger 28 | } 29 | 30 | func DebugF(format string, args ...interface{}) { 31 | zlog.Debugf(format, args...) 32 | } 33 | 34 | func InfoF(format string, args ...interface{}) { 35 | zlog.Infof(format, args...) 36 | } 37 | 38 | func Errorf(format string, args ...interface{}) { 39 | zlog.Errorf(format, args...) 40 | } 41 | 42 | func Debug(args ...interface{}) { 43 | zlog.Debug(args...) 44 | } 45 | 46 | func Info(args ...interface{}) { 47 | zlog.Info(args...) 48 | } 49 | 50 | func Error(args ...interface{}) { 51 | zlog.Error(args...) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/message/etc/userMessage.yaml: -------------------------------------------------------------------------------- 1 | Name: usermessage.rpc 2 | ListenOn: 0.0.0.0:8080 3 | Etcd: 4 | Hosts: 5 | - etcd.etcd.svc.cluster.local:2379 6 | Key: usermessage.rpc 7 | DB: 8 | DataSource: douyin:Z4eEXbWWCApby8dE@tcp(bt.vacant.zone:3306)/douyin?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai 9 | CacheConf: 10 | - Host: redis-master.redis.svc.cluster.local:6379 11 | Pass: redispwd123 12 | FollowRPC: 13 | Etcd: 14 | Hosts: 15 | - etcd.etcd.svc.cluster.local:2379 16 | Key: follow.rpc -------------------------------------------------------------------------------- /pkg/message/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/stores/cache" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | ) 7 | 8 | type Config struct { 9 | zrpc.RpcServerConf 10 | DB struct { 11 | DataSource string 12 | } 13 | CacheConf cache.CacheConf 14 | FollowRPC zrpc.RpcClientConf 15 | } 16 | -------------------------------------------------------------------------------- /pkg/message/internal/logic/getMessageListLogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/common/help/token" 6 | "douyin/pkg/message/internal/svc" 7 | "douyin/pkg/message/userMessagePb" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | ) 10 | 11 | type GetMessageListLogic struct { 12 | ctx context.Context 13 | svcCtx *svc.ServiceContext 14 | logx.Logger 15 | } 16 | 17 | func NewGetMessageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMessageListLogic { 18 | return &GetMessageListLogic{ 19 | ctx: ctx, 20 | svcCtx: svcCtx, 21 | Logger: logx.WithContext(ctx), 22 | } 23 | } 24 | 25 | // -----------------------GetMessageList----------------------- 26 | func (l *GetMessageListLogic) GetMessageList(in *userMessagePb.MessageListReq) (*userMessagePb.MessageListRes, error) { 27 | parseToken := token.ParseToken{} 28 | userid, _ := parseToken.ParseToken(in.Token) 29 | allMessageData, err := l.svcCtx.MessageModel.FindMessageListByUserID(l.ctx, userid.UserId, in.UserId, in.PreTime) 30 | if err != nil { 31 | logx.Errorf("GetCommentList------->SELECT err : %s", err.Error()) 32 | return &userMessagePb.MessageListRes{ 33 | Code: 1, 34 | Msg: "failure", 35 | MessageList: nil, 36 | }, err 37 | } 38 | 39 | var MessageList []*userMessagePb.Message 40 | for _, v := range allMessageData { 41 | var message userMessagePb.Message 42 | message.Id = v.Id 43 | message.ToUserId = v.ToUserId 44 | message.Content = v.Content 45 | message.FromUserId = v.FromUserId 46 | message.CreateTime = v.CreateTime 47 | MessageList = append(MessageList, &message) 48 | } 49 | return &userMessagePb.MessageListRes{ 50 | Code: 0, 51 | Msg: "Success", 52 | MessageList: MessageList, 53 | }, nil 54 | } 55 | -------------------------------------------------------------------------------- /pkg/message/internal/logic/sendMessageLogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "context" 5 | "douyin/common/help/token" 6 | "douyin/common/model/messageModel" 7 | "douyin/pkg/logger" 8 | "douyin/pkg/message/internal/svc" 9 | "douyin/pkg/message/userMessagePb" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | "time" 12 | ) 13 | 14 | type SendMessageLogic struct { 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | logx.Logger 18 | } 19 | 20 | func NewSendMessageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendMessageLogic { 21 | return &SendMessageLogic{ 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | Logger: logx.WithContext(ctx), 25 | } 26 | } 27 | 28 | func (l *SendMessageLogic) SendMessage(in *userMessagePb.MessageReq) (*userMessagePb.MessageRes, error) { 29 | message := &messageModel.Message{} 30 | var parseToken token.ParseToken 31 | claims, err := parseToken.ParseToken(in.Token) 32 | if err != nil { 33 | logger.InfoF("Token解析错误 %s ", err.Error()) 34 | return &userMessagePb.MessageRes{ 35 | Code: -1, 36 | Msg: "Token解析错误", 37 | }, err 38 | } 39 | 40 | message.ToUserId = in.ToUserId 41 | message.Content = in.Content 42 | message.FromUserId = claims.UserId 43 | message.CreateTime = time.Now().Unix() 44 | 45 | _, err = l.svcCtx.MessageModel.Insert(l.ctx, message) 46 | 47 | if err != nil { 48 | logx.Errorf("SendMessage------->SELECT err : %s", err.Error()) 49 | return &userMessagePb.MessageRes{ 50 | Code: -1, 51 | Msg: "failure", 52 | }, err 53 | } 54 | 55 | err = l.svcCtx.FollowModel.UpdateMsg(l.ctx, claims.UserId, in.ToUserId, message.Content) 56 | if err != nil { 57 | logx.Errorf("Update First Msg failed : %s", err.Error()) 58 | return &userMessagePb.MessageRes{ 59 | Code: -1, 60 | Msg: "failure", 61 | }, err 62 | } 63 | 64 | return &userMessagePb.MessageRes{ 65 | Code: 0, 66 | Msg: "Success", 67 | }, nil 68 | } 69 | -------------------------------------------------------------------------------- /pkg/message/internal/server/userMessageServer.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT! 2 | // Source: UserMessage.proto 3 | 4 | package server 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/message/internal/logic" 10 | "douyin/pkg/message/internal/svc" 11 | "douyin/pkg/message/userMessagePb" 12 | ) 13 | 14 | type UserMessageServer struct { 15 | svcCtx *svc.ServiceContext 16 | userMessagePb.UnimplementedUserMessageServer 17 | } 18 | 19 | func NewUserMessageServer(svcCtx *svc.ServiceContext) *UserMessageServer { 20 | return &UserMessageServer{ 21 | svcCtx: svcCtx, 22 | } 23 | } 24 | 25 | // -----------------------SendMessage----------------------- 26 | func (s *UserMessageServer) SendMessage(ctx context.Context, in *userMessagePb.MessageReq) (*userMessagePb.MessageRes, error) { 27 | l := logic.NewSendMessageLogic(ctx, s.svcCtx) 28 | return l.SendMessage(in) 29 | } 30 | 31 | // -----------------------GetMessageList----------------------- 32 | func (s *UserMessageServer) GetMessageList(ctx context.Context, in *userMessagePb.MessageListReq) (*userMessagePb.MessageListRes, error) { 33 | l := logic.NewGetMessageListLogic(ctx, s.svcCtx) 34 | return l.GetMessageList(in) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/message/internal/svc/serviceContext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/common/model/followModel" 5 | "douyin/common/model/messageModel" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/message/internal/config" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | "github.com/zeromicro/go-zero/zrpc" 10 | ) 11 | 12 | type ServiceContext struct { 13 | Config config.Config 14 | MessageModel messageModel.MessageModel 15 | FollowModel followModel.FollowModel 16 | FollowRPC followservice.FollowService 17 | } 18 | 19 | func NewServiceContext(c config.Config) *ServiceContext { 20 | conn := sqlx.NewMysql(c.DB.DataSource) 21 | return &ServiceContext{ 22 | Config: c, 23 | MessageModel: messageModel.NewMessageModel(conn, c.CacheConf), 24 | FollowModel: followModel.NewFollowModel(conn, c.CacheConf), 25 | FollowRPC: followservice.NewFollowService(zrpc.MustNewClient(c.FollowRPC)), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/message/userMessage.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/message/internal/config" 5 | "douyin/pkg/message/internal/server" 6 | "douyin/pkg/message/internal/svc" 7 | "douyin/pkg/message/userMessagePb" 8 | "flag" 9 | "fmt" 10 | 11 | "github.com/zeromicro/go-zero/core/conf" 12 | "github.com/zeromicro/go-zero/core/service" 13 | "github.com/zeromicro/go-zero/zrpc" 14 | "google.golang.org/grpc" 15 | "google.golang.org/grpc/reflection" 16 | ) 17 | 18 | var configFile = flag.String("f", "etc/userMessage.yaml", "the config file") 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | var c config.Config 24 | conf.MustLoad(*configFile, &c) 25 | ctx := svc.NewServiceContext(c) 26 | 27 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { 28 | userMessagePb.RegisterUserMessageServer(grpcServer, server.NewUserMessageServer(ctx)) 29 | 30 | if c.Mode == service.DevMode || c.Mode == service.TestMode { 31 | reflection.Register(grpcServer) 32 | } 33 | }) 34 | defer s.Stop() 35 | 36 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) 37 | s.Start() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/message/userMessagePb/GenPb/UserMessage.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package ="./userMessagePb"; 4 | 5 | package pb; 6 | 7 | // ------------------------------------ 8 | // Messages 9 | // ------------------------------------ 10 | 11 | message MessageReq { 12 | string Token = 1; 13 | int64 ToUserId = 2; 14 | int64 ActionType = 3; 15 | string Content = 4; 16 | } 17 | 18 | message MessageRes { 19 | int64 Code = 1; 20 | string Msg = 2; 21 | } 22 | 23 | message MessageListReq { 24 | int64 UserId = 1; 25 | string Token = 2; 26 | int64 PreTime = 3; 27 | } 28 | 29 | message MessageListRes { 30 | int64 Code = 1; 31 | string Msg = 2; 32 | repeated Message MessageList = 3; 33 | } 34 | 35 | message Message { 36 | int64 Id = 1; 37 | int64 ToUserId = 2; 38 | int64 FromUserId = 3; 39 | string Content = 4; 40 | int64 CreateTime = 5; 41 | } 42 | 43 | 44 | // ------------------------------------ 45 | // Rpc Func 46 | // ------------------------------------ 47 | 48 | service UserMessage{ 49 | //-----------------------SendMessage----------------------- 50 | rpc SendMessage(MessageReq) returns (MessageRes); 51 | //-----------------------GetMessageList----------------------- 52 | rpc GetMessageList(MessageListReq) returns (MessageListRes); 53 | } 54 | -------------------------------------------------------------------------------- /pkg/message/userMessagePb/GenPb/build.sh: -------------------------------------------------------------------------------- 1 | #goctl rpc protoc UserCommentService.proto --go_out=../../ --go-grpc_out=../../ --zrpc_out=../../ --style=goZero --home=../../../../tpl 2 | # 当有多个proto文件时 需要先生成其他的文件 再生成主要的pb文件 3 | 4 | 5 | goctl rpc protoc UserMessage.proto --go_out=../../ --go-grpc_out=../../ --zrpc_out=../../ --style=goZero 6 | -------------------------------------------------------------------------------- /pkg/message/usermessage/userMessage.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT! 2 | // Source: UserMessage.proto 3 | 4 | package usermessage 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/message/userMessagePb" 10 | 11 | "github.com/zeromicro/go-zero/zrpc" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | type ( 16 | Message = userMessagePb.Message 17 | MessageListReq = userMessagePb.MessageListReq 18 | MessageListRes = userMessagePb.MessageListRes 19 | MessageReq = userMessagePb.MessageReq 20 | MessageRes = userMessagePb.MessageRes 21 | 22 | UserMessage interface { 23 | // -----------------------SendMessage----------------------- 24 | SendMessage(ctx context.Context, in *MessageReq, opts ...grpc.CallOption) (*MessageRes, error) 25 | // -----------------------GetMessageList----------------------- 26 | GetMessageList(ctx context.Context, in *MessageListReq, opts ...grpc.CallOption) (*MessageListRes, error) 27 | } 28 | 29 | defaultUserMessage struct { 30 | cli zrpc.Client 31 | } 32 | ) 33 | 34 | func NewUserMessage(cli zrpc.Client) UserMessage { 35 | return &defaultUserMessage{ 36 | cli: cli, 37 | } 38 | } 39 | 40 | // -----------------------SendMessage----------------------- 41 | func (m *defaultUserMessage) SendMessage(ctx context.Context, in *MessageReq, opts ...grpc.CallOption) (*MessageRes, error) { 42 | client := userMessagePb.NewUserMessageClient(m.cli.Conn()) 43 | return client.SendMessage(ctx, in, opts...) 44 | } 45 | 46 | // -----------------------GetMessageList----------------------- 47 | func (m *defaultUserMessage) GetMessageList(ctx context.Context, in *MessageListReq, opts ...grpc.CallOption) (*MessageListRes, error) { 48 | client := userMessagePb.NewUserMessageClient(m.cli.Conn()) 49 | return client.GetMessageList(ctx, in, opts...) 50 | } 51 | -------------------------------------------------------------------------------- /pkg/minio-client/etc/minioclient.yaml: -------------------------------------------------------------------------------- 1 | Name: minioclient.rpc 2 | ListenOn: 0.0.0.0:30001 3 | Etcd: 4 | Hosts: 5 | - etcd.etcd.svc.cluster.local:2379 6 | Key: minioclient.rpc 7 | -------------------------------------------------------------------------------- /pkg/minio-client/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/zeromicro/go-zero/zrpc" 4 | 5 | type Config struct { 6 | zrpc.RpcServerConf 7 | } 8 | -------------------------------------------------------------------------------- /pkg/minio-client/internal/logic/uploadfilelogic.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "douyin/pkg/logger" 7 | "douyin/pkg/minio-client/internal/svc" 8 | "douyin/pkg/minio-client/types/minio-client" 9 | "fmt" 10 | "time" 11 | 12 | "github.com/zeromicro/go-zero/core/logx" 13 | ) 14 | 15 | type UploadFileLogic struct { 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | logx.Logger 19 | } 20 | 21 | func NewUploadFileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileLogic { 22 | return &UploadFileLogic{ 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | Logger: logx.WithContext(ctx), 26 | } 27 | } 28 | 29 | func (l *UploadFileLogic) UploadFile(in *minio_client.UploadFileRequest) (*minio_client.UploadFileReply, error) { 30 | pngFrame, err := getVideoFrame(in.Data, 1) 31 | if err != nil { 32 | logger.Errorf("Fail to get video frame, err: %v", err) 33 | return nil, err 34 | } 35 | 36 | client := makeMinIOClient() 37 | bucket := "douyin" 38 | if in.Data == nil || in.Title == "" { 39 | logger.Error("UploadFile's parameter cant be nil") 40 | panic("UploadFile's parameter cant be nil") 41 | } 42 | 43 | videoUrl, err := uploadFile(client, bytes.NewReader(in.Data), fmt.Sprintf("%v.mp4", time.Now().Unix()), bucket, "") 44 | if err != nil { 45 | logger.Errorf("Fail to upload video file, err: %v", err) 46 | return nil, err 47 | } 48 | 49 | frameUrl, err := uploadFile(client, pngFrame, fmt.Sprintf("%v.png", time.Now().Unix()), bucket, "") 50 | if err != nil { 51 | logger.Errorf("Fail to upload frame file, err: %v, err") 52 | return nil, err 53 | } 54 | 55 | return &minio_client.UploadFileReply{ 56 | Success: true, 57 | VideoUrl: videoUrl, 58 | FrontImgUrl: frameUrl, 59 | }, nil 60 | } 61 | -------------------------------------------------------------------------------- /pkg/minio-client/internal/logic/utils.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "douyin/pkg/logger" 7 | "fmt" 8 | "github.com/minio/minio-go/v7" 9 | ffmpeg "github.com/u2takey/ffmpeg-go" 10 | "os" 11 | ) 12 | 13 | import ( 14 | "github.com/minio/minio-go/v7/pkg/credentials" 15 | ) 16 | 17 | func makeMinIOClient() *minio.Client { 18 | var endpoint = "minio.minio.svc.cluster.local:9000" 19 | var accessKeyID = "douyin" 20 | var secretAccessKey = "douyin_pass" 21 | 22 | // Create a client, all operations must use it 23 | client, err := minio.New(endpoint, &minio.Options{ 24 | Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), 25 | }) 26 | if err != nil { 27 | logger.Errorf("Make MinIO client error:", err) 28 | panic(err) 29 | } 30 | return client 31 | } 32 | 33 | func getVideoFrame(data []byte, frame int) (*bytes.Reader, error) { 34 | tmp, _ := os.Create("tmp.mp4") 35 | tmp.Write(data) 36 | tmp.Close() 37 | 38 | pngBuffer := bytes.NewBuffer(nil) 39 | err := ffmpeg.Input("tmp.mp4").Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frame)}). 40 | Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}). 41 | WithOutput(pngBuffer).Run() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | return bytes.NewReader(pngBuffer.Bytes()), nil 47 | } 48 | 49 | func uploadFile(client *minio.Client, reader *bytes.Reader, fileName string, bucket string, contentType string) (string, error) { 50 | _, err := client.PutObject(context.Background(), 51 | bucket, fileName, reader, reader.Size(), minio.PutObjectOptions{}) 52 | if err != nil { 53 | logger.Errorf("Fail to upload file, name: %v, err: %v", fileName, err) 54 | return "", err 55 | } 56 | 57 | url := fmt.Sprintf("http://192.168.10.2:9000/%s/%s", bucket, fileName) 58 | 59 | logger.InfoF("Success to upload object to minio, fileName: %v, url: %v", fileName, url) 60 | return url, nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/minio-client/internal/server/minioclientserver.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: minio-client.proto 3 | 4 | package server 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/minio-client/internal/logic" 10 | "douyin/pkg/minio-client/internal/svc" 11 | "douyin/pkg/minio-client/types/minio-client" 12 | ) 13 | 14 | type MinIOClientServer struct { 15 | svcCtx *svc.ServiceContext 16 | minio_client.UnimplementedMinIOClientServer 17 | } 18 | 19 | func NewMinIOClientServer(svcCtx *svc.ServiceContext) *MinIOClientServer { 20 | return &MinIOClientServer{ 21 | svcCtx: svcCtx, 22 | } 23 | } 24 | 25 | func (s *MinIOClientServer) UploadFile(ctx context.Context, in *minio_client.UploadFileRequest) (*minio_client.UploadFileReply, error) { 26 | l := logic.NewUploadFileLogic(ctx, s.svcCtx) 27 | return l.UploadFile(in) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/minio-client/internal/svc/servicecontext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import "douyin/pkg/minio-client/internal/config" 4 | 5 | type ServiceContext struct { 6 | Config config.Config 7 | } 8 | 9 | func NewServiceContext(c config.Config) *ServiceContext { 10 | return &ServiceContext{ 11 | Config: c, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/minio-client/minioclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | 7 | "douyin/pkg/minio-client/internal/config" 8 | "douyin/pkg/minio-client/internal/server" 9 | "douyin/pkg/minio-client/internal/svc" 10 | "douyin/pkg/minio-client/types/minio-client" 11 | 12 | "github.com/zeromicro/go-zero/core/conf" 13 | "github.com/zeromicro/go-zero/core/service" 14 | "github.com/zeromicro/go-zero/zrpc" 15 | "google.golang.org/grpc" 16 | "google.golang.org/grpc/reflection" 17 | ) 18 | 19 | var configFile = flag.String("f", "etc/minioclient.yaml", "the config file") 20 | 21 | func main() { 22 | flag.Parse() 23 | 24 | var c config.Config 25 | conf.MustLoad(*configFile, &c) 26 | ctx := svc.NewServiceContext(c) 27 | 28 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { 29 | minio_client.RegisterMinIOClientServer(grpcServer, server.NewMinIOClientServer(ctx)) 30 | 31 | if c.Mode == service.DevMode || c.Mode == service.TestMode { 32 | reflection.Register(grpcServer) 33 | } 34 | }) 35 | defer s.Stop() 36 | 37 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) 38 | s.Start() 39 | } 40 | -------------------------------------------------------------------------------- /pkg/minio-client/minioclient/minioclient.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | // Source: minio-client.proto 3 | 4 | package minioclient 5 | 6 | import ( 7 | "context" 8 | 9 | "douyin/pkg/minio-client/types/minio-client" 10 | 11 | "github.com/zeromicro/go-zero/zrpc" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | type ( 16 | UploadFileReply = minio_client.UploadFileReply 17 | UploadFileRequest = minio_client.UploadFileRequest 18 | 19 | MinIOClient interface { 20 | UploadFile(ctx context.Context, in *UploadFileRequest, opts ...grpc.CallOption) (*UploadFileReply, error) 21 | } 22 | 23 | defaultMinIOClient struct { 24 | cli zrpc.Client 25 | } 26 | ) 27 | 28 | func NewMinIOClient(cli zrpc.Client) MinIOClient { 29 | return &defaultMinIOClient{ 30 | cli: cli, 31 | } 32 | } 33 | 34 | func (m *defaultMinIOClient) UploadFile(ctx context.Context, in *UploadFileRequest, opts ...grpc.CallOption) (*UploadFileReply, error) { 35 | client := minio_client.NewMinIOClientClient(m.cli.Conn()) 36 | return client.UploadFile(ctx, in, opts...) 37 | } 38 | -------------------------------------------------------------------------------- /pkg/minio-client/proto/minio-client.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package minio_client; 4 | 5 | option go_package="./minio-client"; 6 | 7 | message UploadFileRequest { 8 | bytes data = 1; // 视频数据 9 | string title = 2; // 视频名称(也是路径direction/filename) 10 | } 11 | 12 | message UploadFileReply { 13 | bool success = 1; 14 | string videoUrl = 2; 15 | string frontImgUrl = 3; 16 | } 17 | 18 | service MinIOClient { 19 | rpc UploadFile(UploadFileRequest) returns(UploadFileReply); 20 | } 21 | -------------------------------------------------------------------------------- /pkg/mq/etc/mq.yaml: -------------------------------------------------------------------------------- 1 | Name: mq 2 | Host: 0.0.0.0 3 | Port: 3001 4 | Mode: dev 5 | 6 | UserCommentOptServiceConf: 7 | Name: UserCommentOptService 8 | Brokers: 9 | - kafka.kafka.svc.cluster.local:9092 10 | Group: UserCommentOptService-group 11 | Topic: UserCommentOptService-topic 12 | Offset: first 13 | Consumers: 1 14 | Processors: 1 15 | 16 | UserFollowOptServiceConf: 17 | Name: UserFollowOptService 18 | Brokers: 19 | - kafka.kafka.svc.cluster.local:9092 20 | Group: UserFollowOptService-group 21 | Topic: UserFollowOptService-topic 22 | Offset: first 23 | Consumers: 1 24 | Processors: 1 25 | 26 | UserFavoriteOptServiceConf: 27 | Name: UserFavoriteOptService 28 | Brokers: 29 | - kafka.kafka.svc.cluster.local:9092 30 | Group: UserFavoriteOptService-group 31 | Topic: UserFavoriteOptService-topic 32 | Offset: first 33 | Consumers: 1 34 | Processors: 1 35 | 36 | UserCommentRpc: 37 | Etcd: 38 | Hosts: 39 | - etcd.etcd.svc.cluster.local:2379 40 | Key: usercomment.rpc 41 | NonBlock: true 42 | 43 | UserFavoriteRpc: 44 | Etcd: 45 | Hosts: 46 | - etcd.etcd.svc.cluster.local:2379 47 | Key: useropt.rpc 48 | 49 | UserFollowRpc: 50 | Etcd: 51 | Hosts: 52 | - etcd.etcd.svc.cluster.local:2379 53 | Key: follow.rpc 54 | 55 | RedisCacheConf: 56 | Host: redis-master.redis.svc.cluster.local:6379 57 | Pass: redispwd123 58 | -------------------------------------------------------------------------------- /pkg/mq/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-queue/kq" 5 | "github.com/zeromicro/go-zero/core/service" 6 | "github.com/zeromicro/go-zero/core/stores/redis" 7 | "github.com/zeromicro/go-zero/zrpc" 8 | ) 9 | 10 | type Config struct { 11 | service.ServiceConf 12 | 13 | // redis 14 | RedisCacheConf redis.RedisConf 15 | 16 | // kq : pub sub 17 | UserCommentOptServiceConf kq.KqConf 18 | UserFavoriteOptServiceConf kq.KqConf 19 | UserFollowOptServiceConf kq.KqConf 20 | 21 | // rpc 22 | UserCommentRpc zrpc.RpcClientConf 23 | UserFavoriteRpc zrpc.RpcClientConf 24 | UserFollowRpc zrpc.RpcClientConf 25 | } 26 | -------------------------------------------------------------------------------- /pkg/mq/internal/listen/kqMqs.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/mq/internal/config" 6 | kqMq "douyin/pkg/mq/internal/mqs/kq" 7 | "douyin/pkg/mq/internal/svc" 8 | "github.com/zeromicro/go-queue/kq" 9 | "github.com/zeromicro/go-zero/core/service" 10 | ) 11 | 12 | // pub sub use kq (kafka) 13 | func KqMqs(c config.Config, ctx context.Context, svcContext *svc.ServiceContext) []service.Service { 14 | 15 | return []service.Service{ 16 | //Listening for changes in consumption flow status 17 | kq.MustNewQueue(c.UserCommentOptServiceConf, kqMq.NewUserCommentUpdateMq(ctx, svcContext)), 18 | kq.MustNewQueue(c.UserFavoriteOptServiceConf, kqMq.NewUserFavoriteUpdateMq(ctx, svcContext)), 19 | kq.MustNewQueue(c.UserFollowOptServiceConf, kqMq.NewUserFollowUpdateMq(ctx, svcContext)), 20 | //..... 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /pkg/mq/internal/listen/listen.go: -------------------------------------------------------------------------------- 1 | package listen 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/mq/internal/config" 6 | "douyin/pkg/mq/internal/svc" 7 | 8 | "github.com/zeromicro/go-zero/core/service" 9 | ) 10 | 11 | // back to all consumers 12 | func Mqs(c config.Config) []service.Service { 13 | 14 | svcContext := svc.NewServiceContext(c) 15 | ctx := context.Background() 16 | 17 | var services []service.Service 18 | 19 | //kq :pub sub 20 | services = append(services, KqMqs(c, ctx, svcContext)...) 21 | 22 | return services 23 | } 24 | -------------------------------------------------------------------------------- /pkg/mq/internal/mqs/kq/userCommentUpdate.go: -------------------------------------------------------------------------------- 1 | package kq 2 | 3 | import ( 4 | "context" 5 | "douyin/common/messageTypes" 6 | "douyin/pkg/comment/usercomment" 7 | "douyin/pkg/mq/internal/svc" 8 | "encoding/json" 9 | "fmt" 10 | "github.com/pkg/errors" 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | /* 15 | Listening to the payment flow status change notification message queue 16 | */ 17 | type UserCommentOpt struct { 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewUserCommentUpdateMq(ctx context.Context, svcCtx *svc.ServiceContext) *UserCommentOpt { 23 | return &UserCommentOpt{ 24 | ctx: ctx, 25 | svcCtx: svcCtx, 26 | } 27 | } 28 | 29 | func (l *UserCommentOpt) Consume(_, val string) error { 30 | var message messageTypes.UserCommentOptMessage 31 | if err := json.Unmarshal([]byte(val), &message); err != nil { 32 | logx.WithContext(l.ctx).Error("UserCommentOptMessage->Consume Unmarshal err : %v , val : %s", err, val) 33 | return err 34 | } 35 | 36 | if err := l.execService(message); err != nil { 37 | logx.WithContext(l.ctx).Error("UserCommentOptMessage->execService err : %v , val : %s , message:%+v", err, val, message) 38 | return err 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // 处理逻辑 45 | func (l *UserCommentOpt) execService(message messageTypes.UserCommentOptMessage) error { 46 | fmt.Printf("消费者开始消费------------------------------\n") 47 | if message.ActionType != messageTypes.ActionADD && message.ActionType != messageTypes.ActionCancel { 48 | return errors.New("UserCommentOptMessage->execService getActionType err") 49 | } 50 | 51 | // 调用rpc 更新user_comment表 52 | _, err := l.svcCtx.UserCommentRpc.UpdateCommentStatus(l.ctx, &usercomment.UpdateCommentStatusReq{ 53 | VideoId: message.VideoId, 54 | UserId: message.UserId, 55 | Content: message.CommentText, 56 | CommentId: message.CommentId, 57 | ActionType: message.ActionType, 58 | }) 59 | 60 | if err != nil { 61 | logx.Errorf("UserCommentOptMessage->execService err : %v , val : %s , message:%+v", err, message) 62 | return err 63 | } 64 | fmt.Printf("消费者消费成功------------------------------\n") 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/mq/internal/mqs/kq/userFavoriteUpdate.go: -------------------------------------------------------------------------------- 1 | package kq 2 | 3 | import ( 4 | "context" 5 | "douyin/common/messageTypes" 6 | "douyin/pkg/favorite/useroptservice" 7 | "douyin/pkg/mq/internal/svc" 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | /* 15 | Listening to the payment flow status change notification message queue 16 | */ 17 | type UserFavoriteOpt struct { 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewUserFavoriteUpdateMq(ctx context.Context, svcCtx *svc.ServiceContext) *UserFavoriteOpt { 23 | return &UserFavoriteOpt{ 24 | ctx: ctx, 25 | svcCtx: svcCtx, 26 | } 27 | } 28 | 29 | func (l *UserFavoriteOpt) Consume(_, val string) error { 30 | var message messageTypes.UserFavoriteOptMessage 31 | 32 | if err := json.Unmarshal([]byte(val), &message); err != nil { 33 | logx.WithContext(l.ctx).Error("UserFavoriteOptMessage->Consume Unmarshal err : %v , val : %s", err, val) 34 | return err 35 | } 36 | 37 | if err := l.execService(message); err != nil { 38 | logx.WithContext(l.ctx).Error("UserFavoriteOptMessage->execService err : %v , val : %s , message:%+v", err, val, message) 39 | logx.Errorf("UserFavoriteOptMessage->execService err : %v , val : %s , message:%+v", err, val, message) 40 | return err 41 | } 42 | return nil 43 | } 44 | 45 | // 处理逻辑 46 | func (l *UserFavoriteOpt) execService(message messageTypes.UserFavoriteOptMessage) error { 47 | fmt.Printf("消费者开始消费------------------------------\n") 48 | if message.ActionType != messageTypes.ActionADD && message.ActionType != messageTypes.ActionCancel { 49 | return errors.New("UserCommentOptMessage->execService getActionType err") 50 | } 51 | 52 | _, err := l.svcCtx.UserFavoriteRpc.UpdateFavoriteStatus(l.ctx, &useroptservice.UpdateFavoriteStatusReq{ 53 | VideoId: message.VideoId, 54 | UserId: message.UserId, 55 | ActionType: message.ActionType, 56 | }) 57 | 58 | if err != nil { 59 | logx.Errorf("UserCommentOptMessage->execService err : %v , val : %s , message:%+v", err, message) 60 | return err 61 | } 62 | fmt.Printf("消费者消费成功------------------------------\n") 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/mq/internal/mqs/kq/userFollowUpdate.go: -------------------------------------------------------------------------------- 1 | package kq 2 | 3 | import ( 4 | "context" 5 | "douyin/common/messageTypes" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/mq/internal/svc" 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | /* 15 | Listening to the payment flow status change notification message queue 16 | */ 17 | type UserFollowOpt struct { 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewUserFollowUpdateMq(ctx context.Context, svcCtx *svc.ServiceContext) *UserFollowOpt { 23 | return &UserFollowOpt{ 24 | ctx: ctx, 25 | svcCtx: svcCtx, 26 | } 27 | } 28 | 29 | func (l *UserFollowOpt) Consume(_, val string) error { 30 | var message messageTypes.UserFollowOptMessage 31 | 32 | if err := json.Unmarshal([]byte(val), &message); err != nil { 33 | logx.WithContext(l.ctx).Error("UserFollowOptMessage->Consume Unmarshal err : %v , val : %s", err, val) 34 | return err 35 | } 36 | 37 | if err := l.execService(message); err != nil { 38 | logx.WithContext(l.ctx).Error("UserFollowOptMessage->execService err : %v , val : %s , message:%+v", err, val, message) 39 | logx.Errorf("UserFollowOptMessage->execService err : %v , val : %s , message:%+v", err, val, message) 40 | return err 41 | } 42 | return nil 43 | } 44 | 45 | // 处理逻辑 46 | func (l *UserFollowOpt) execService(message messageTypes.UserFollowOptMessage) error { 47 | if message.ActionType != messageTypes.ActionADD && message.ActionType != messageTypes.ActionCancel { 48 | return errors.New("UserCommentOptMessage->execService getActionType err") 49 | } 50 | 51 | _, err := l.svcCtx.UserFollowRPC.Follow(l.ctx, &followservice.FollowReq{ 52 | ToUserId: message.ToUserId, 53 | ActionType: message.ActionType, 54 | UserId: message.UserId, 55 | }) 56 | 57 | if err != nil { 58 | logx.Errorf("UserFollowOptMessage->execService err : %v , val : %s , message:%+v", err, message) 59 | return err 60 | } 61 | fmt.Printf("消费者消费成功------------------------------\n") 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/mq/internal/svc/serviceContext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "douyin/pkg/comment/usercomment" 5 | "douyin/pkg/favorite/useroptservice" 6 | "douyin/pkg/follow/followservice" 7 | "douyin/pkg/mq/internal/config" 8 | "github.com/zeromicro/go-zero/zrpc" 9 | ) 10 | 11 | type ServiceContext struct { 12 | Config config.Config 13 | UserCommentRpc usercomment.UserComment 14 | UserFavoriteRpc useroptservice.UserOptService 15 | UserFollowRPC followservice.FollowService 16 | } 17 | 18 | func NewServiceContext(c config.Config) *ServiceContext { 19 | return &ServiceContext{ 20 | Config: c, 21 | UserCommentRpc: usercomment.NewUserComment(zrpc.MustNewClient(c.UserCommentRpc)), 22 | UserFavoriteRpc: useroptservice.NewUserOptService(zrpc.MustNewClient(c.UserFavoriteRpc)), 23 | UserFollowRPC: followservice.NewFollowService(zrpc.MustNewClient(c.UserFollowRpc)), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkg/mq/mq.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "douyin/pkg/mq/internal/config" 5 | "douyin/pkg/mq/internal/listen" 6 | "flag" 7 | "github.com/zeromicro/go-zero/core/conf" 8 | "github.com/zeromicro/go-zero/core/service" 9 | ) 10 | 11 | var configFile = flag.String("f", "etc/mq.yaml", "Specify the config file") 12 | 13 | func main() { 14 | flag.Parse() 15 | var c config.Config 16 | 17 | conf.MustLoad(*configFile, &c) 18 | 19 | // log、prometheus、trace、metricsUrl. 20 | if err := c.SetUp(); err != nil { 21 | panic(err) 22 | } 23 | 24 | serviceGroup := service.NewServiceGroup() 25 | defer serviceGroup.Stop() 26 | for _, mq := range listen.Mqs(c) { 27 | serviceGroup.Add(mq) 28 | } 29 | 30 | serviceGroup.Start() 31 | } 32 | -------------------------------------------------------------------------------- /pkg/sql/01_test.go: -------------------------------------------------------------------------------- 1 | package pack 2 | 3 | import ( 4 | "context" 5 | "douyin/pkg/sql/dal/model" 6 | "douyin/pkg/sql/dal/query" 7 | "douyin/pkg/sql/pack" 8 | "testing" 9 | ) 10 | 11 | func TestTransaction(t *testing.T) { 12 | db := pack.GetConn() 13 | q := pack.GetQuery(db) 14 | 15 | err := q.Transaction(func(tx *query.Query) error { 16 | e := tx.WithContext(context.Background()).Chat.Create( 17 | &model.Chat{ 18 | Sender: 1, 19 | Receiver: 2, 20 | Msg: "hahahah"}, 21 | ) 22 | if e != nil { 23 | return e 24 | } 25 | 26 | e = tx.Video.WithContext(context.Background()).Create(&model.Video{ 27 | Title: "let other all be null, coming error?", 28 | }) 29 | // no error will be a error 30 | if e == nil { 31 | return e 32 | } 33 | 34 | return nil 35 | }) 36 | pack.Check(err) 37 | 38 | } 39 | 40 | func TestWithHandle(t *testing.T) { 41 | // User 42 | db := pack.GetConn() 43 | { 44 | icd := pack.GetIChatDO(db) 45 | icd.Create(&model.Chat{ 46 | Msg: "[01_test::TestWithHandle]", 47 | Sender: 1, 48 | Receiver: 2, 49 | }) 50 | 51 | Chats, err := icd.FindByReceiver(2) 52 | check(err, t) 53 | 54 | bFound := false 55 | for _, chat := range Chats { 56 | if chat.Msg == "[01_test::TestWithHandle]" && 57 | chat.Sender == 1 && 58 | chat.Receiver == 2 { 59 | bFound = true 60 | break 61 | } 62 | } 63 | if !bFound { 64 | t.Error("Did not find the message that I send!!!!") 65 | } 66 | 67 | } 68 | } 69 | 70 | func check(e error, t *testing.T) { 71 | if e != nil { 72 | t.Error(e) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pkg/sql/README.md: -------------------------------------------------------------------------------- 1 | # package sql 2 | 3 | > Query methods were defined in `pkg/dal/methos.go` 4 | 5 | > Please rerun `make mysql-regenerate-codes` or `cmd/mysqlgen/gen.go` to update codes 6 | 7 | You can get the specific `handle` of a table, or a raw `query` from pack. 8 | 9 | For more infos, see tests. 10 | 11 | 12 | -------------------------------------------------------------------------------- /pkg/sql/dal/dal.go: -------------------------------------------------------------------------------- 1 | package dal 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | 7 | constantx "douyin/pkg/constant" 8 | 9 | "gorm.io/driver/mysql" 10 | "gorm.io/gorm" 11 | ) 12 | 13 | var DBI *gorm.DB 14 | var once sync.Once 15 | 16 | func init() { 17 | once.Do(func() { 18 | DBI = ConnectDB() 19 | err := DBI.AutoMigrate() 20 | if err != nil { 21 | panic(err) 22 | } 23 | }) 24 | } 25 | 26 | func ConnectDB() (conn *gorm.DB) { 27 | conn, err := gorm.Open(mysql.Open(constantx.MYSQL_Dsn), &gorm.Config{ 28 | SkipDefaultTransaction: constantx.MYSQL_SkipDefaultTransaction, // close default tx 29 | PrepareStmt: constantx.MYSQL_PrepareStmt, // cache precompile sentence 30 | }) 31 | if err != nil { 32 | panic(fmt.Errorf("cannot setup db conn: %v", err)) 33 | } 34 | if conn == nil { 35 | panic("conn is null") 36 | } 37 | return conn 38 | } 39 | -------------------------------------------------------------------------------- /pkg/sql/dal/method.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | 4 | @Desc: Define your sql methods here 5 | 6 | * 7 | */ 8 | package dal 9 | 10 | import ( 11 | "time" 12 | 13 | "gorm.io/gen" 14 | ) 15 | 16 | type DefaultMethod interface { 17 | 18 | // sql(select * from @@table) 19 | FindAll() ([]gen.T, error) 20 | 21 | // Where("id=@id") 22 | FindById(id uint) (gen.T, error) 23 | 24 | // Where("removed=@removed") 25 | FindByRemoved(removed uint) ([]gen.T, error) 26 | } 27 | 28 | type UserMethod interface { 29 | 30 | // Where("username=@username") 31 | FindByUsernmae(username string) ([]gen.T, error) 32 | 33 | // Where("type=@theType") 34 | FindByType(theType uint) ([]gen.T, error) 35 | 36 | // Where("enable=@enable") 37 | FindByEnable(enable uint) ([]gen.T, error) 38 | } 39 | 40 | type ChatMethod interface { 41 | 42 | // Where("sender=@sender") 43 | FindBySender(sender uint) ([]gen.T, error) 44 | 45 | // Where("receiver=@receiver") 46 | FindByReceiver(receiver uint) ([]gen.T, error) 47 | 48 | // Where("sender=@userId or receiver=@userId") 49 | FindMessageByUserId(userId uint) ([]gen.T, error) 50 | } 51 | 52 | type FollowMethod interface { 53 | 54 | // Where("user_id=@userId") 55 | FindFolloweesByUserId(userId uint) ([]gen.T, error) 56 | 57 | // Where("fun_id=@userId") 58 | FindFollowersByUserId(userId uint) ([]gen.T, error) 59 | } 60 | 61 | type VideoMethod interface { 62 | // Where("user_id=@userId") 63 | FindByAuthor(userId uint) ([]gen.T, error) 64 | 65 | // Where("play_url=@playUrl") 66 | FindByPlayUrl(playUrl string) (gen.T, error) 67 | 68 | // Where("time=@time") 69 | FindByTime(time uint) ([]gen.T, error) 70 | // Where("time>=@time") 71 | FindByTimeLongerThan(time uint) ([]gen.T, error) 72 | 73 | // where("title=@title or title like @title") 74 | FindByTitle(title string) ([]gen.T, error) 75 | } 76 | 77 | type CommentMethod interface { 78 | 79 | // where("user_id=@userId") 80 | FindByUserId(userId uint) ([]gen.T, error) 81 | 82 | // Where("video_id=@videoId") 83 | FindByVideoId(videoId uint) ([]gen.T, error) 84 | 85 | // Where("create_time >= @createTime") 86 | FindNewerThanCreateTime(createTime *time.Time) 87 | 88 | // Where("deleted=@deleted") 89 | FindByDeleted(deleted uint) ([]gen.T, error) 90 | } 91 | 92 | type FavoriteMethod interface { 93 | // where("user_id=@userId") 94 | FindByUserId(userId uint) ([]gen.T, error) 95 | 96 | // Where("video_id=@videoId") 97 | FindByVideoId(videoId uint) ([]gen.T, error) 98 | } 99 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/chat.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | import ( 8 | "time" 9 | ) 10 | 11 | const TableNameChat = "chat" 12 | 13 | // Chat mapped from table 14 | type Chat struct { 15 | ID uint `gorm:"column:id;type:int;primaryKey;autoIncrement:true" json:"id"` 16 | Msg string `gorm:"column:msg;type:text;not null" json:"msg"` 17 | Sender uint `gorm:"column:sender;type:int;not null" json:"sender"` 18 | Receiver uint `gorm:"column:receiver;type:int;not null" json:"receiver"` 19 | Createtime time.Time `gorm:"column:createtime;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"createtime"` 20 | } 21 | 22 | // TableName Chat's table name 23 | func (*Chat) TableName() string { 24 | return TableNameChat 25 | } 26 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/comment.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | import ( 8 | "time" 9 | ) 10 | 11 | const TableNameComment = "comment" 12 | 13 | // Comment mapped from table 14 | type Comment struct { 15 | ID uint `gorm:"column:id;type:int;primaryKey;autoIncrement:true" json:"id"` 16 | UserID uint `gorm:"column:user_id;type:int;not null" json:"user_id"` 17 | VideoID uint `gorm:"column:video_id;type:int;not null" json:"video_id"` 18 | CreateTime time.Time `gorm:"column:create_time;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"create_time"` 19 | Removed uint `gorm:"column:removed;type:tinyint;not null" json:"removed"` 20 | Deleted uint `gorm:"column:deleted;type:tinyint;not null" json:"deleted"` 21 | Content string `gorm:"column:content;type:text;not null" json:"content"` 22 | } 23 | 24 | // TableName Comment's table name 25 | func (*Comment) TableName() string { 26 | return TableNameComment 27 | } 28 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/favorite.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | const TableNameFavorite = "favorite" 8 | 9 | // Favorite mapped from table 10 | type Favorite struct { 11 | ID uint `gorm:"column:id;type:int;primaryKey;autoIncrement:true" json:"id"` 12 | VideoID uint `gorm:"column:video_id;type:int;not null" json:"video_id"` 13 | UserID uint `gorm:"column:user_id;type:int;not null" json:"user_id"` 14 | Removed uint `gorm:"column:removed;type:tinyint;not null" json:"removed"` 15 | } 16 | 17 | // TableName Favorite's table name 18 | func (*Favorite) TableName() string { 19 | return TableNameFavorite 20 | } 21 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/follow.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | const TableNameFollow = "follow" 8 | 9 | // Follow mapped from table 10 | type Follow struct { 11 | ID uint `gorm:"column:id;type:int;primaryKey;autoIncrement:true" json:"id"` 12 | UserID uint `gorm:"column:user_id;type:int" json:"user_id"` 13 | FunID uint `gorm:"column:fun_id;type:int;not null" json:"fun_id"` 14 | Removed uint `gorm:"column:removed;type:tinyint;not null" json:"removed"` 15 | Msg string `gorm:"column:msg;type:text" json:"msg"` 16 | } 17 | 18 | // TableName Follow's table name 19 | func (*Follow) TableName() string { 20 | return TableNameFollow 21 | } 22 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/user.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | import ( 8 | "time" 9 | ) 10 | 11 | const TableNameUser = "user" 12 | 13 | // User mapped from table 14 | type User struct { 15 | ID uint `gorm:"column:id;type:int;primaryKey;autoIncrement:true" json:"id"` 16 | Username string `gorm:"column:username;type:varchar(32);not null" json:"username"` 17 | Password string `gorm:"column:password;type:varchar(32);not null" json:"password"` 18 | Enable uint `gorm:"column:enable;type:tinyint;default:1" json:"enable"` 19 | Type uint `gorm:"column:type;type:tinyint;not null" json:"type"` 20 | LoginTime time.Time `gorm:"column:login_time;type:datetime;default:CURRENT_TIMESTAMP" json:"login_time"` 21 | CreateTime time.Time `gorm:"column:create_time;type:timestamp;default:CURRENT_TIMESTAMP" json:"create_time"` 22 | } 23 | 24 | // TableName User's table name 25 | func (*User) TableName() string { 26 | return TableNameUser 27 | } 28 | -------------------------------------------------------------------------------- /pkg/sql/dal/model/video.gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by gorm.io/gen. DO NOT EDIT. 2 | // Code generated by gorm.io/gen. DO NOT EDIT. 3 | // Code generated by gorm.io/gen. DO NOT EDIT. 4 | 5 | package model 6 | 7 | const TableNameVideo = "video" 8 | 9 | // Video mapped from table