Viviman
2 months ago
commit
77744424ad
553 changed files with 79308 additions and 0 deletions
@ -0,0 +1,15 @@ |
|||||
|
.vscode/ |
||||
|
.idea/ |
||||
|
hbase-data/ |
||||
|
hbase-2.1.3/ |
||||
|
hbase-zoo-data/ |
||||
|
*_data/ |
||||
|
tmp |
||||
|
log |
||||
|
zip |
||||
|
|
||||
|
__debug* |
||||
|
applications/api/docs/swagger.yaml |
||||
|
|
||||
|
go.sum |
||||
|
/.github/ |
@ -0,0 +1,164 @@ |
|||||
|
linters: |
||||
|
disable-all: true # 关闭其他linter |
||||
|
enable: |
||||
|
# 进制使用非ASCII字符 |
||||
|
- asciicheck |
||||
|
- bidichk |
||||
|
# 降低代码复杂度 |
||||
|
- cyclop |
||||
|
- gocognit |
||||
|
- gocyclo |
||||
|
- maintidx |
||||
|
# 高可拓展性的go源码linter |
||||
|
- gocritic |
||||
|
# 禁止保留未使用的代码块 |
||||
|
#--------------------------------------- |
||||
|
#- deadcode |
||||
|
# The linter 'deadcode' is deprecated (since v1.49.0) due to: The owner seems to have abandoned the linter |
||||
|
# 新版本的linter已经不建议使用deadcode了,不使用的代码不会被报错了 |
||||
|
#--------------------------------------- |
||||
|
- ineffassign |
||||
|
# 减少代码拷贝 |
||||
|
- dupl |
||||
|
# 禁止两个time.Duration类型相乘 |
||||
|
- durationcheck |
||||
|
# 所有err都要处理 |
||||
|
- errcheck |
||||
|
# 在Go 1.13之后使用errors.Wrap可能导致的问题 |
||||
|
- errorlint |
||||
|
# 检查switch的全面性,以免遗漏场景 |
||||
|
- exhaustive |
||||
|
# 禁止将for-range value的指针暴露给外部 |
||||
|
- exportloopref |
||||
|
# 禁止使用特定的标识符 |
||||
|
- forbidigo |
||||
|
# 禁止出现长函数 |
||||
|
- funlen |
||||
|
# 控制golang的包引用的顺序 |
||||
|
- gci |
||||
|
# 禁止使用全局变量 --需要使用 //nolint:gochecknoglobals // 说明原因 |
||||
|
- gochecknoglobals |
||||
|
# 禁止使用init函数 |
||||
|
- gochecknoinits |
||||
|
# 如果有相同的string变量请使用consts替换 |
||||
|
- goconst |
||||
|
# 检查if语句是否有简单的语法 |
||||
|
- ifshort |
||||
|
# 禁止出现长语句 |
||||
|
- lll |
||||
|
# struct禁止包含context.Context字段 |
||||
|
- containedctx |
||||
|
# 返回两个参数,一个数据,一个是err,禁止两个都是nil |
||||
|
- nilnil |
||||
|
# 禁止使用Sprintf去构造URL中的host和port |
||||
|
- nosprintfhostport |
||||
|
# 如果知道slice大小,定义时需分配空间 |
||||
|
- prealloc |
||||
|
# 检查prometheus meteics的指标名是否规范 |
||||
|
- promlinter |
||||
|
# 强制要求const/import/var在一个组 |
||||
|
- grouper |
||||
|
# 检查go1.17的版本是否使用os.Setenv替换t.Setenv |
||||
|
- tenv |
||||
|
# 检查变量名长度 |
||||
|
- varnamelen |
||||
|
# 强制一致性的impotr别名 |
||||
|
- importas |
||||
|
# 类型断言时需检查是否成功 |
||||
|
- forcetypeassert |
||||
|
# 保证类型、常量、变量和函数的声明顺序和数量 |
||||
|
- decorder |
||||
|
# 检查err的定义规范--types类型的定义是以Error结尾的,常量的定义是Err打头的 |
||||
|
- errname |
||||
|
# SQL Query方法错误检查 |
||||
|
- execinquery |
||||
|
# 禁止errors使用'=='和'!='等表达式--与nil和io.EOF比较除外 |
||||
|
- goerr113 |
||||
|
# 官方代码格式化 |
||||
|
- gofmt |
||||
|
- gofumpt |
||||
|
- goimports |
||||
|
# 禁止使用魔法数字 |
||||
|
- gomnd |
||||
|
# 检查依赖的黑白名单 |
||||
|
- gomodguard |
||||
|
# 检查类似printf的函数是否以f结尾 |
||||
|
- goprintffuncname |
||||
|
# 安全检查 |
||||
|
- gosec |
||||
|
# 官方错误检查 |
||||
|
- govet |
||||
|
# 检查拼写错误 |
||||
|
- misspell |
||||
|
# 如果函数过长,禁用裸返回 |
||||
|
- nakedret |
||||
|
# 禁止深度嵌套的if语句 |
||||
|
- nestif |
||||
|
# 如果使用nolint指令需要给出理由-- //nolint:gochecknoglobals // 原因 |
||||
|
- nolintlint |
||||
|
# 禁止使用Go关键字命名 |
||||
|
- predeclared |
||||
|
# 去掉没有必要的type转换 |
||||
|
- unconvert |
||||
|
# 强制使用空行 |
||||
|
- wsl |
||||
|
# 检查文件头部和尾部的换行 |
||||
|
- whitespace |
||||
|
# 替换golint的 |
||||
|
- revive |
||||
|
# 测试代码使用*_test的包目录 |
||||
|
- testpackage |
||||
|
# 启用并行测试 |
||||
|
- paralleltest |
||||
|
# 检查帮助函数里面有没有调用t.Helper()函数 |
||||
|
- thelper |
||||
|
linters-settings: |
||||
|
errcheck: |
||||
|
check-type-assertions: true # 检查类型断言 |
||||
|
check-blank: true # 检查使用 _ 来处理错误 |
||||
|
errorlint: |
||||
|
errorf: true # 检查fmt.Errorf错误是否用%w |
||||
|
exhaustive: |
||||
|
check-generated: false # 不检查生成的文件 |
||||
|
default-signifies-exhaustive: false # 不检查是否有default |
||||
|
funlen: |
||||
|
lines: 65 # 一个函数总行数限制 |
||||
|
statements: 40 # 检查函数中语句的数量 |
||||
|
gci: |
||||
|
sections: |
||||
|
- standard # 标准库 |
||||
|
- default # 默认按字典顺序排序 |
||||
|
- prefix(cos/lobbyplatform) # 特殊前缀的包 |
||||
|
gomodguard: # 检查依赖的黑白名单 |
||||
|
allowed: |
||||
|
# List of allowed modules. |
||||
|
# Default: [] |
||||
|
modules: |
||||
|
- gopkg.in/yaml.v2 |
||||
|
# List of allowed module domains. |
||||
|
# Default: [] |
||||
|
domains: |
||||
|
- golang.org |
||||
|
blocked: |
||||
|
# List of blocked modules. |
||||
|
# Default: [] |
||||
|
modules: |
||||
|
# Blocked module. |
||||
|
- github.com/uudashr/go-module: |
||||
|
# Recommended modules that should be used instead. (Optional) |
||||
|
recommendations: |
||||
|
- golang.org/x/mod |
||||
|
# Reason why the recommended module should be used. (Optional) |
||||
|
reason: "`mod` is the official go.mod parser library." |
||||
|
# List of blocked module version constraints. |
||||
|
# Default: [] |
||||
|
versions: |
||||
|
# Blocked module with version constraint. |
||||
|
- github.com/mitchellh/go-homedir: |
||||
|
# Version constraint, see https://github.com/Masterminds/semver#basic-comparisons. |
||||
|
version: "< 1.1.0" |
||||
|
# Reason why the version constraint exists. (Optional) |
||||
|
reason: "testing if blocked version constraint works." |
||||
|
# Set to true to raise lint issues for packages that are loaded from a local path via replace directive. |
||||
|
# Default: false |
||||
|
local_replace_directives: false |
@ -0,0 +1,26 @@ |
|||||
|
# How to contribute |
||||
|
|
||||
|
## Issue & Discussion |
||||
|
|
||||
|
Any issues and discussions are welcome. Feel free for submit an issue or open a discussion. |
||||
|
|
||||
|
If you want to submit an issue, we suggest that use the given issue templates. Of course, you can also submit one without any templates or using any other templates. The first goal is to make everyone understand your ideas. |
||||
|
|
||||
|
## Pull Request |
||||
|
|
||||
|
We use git-flow as our branch organization, as known as FDD. |
||||
|
|
||||
|
At least, if you want to open a pull request you should follow these steps: |
||||
|
|
||||
|
1. Fork the repository |
||||
|
2. Create a new branch |
||||
|
3. Do something & write some code |
||||
|
4. Commit and push |
||||
|
5. Open a pull request |
||||
|
|
||||
|
For a better flow to manage PRs, we suggest that: |
||||
|
|
||||
|
1. Use the given PR templates |
||||
|
2. Use `rebase` to resolve conflicts |
||||
|
3. Submit as few commit as possible in a PR |
||||
|
4. Use a linter to check code before open a PR |
@ -0,0 +1,27 @@ |
|||||
|
FROM golang:1.18-alpine3.16 AS builder |
||||
|
|
||||
|
ARG target |
||||
|
ENV target=${target} |
||||
|
|
||||
|
ARG proxy=https://proxy.golang.org |
||||
|
ENV proxy=${proxy} |
||||
|
RUN echo ${proxy} |
||||
|
|
||||
|
WORKDIR /build |
||||
|
|
||||
|
ENV GOPROXY ${proxy} |
||||
|
COPY go.mod . |
||||
|
COPY go.sum . |
||||
|
RUN go mod download |
||||
|
|
||||
|
COPY . . |
||||
|
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -a -o serve ./applications/${target}/ |
||||
|
|
||||
|
FROM alpine:3.16 AS doutok-serve |
||||
|
|
||||
|
WORKDIR /app |
||||
|
RUN mkdir tmp |
||||
|
COPY --from=builder /build/serve /app |
||||
|
COPY --from=builder /build/config /app/config |
||||
|
|
||||
|
ENTRYPOINT ["/app/serve"] |
@ -0,0 +1,201 @@ |
|||||
|
Apache License |
||||
|
Version 2.0, January 2004 |
||||
|
http://www.apache.org/licenses/ |
||||
|
|
||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
|
||||
|
1. Definitions. |
||||
|
|
||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
|
||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||
|
the copyright owner that is granting the License. |
||||
|
|
||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||
|
other entities that control, are controlled by, or are under common |
||||
|
control with that entity. For the purposes of this definition, |
||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||
|
direction or management of such entity, whether by contract or |
||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
|
||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||
|
exercising permissions granted by this License. |
||||
|
|
||||
|
"Source" form shall mean the preferred form for making modifications, |
||||
|
including but not limited to software source code, documentation |
||||
|
source, and configuration files. |
||||
|
|
||||
|
"Object" form shall mean any form resulting from mechanical |
||||
|
transformation or translation of a Source form, including but |
||||
|
not limited to compiled object code, generated documentation, |
||||
|
and conversions to other media types. |
||||
|
|
||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||
|
Object form, made available under the License, as indicated by a |
||||
|
copyright notice that is included in or attached to the work |
||||
|
(an example is provided in the Appendix below). |
||||
|
|
||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||
|
form, that is based on (or derived from) the Work and for which the |
||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||
|
of this License, Derivative Works shall not include works that remain |
||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||
|
the Work and Derivative Works thereof. |
||||
|
|
||||
|
"Contribution" shall mean any work of authorship, including |
||||
|
the original version of the Work and any modifications or additions |
||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||
|
means any form of electronic, verbal, or written communication sent |
||||
|
to the Licensor or its representatives, including but not limited to |
||||
|
communication on electronic mailing lists, source code control systems, |
||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||
|
excluding communication that is conspicuously marked or otherwise |
||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
|
||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||
|
subsequently incorporated within the Work. |
||||
|
|
||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||
|
Work and such Derivative Works in Source or Object form. |
||||
|
|
||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
(except as stated in this section) patent license to make, have made, |
||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
|
where such license applies only to those patent claims licensable |
||||
|
by such Contributor that are necessarily infringed by their |
||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||
|
institute patent litigation against any entity (including a |
||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
|
or a Contribution incorporated within the Work constitutes direct |
||||
|
or contributory patent infringement, then any patent licenses |
||||
|
granted to You under this License for that Work shall terminate |
||||
|
as of the date such litigation is filed. |
||||
|
|
||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||
|
Work or Derivative Works thereof in any medium, with or without |
||||
|
modifications, and in Source or Object form, provided that You |
||||
|
meet the following conditions: |
||||
|
|
||||
|
(a) You must give any other recipients of the Work or |
||||
|
Derivative Works a copy of this License; and |
||||
|
|
||||
|
(b) You must cause any modified files to carry prominent notices |
||||
|
stating that You changed the files; and |
||||
|
|
||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||
|
that You distribute, all copyright, patent, trademark, and |
||||
|
attribution notices from the Source form of the Work, |
||||
|
excluding those notices that do not pertain to any part of |
||||
|
the Derivative Works; and |
||||
|
|
||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||
|
distribution, then any Derivative Works that You distribute must |
||||
|
include a readable copy of the attribution notices contained |
||||
|
within such NOTICE file, excluding those notices that do not |
||||
|
pertain to any part of the Derivative Works, in at least one |
||||
|
of the following places: within a NOTICE text file distributed |
||||
|
as part of the Derivative Works; within the Source form or |
||||
|
documentation, if provided along with the Derivative Works; or, |
||||
|
within a display generated by the Derivative Works, if and |
||||
|
wherever such third-party notices normally appear. The contents |
||||
|
of the NOTICE file are for informational purposes only and |
||||
|
do not modify the License. You may add Your own attribution |
||||
|
notices within Derivative Works that You distribute, alongside |
||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||
|
that such additional attribution notices cannot be construed |
||||
|
as modifying the License. |
||||
|
|
||||
|
You may add Your own copyright statement to Your modifications and |
||||
|
may provide additional or different license terms and conditions |
||||
|
for use, reproduction, or distribution of Your modifications, or |
||||
|
for any such Derivative Works as a whole, provided Your use, |
||||
|
reproduction, and distribution of the Work otherwise complies with |
||||
|
the conditions stated in this License. |
||||
|
|
||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||
|
by You to the Licensor shall be under the terms and conditions of |
||||
|
this License, without any additional terms or conditions. |
||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||
|
the terms of any separate license agreement you may have executed |
||||
|
with Licensor regarding such Contributions. |
||||
|
|
||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||
|
except as required for reasonable and customary use in describing the |
||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
|
||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
|
agreed to in writing, Licensor provides the Work (and each |
||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
|
implied, including, without limitation, any warranties or conditions |
||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
|
appropriateness of using or redistributing the Work and assume any |
||||
|
risks associated with Your exercise of permissions under this License. |
||||
|
|
||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||
|
whether in tort (including negligence), contract, or otherwise, |
||||
|
unless required by applicable law (such as deliberate and grossly |
||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||
|
liable to You for damages, including any direct, indirect, special, |
||||
|
incidental, or consequential damages of any character arising as a |
||||
|
result of this License or out of the use or inability to use the |
||||
|
Work (including but not limited to damages for loss of goodwill, |
||||
|
work stoppage, computer failure or malfunction, or any and all |
||||
|
other commercial damages or losses), even if such Contributor |
||||
|
has been advised of the possibility of such damages. |
||||
|
|
||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
|
or other liability obligations and/or rights consistent with this |
||||
|
License. However, in accepting such obligations, You may act only |
||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||
|
of any other Contributor, and only if You agree to indemnify, |
||||
|
defend, and hold each Contributor harmless for any liability |
||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||
|
of your accepting any such warranty or additional liability. |
||||
|
|
||||
|
END OF TERMS AND CONDITIONS |
||||
|
|
||||
|
APPENDIX: How to apply the Apache License to your work. |
||||
|
|
||||
|
To apply the Apache License to your work, attach the following |
||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
|
replaced with your own identifying information. (Don't include |
||||
|
the brackets!) The text should be enclosed in the appropriate |
||||
|
comment syntax for the file format. We also recommend that a |
||||
|
file or class name and description of purpose be included on the |
||||
|
same "printed page" as the copyright notice for easier |
||||
|
identification within third-party archives. |
||||
|
|
||||
|
Copyright [yyyy] [name of copyright owner] |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
@ -0,0 +1,9 @@ |
|||||
|
genIdl: |
||||
|
kitex -module github.com/TremblingV5/DouTok -type protobuf -I ./proto/ -service $(module) ./proto/$(module).proto && rm handler.go && rm -rf ./script && rm kitex.yaml && rm build.sh && rm main.go |
||||
|
|
||||
|
install-swagger: |
||||
|
go install github.com/swaggo/swag/cmd/swag@latest |
||||
|
|
||||
|
generate-swagger: install-swagger |
||||
|
@cd applications/api && $(MAKE) swag && cd - |
||||
|
@rm -rf ./applications/api/docs/swagger.yaml |
@ -0,0 +1,184 @@ |
|||||
|
DouTok目前已转战V2:https://github.com/cloudzenith/DouTok,本仓库不再高强度维护 |
||||
|
|
||||
|
**为什么要开一个V2版本的仓库?** |
||||
|
|
||||
|
DouTok最初是字节跳动青训营的参赛项目(并取得了比较靠前的名次),在参加青训营的过程中,由于种种原因,导致项目中存在诸多不合理的地方。 |
||||
|
|
||||
|
例如:DouTok现版本的微服务划分不够合理,拆的过于零碎,也许看起来很“微服务”,但与实际工作生产环境上的服务划分却背道而驰,微服务的划分不应过分追求“微”,而是适应项目发展,在完善基本设计的前提下进行拆分。除此之外,过多的“微服务”导致维护过程中的困难,想要调试就需要启动非常多的服务,对维护过程非常折磨。 |
||||
|
|
||||
|
在青训营之后,我们开始考虑继续维护DouTok。让DouTok继续扩张的一个卡点是其本身没有前端,只能依赖青训营中提供的“抖声”APP。为了让DouTok顺利扩张,所以我们决定开发一个全新的V2版本。在V2版本中,DouTok减少了服务的划分,增加了前端项目,虽然现阶段依然不够完整,但是已经具备了继续扩张的土壤。 |
||||
|
|
||||
|
对参与过DouTok维护的所有同学表示感谢! |
||||
|
|
||||
|
![image-20230223111012814](./documents/imgs/banner.jpeg) |
||||
|
|
||||
|
DouTok is a backend for TikTok client based on Kitex and Hertz. |
||||
|
|
||||
|
![Hertz](https://img.shields.io/static/v1?label=Golang&message=1.18&color=brightgreen&style=plastic&logo=go) ![Hertz](https://img.shields.io/static/v1?label=Hertz&message=using&color=green&style=plastic&logo=go) ![Hertz](https://img.shields.io/static/v1?label=Kitex&message=using&color=yellowgreen&style=plastic&logo=go) ![Hertz](https://img.shields.io/static/v1?label=gorm/gen&message=using&color=yellow&style=plastic&logo=etcd) ![Hertz](https://img.shields.io/static/v1?label=etcd&message=3.4&color=orange&style=plastic&logo=etcd) ![Hertz](https://img.shields.io/static/v1?label=MySQL&message=8.0&color=red&style=plastic&logo=mysql) ![Hertz](https://img.shields.io/static/v1?label=Redis&message=7.0&color=blue&style=plastic&logo=redis) ![Hertz](https://img.shields.io/static/v1?label=HBase&message=2.1.3&color=blueviolet&style=plastic&logo=ApacheHadoop) ![Hertz](https://img.shields.io/static/v1?label=kafka&message=Tencent&color=ff69b4&style=plastic&logo=ApacheKafka) |
||||
|
|
||||
|
## Documents |
||||
|
|
||||
|
DouTok now have a documents site: [https://doutok.zhengfei.xin](https://doutok.zhengfei.xin) |
||||
|
|
||||
|
## Quick Start |
||||
|
|
||||
|
1. Deploy dependencies |
||||
|
Deploy some dependencies such as MySQL, Redis etc. Run them by using `docker-compose` with `.yml` files in `./deploy` or deploy them by yourself. |
||||
|
|
||||
|
```sh |
||||
|
docker-compose -f ./deploy/env.yml up -d |
||||
|
``` |
||||
|
|
||||
|
2. Update config files |
||||
|
|
||||
|
There's an elegant way to run applications in this repo which is using `docker-compose`. So update config files in `./config_docker_compose` if you use `docker-comopse`. If you don't want to run them in this way, you must update config files in `./config` for ensuring them working. |
||||
|
|
||||
|
3. Run applications by using `docker-compose` |
||||
|
Everything is ready now, ensure that there's a `docker-compose.yml` in the root directory and run this command in terminal |
||||
|
|
||||
|
```sh |
||||
|
docker-compose up -d |
||||
|
``` |
||||
|
|
||||
|
### Download Client |
||||
|
|
||||
|
We can download `.apk` file from `./ui` of this repo. Now the client is only support Android. After downloading and installing of this app. We can open it firstly. Then we can click `我` on the right bottom to enter configure page. After opening `高级配置`, we can input base url of the backend. An example is `http://localhost:8080/`. |
||||
|
|
||||
|
## Architecture |
||||
|
|
||||
|
### Technology Architecture |
||||
|
|
||||
|
![image-20230223111253963](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20230223111253963.png) |
||||
|
|
||||
|
### Tracing |
||||
|
|
||||
|
> Visit `http://127.0.0.1:16686/` on browser. |
||||
|
|
||||
|
![image-20230223111410359](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20230223111410359.png) |
||||
|
|
||||
|
### Metric |
||||
|
|
||||
|
> Visit `http://127.0.0.1:3000/` on browser. |
||||
|
|
||||
|
![image-20230223111633341](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20230223111633341.png) |
||||
|
|
||||
|
### API Introduce |
||||
|
|
||||
|
| 接口 | 功能 | 读/写 | 特点 | 备注 | |
||||
|
| ------------------------------- | ---------- | ----- | ------------ | ------------------ | |
||||
|
| /douyin/feed/ | 视频流接口 | 读 | 根本功能接口 | 存储优化,缓存优化 | |
||||
|
| /douyin/user/register/ | 注册接口 | 写 | | | |
||||
|
| /douyin/user/login/ | 登陆接口 | 读 | | | |
||||
|
| /douyin/user/ | 用户信息 | 读 | | | |
||||
|
| /douyin/publish/action/ | 发布视频 | 写 | | 存储优化 | |
||||
|
| /douyin/publish/list/ | 发布列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/favorite/action/ | 点赞接口 | 写 | 操作数大 | 延迟处理 | |
||||
|
| /douyin/favorite/list/ | 点赞列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/comment/action/ | 评论接口 | 写 | 操作数大 | 延迟处理 | |
||||
|
| /douyin/comment/list/ | 评论列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/relation/action/ | 关系操作 | 写 | 操作数大 | 延迟处理 | |
||||
|
| /douyin/relation/follow/list/ | 关注列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/relation/follower/list/ | 粉丝列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/relation/friend/list/ | 朋友列表 | 读 | | 缓存优化 | |
||||
|
| /douyin/message/chat/ | 聊天记录 | 读 | | 存储优化,缓存优化 | |
||||
|
| /douyin/message/action/ | 消息操作 | 写 | | 延迟处理 | |
||||
|
|
||||
|
## CI/CD |
||||
|
|
||||
|
- Build docker images by using github actions |
||||
|
- Push docker images to private repo created with Aliyun by using github actions |
||||
|
- DOING: Try to run applications with k8s automatically |
||||
|
|
||||
|
## Directories |
||||
|
|
||||
|
```tree |
||||
|
. |
||||
|
├── applications // 模块逻辑目录 |
||||
|
│ ├── api // api模块逻辑实现 |
||||
|
│ │ ├── biz // api模块主要逻辑实现 |
||||
|
│ │ │ ├── handler |
||||
|
│ │ │ │ ├── api |
||||
|
│ │ │ │ ├── pack.go |
||||
|
│ │ │ │ └── ping.go |
||||
|
│ │ │ ├── model |
||||
|
│ │ │ │ └── api |
||||
|
│ │ │ └── router |
||||
|
│ │ │ ├── api |
||||
|
│ │ │ └── register.go |
||||
|
│ │ ├── chat |
||||
|
│ │ ├── initialize |
||||
|
│ │ │ ├── init_hertz.go |
||||
|
│ │ │ ├── jwt.go |
||||
|
│ │ │ ├── redis.go |
||||
|
│ │ │ ├── rpc |
||||
|
│ │ │ └── viper.go |
||||
|
│ │ ├── main.go |
||||
|
│ │ ├── Makefile |
||||
|
│ │ ├── router_gen.go |
||||
|
│ │ └── router.go |
||||
|
│ ├── comment // comment模块逻辑实现 |
||||
|
│ │ ├── build.sh |
||||
|
│ │ ├── dal // 数据层 |
||||
|
│ │ │ ├── gen.go // gorm/gen生成代码 |
||||
|
│ │ │ ├── migrate // gorm自动迁移 |
||||
|
│ │ │ │ └── main.go |
||||
|
│ │ │ ├── model // model层 |
||||
|
│ │ │ └── query // gorm/gen生成结果 |
||||
|
│ │ │ ├── comment_counts.gen.go |
||||
|
│ │ │ ├── comments.gen.go |
||||
|
│ │ │ ├── gen.go |
||||
|
│ │ │ └── var.go |
||||
|
│ │ ├── handler // RPC服务的接口入口 |
||||
|
│ │ ├── main.go // 模块入口 |
||||
|
│ │ ├── Makefile |
||||
|
│ │ ├── misc // 模块所需的一些简单零散逻辑 |
||||
|
│ │ ├── pack // 将service层提供的数据查询结果包装成接口的返回消息 |
||||
|
│ │ ├── rpc // 初始化调用其他微服务 |
||||
|
│ │ ├── script |
||||
|
│ │ ├── service // 数据查询 |
||||
|
│ ├── favorite // favorite模块 |
||||
|
│ ├── feed // feed模块 |
||||
|
│ ├── message // message模块 |
||||
|
│ ├── publish // publish模块 |
||||
|
│ ├── relation // relation模块 |
||||
|
│ └── user // user模块 |
||||
|
├── config // 项目所需要的配置文件 |
||||
|
├── deploy // 项目所需的环境部署 |
||||
|
├── documents // 相关文档 |
||||
|
├── go.mod |
||||
|
├── go.sum |
||||
|
├── kitex_gen // Kitex生成的代码 |
||||
|
│ ├── comment |
||||
|
│ ├── favorite |
||||
|
│ ├── feed |
||||
|
│ ├── message |
||||
|
│ ├── publish |
||||
|
│ ├── relation |
||||
|
│ └── user |
||||
|
├── pkg // 项目所依赖的一些公共包 |
||||
|
│ ├── constants // 常量包 |
||||
|
│ ├── dlog // 日志包 |
||||
|
│ ├── dtviper // 配置包 |
||||
|
│ ├── errno // 错误码包 |
||||
|
│ ├── hbaseHandle // HBase操作包 |
||||
|
│ ├── initHelper // 初始化服务助手 |
||||
|
│ ├── kafka // Kafka操作包 |
||||
|
│ ├── middleware // 中间件 |
||||
|
│ ├── misc // 一些零散逻辑 |
||||
|
│ ├── mock // Mock测试包 |
||||
|
│ │ ├── comment |
||||
|
│ │ ├── favorite |
||||
|
│ │ ├── feed |
||||
|
│ │ ├── message |
||||
|
│ │ ├── publish |
||||
|
│ │ ├── relation |
||||
|
│ │ └── user |
||||
|
│ ├── mysqlIniter // MySQL操作包 |
||||
|
│ ├── ossHandle // OSS操作包 |
||||
|
│ ├── redisHandle // Redis操作包 |
||||
|
│ ├── safeMap // 线程安全的Map |
||||
|
│ └── utils // 其他组件 |
||||
|
├── proto // 基于Protobuf3完成的IDL |
||||
|
├── README.md |
||||
|
└── scripts |
||||
|
``` |
@ -0,0 +1,60 @@ |
|||||
|
## 技术栈 |
||||
|
|
||||
|
### 服务端 |
||||
|
|
||||
|
- go1.18 及以上 |
||||
|
- HTTP 框架:[Hertz](https://www.cloudwego.io/docs/hertz/) |
||||
|
- RPC 框架:[Kitex](https://www.cloudwego.io/docs/kitex/) |
||||
|
- 中间件:kafka、redis |
||||
|
- 存储:mysql、hbase、minio |
||||
|
|
||||
|
#### 项目启动 |
||||
|
|
||||
|
🌟 下面的内容需要配合 `DouTok/guidlines.md` 食用 |
||||
|
|
||||
|
0. 安卓手机 + pc,处在一个局域网内。 |
||||
|
1. 克隆 reborn 分支代码(该分支仅用于验证项目启动,只能用于测试用户注册登陆流程,其他功能可能有问题,预计两天内合入main,开放所有功能) |
||||
|
2. 修改 hosts 文件,添加 `127.0.0.1 hb-master`。 |
||||
|
3. 将 `./env/dependencies.yml` 中 `KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.1.119:9092` 的ip 替换成自己的局域网 IP。 |
||||
|
4. 启动依赖环境:docker-compose -f ./env/dependencies.yml up -d(reborn 版相比 main 少了一些依赖,会影响部分功能,但是不影响开发者验证启动流程正确性)。 |
||||
|
5. 登陆 mysql,在 DouTok 数据库中执行 scripts/DouTok.sql。 |
||||
|
6. 通过容器访问 kafka,为需要 kafka 的服务创建 topic。 |
||||
|
|
||||
|
```shell |
||||
|
# 以交互式模式进入容器 |
||||
|
docker exec -it 容器id /bin/bash |
||||
|
# 进入Kafka目录 |
||||
|
cd /opt/kafka_2.13-2.8.1/ |
||||
|
# 创建名为message_1的主题,1个分区,每个分区1个副本 |
||||
|
bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 1 --topic message_1 |
||||
|
# 创建名为relation_1的主题,1个分区,每个分区1个副本 |
||||
|
bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 1 --topic relation_1 |
||||
|
``` |
||||
|
|
||||
|
7. 启动服务(因为项目在迭代中,所以不同服务启动方式有些不同,详情参考 guidelines.md,将启动过程中涉及到的 kafka 的 ip 设置成局域网的 ip,对应配置文件路径为 DouTok/config/xxx,xxx 对应某一个服务。 |
||||
|
|
||||
|
8. 打开客户端,右下角“我”长按。 |
||||
|
|
||||
|
![image-20240227000742899](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20240227000742899.png) |
||||
|
|
||||
|
9. 跳转至输入连接的服务端口,这里输入连接的后端网关服务地址(最后一个 "/" 不要忘记): |
||||
|
|
||||
|
![image-20240227000823094](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20240227000823094.png) |
||||
|
|
||||
|
10. 体验注册登陆等功能。 |
||||
|
|
||||
|
### 前端 |
||||
|
|
||||
|
- 技术栈:React Hooks、TypeScript、Redux Saga、Vite |
||||
|
|
||||
|
- 项目目录 |
||||
|
|
||||
|
![image-20240226234007434](https://baize-blog-images.oss-cn-shanghai.aliyuncs.com/img/image-20240226234007434.png) |
||||
|
|
||||
|
#### 项目启动 |
||||
|
|
||||
|
```shell |
||||
|
npm install |
||||
|
npm run dev |
||||
|
``` |
||||
|
|
@ -0,0 +1,36 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
services=( |
||||
|
"api" "comment" "commentDomain" "favorite" "favoriteDomain" |
||||
|
"feed" "message" "messageDomain" "publish" "relation" "relationDomain" |
||||
|
"user" "userDomain" "videoDomain" |
||||
|
) |
||||
|
|
||||
|
if [ $1 == "start" ]; then |
||||
|
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
||||
|
do |
||||
|
nohup go run ./applications/${services[i]}/ > ./log/${services[i]}.out 2>&1 & |
||||
|
done |
||||
|
fi |
||||
|
|
||||
|
if [ $1 == "stop" ]; then |
||||
|
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
||||
|
do |
||||
|
process=`ps -ef | grep "go run ./applications/${services[i]}/" | grep -v grep | awk '{print $2}'` |
||||
|
for j in $process |
||||
|
do |
||||
|
echo "Kill: ${services[i]} $j" |
||||
|
kill -9 $j |
||||
|
done |
||||
|
done |
||||
|
|
||||
|
for i in 8088 8087 8086 8085 8084 8083 8082 8081 8079 8078 8077 8076 8075 8074 |
||||
|
do |
||||
|
process=`lsof -i:$i | grep LISTEN | awk '{print $2}'` |
||||
|
for j in $process |
||||
|
do |
||||
|
echo "Kill: port $i $j" |
||||
|
kill -9 $j |
||||
|
done |
||||
|
done |
||||
|
fi |
@ -0,0 +1,3 @@ |
|||||
|
// Code generated by hz. DO NOT EDIT. |
||||
|
|
||||
|
hz version: v0.5.0 |
@ -0,0 +1,8 @@ |
|||||
|
init: |
||||
|
hz new -idl ../../proto/api.proto -mod github.com/TremblingV5/DouTok/applications/api |
||||
|
|
||||
|
update: |
||||
|
hz update -idl ../../proto/api.proto |
||||
|
|
||||
|
swag: |
||||
|
swag init --parseDependency |
@ -0,0 +1,83 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// CommentAction .
|
||||
|
//
|
||||
|
// @Tags Comment评论
|
||||
|
//
|
||||
|
// @Summary 添加或删除评论
|
||||
|
// @Description
|
||||
|
// @Param req body api.DouyinCommentActionRequest true "评论操作信息"
|
||||
|
// @Success 200 {object} comment.DouyinCommentActionResponse
|
||||
|
// @Failure default {object} api.DouyinCommentActionResponse
|
||||
|
// @router /douyin/comment/action [POST]
|
||||
|
func CommentAction(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinCommentActionRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildCommendActionResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
rpcReq := comment.DouyinCommentActionRequest{ |
||||
|
VideoId: req.VideoId, |
||||
|
ActionType: req.ActionType, |
||||
|
UserId: userId, |
||||
|
CommentId: req.CommentId, |
||||
|
CommentText: req.CommentText, |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.CommentAction(ctx, rpc.CommentClient, &rpcReq) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildCommendActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// CommentList .
|
||||
|
//
|
||||
|
// @Tags Comment评论
|
||||
|
//
|
||||
|
// @Summary 获取某个视频之下的评论列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinCommentListRequest true "获取评论的参数"
|
||||
|
// @Success 200 {object} comment.DouyinCommentListResponse
|
||||
|
// @Failure default {object} api.DouyinCommentListResponse
|
||||
|
// @router /douyin/comment/list [GET]
|
||||
|
func CommentList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinCommentListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildCommendListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.CommentList(ctx, rpc.CommentClient, &comment.DouyinCommentListRequest{ |
||||
|
VideoId: req.VideoId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildCommendListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// FavoriteAction .
|
||||
|
//
|
||||
|
// @Tags Favorite点赞
|
||||
|
//
|
||||
|
// @Summary 点赞或取消点赞
|
||||
|
// @Description
|
||||
|
// @Param req body api.DouyinFavoriteActionRequest true "点赞操作信息"
|
||||
|
// @Success 200 {object} favorite.DouyinFavoriteActionResponse
|
||||
|
// @Failure default {object} api.DouyinFavoriteActionResponse
|
||||
|
// @router /douyin/favorite/action [POST]
|
||||
|
func FavoriteAction(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinFavoriteActionRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildFavoriteActionResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
resp, err := rpc.FavoriteAction(ctx, rpc.FavoriteClient, &favorite.DouyinFavoriteActionRequest{ |
||||
|
VideoId: req.VideoId, |
||||
|
ActionType: req.ActionType, |
||||
|
UserId: userId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildFavoriteActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// FavoriteList .
|
||||
|
//
|
||||
|
// @Tags Favorite点赞
|
||||
|
//
|
||||
|
// @Summary 返回点赞视频列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinFavoriteListRequest true "获取某个用户点赞了的视频的参数"
|
||||
|
// @Success 200 {object} favorite.DouyinFavoriteListResponse
|
||||
|
// @Failure default {object} api.DouyinFavoriteListResponse
|
||||
|
//
|
||||
|
// @router /douyin/favorite/list [GET]
|
||||
|
func FavoriteList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinFavoriteListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildFavoriteListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.FavoriteList(ctx, rpc.FavoriteClient, &favorite.DouyinFavoriteListRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildFavoriteListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/feed" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// GetUserFeed .
|
||||
|
//
|
||||
|
// @Tags Feed视频流相关
|
||||
|
//
|
||||
|
// @Summary 返回一个视频列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinFeedRequest false "返回哪些视频的限制参数"
|
||||
|
// @Success 200 {object} feed.DouyinFeedResponse
|
||||
|
// @Failure default {object} api.DouyinFeedResponse
|
||||
|
// @router /douyin/feed [GET]
|
||||
|
func GetUserFeed(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinFeedRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildGetUserFeedResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(0) |
||||
|
if req.Token != "" { |
||||
|
userId = int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.GetUserFeed(ctx, rpc.FeedClient, &feed.DouyinFeedRequest{ |
||||
|
LatestTime: req.LatestTime, |
||||
|
UserId: userId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildGetUserFeedResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/message" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// MessageChat .
|
||||
|
//
|
||||
|
// @Tags Message聊天相关
|
||||
|
//
|
||||
|
// @Summary 获取和某人的聊天记录
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinMessageChatRequest true "获取聊天记录的参数"
|
||||
|
// @Success 200 {object} message.DouyinMessageChatResponse
|
||||
|
// @Failure default {object} api.DouyinMessageChatResponse
|
||||
|
// @router /douyin/message/chat [GET]
|
||||
|
func MessageChat(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinMessageChatRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageChatResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
|
||||
|
resp, err := rpc.MessageChat(ctx, rpc.MessageClient, &message.DouyinMessageChatRequest{ |
||||
|
UserId: userId, |
||||
|
ToUserId: req.ToUserId, |
||||
|
PreMsgTime: req.PreMsgTime, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageChatResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// MessageAction .
|
||||
|
//
|
||||
|
// @Tags Message聊天相关
|
||||
|
//
|
||||
|
// @Summary 发送消息操作
|
||||
|
// @Description
|
||||
|
// @Param req body api.DouyinMessageActionRequest true "发送的消息的相关信息"
|
||||
|
// @Success 200 {object} message.DouyinMessageActionResponse
|
||||
|
// @Failure default {object} api.DouyinMessageActionResponse
|
||||
|
// @router /douyin/message/action [POST]
|
||||
|
func MessageAction(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinMessageActionRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
|
||||
|
resp, err := rpc.MessageAction(ctx, rpc.MessageClient, &message.DouyinMessageActionRequest{ |
||||
|
UserId: userId, |
||||
|
ToUserId: req.ToUserId, |
||||
|
ActionType: req.ActionType, |
||||
|
Content: req.Content, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
handler.SendResponse(c, resp) |
||||
|
//chat.ServeWs(ctx, c)
|
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"context" |
||||
|
"io" |
||||
|
"log" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/publish" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// PublishAction .
|
||||
|
//
|
||||
|
// @Tags Publish视频投稿相关
|
||||
|
//
|
||||
|
// @Summary 发布视频操作
|
||||
|
// @Description
|
||||
|
// @Param token formData string true "用户鉴权token"
|
||||
|
// @Param title formData string true "视频标题"
|
||||
|
// @Param data formData file true "视频数据"
|
||||
|
// @Success 200 {object} publish.DouyinPublishActionResponse
|
||||
|
// @Failure default {object} api.DouyinPublishActionResponse
|
||||
|
// @router /douyin/publish/action [POST]
|
||||
|
func PublishAction(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinPublishActionRequest |
||||
|
// err = c.BindAndValidate(&req)
|
||||
|
// if err != nil {
|
||||
|
// handler.SendResponse(c, handler.BuildPublishActionResp(errno.ErrBind))
|
||||
|
// return
|
||||
|
// }
|
||||
|
|
||||
|
req.Token = c.PostForm("token") |
||||
|
req.Title = c.PostForm("title") |
||||
|
fs, _ := c.FormFile("data") |
||||
|
f, _ := fs.Open() |
||||
|
buff := new(bytes.Buffer) |
||||
|
_, err = io.Copy(buff, f) |
||||
|
if err != nil { |
||||
|
log.Panicln(err) |
||||
|
} |
||||
|
req.Data = buff.Bytes() |
||||
|
|
||||
|
// TODO 这个绑定是否能够实现二进制文件的绑定(待测试)
|
||||
|
resp, err := rpc.PublishAction(ctx, rpc.PublishClient, &publish.DouyinPublishActionRequest{ |
||||
|
Title: req.Title, |
||||
|
Data: req.Data, |
||||
|
UserId: int64(c.Keys["user_id"].(float64)), |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildPublishActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// PublishList .
|
||||
|
//
|
||||
|
// @Tags Publish视频投稿相关
|
||||
|
//
|
||||
|
// @Summary 获取用户已发布视频的列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinPublishListRequest true "获取某个用户发布的视频列表的参数"
|
||||
|
// @Success 200 {object} publish.DouyinPublishListResponse
|
||||
|
// @Failure default {object} api.DouyinPublishListResponse
|
||||
|
// @router /douyin/publish/list [GET]
|
||||
|
func PublishList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinPublishListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildPublishListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.PublishList(ctx, rpc.PublishClient, &publish.DouyinPublishListRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildPublishListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
@ -0,0 +1,144 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/relation" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
// RelationAction .
|
||||
|
//
|
||||
|
// @Tags Relation关注
|
||||
|
//
|
||||
|
// @Summary 关注或取消关注
|
||||
|
// @Description
|
||||
|
// @Param req body api.DouyinRelationActionRequest true "关注操作信息"
|
||||
|
// @Success 200 {object} relation.DouyinRelationActionResponse
|
||||
|
// @Failure default {object} api.DouyinRelationActionResponse
|
||||
|
// @router /douyin/relation/action [POST]
|
||||
|
func RelationAction(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinRelationActionRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationActionResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
userId := int64(jwt.ExtractClaims(ctx, c)[initialize.AuthMiddleware.IdentityKey].(float64)) |
||||
|
|
||||
|
rpcReq := relation.DouyinRelationActionRequest{ |
||||
|
UserId: userId, |
||||
|
ToUserId: req.ToUserId, |
||||
|
ActionType: req.ActionType, |
||||
|
} |
||||
|
resp, err := rpc.RelationAction(ctx, rpc.RelationClient, &rpcReq) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// RelationFollowList .
|
||||
|
//
|
||||
|
// @Tags Relation关注
|
||||
|
//
|
||||
|
// @Summary 获取已关注用户的列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinRelationFollowListRequest true "获取操作信息"
|
||||
|
// @Success 200 {object} relation.DouyinRelationFollowListResponse
|
||||
|
// @Failure default {object} api.DouyinRelationFollowListResponse
|
||||
|
//
|
||||
|
// @router /douyin/relation/follow/list [GET]
|
||||
|
func RelationFollowList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinRelationFollowListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFollowListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.RelationFollowList(ctx, rpc.RelationClient, &relation.DouyinRelationFollowListRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFollowListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// RelationFollowerList .
|
||||
|
//
|
||||
|
// @Tags Relation关注
|
||||
|
//
|
||||
|
// @Summary 获取粉丝用户列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinRelationFollowerListRequest true "获取操作信息"
|
||||
|
// @Success 200 {object} relation.DouyinRelationFollowerListResponse
|
||||
|
// @Failure default {object} api.DouyinRelationFollowerListResponse
|
||||
|
// @router /douyin/relation/follower/list [GET]
|
||||
|
func RelationFollowerList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinRelationFollowerListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFollowerListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.RelationFollowerList(ctx, rpc.RelationClient, &relation.DouyinRelationFollowerListRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFollowerListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// RelationFriendList .
|
||||
|
//
|
||||
|
// @Tags Relation关注
|
||||
|
//
|
||||
|
// @Summary 获取好友列表
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinRelationFollowerListRequest true "获取操作信息"
|
||||
|
// @Success 200 {object} relation.DouyinRelationFollowerListResponse
|
||||
|
// @Failure default {object} api.DouyinRelationFollowerListResponse
|
||||
|
// @router /douyin/relation/friend/list [GET]
|
||||
|
//
|
||||
|
// 内部为调用获取粉丝列表
|
||||
|
func RelationFriendList(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinRelationFriendListRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFriendListResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.RelationFriendList(ctx, rpc.RelationClient, &relation.DouyinRelationFriendListRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildRelationFriendListResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
) |
||||
|
|
||||
|
// Register .
|
||||
|
//
|
||||
|
// @Tags User用户相关
|
||||
|
//
|
||||
|
// @Summary 用户注册
|
||||
|
// @Description 添加一个用户到数据库中
|
||||
|
// @Param req body api.DouyinUserRegisterRequest true "用户信息"
|
||||
|
// @Success 200 {object} user.DouyinUserResponse
|
||||
|
// @Failure default {object} api.DouyinUserRegisterResponse
|
||||
|
// @router /douyin/user/register [POST]
|
||||
|
func Register(ctx context.Context, c *app.RequestContext) { |
||||
|
var err error |
||||
|
var req api.DouyinUserRegisterRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildUserRegisterResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if len(req.Username) == 0 || len(req.Password) == 0 { |
||||
|
handler.SendResponse(c, handler.BuildUserRegisterResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.Register(ctx, rpc.UserClient, &user.DouyinUserRegisterRequest{ |
||||
|
Username: req.Username, |
||||
|
Password: req.Password, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildUserRegisterResp(errno.ConvertErr(err))) |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// GetUserById .
|
||||
|
//
|
||||
|
// @Tags User用户相关
|
||||
|
//
|
||||
|
// @Summary 通过用户ID获取用户
|
||||
|
// @Description
|
||||
|
// @Param req query api.DouyinUserRequest true "指明需要获取的用户的参数"
|
||||
|
// @Success 200 {object} user.DouyinUserResponse
|
||||
|
// @Failure default {object} api.DouyinUserResponse
|
||||
|
// @router /douyin/user [GET]
|
||||
|
func GetUserById(ctx context.Context, c *app.RequestContext) { |
||||
|
// 如果是需要授权访问的接口,则在进入时已经被中间件从 body 中获取 token 解析完成了,这里无需额外解析
|
||||
|
var err error |
||||
|
var req api.DouyinUserRequest |
||||
|
err = c.BindAndValidate(&req) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildGetUserResp(errno.ErrBind)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
resp, err := rpc.GetUserById(ctx, rpc.UserClient, &user.DouyinUserRequest{ |
||||
|
UserId: req.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildGetUserResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// TODO 此处直接返回了 rpc 的 resp
|
||||
|
handler.SendResponse(c, resp) |
||||
|
} |
||||
|
|
||||
|
// Login 确实有登录的接口,但是业务逻辑是在JWT中,写在这里是为了生成接口文档
|
||||
|
//
|
||||
|
// @Tags User用户相关
|
||||
|
//
|
||||
|
// @Summary 用户登录
|
||||
|
// @Description 输入账号密码登录获取Token
|
||||
|
// @Param req body api.DouyinUserLoginRequest true "用户信息"
|
||||
|
// @Success 200 {object} user.DouyinUserResponse
|
||||
|
// @Failure default {object} api.DouyinUserLoginResponse
|
||||
|
// @router /douyin/user/login [POST]
|
||||
|
func Login() { |
||||
|
|
||||
|
} |
@ -0,0 +1,229 @@ |
|||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
"github.com/cloudwego/hertz/pkg/protocol/consts" |
||||
|
) |
||||
|
|
||||
|
// SendResponse pack response
|
||||
|
func SendResponse(c *app.RequestContext, response interface{}) { |
||||
|
c.JSON(consts.StatusOK, response) |
||||
|
} |
||||
|
|
||||
|
// message
|
||||
|
func messageChatResp(err errno.ErrNo) *api.DouyinMessageChatResponse { |
||||
|
return &api.DouyinMessageChatResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func messageActionResp(err errno.ErrNo) *api.DouyinMessageActionResponse { |
||||
|
return &api.DouyinMessageActionResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildMessageChatResp(err error) *api.DouyinMessageChatResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return messageChatResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return messageChatResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildMessageActionResp(err error) *api.DouyinMessageActionResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return messageActionResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return messageActionResp(e) |
||||
|
} |
||||
|
|
||||
|
// user
|
||||
|
func userRegisterResp(err errno.ErrNo) *api.DouyinUserRegisterResponse { |
||||
|
return &api.DouyinUserRegisterResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func userLoginResp(err errno.ErrNo) *api.DouyinUserLoginResponse { |
||||
|
return &api.DouyinUserLoginResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func getUserResp(err errno.ErrNo) *api.DouyinUserResponse { |
||||
|
return &api.DouyinUserResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildUserRegisterResp(err error) *api.DouyinUserRegisterResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return userRegisterResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return userRegisterResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildUserLoginResp(err error) *api.DouyinUserLoginResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return userLoginResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return userLoginResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildGetUserResp(err error) *api.DouyinUserResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return getUserResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return getUserResp(e) |
||||
|
} |
||||
|
|
||||
|
// relation
|
||||
|
func relationActionResp(err errno.ErrNo) *api.DouyinRelationActionResponse { |
||||
|
return &api.DouyinRelationActionResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func relationFollowListResp(err errno.ErrNo) *api.DouyinRelationFollowListResponse { |
||||
|
return &api.DouyinRelationFollowListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func relationFollowerListResp(err errno.ErrNo) *api.DouyinRelationFollowerListResponse { |
||||
|
return &api.DouyinRelationFollowerListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func relationFriendListResp(err errno.ErrNo) *api.DouyinRelationFriendListResponse { |
||||
|
return &api.DouyinRelationFriendListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildRelationActionResp(err error) *api.DouyinRelationActionResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return relationActionResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return relationActionResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildRelationFollowListResp(err error) *api.DouyinRelationFollowListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return relationFollowListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return relationFollowListResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildRelationFollowerListResp(err error) *api.DouyinRelationFollowerListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return relationFollowerListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return relationFollowerListResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildRelationFriendListResp(err error) *api.DouyinRelationFriendListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return relationFriendListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return relationFriendListResp(e) |
||||
|
} |
||||
|
|
||||
|
// publish
|
||||
|
func publishActionResp(err errno.ErrNo) *api.DouyinPublishActionResponse { |
||||
|
return &api.DouyinPublishActionResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func publishListResp(err errno.ErrNo) *api.DouyinPublishListResponse { |
||||
|
return &api.DouyinPublishListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildPublishActionResp(err error) *api.DouyinPublishActionResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return publishActionResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return publishActionResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildPublishListResp(err error) *api.DouyinPublishListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return publishListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return publishListResp(e) |
||||
|
} |
||||
|
|
||||
|
// feed
|
||||
|
func getUserFeedResp(err errno.ErrNo) *api.DouyinFeedResponse { |
||||
|
return &api.DouyinFeedResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildGetUserFeedResp(err error) *api.DouyinFeedResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return getUserFeedResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return getUserFeedResp(e) |
||||
|
} |
||||
|
|
||||
|
// favorite
|
||||
|
func favoriteActionResp(err errno.ErrNo) *api.DouyinFavoriteActionResponse { |
||||
|
return &api.DouyinFavoriteActionResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func favoriteListResp(err errno.ErrNo) *api.DouyinFavoriteListResponse { |
||||
|
return &api.DouyinFavoriteListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildFavoriteActionResp(err error) *api.DouyinFavoriteActionResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return favoriteActionResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return favoriteActionResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildFavoriteListResp(err error) *api.DouyinFavoriteListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return favoriteListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return favoriteListResp(e) |
||||
|
} |
||||
|
|
||||
|
// comment
|
||||
|
func commentActionResp(err errno.ErrNo) *api.DouyinCommentActionResponse { |
||||
|
return &api.DouyinCommentActionResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func commentListResp(err errno.ErrNo) *api.DouyinCommentListResponse { |
||||
|
return &api.DouyinCommentListResponse{StatusCode: int32(err.ErrCode), StatusMsg: err.ErrMsg} |
||||
|
} |
||||
|
|
||||
|
func BuildCommendActionResp(err error) *api.DouyinCommentActionResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return commentActionResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return commentActionResp(e) |
||||
|
} |
||||
|
|
||||
|
func BuildCommendListResp(err error) *api.DouyinCommentListResponse { |
||||
|
e := errno.ErrNo{} |
||||
|
if errors.As(err, &e) { |
||||
|
return commentListResp(e) |
||||
|
} |
||||
|
e = errno.InternalErr.WithMessage(err.Error()) |
||||
|
return commentListResp(e) |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
"github.com/cloudwego/hertz/pkg/common/utils" |
||||
|
"github.com/cloudwego/hertz/pkg/protocol/consts" |
||||
|
) |
||||
|
|
||||
|
// Ping 测试 handler
|
||||
|
//
|
||||
|
// @Summary Ping测试
|
||||
|
// @Description 测试 Description
|
||||
|
//
|
||||
|
// @Tags Ping
|
||||
|
//
|
||||
|
// @Accept application/json
|
||||
|
// @Produce application/json
|
||||
|
// @Router /ping [get]
|
||||
|
// @success 200 {string} map[string]string
|
||||
|
func Ping(ctx context.Context, c *app.RequestContext) { |
||||
|
c.JSON(consts.StatusOK, utils.H{ |
||||
|
"message": "pong", |
||||
|
}) |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,480 @@ |
|||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
|
// versions:
|
||||
|
// protoc-gen-go v1.28.0
|
||||
|
// protoc v3.19.4
|
||||
|
// source: hz.proto
|
||||
|
|
||||
|
package api |
||||
|
|
||||
|
import ( |
||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
|
descriptorpb "google.golang.org/protobuf/types/descriptorpb" |
||||
|
reflect "reflect" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
|
) |
||||
|
|
||||
|
var file_hz_proto_extTypes = []protoimpl.ExtensionInfo{ |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50101, |
||||
|
Name: "api.raw_body", |
||||
|
Tag: "bytes,50101,opt,name=raw_body", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50102, |
||||
|
Name: "api.query", |
||||
|
Tag: "bytes,50102,opt,name=query", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50103, |
||||
|
Name: "api.header", |
||||
|
Tag: "bytes,50103,opt,name=header", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50104, |
||||
|
Name: "api.cookie", |
||||
|
Tag: "bytes,50104,opt,name=cookie", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50105, |
||||
|
Name: "api.body", |
||||
|
Tag: "bytes,50105,opt,name=body", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50106, |
||||
|
Name: "api.path", |
||||
|
Tag: "bytes,50106,opt,name=path", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50107, |
||||
|
Name: "api.vd", |
||||
|
Tag: "bytes,50107,opt,name=vd", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50108, |
||||
|
Name: "api.form", |
||||
|
Tag: "bytes,50108,opt,name=form", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 51001, |
||||
|
Name: "api.go_tag", |
||||
|
Tag: "bytes,51001,opt,name=go_tag", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50109, |
||||
|
Name: "api.js_conv", |
||||
|
Tag: "bytes,50109,opt,name=js_conv", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50201, |
||||
|
Name: "api.get", |
||||
|
Tag: "bytes,50201,opt,name=get", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50202, |
||||
|
Name: "api.post", |
||||
|
Tag: "bytes,50202,opt,name=post", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50203, |
||||
|
Name: "api.put", |
||||
|
Tag: "bytes,50203,opt,name=put", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50204, |
||||
|
Name: "api.delete", |
||||
|
Tag: "bytes,50204,opt,name=delete", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50205, |
||||
|
Name: "api.patch", |
||||
|
Tag: "bytes,50205,opt,name=patch", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50206, |
||||
|
Name: "api.options", |
||||
|
Tag: "bytes,50206,opt,name=options", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50207, |
||||
|
Name: "api.head", |
||||
|
Tag: "bytes,50207,opt,name=head", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50208, |
||||
|
Name: "api.any", |
||||
|
Tag: "bytes,50208,opt,name=any", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50301, |
||||
|
Name: "api.gen_path", |
||||
|
Tag: "bytes,50301,opt,name=gen_path", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50302, |
||||
|
Name: "api.api_version", |
||||
|
Tag: "bytes,50302,opt,name=api_version", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50303, |
||||
|
Name: "api.tag", |
||||
|
Tag: "bytes,50303,opt,name=tag", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50304, |
||||
|
Name: "api.name", |
||||
|
Tag: "bytes,50304,opt,name=name", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50305, |
||||
|
Name: "api.api_level", |
||||
|
Tag: "bytes,50305,opt,name=api_level", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50306, |
||||
|
Name: "api.serializer", |
||||
|
Tag: "bytes,50306,opt,name=serializer", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50307, |
||||
|
Name: "api.param", |
||||
|
Tag: "bytes,50307,opt,name=param", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.MethodOptions)(nil), |
||||
|
ExtensionType: (*string)(nil), |
||||
|
Field: 50308, |
||||
|
Name: "api.baseurl", |
||||
|
Tag: "bytes,50308,opt,name=baseurl", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
{ |
||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil), |
||||
|
ExtensionType: (*int32)(nil), |
||||
|
Field: 50401, |
||||
|
Name: "api.http_code", |
||||
|
Tag: "varint,50401,opt,name=http_code", |
||||
|
Filename: "hz.proto", |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
// Extension fields to descriptorpb.FieldOptions.
|
||||
|
var ( |
||||
|
// optional string raw_body = 50101;
|
||||
|
E_RawBody = &file_hz_proto_extTypes[0] |
||||
|
// optional string query = 50102;
|
||||
|
E_Query = &file_hz_proto_extTypes[1] |
||||
|
// optional string header = 50103;
|
||||
|
E_Header = &file_hz_proto_extTypes[2] |
||||
|
// optional string cookie = 50104;
|
||||
|
E_Cookie = &file_hz_proto_extTypes[3] |
||||
|
// optional string body = 50105;
|
||||
|
E_Body = &file_hz_proto_extTypes[4] |
||||
|
// optional string path = 50106;
|
||||
|
E_Path = &file_hz_proto_extTypes[5] |
||||
|
// optional string vd = 50107;
|
||||
|
E_Vd = &file_hz_proto_extTypes[6] |
||||
|
// optional string form = 50108;
|
||||
|
E_Form = &file_hz_proto_extTypes[7] |
||||
|
// optional string go_tag = 51001;
|
||||
|
E_GoTag = &file_hz_proto_extTypes[8] |
||||
|
// optional string js_conv = 50109;
|
||||
|
E_JsConv = &file_hz_proto_extTypes[9] |
||||
|
) |
||||
|
|
||||
|
// Extension fields to descriptorpb.MethodOptions.
|
||||
|
var ( |
||||
|
// optional string get = 50201;
|
||||
|
E_Get = &file_hz_proto_extTypes[10] |
||||
|
// optional string post = 50202;
|
||||
|
E_Post = &file_hz_proto_extTypes[11] |
||||
|
// optional string put = 50203;
|
||||
|
E_Put = &file_hz_proto_extTypes[12] |
||||
|
// optional string delete = 50204;
|
||||
|
E_Delete = &file_hz_proto_extTypes[13] |
||||
|
// optional string patch = 50205;
|
||||
|
E_Patch = &file_hz_proto_extTypes[14] |
||||
|
// optional string options = 50206;
|
||||
|
E_Options = &file_hz_proto_extTypes[15] |
||||
|
// optional string head = 50207;
|
||||
|
E_Head = &file_hz_proto_extTypes[16] |
||||
|
// optional string any = 50208;
|
||||
|
E_Any = &file_hz_proto_extTypes[17] |
||||
|
// optional string gen_path = 50301;
|
||||
|
E_GenPath = &file_hz_proto_extTypes[18] |
||||
|
// optional string api_version = 50302;
|
||||
|
E_ApiVersion = &file_hz_proto_extTypes[19] |
||||
|
// optional string tag = 50303;
|
||||
|
E_Tag = &file_hz_proto_extTypes[20] |
||||
|
// optional string name = 50304;
|
||||
|
E_Name = &file_hz_proto_extTypes[21] |
||||
|
// optional string api_level = 50305;
|
||||
|
E_ApiLevel = &file_hz_proto_extTypes[22] |
||||
|
// optional string serializer = 50306;
|
||||
|
E_Serializer = &file_hz_proto_extTypes[23] |
||||
|
// optional string param = 50307;
|
||||
|
E_Param = &file_hz_proto_extTypes[24] |
||||
|
// optional string baseurl = 50308;
|
||||
|
E_Baseurl = &file_hz_proto_extTypes[25] |
||||
|
) |
||||
|
|
||||
|
// Extension fields to descriptorpb.EnumValueOptions.
|
||||
|
var ( |
||||
|
// optional int32 http_code = 50401;
|
||||
|
E_HttpCode = &file_hz_proto_extTypes[26] |
||||
|
) |
||||
|
|
||||
|
var File_hz_proto protoreflect.FileDescriptor |
||||
|
|
||||
|
var file_hz_proto_rawDesc = []byte{ |
||||
|
0x0a, 0x08, 0x68, 0x7a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, |
||||
|
0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, |
||||
|
0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, |
||||
|
0x6f, 0x3a, 0x3a, 0x0a, 0x08, 0x72, 0x61, 0x77, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x1d, 0x2e, |
||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, |
||||
|
0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb5, 0x87, 0x03, |
||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x61, 0x77, 0x42, 0x6f, 0x64, 0x79, 0x3a, 0x35, 0x0a, |
||||
|
0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, |
||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, |
||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb6, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, |
||||
|
0x75, 0x65, 0x72, 0x79, 0x3a, 0x37, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, |
||||
|
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, |
||||
|
0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb7, 0x87, |
||||
|
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x3a, 0x37, 0x0a, |
||||
|
0x06, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, |
||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, |
||||
|
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb8, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, |
||||
|
0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x3a, 0x33, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x1d, |
||||
|
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, |
||||
|
0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb9, 0x87, |
||||
|
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x33, 0x0a, 0x04, 0x70, |
||||
|
0x61, 0x74, 0x68, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, |
||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, |
||||
|
0x6e, 0x73, 0x18, 0xba, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, |
||||
|
0x3a, 0x2f, 0x0a, 0x02, 0x76, 0x64, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, |
||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, |
||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xbb, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x76, |
||||
|
0x64, 0x3a, 0x33, 0x0a, 0x04, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, |
||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, |
||||
|
0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xbc, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, |
||||
|
0x52, 0x04, 0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x36, 0x0a, 0x06, 0x67, 0x6f, 0x5f, 0x74, 0x61, 0x67, |
||||
|
0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, |
||||
|
0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, |
||||
|
0xb9, 0x8e, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x6f, 0x54, 0x61, 0x67, 0x3a, 0x38, |
||||
|
0x0a, 0x07, 0x6a, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x76, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, |
||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, |
||||
|
0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xbd, 0x87, 0x03, 0x20, 0x01, 0x28, 0x09, |
||||
|
0x52, 0x06, 0x6a, 0x73, 0x43, 0x6f, 0x6e, 0x76, 0x3a, 0x32, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x12, |
||||
|
0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, |
||||
|
0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, |
||||
|
0x99, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x67, 0x65, 0x74, 0x3a, 0x34, 0x0a, 0x04, |
||||
|
0x70, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, |
||||
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, |
||||
|
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, |
||||
|
0x73, 0x74, 0x3a, 0x32, 0x0a, 0x03, 0x70, 0x75, 0x74, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, |
||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, |
||||
|
0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x88, 0x03, 0x20, 0x01, 0x28, |
||||
|
0x09, 0x52, 0x03, 0x70, 0x75, 0x74, 0x3a, 0x38, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, |
||||
|
0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, |
||||
|
0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, |
||||
|
0x18, 0x9c, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, |
||||
|
0x3a, 0x36, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, |
||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, |
||||
|
0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9d, 0x88, 0x03, 0x20, 0x01, 0x28, |
||||
|
0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x3a, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, |
||||
|
0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, |
||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, |
||||
|
0x6f, 0x6e, 0x73, 0x18, 0x9e, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, |
||||
|
0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x34, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x64, 0x12, 0x1e, 0x2e, 0x67, |
||||
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, |
||||
|
0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9f, 0x88, 0x03, |
||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x65, 0x61, 0x64, 0x3a, 0x32, 0x0a, 0x03, 0x61, 0x6e, |
||||
|
0x79, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, |
||||
|
0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, |
||||
|
0x73, 0x18, 0xa0, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x6e, 0x79, 0x3a, 0x3b, |
||||
|
0x0a, 0x08, 0x67, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, |
||||
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, |
||||
|
0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xfd, 0x88, 0x03, 0x20, 0x01, |
||||
|
0x28, 0x09, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x3a, 0x41, 0x0a, 0x0b, 0x61, |
||||
|
0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, |
||||
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, |
||||
|
0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xfe, 0x88, 0x03, 0x20, 0x01, |
||||
|
0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x32, |
||||
|
0x0a, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, |
||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, |
||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x88, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, |
||||
|
0x61, 0x67, 0x3a, 0x34, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, |
||||
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, |
||||
|
0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x80, 0x89, 0x03, 0x20, 0x01, |
||||
|
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x3d, 0x0a, 0x09, 0x61, 0x70, 0x69, 0x5f, |
||||
|
0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, |
||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, |
||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x81, 0x89, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, |
||||
|
0x70, 0x69, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x40, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, |
||||
|
0x6c, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, |
||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, |
||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x82, 0x89, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, |
||||
|
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x72, 0x3a, 0x36, 0x0a, 0x05, 0x70, 0x61, 0x72, |
||||
|
0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, |
||||
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, |
||||
|
0x6e, 0x73, 0x18, 0x83, 0x89, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x72, 0x61, |
||||
|
0x6d, 0x3a, 0x3a, 0x0a, 0x07, 0x62, 0x61, 0x73, 0x65, 0x75, 0x72, 0x6c, 0x12, 0x1e, 0x2e, 0x67, |
||||
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, |
||||
|
0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x84, 0x89, 0x03, |
||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x75, 0x72, 0x6c, 0x3a, 0x40, 0x0a, |
||||
|
0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, |
||||
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, |
||||
|
0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe1, 0x89, |
||||
|
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x68, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x42, |
||||
|
0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x72, |
||||
|
0x65, 0x6d, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x56, 0x35, 0x2f, 0x44, 0x6f, 0x75, 0x54, 0x6f, 0x6b, |
||||
|
0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x70, |
||||
|
0x69, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x5f, |
||||
|
0x79, 0x61, 0x6d, 0x6c, |
||||
|
} |
||||
|
|
||||
|
var file_hz_proto_goTypes = []interface{}{ |
||||
|
(*descriptorpb.FieldOptions)(nil), // 0: google.protobuf.FieldOptions
|
||||
|
(*descriptorpb.MethodOptions)(nil), // 1: google.protobuf.MethodOptions
|
||||
|
(*descriptorpb.EnumValueOptions)(nil), // 2: google.protobuf.EnumValueOptions
|
||||
|
} |
||||
|
var file_hz_proto_depIdxs = []int32{ |
||||
|
0, // 0: api.raw_body:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 1: api.query:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 2: api.header:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 3: api.cookie:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 4: api.body:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 5: api.path:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 6: api.vd:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 7: api.form:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 8: api.go_tag:extendee -> google.protobuf.FieldOptions
|
||||
|
0, // 9: api.js_conv:extendee -> google.protobuf.FieldOptions
|
||||
|
1, // 10: api.get:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 11: api.post:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 12: api.put:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 13: api.delete:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 14: api.patch:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 15: api.options:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 16: api.head:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 17: api.any:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 18: api.gen_path:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 19: api.api_version:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 20: api.tag:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 21: api.name:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 22: api.api_level:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 23: api.serializer:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 24: api.param:extendee -> google.protobuf.MethodOptions
|
||||
|
1, // 25: api.baseurl:extendee -> google.protobuf.MethodOptions
|
||||
|
2, // 26: api.http_code:extendee -> google.protobuf.EnumValueOptions
|
||||
|
27, // [27:27] is the sub-list for method output_type
|
||||
|
27, // [27:27] is the sub-list for method input_type
|
||||
|
27, // [27:27] is the sub-list for extension type_name
|
||||
|
0, // [0:27] is the sub-list for extension extendee
|
||||
|
0, // [0:0] is the sub-list for field type_name
|
||||
|
} |
||||
|
|
||||
|
func init() { file_hz_proto_init() } |
||||
|
func file_hz_proto_init() { |
||||
|
if File_hz_proto != nil { |
||||
|
return |
||||
|
} |
||||
|
type x struct{} |
||||
|
out := protoimpl.TypeBuilder{ |
||||
|
File: protoimpl.DescBuilder{ |
||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
|
RawDescriptor: file_hz_proto_rawDesc, |
||||
|
NumEnums: 0, |
||||
|
NumMessages: 0, |
||||
|
NumExtensions: 27, |
||||
|
NumServices: 0, |
||||
|
}, |
||||
|
GoTypes: file_hz_proto_goTypes, |
||||
|
DependencyIndexes: file_hz_proto_depIdxs, |
||||
|
ExtensionInfos: file_hz_proto_extTypes, |
||||
|
}.Build() |
||||
|
File_hz_proto = out.File |
||||
|
file_hz_proto_rawDesc = nil |
||||
|
file_hz_proto_goTypes = nil |
||||
|
file_hz_proto_depIdxs = nil |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
// Code generated by hertz generator. DO NOT EDIT.
|
||||
|
|
||||
|
package Api |
||||
|
|
||||
|
import ( |
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/handler/api" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server" |
||||
|
) |
||||
|
|
||||
|
/* |
||||
|
This file will register all the routes of the services in the master idl. |
||||
|
And it will update automatically when you use the "update" command for the idl. |
||||
|
So don't modify the contents of the file, or your code will be deleted when it is updated. |
||||
|
*/ |
||||
|
|
||||
|
// Register register routes based on the IDL 'api.yaml.${HTTP Method}' annotation.
|
||||
|
func Register(r *server.Hertz) { |
||||
|
|
||||
|
root := r.Group("/", rootMw()...) |
||||
|
{ |
||||
|
_douyin := root.Group("/douyin", _douyinMw()...) |
||||
|
_douyin.GET("/feed/", append(_getuserfeedMw(), api.GetUserFeed)...) |
||||
|
_douyin.GET("/user/", append(_getuserbyidMw(), api.GetUserById)...) |
||||
|
{ |
||||
|
_comment := _douyin.Group("/comment", _commentMw()...) |
||||
|
_comment.POST("/action/", append(_comment_ctionMw(), api.CommentAction)...) |
||||
|
_comment.GET("/list/", append(_commentlistMw(), api.CommentList)...) |
||||
|
} |
||||
|
{ |
||||
|
_favorite := _douyin.Group("/favorite", _favoriteMw()...) |
||||
|
_favorite.POST("/action/", append(_favorite_ctionMw(), api.FavoriteAction)...) |
||||
|
_favorite.GET("/list/", append(_favoritelistMw(), api.FavoriteList)...) |
||||
|
} |
||||
|
{ |
||||
|
_message := _douyin.Group("/message", _messageMw()...) |
||||
|
_message.POST("/action/", append(_message_ctionMw(), api.MessageAction)...) |
||||
|
_message.GET("/chat/", append(_messagechatMw(), api.MessageChat)...) |
||||
|
} |
||||
|
{ |
||||
|
_publish := _douyin.Group("/publish", _publishMw()...) |
||||
|
_publish.POST("/action/", append(_publish_ctionMw(), api.PublishAction)...) |
||||
|
_publish.GET("/list/", append(_publishlistMw(), api.PublishList)...) |
||||
|
} |
||||
|
{ |
||||
|
_relation := _douyin.Group("/relation", _relationMw()...) |
||||
|
_relation.POST("/action/", append(_relation_ctionMw(), api.RelationAction)...) |
||||
|
{ |
||||
|
_follow := _relation.Group("/follow", _followMw()...) |
||||
|
_follow.GET("/list/", append(_relationfollowlistMw(), api.RelationFollowList)...) |
||||
|
} |
||||
|
{ |
||||
|
_follower := _relation.Group("/follower", _followerMw()...) |
||||
|
_follower.GET("/list/", append(_relationfollowerlistMw(), api.RelationFollowerList)...) |
||||
|
} |
||||
|
{ |
||||
|
_friend := _relation.Group("/friend", _friendMw()...) |
||||
|
_friend.GET("/list/", append(_relationfriendlistMw(), api.RelationFriendList)...) |
||||
|
} |
||||
|
} |
||||
|
{ |
||||
|
_user := _douyin.Group("/user", _userMw()...) |
||||
|
_user.POST("/login/", append(_loginMw(), initialize.AuthMiddleware.LoginHandler)...) |
||||
|
_user.POST("/register/", append(_registerMw(), api.Register)...) |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,160 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package Api |
||||
|
|
||||
|
import ( |
||||
|
middleware2 "github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
) |
||||
|
|
||||
|
func rootMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware.Recovery(), |
||||
|
middleware.CacheAPIRequest(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _douyinMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _getuserfeedMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _getuserbyidMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _commentMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _comment_ctionMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _commentlistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _favoriteMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _favorite_ctionMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _favoritelistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _messageMw() []app.HandlerFunc { |
||||
|
//your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _message_ctionMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _messagechatMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _publishMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _publish_ctionMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _publishlistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _relationMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return []app.HandlerFunc{ |
||||
|
middleware2.AuthMiddleware.MiddlewareFunc(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func _relation_ctionMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _followMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _relationfollowlistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _followerMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _relationfollowerlistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _friendMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _relationfriendlistMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _userMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _loginMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func _registerMw() []app.HandlerFunc { |
||||
|
// your code...
|
||||
|
return nil |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
// Code generated by hertz generator. DO NOT EDIT.
|
||||
|
|
||||
|
package router |
||||
|
|
||||
|
import ( |
||||
|
api "github.com/TremblingV5/DouTok/applications/api/biz/router/api" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server" |
||||
|
) |
||||
|
|
||||
|
// GeneratedRegister registers routers generated by IDL.
|
||||
|
func GeneratedRegister(r *server.Hertz) { |
||||
|
//INSERT_POINT: DO NOT DELETE THIS LINE!
|
||||
|
api.Register(r) |
||||
|
} |
@ -0,0 +1,164 @@ |
|||||
|
package chat |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"encoding/json" |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
|
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
"github.com/cloudwego/hertz/pkg/common/hlog" |
||||
|
"github.com/hertz-contrib/websocket" |
||||
|
"github.com/jellydator/ttlcache/v2" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/message" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
// Time allowed to write a message to the peer.
|
||||
|
// writeWait = 10 * time.Second
|
||||
|
|
||||
|
// Time allowed to read the next pong message from the peer.
|
||||
|
// pongWait = 60 * time.Second
|
||||
|
|
||||
|
// Send pings to peer with this period. Must be less than pongWait.
|
||||
|
// pingPeriod = (pongWait * 9) / 10
|
||||
|
|
||||
|
// Maximum message size allowed from peer.
|
||||
|
// maxMessageSize = 512
|
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
// newline = []byte{'\n'}
|
||||
|
// space = []byte{' '}
|
||||
|
upgrader = websocket.HertzUpgrader{ |
||||
|
ReadBufferSize: 1024, |
||||
|
WriteBufferSize: 1024, |
||||
|
CheckOrigin: func(ctx *app.RequestContext) bool { |
||||
|
return true |
||||
|
}, |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
// Client is a middleman between the websocket connection and the hub.
|
||||
|
type Client struct { |
||||
|
// The websocket connection.
|
||||
|
conn *websocket.Conn |
||||
|
|
||||
|
// to user id
|
||||
|
userId string |
||||
|
} |
||||
|
|
||||
|
type ClientMsg struct { |
||||
|
UserId int64 `json:"user_id"` |
||||
|
ToUserId int64 `json:"to_user_id"` |
||||
|
MsgContent string `json:"msg_content"` |
||||
|
} |
||||
|
|
||||
|
type ServerMsg struct { |
||||
|
FromUserId int64 `json:"from_user_id"` |
||||
|
MsgContent string `json:"msg_content"` |
||||
|
} |
||||
|
|
||||
|
// websocket 服务端的实现
|
||||
|
// serveWs handles websocket requests from the peer.
|
||||
|
func ServeWs(ctx context.Context, c *app.RequestContext) { |
||||
|
|
||||
|
err := upgrader.Upgrade(c, func(conn *websocket.Conn) { |
||||
|
|
||||
|
// 注册 client
|
||||
|
|
||||
|
for { |
||||
|
_, msg, err := conn.ReadMessage() |
||||
|
if err != nil { |
||||
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { |
||||
|
log.Printf("error: %v", err) |
||||
|
} |
||||
|
break |
||||
|
} |
||||
|
// TODO 这里消息编解码可能有问题,需要考虑到客户端的处理方式
|
||||
|
clientMsg := ClientMsg{} |
||||
|
if err := json.Unmarshal(msg, &clientMsg); err != nil { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
clientFrom, err := hub.clients.Get(fmt.Sprint(clientMsg.UserId)) |
||||
|
if errors.Is(err, ttlcache.ErrNotFound) { |
||||
|
// 注册 client
|
||||
|
client := &Client{conn: conn, userId: fmt.Sprint(clientMsg.UserId)} |
||||
|
hub.register <- client |
||||
|
} else { |
||||
|
if err != nil { |
||||
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { |
||||
|
log.Printf("error: %v", err) |
||||
|
} |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
// 向 message 模块发送消息
|
||||
|
resp, err := rpc.MessageAction(ctx, rpc.MessageClient, &message.DouyinMessageActionRequest{ |
||||
|
ToUserId: clientMsg.ToUserId, |
||||
|
ActionType: 1, |
||||
|
Content: clientMsg.MsgContent, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
// 获取 B 用户的连接并发送消息
|
||||
|
clientTo, err := hub.clients.Get(fmt.Sprint(clientMsg.ToUserId)) |
||||
|
if errors.Is(err, ttlcache.ErrNotFound) { |
||||
|
// B 不在线
|
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.Success)) |
||||
|
return |
||||
|
} else { |
||||
|
if err != nil { |
||||
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { |
||||
|
hlog.Info("error: %v", err) |
||||
|
} |
||||
|
break |
||||
|
} else { |
||||
|
// B 在线
|
||||
|
serverMsg := ServerMsg{ |
||||
|
FromUserId: clientMsg.UserId, |
||||
|
MsgContent: clientMsg.MsgContent, |
||||
|
} |
||||
|
data, err := json.Marshal(serverMsg) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
if err := clientTo.(Client).conn.WriteMessage(websocket.TextMessage, data); err != nil { |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 返回 websocket 响应
|
||||
|
data, err := json.Marshal(resp) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ConvertErr(err))) |
||||
|
return |
||||
|
} |
||||
|
if err := clientFrom.(Client).conn.WriteMessage(websocket.TextMessage, data); err != nil { |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
if err != nil { |
||||
|
handler.SendResponse(c, handler.BuildMessageActionResp(errno.ConvertErr(err))) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 实现 socket 消息推送中心
|
||||
|
func SocketChat(ctx context.Context, c *app.RequestContext) { |
||||
|
/** |
||||
|
conn 等价于最初 hertz-server 握手之后创建的 conn, |
||||
|
如果能够维护一个map,在保证对应conn在keep-alive期间,是可以实现消息的转发操作的 |
||||
|
是否有必要? |
||||
|
*/ |
||||
|
//conn := c.GetConn()
|
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
package chat |
||||
|
|
||||
|
import ( |
||||
|
"sync" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/jellydator/ttlcache/v2" |
||||
|
) |
||||
|
|
||||
|
// Hub maintains the set of active clients and send messages to the client
|
||||
|
type Hub struct { |
||||
|
// Registered clients.
|
||||
|
clients *ttlcache.Cache |
||||
|
clientsLock sync.RWMutex |
||||
|
|
||||
|
// Register requests from the clients.
|
||||
|
register chan *Client |
||||
|
|
||||
|
// Unregister requests from clients.
|
||||
|
unregister chan *Client |
||||
|
} |
||||
|
|
||||
|
var hub = newHub() |
||||
|
|
||||
|
func newHub() *Hub { |
||||
|
return &Hub{ |
||||
|
clients: ttlcache.NewCache(), |
||||
|
register: make(chan *Client), |
||||
|
unregister: make(chan *Client), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (h *Hub) run() { //nolint
|
||||
|
for { |
||||
|
select { |
||||
|
case client := <-h.register: |
||||
|
if err := h.Register(client.userId, client); err != nil { |
||||
|
continue |
||||
|
} |
||||
|
case client := <-h.unregister: |
||||
|
if err := h.Unregister(client.userId); err != nil { |
||||
|
continue |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (h *Hub) Register(key string, client *Client) error { |
||||
|
return h.AddClient(key, client) |
||||
|
} |
||||
|
|
||||
|
func (h *Hub) AddClient(key string, client *Client) error { |
||||
|
h.clientsLock.Lock() |
||||
|
defer h.clientsLock.Unlock() |
||||
|
return h.clients.SetWithTTL(key, client, time.Hour) |
||||
|
} |
||||
|
|
||||
|
func (h *Hub) Unregister(key string) error { |
||||
|
return h.DelClient(key) |
||||
|
} |
||||
|
|
||||
|
func (h *Hub) DelClient(key string) error { |
||||
|
h.clientsLock.Lock() |
||||
|
defer h.clientsLock.Unlock() |
||||
|
return h.clients.Remove(key) |
||||
|
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,192 @@ |
|||||
|
package initialize |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"crypto/tls" |
||||
|
"encoding/json" |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"github.com/TremblingV5/DouTok/pkg/constants" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtnetwork" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server/registry" |
||||
|
"github.com/cloudwego/hertz/pkg/common/config" |
||||
|
"github.com/cloudwego/hertz/pkg/common/hlog" |
||||
|
"github.com/cloudwego/hertz/pkg/common/utils" |
||||
|
"github.com/hertz-contrib/gzip" |
||||
|
h2config "github.com/hertz-contrib/http2/config" |
||||
|
"github.com/hertz-contrib/http2/factory" |
||||
|
"github.com/hertz-contrib/obs-opentelemetry/provider" |
||||
|
hertztracing "github.com/hertz-contrib/obs-opentelemetry/tracing" |
||||
|
"github.com/hertz-contrib/registry/etcd" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
ServiceAddr string |
||||
|
EtcdAddress string |
||||
|
hertzCfg HertzCfg |
||||
|
) |
||||
|
|
||||
|
type HertzCfg struct { |
||||
|
UseNetpoll bool `json:"UseNetpoll" yaml:"UseNetpoll"` |
||||
|
Http2 Http2 `json:"Http2" yaml:"Http2"` |
||||
|
Tls Tls `json:"Tls" yaml:"Tls"` |
||||
|
} |
||||
|
|
||||
|
type Tls struct { |
||||
|
Enable bool `json:"Enable" yaml:"Enable"` |
||||
|
Cfg tls.Config |
||||
|
Cert string `json:"CertFile" yaml:"CertFile"` |
||||
|
Key string `json:"KeyFile" yaml:"KeyFile"` |
||||
|
ALPN bool `json:"ALPN" yaml:"ALPN"` |
||||
|
} |
||||
|
|
||||
|
type Http2 struct { |
||||
|
Enable bool `json:"Enable" yaml:"Enable"` |
||||
|
DisableKeepalive bool `json:"DisableKeepalive" yaml:"DisableKeepalive"` |
||||
|
ReadTimeout Duration `json:"ReadTimeout" yaml:"ReadTimeout"` |
||||
|
} |
||||
|
|
||||
|
type Duration struct { |
||||
|
time.Duration |
||||
|
} |
||||
|
|
||||
|
func (d Duration) MarshalJSON() ([]byte, error) { |
||||
|
return json.Marshal(d.String()) |
||||
|
} |
||||
|
|
||||
|
func (d *Duration) UnmarshalJSON(b []byte) error { |
||||
|
var v interface{} |
||||
|
if err := json.Unmarshal(b, &v); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
switch value := v.(type) { |
||||
|
case float64: |
||||
|
d.Duration = time.Duration(value) |
||||
|
return nil |
||||
|
case string: |
||||
|
var err error |
||||
|
d.Duration, err = time.ParseDuration(value) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
return nil |
||||
|
default: |
||||
|
return errors.New("invalid duration") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 初始化 API 配置
|
||||
|
func Init() { |
||||
|
InitViper() |
||||
|
rpc.InitRPC() |
||||
|
InitJwt() |
||||
|
InitRedisClient() |
||||
|
} |
||||
|
|
||||
|
func InitHertzCfg() { |
||||
|
ServiceAddr = fmt.Sprintf("%s:%d", ViperConfig.Viper.GetString("Server.Address"), ViperConfig.Viper.GetInt("Server.Port")) |
||||
|
EtcdAddress = fmt.Sprintf("%s:%d", ViperConfig.Viper.GetString("Etcd.Address"), ViperConfig.Viper.GetInt("Etcd.Port")) |
||||
|
|
||||
|
hertzV, err := json.Marshal(ViperConfig.Viper.Sub("Hertz").AllSettings()) |
||||
|
if err != nil { |
||||
|
hlog.Fatalf("Error marshalling Hertz config %s", err) |
||||
|
} |
||||
|
if err := json.Unmarshal(hertzV, &hertzCfg); err != nil { |
||||
|
hlog.Fatalf("Error unmarshalling Hertz config %s", err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 初始化 Hertz
|
||||
|
func InitHertz() (*server.Hertz, func()) { |
||||
|
InitHertzCfg() |
||||
|
|
||||
|
opts := []config.Option{server.WithHostPorts(ServiceAddr)} |
||||
|
|
||||
|
opts = append(opts, server.WithMaxRequestBodySize(1024*1024*1024)) |
||||
|
|
||||
|
// 服务注册
|
||||
|
if ViperConfig.Viper.GetBool("Etcd.Enable") { |
||||
|
r, err := etcd.NewEtcdRegistry([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
hlog.Fatal(err) |
||||
|
} |
||||
|
opts = append(opts, server.WithRegistry(r, ®istry.Info{ |
||||
|
ServiceName: constants.ApiServerName, |
||||
|
Addr: utils.NewNetAddr("tcp", ServiceAddr), |
||||
|
Weight: 10, |
||||
|
Tags: nil, |
||||
|
})) |
||||
|
} |
||||
|
|
||||
|
var p provider.OtelProvider |
||||
|
if ViperConfig.Viper.GetBool("Otel.Enable") { |
||||
|
//链路追踪
|
||||
|
p = provider.NewOpenTelemetryProvider( |
||||
|
provider.WithServiceName(constants.ApiServerName), |
||||
|
provider.WithExportEndpoint(fmt.Sprintf("%s:%s", ViperConfig.Viper.GetString("Otel.Host"), ViperConfig.Viper.GetString("Otel.Port"))), |
||||
|
provider.WithInsecure(), |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
tracer, tracerCfg := hertztracing.NewServerTracer() |
||||
|
opts = append(opts, tracer) |
||||
|
|
||||
|
// 网络库
|
||||
|
hertzNet := dtnetwork.GetTransporter(hertzCfg.UseNetpoll) |
||||
|
|
||||
|
opts = append(opts, server.WithTransport(hertzNet)) |
||||
|
|
||||
|
// TLS & Http2
|
||||
|
tlsEnable := hertzCfg.Tls.Enable |
||||
|
h2Enable := hertzCfg.Http2.Enable |
||||
|
hertzCfg.Tls.Cfg = tls.Config{ |
||||
|
MinVersion: tls.VersionTLS12, |
||||
|
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, |
||||
|
CipherSuites: []uint16{ |
||||
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, |
||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
||||
|
}, |
||||
|
} |
||||
|
if tlsEnable { |
||||
|
cert, err := tls.LoadX509KeyPair(hertzCfg.Tls.Cert, hertzCfg.Tls.Key) |
||||
|
if err != nil { |
||||
|
hlog.Error(err) |
||||
|
} |
||||
|
hertzCfg.Tls.Cfg.Certificates = append(hertzCfg.Tls.Cfg.Certificates, cert) |
||||
|
opts = append(opts, server.WithTLS(&hertzCfg.Tls.Cfg)) |
||||
|
|
||||
|
if alpn := hertzCfg.Tls.ALPN; alpn { |
||||
|
opts = append(opts, server.WithALPN(alpn)) |
||||
|
} |
||||
|
} else if h2Enable { |
||||
|
opts = append(opts, server.WithH2C(h2Enable)) |
||||
|
} |
||||
|
|
||||
|
// Hertz
|
||||
|
h := server.Default(opts...) |
||||
|
h.Use(gzip.Gzip(gzip.DefaultCompression), |
||||
|
hertztracing.ServerMiddleware(tracerCfg)) |
||||
|
|
||||
|
// Protocol
|
||||
|
if h2Enable { |
||||
|
h.AddProtocol("h2", factory.NewServerFactory( |
||||
|
h2config.WithReadTimeout(hertzCfg.Http2.ReadTimeout.Duration), |
||||
|
h2config.WithDisableKeepAlive(hertzCfg.Http2.DisableKeepalive))) |
||||
|
if tlsEnable { |
||||
|
hertzCfg.Tls.Cfg.NextProtos = append(hertzCfg.Tls.Cfg.NextProtos, "h2") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ViperConfig.Viper.GetBool("Otel.Enable") { |
||||
|
return h, func() { |
||||
|
} |
||||
|
} |
||||
|
return h, func() { |
||||
|
_ = p.Shutdown(context.Background()) //nolint
|
||||
|
} |
||||
|
} |
@ -0,0 +1,121 @@ |
|||||
|
package initialize |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/cloudwego/hertz/pkg/protocol" |
||||
|
"strings" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/hertz-contrib/jwt" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/api/biz/model/api" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize/rpc" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user" |
||||
|
"github.com/TremblingV5/DouTok/pkg/constants" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
"github.com/cloudwego/hertz/pkg/protocol/consts" |
||||
|
) |
||||
|
|
||||
|
var AuthMiddleware *jwt.HertzJWTMiddleware |
||||
|
|
||||
|
type LoginResp struct { |
||||
|
StatusCode int `json:"status_code"` |
||||
|
StatusMsg string `json:"status_msg"` |
||||
|
UserId int64 `json:"user_id,string"` |
||||
|
Token string `json:"token"` |
||||
|
} |
||||
|
|
||||
|
func InitJwt() { |
||||
|
AuthMiddleware, _ = jwt.New(&jwt.HertzJWTMiddleware{ |
||||
|
Key: []byte(ViperConfig.Viper.GetString("JWT.signingKey")), |
||||
|
Timeout: 12 * time.Hour, |
||||
|
MaxRefresh: time.Hour, |
||||
|
PayloadFunc: func(data interface{}) jwt.MapClaims { |
||||
|
if v, ok := data.(int64); ok { |
||||
|
return jwt.MapClaims{ |
||||
|
constants.IdentityKey: v, |
||||
|
} |
||||
|
} |
||||
|
return jwt.MapClaims{} |
||||
|
}, |
||||
|
HTTPStatusMessageFunc: func(e error, ctx context.Context, c *app.RequestContext) string { |
||||
|
switch e.(type) { //nolint
|
||||
|
case errno.ErrNo: |
||||
|
return e.(errno.ErrNo).ErrMsg //nolint
|
||||
|
default: |
||||
|
return e.Error() |
||||
|
} |
||||
|
}, |
||||
|
LoginResponse: func(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) { |
||||
|
claims := jwt.ExtractClaims(ctx, c) |
||||
|
// Long 型数据在返回前端时会失真,需使用string类型
|
||||
|
//userId := strconv.FormatInt(claims[constants.IdentityKey].(int64), 10)
|
||||
|
c.SetCookie("token", token, 24*60*60, "/", "", protocol.CookieSameSiteDefaultMode, false, true) |
||||
|
|
||||
|
userId := claims[constants.IdentityKey].(int64) |
||||
|
c.JSON(consts.StatusOK, LoginResp{ |
||||
|
StatusCode: errno.SuccessCode, |
||||
|
StatusMsg: errno.Success.ErrMsg, |
||||
|
UserId: userId, |
||||
|
Token: token, |
||||
|
}) |
||||
|
}, |
||||
|
WithNext: func(ctx context.Context, c *app.RequestContext) bool { |
||||
|
if strings.Contains(string(c.Request.Path()), "feed") { |
||||
|
var req api.DouyinFeedRequest |
||||
|
err := c.BindAndValidate(&req) |
||||
|
if err == nil && req.Token == "" { |
||||
|
return true |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
//if strings.Contains(string(c.Request.Path()), "publish") {
|
||||
|
// tokenInForm := string(c.FormValue("token"))
|
||||
|
//
|
||||
|
// if tokenInForm != "" {
|
||||
|
// jwt1.Parse(tokenInForm, func(token *jwt1.Token) (interface{}, error) {
|
||||
|
// if _, ok := token.Method.(*jwt1.SigningMethodRSA); !ok {
|
||||
|
// return nil, errors.New("unsupported signing method")
|
||||
|
// }
|
||||
|
// return
|
||||
|
// })
|
||||
|
// return true
|
||||
|
// }
|
||||
|
//
|
||||
|
// return false
|
||||
|
//}
|
||||
|
return false |
||||
|
}, |
||||
|
IdentityKey: constants.IdentityKey, |
||||
|
IdentityHandler: func(ctx context.Context, c *app.RequestContext) interface{} { |
||||
|
claims := jwt.ExtractClaims(ctx, c) |
||||
|
return claims[constants.IdentityKey].(float64) |
||||
|
}, |
||||
|
Unauthorized: func(ctx context.Context, c *app.RequestContext, code int, message string) { |
||||
|
c.JSON(code, map[string]interface{}{ |
||||
|
"status_code": errno.AuthorizationFailedErrCode, |
||||
|
"status_msg": message, |
||||
|
}) |
||||
|
}, |
||||
|
Authenticator: func(ctx context.Context, c *app.RequestContext) (interface{}, error) { |
||||
|
var loginVar api.DouyinUserLoginRequest |
||||
|
if err := c.Bind(&loginVar); err != nil { |
||||
|
return "", jwt.ErrMissingLoginValues |
||||
|
} |
||||
|
|
||||
|
if len(loginVar.Username) == 0 || len(loginVar.Password) == 0 { |
||||
|
return "", jwt.ErrMissingLoginValues |
||||
|
} |
||||
|
userId, err := rpc.Login(context.Background(), rpc.UserClient, &user.DouyinUserLoginRequest{Username: loginVar.Username, Password: loginVar.Password}) |
||||
|
if err == nil && userId != 0 { |
||||
|
c.Set("JWT_PAYLOAD", jwt.MapClaims{ |
||||
|
constants.IdentityKey: userId, |
||||
|
}) |
||||
|
} |
||||
|
return userId, err |
||||
|
}, |
||||
|
TokenLookup: "query: token, form: token, param: token, cookie: token", |
||||
|
TimeFunc: time.Now, |
||||
|
}) |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package initialize |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
redishandle "github.com/TremblingV5/DouTok/pkg/redisHandle" |
||||
|
"github.com/go-redis/redis/v8" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
RedisClient *redis.Client |
||||
|
) |
||||
|
|
||||
|
func InitRedisClient() { |
||||
|
|
||||
|
Client, err := redishandle.InitRedisClient( |
||||
|
fmt.Sprintf("%s:%d", ViperConfig.Viper.GetString("Redis.Host"), ViperConfig.Viper.GetInt("Redis.Port")), |
||||
|
ViperConfig.Viper.GetString("Redis.Password"), |
||||
|
ViperConfig.Viper.GetInt("Redis.Databases.Default"), |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
RedisClient = Client |
||||
|
} |
@ -0,0 +1,87 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment/commentservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var CommentClient commentservice.Client |
||||
|
|
||||
|
// Comment RPC 客户端初始化
|
||||
|
func initCommentRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := commentservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
CommentClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 评论操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func CommentAction(ctx context.Context, commentClient commentservice.Client, req *comment.DouyinCommentActionRequest) (resp *comment.DouyinCommentActionResponse, err error) { |
||||
|
resp, err = commentClient.CommentAction(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取评论列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func CommentList(ctx context.Context, commentClient commentservice.Client, req *comment.DouyinCommentListRequest) (resp *comment.DouyinCommentListResponse, err error) { |
||||
|
resp, err = commentClient.CommentList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,87 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite/favoriteservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var FavoriteClient favoriteservice.Client |
||||
|
|
||||
|
// Favorite RPC 客户端初始化
|
||||
|
func initFavoriteRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := favoriteservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
FavoriteClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 点赞操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func FavoriteAction(ctx context.Context, favoriteClient favoriteservice.Client, req *favorite.DouyinFavoriteActionRequest) (resp *favorite.DouyinFavoriteActionResponse, err error) { |
||||
|
resp, err = favoriteClient.FavoriteAction(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取点赞列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func FavoriteList(ctx context.Context, favoriteClient favoriteservice.Client, req *favorite.DouyinFavoriteListRequest) (resp *favorite.DouyinFavoriteListResponse, err error) { |
||||
|
resp, err = favoriteClient.FavoriteList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/feed" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/feed/feedservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var FeedClient feedservice.Client |
||||
|
|
||||
|
// Feed RPC 客户端初始化
|
||||
|
func initFeedRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := feedservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
FeedClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 获取视频流操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func GetUserFeed(ctx context.Context, feedClient feedservice.Client, req *feed.DouyinFeedRequest) (resp *feed.DouyinFeedResponse, err error) { |
||||
|
resp, err = feedClient.GetUserFeed(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
) |
||||
|
|
||||
|
// InitRPC init rpc client
|
||||
|
func InitRPC() { |
||||
|
UserConfig := dtviper.ConfigInit("DOUTOK_USER", "user") |
||||
|
initUserRpc(UserConfig) |
||||
|
|
||||
|
FeedConfig := dtviper.ConfigInit("DOUTOK_FEED", "feed") |
||||
|
initFeedRpc(FeedConfig) |
||||
|
|
||||
|
PublishConfig := dtviper.ConfigInit("DOUTOK_PUBLISH", "publish") |
||||
|
initPublishRpc(PublishConfig) |
||||
|
|
||||
|
FavoriteConfig := dtviper.ConfigInit("DOUTOK_FAVORITE", "favorite") |
||||
|
initFavoriteRpc(FavoriteConfig) |
||||
|
|
||||
|
CommentConfig := dtviper.ConfigInit("DOUTOK_COMMENT", "comment") |
||||
|
initCommentRpc(CommentConfig) |
||||
|
|
||||
|
RelationConfig := dtviper.ConfigInit("DOUTOK_RELATION", "relation") |
||||
|
initRelationRpc(RelationConfig) |
||||
|
|
||||
|
MessageConfig := dtviper.ConfigInit("DOUTOK_MESSAGE", "message") |
||||
|
initMessageRpc(MessageConfig) |
||||
|
} |
@ -0,0 +1,87 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/message" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/message/messageservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var MessageClient messageservice.Client |
||||
|
|
||||
|
// Comment RPC 客户端初始化
|
||||
|
func initMessageRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := messageservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
MessageClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 发布视频操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func MessageAction(ctx context.Context, messageClient messageservice.Client, req *message.DouyinMessageActionRequest) (resp *message.DouyinMessageActionResponse, err error) { |
||||
|
resp, err = messageClient.MessageAction(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取用户发布视频列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func MessageChat(ctx context.Context, messageClient messageservice.Client, req *message.DouyinMessageChatRequest) (resp *message.DouyinMessageChatResponse, err error) { |
||||
|
resp, err = messageClient.MessageChat(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,88 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/publish" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/publish/publishservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var PublishClient publishservice.Client |
||||
|
|
||||
|
// Publish RPC 客户端初始化
|
||||
|
func initPublishRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := publishservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
PublishClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 发布视频操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func PublishAction(ctx context.Context, publishClient publishservice.Client, req *publish.DouyinPublishActionRequest) (resp *publish.DouyinPublishActionResponse, err error) { |
||||
|
resp, err = publishClient.PublishAction(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取用户发布视频列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func PublishList(ctx context.Context, publishClient publishservice.Client, req *publish.DouyinPublishListRequest) (resp *publish.DouyinPublishListResponse, err error) { |
||||
|
resp, err = publishClient.PublishList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/relation" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/relation/relationservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var RelationClient relationservice.Client |
||||
|
|
||||
|
// Relation RPC 客户端初始化
|
||||
|
func initRelationRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := relationservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
RelationClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 关注操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func RelationAction(ctx context.Context, relationClient relationservice.Client, req *relation.DouyinRelationActionRequest) (resp *relation.DouyinRelationActionResponse, err error) { |
||||
|
resp, err = relationClient.RelationAction(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取正在关注列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func RelationFollowList(ctx context.Context, relationClient relationservice.Client, req *relation.DouyinRelationFollowListRequest) (resp *relation.DouyinRelationFollowListResponse, err error) { |
||||
|
resp, err = relationClient.RelationFollowList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取粉丝列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func RelationFollowerList(ctx context.Context, relationClient relationservice.Client, req *relation.DouyinRelationFollowerListRequest) (resp *relation.DouyinRelationFollowerListResponse, err error) { |
||||
|
resp, err = relationClient.RelationFollowerList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取好友列表操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func RelationFriendList(ctx context.Context, relationClient relationservice.Client, req *relation.DouyinRelationFriendListRequest) (resp *relation.DouyinRelationFriendListResponse, err error) { |
||||
|
resp, err = relationClient.RelationFriendList(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,99 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user/userservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/TremblingV5/DouTok/pkg/middleware" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
"github.com/cloudwego/kitex/pkg/remote/trans/gonet" |
||||
|
"github.com/cloudwego/kitex/pkg/retry" |
||||
|
"github.com/cloudwego/kitex/pkg/rpcinfo" |
||||
|
"github.com/kitex-contrib/obs-opentelemetry/tracing" |
||||
|
etcd "github.com/kitex-contrib/registry-etcd" |
||||
|
) |
||||
|
|
||||
|
var UserClient userservice.Client |
||||
|
|
||||
|
// User RPC 客户端初始化
|
||||
|
func initUserRpc(Config *dtviper.Config) { |
||||
|
EtcdAddress := fmt.Sprintf("%s:%d", Config.Viper.GetString("Etcd.Address"), Config.Viper.GetInt("Etcd.Port")) |
||||
|
r, err := etcd.NewEtcdResolver([]string{EtcdAddress}) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
ServiceName := Config.Viper.GetString("Server.Name") |
||||
|
|
||||
|
//p := provider.NewOpenTelemetryProvider(
|
||||
|
// provider.WithServiceName(ServiceName),
|
||||
|
// provider.WithExportEndpoint("localhost:4317"),
|
||||
|
// provider.WithInsecure(),
|
||||
|
//)
|
||||
|
//defer p.Shutdown(context.Background())
|
||||
|
options := []client.Option{ |
||||
|
client.WithMiddleware(middleware.CommonMiddleware), |
||||
|
client.WithInstanceMW(middleware.ClientMiddleware), |
||||
|
client.WithRPCTimeout(30 * time.Second), // rpc timeout
|
||||
|
client.WithConnectTimeout(30000 * time.Millisecond), // conn timeout
|
||||
|
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
|
||||
|
client.WithSuite(tracing.NewClientSuite()), // tracer
|
||||
|
client.WithResolver(r), // resolver
|
||||
|
// Please keep the same as provider.WithServiceName
|
||||
|
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: ServiceName}), |
||||
|
} |
||||
|
if runtime.GOOS == "windows" { |
||||
|
options = append(options, client.WithTransHandlerFactory(gonet.NewCliTransHandlerFactory())) |
||||
|
} else { |
||||
|
options = append(options, client.WithMuxConnection(1)) // mux
|
||||
|
} |
||||
|
c, err := userservice.NewClient( |
||||
|
ServiceName, |
||||
|
options..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
UserClient = c |
||||
|
} |
||||
|
|
||||
|
// 传递 注册操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func Register(ctx context.Context, userClient userservice.Client, req *user.DouyinUserRegisterRequest) (resp *user.DouyinUserRegisterResponse, err error) { |
||||
|
resp, err = userClient.Register(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 登录操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func Login(ctx context.Context, userClient userservice.Client, req *user.DouyinUserLoginRequest) (int64, error) { |
||||
|
resp, err := userClient.Login(ctx, req) |
||||
|
if err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return 0, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp.UserId, nil |
||||
|
} |
||||
|
|
||||
|
// 传递 获取用户信息操作 的上下文, 并获取 RPC Server 端的响应.
|
||||
|
func GetUserById(ctx context.Context, userClient userservice.Client, req *user.DouyinUserRequest) (resp *user.DouyinUserResponse, err error) { |
||||
|
resp, err = userClient.GetUserById(ctx, req) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if resp.StatusCode != 0 { |
||||
|
return nil, errno.NewErrNo(int(resp.StatusCode), resp.StatusMsg) |
||||
|
} |
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package initialize |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
|
||||
|
var ( |
||||
|
ViperConfig *dtviper.Config |
||||
|
) |
||||
|
|
||||
|
func InitViper() { |
||||
|
ViperConfig = dtviper.ConfigInit("DOUTOK_API", "api") |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
_ "github.com/TremblingV5/DouTok/applications/api/docs" |
||||
|
"github.com/TremblingV5/DouTok/applications/api/initialize" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dlog" |
||||
|
"github.com/cloudwego/hertz/pkg/common/hlog" |
||||
|
"github.com/hertz-contrib/pprof" |
||||
|
"github.com/hertz-contrib/swagger" |
||||
|
swaggerFiles "github.com/swaggo/files" |
||||
|
) |
||||
|
|
||||
|
// @title DouTokApi
|
||||
|
// @version 1.0
|
||||
|
// @description DouTok 项目后端
|
||||
|
|
||||
|
// @contact.name DouTok
|
||||
|
// @contact.url https://github.com/TremblingV5/DouTok
|
||||
|
|
||||
|
// @license.name Apache 2.0
|
||||
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
|
||||
|
// @host localhost:8088
|
||||
|
// @BasePath /
|
||||
|
// @schemes http
|
||||
|
//
|
||||
|
// 初始化 Hertz API 及 Router
|
||||
|
func main() { |
||||
|
|
||||
|
logger := dlog.InitHertzLog(3) |
||||
|
defer logger.Sync() |
||||
|
|
||||
|
hlog.SetLogger(logger) |
||||
|
|
||||
|
initialize.Init() |
||||
|
|
||||
|
h, shutdown := initialize.InitHertz() |
||||
|
defer shutdown() |
||||
|
|
||||
|
pprof.Register(h) |
||||
|
|
||||
|
register(h) |
||||
|
|
||||
|
url := swagger.URL("http://localhost:8088/swagger/doc.json") // The url pointing to API definition
|
||||
|
h.GET("/swagger/*any", swagger.WrapHandler(swaggerFiles.Handler, url)) |
||||
|
|
||||
|
fmt.Println("http://localhost:8088/swagger/index.html") |
||||
|
|
||||
|
h.Spin() |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
// Code generated by hertz generator.
|
||||
|
|
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
handler "github.com/TremblingV5/DouTok/applications/api/biz/handler" |
||||
|
"github.com/cloudwego/hertz/pkg/app" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server" |
||||
|
"github.com/cloudwego/hertz/pkg/protocol/consts" |
||||
|
) |
||||
|
|
||||
|
// customizeRegister registers customize routers.
|
||||
|
func customizedRegister(r *server.Hertz) { |
||||
|
r.GET("/ping", handler.Ping) |
||||
|
|
||||
|
// your code ...
|
||||
|
r.NoRoute(func(ctx context.Context, c *app.RequestContext) { // used for HTTP 404
|
||||
|
c.String(consts.StatusOK, "no route") |
||||
|
}) |
||||
|
r.NoMethod(func(ctx context.Context, c *app.RequestContext) { // used for HTTP 405
|
||||
|
c.String(consts.StatusOK, "no method") |
||||
|
}) |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
// Code generated by hertz generator. DO NOT EDIT.
|
||||
|
|
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
router "github.com/TremblingV5/DouTok/applications/api/biz/router" |
||||
|
"github.com/cloudwego/hertz/pkg/app/server" |
||||
|
) |
||||
|
|
||||
|
// register registers all routers.
|
||||
|
func register(r *server.Hertz) { |
||||
|
|
||||
|
router.GeneratedRegister(r) |
||||
|
|
||||
|
customizedRegister(r) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
server: |
||||
|
kitex -module github.com/TremblingV5/DouTok -type protobuf -I ../../proto/ -service comment ../../proto/comment.proto |
@ -0,0 +1,5 @@ |
|||||
|
# Comment |
||||
|
|
||||
|
Different with other modules, this module is used to as an experimental unit of DDD. |
||||
|
|
||||
|
Because all contributors of DouTok now are not familiar with DDD, so we need to practice it in a small module. |
@ -0,0 +1,75 @@ |
|||||
|
package comment_api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/rpc" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/services/comment_service" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
"github.com/TremblingV5/DouTok/pkg/utils" |
||||
|
) |
||||
|
|
||||
|
type CommentServiceImpl struct { |
||||
|
commentService *comment_service.Service |
||||
|
clients *rpc.Clients |
||||
|
} |
||||
|
|
||||
|
func New(commentService *comment_service.Service, clients *rpc.Clients) *CommentServiceImpl { |
||||
|
return &CommentServiceImpl{ |
||||
|
commentService: commentService, |
||||
|
clients: clients, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *CommentServiceImpl) CommentAction(ctx context.Context, req *comment.DouyinCommentActionRequest) (resp *comment.DouyinCommentActionResponse, err error) { |
||||
|
if result := CheckCommentActionArgs(req); !result { |
||||
|
return s.packCommentActionResp(int32(misc.ParamsErr.ErrCode), misc.ParamsErr.ErrMsg, nil, req.UserId) |
||||
|
} |
||||
|
|
||||
|
// 判断请求的动作,1为新加评论,2为删除评论
|
||||
|
if req.ActionType == 1 { |
||||
|
result, err := s.commentService.AddComment( |
||||
|
ctx, req.VideoId, req.UserId, utils.GetSnowFlakeId().Int64(), 0, 0, req.CommentText, |
||||
|
) |
||||
|
if err != nil { |
||||
|
return s.packCommentActionResp(int32(misc.SystemErr.ErrCode), misc.SystemErr.ErrMsg, nil, req.UserId) |
||||
|
} |
||||
|
return s.packCommentActionResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, result, req.UserId) |
||||
|
} else if req.ActionType == 2 { |
||||
|
errNo, err := s.commentService.RmComment(ctx, req.UserId, req.CommentId) |
||||
|
if err != nil { |
||||
|
return s.packCommentActionResp(int32(errNo.ErrCode), errNo.ErrMsg, nil, req.UserId) |
||||
|
} |
||||
|
return s.packCommentActionResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, nil, req.UserId) |
||||
|
} else { |
||||
|
return s.packCommentActionResp(int32(misc.BindingErr.ErrCode), misc.BindingErr.ErrMsg, nil, req.UserId) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *CommentServiceImpl) CommentCount(ctx context.Context, req *comment.DouyinCommentCountRequest) (resp *comment.DouyinCommentCountResponse, err error) { |
||||
|
if len(req.VideoIdList) == 0 { |
||||
|
return s.packCommentCountResp(int32(misc.ListEmptyErr.ErrCode), misc.ListEmptyErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
res, errNo, err := s.commentService.CountComment(ctx, req.VideoIdList...) |
||||
|
if err != nil { |
||||
|
return s.packCommentCountResp(int32(errNo.ErrCode), errNo.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
return s.packCommentCountResp(int32(errNo.ErrCode), errNo.ErrMsg, res) |
||||
|
} |
||||
|
|
||||
|
func (s *CommentServiceImpl) CommentList(ctx context.Context, req *comment.DouyinCommentListRequest) (resp *comment.DouyinCommentListResponse, err error) { |
||||
|
if !CheckCommentListArgs(req) { |
||||
|
return s.packCommentListResp(int32(misc.VideoIdErr.ErrCode), misc.VideoIdErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
res, errNo, err := s.commentService.ListComment(ctx, req.VideoId) |
||||
|
if err != nil { |
||||
|
return s.packCommentListResp(int32(errNo.ErrCode), errNo.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
return s.packCommentListResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, res) |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
package comment_api |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
commententity "github.com/TremblingV5/DouTok/applications/comment/domain/entity/comment" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/services/comment_service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func (s *CommentServiceImpl) packCommentActionResp(code int32, msg string, cmt *commententity.Entity, userId int64) (resp *comment.DouyinCommentActionResponse, err error) { |
||||
|
var result *comment.Comment |
||||
|
|
||||
|
result.Id = cmt.Id |
||||
|
result.Content = cmt.Content |
||||
|
result.CreateDate = cmt.Timestamp |
||||
|
|
||||
|
if code == int32(misc.Success.ErrCode) { |
||||
|
reqUser, err := s.clients.User.Client.GetUserById(context.Background(), &user.DouyinUserRequest{ |
||||
|
UserId: userId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
user := user.User{ |
||||
|
Id: reqUser.User.Id, |
||||
|
Name: reqUser.User.Name, |
||||
|
Avatar: reqUser.User.Avatar, |
||||
|
BackgroundImage: reqUser.User.BackgroundImage, |
||||
|
Signature: reqUser.User.Signature, |
||||
|
FollowCount: reqUser.User.FollowCount, |
||||
|
FollowerCount: reqUser.User.FollowerCount, |
||||
|
} |
||||
|
|
||||
|
result.User = &user |
||||
|
} |
||||
|
|
||||
|
return &comment.DouyinCommentActionResponse{ |
||||
|
StatusCode: code, |
||||
|
StatusMsg: msg, |
||||
|
Comment: result, |
||||
|
}, nil |
||||
|
} |
||||
|
|
||||
|
func (s *CommentServiceImpl) packCommentCountResp(code int32, msg string, countList map[int64]int64) (*comment.DouyinCommentCountResponse, error) { |
||||
|
return &comment.DouyinCommentCountResponse{ |
||||
|
StatusCode: code, |
||||
|
StatusMsg: msg, |
||||
|
Result: countList, |
||||
|
}, nil |
||||
|
} |
||||
|
|
||||
|
func (s *CommentServiceImpl) packCommentListResp(code int32, msg string, comments []*commententity.Entity) (resp *comment.DouyinCommentListResponse, err error) { |
||||
|
resp = &comment.DouyinCommentListResponse{ |
||||
|
StatusCode: code, |
||||
|
StatusMsg: msg, |
||||
|
} |
||||
|
|
||||
|
var commentList []*comment.Comment |
||||
|
|
||||
|
currentTime := time.Now().Unix() |
||||
|
|
||||
|
for _, v := range comments { |
||||
|
temp := comment.Comment{ |
||||
|
Id: v.Id, |
||||
|
Content: v.Content, |
||||
|
CreateDate: comment_service.GetTimeRecall(v.Timestamp, currentTime), |
||||
|
} |
||||
|
|
||||
|
reqUser, err := s.clients.User.Client.GetUserById(context.Background(), &user.DouyinUserRequest{ |
||||
|
UserId: v.UserId, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
tempUser := user.User{ |
||||
|
Id: reqUser.User.Id, |
||||
|
Name: reqUser.User.Name, |
||||
|
FollowCount: reqUser.User.FollowCount, |
||||
|
FollowerCount: reqUser.User.FollowerCount, |
||||
|
Avatar: reqUser.User.Avatar, |
||||
|
BackgroundImage: reqUser.User.BackgroundImage, |
||||
|
Signature: reqUser.User.Signature, |
||||
|
} |
||||
|
|
||||
|
temp.User = &tempUser |
||||
|
commentList = append(commentList, &temp) |
||||
|
} |
||||
|
|
||||
|
resp.CommentList = commentList |
||||
|
|
||||
|
return resp, nil |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package comment_api |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
|
||||
|
func CheckCommentActionArgs(req *comment.DouyinCommentActionRequest) bool { |
||||
|
return req.CommentText != "" |
||||
|
} |
||||
|
|
||||
|
func CheckCommentListArgs(req *comment.DouyinCommentListRequest) bool { |
||||
|
return req.VideoId >= 0 |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
RUN_NAME="comment" |
||||
|
|
||||
|
mkdir -p output/bin |
||||
|
cp script/* output/ |
||||
|
chmod +x output/bootstrap.sh |
||||
|
|
||||
|
if [ "$IS_SYSTEM_TEST_ENV" != "1" ]; then |
||||
|
go build -o output/bin/${RUN_NAME} |
||||
|
else |
||||
|
go test -c -covermode=set -o output/bin/${RUN_NAME} -coverpkg=./... |
||||
|
fi |
@ -0,0 +1,45 @@ |
|||||
|
package comment |
||||
|
|
||||
|
import "errors" |
||||
|
|
||||
|
type EntityCheckOption func(*Entity) error |
||||
|
|
||||
|
func IsIdValid() EntityCheckOption { |
||||
|
return func(c *Entity) error { |
||||
|
if c.Id == 0 { |
||||
|
return errors.New("comment id can't be 0") |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func IsVideoIdValid() EntityCheckOption { |
||||
|
return func(c *Entity) error { |
||||
|
if c.VideoId == 0 { |
||||
|
return errors.New("comment video id can't be 0") |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func IsUserIdValid() EntityCheckOption { |
||||
|
return func(c *Entity) error { |
||||
|
if c.UserId == 0 { |
||||
|
return errors.New("comment user id can't be 0") |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func IsBelongToUser(userId int64) EntityCheckOption { |
||||
|
return func(c *Entity) error { |
||||
|
if c.UserId != userId { |
||||
|
return errors.New("comment is not belong to user") |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
} |
@ -0,0 +1,101 @@ |
|||||
|
package comment |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
) |
||||
|
|
||||
|
type Entity struct { |
||||
|
Id int64 |
||||
|
VideoId int64 |
||||
|
UserId int64 |
||||
|
ConversationId int64 |
||||
|
LastId int64 |
||||
|
ToUserId int64 |
||||
|
Content string |
||||
|
Timestamp string |
||||
|
Status bool |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) check(options ...EntityCheckOption) error { |
||||
|
for _, option := range options { |
||||
|
if err := option(c); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) isValid() error { |
||||
|
return c.check( |
||||
|
IsVideoIdValid(), |
||||
|
IsUserIdValid(), |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
func New(options ...EntityOption) (*Entity, error) { |
||||
|
comment := &Entity{} |
||||
|
|
||||
|
for _, option := range options { |
||||
|
option(comment) |
||||
|
} |
||||
|
|
||||
|
return comment, comment.isValid() |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) ToModel() *model.Comment { |
||||
|
return &model.Comment{ |
||||
|
Id: c.Id, |
||||
|
VideoId: c.VideoId, |
||||
|
UserId: c.UserId, |
||||
|
ConversationId: c.ConversationId, |
||||
|
LastId: c.LastId, |
||||
|
ToUserId: c.ToUserId, |
||||
|
Content: c.Content, |
||||
|
Timestamp: c.Timestamp, |
||||
|
Status: c.Status, |
||||
|
CreatedAt: c.CreatedAt, |
||||
|
UpdatedAt: c.UpdatedAt, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) ToHBModel() *model.CommentInHB { |
||||
|
return &model.CommentInHB{ |
||||
|
Id: []byte(fmt.Sprint(c.Id)), |
||||
|
VideoId: []byte(fmt.Sprint(c.VideoId)), |
||||
|
UserId: []byte(fmt.Sprint(c.UserId)), |
||||
|
ConversationId: []byte(fmt.Sprint(c.ConversationId)), |
||||
|
LastId: []byte(fmt.Sprint(c.LastId)), |
||||
|
ToUserId: []byte(fmt.Sprint(c.ToUserId)), |
||||
|
Content: []byte(c.Content), |
||||
|
Timestamp: []byte(c.Timestamp), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) TransformFromModel(comment *model.Comment) { |
||||
|
c.Id = comment.Id |
||||
|
c.VideoId = comment.VideoId |
||||
|
c.UserId = comment.UserId |
||||
|
c.ConversationId = comment.ConversationId |
||||
|
c.LastId = comment.LastId |
||||
|
c.ToUserId = comment.ToUserId |
||||
|
c.Content = comment.Content |
||||
|
c.Timestamp = comment.Timestamp |
||||
|
c.Status = comment.Status |
||||
|
c.CreatedAt = comment.CreatedAt |
||||
|
c.UpdatedAt = comment.UpdatedAt |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) MarkAsDelete() { |
||||
|
c.Status = false |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) IsBelongUser(userId int64) (bool, error) { |
||||
|
err := c.check(IsBelongToUser(userId)) |
||||
|
return err == nil, err |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package comment |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
) |
||||
|
|
||||
|
type List []*Entity |
||||
|
|
||||
|
func NewListFromHBModels(models []*model.CommentInHB) List { |
||||
|
var result List |
||||
|
for _, model := range models { |
||||
|
result = append(result, &Entity{ |
||||
|
Id: model.GetId(), |
||||
|
VideoId: model.GetVideoId(), |
||||
|
UserId: model.GetUserId(), |
||||
|
ConversationId: model.GetConversationId(), |
||||
|
LastId: model.GetLastId(), |
||||
|
ToUserId: model.GetToUserId(), |
||||
|
Content: model.GetContent(), |
||||
|
Timestamp: model.GetTimestamp(), |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return result |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
package comment |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
type EntityOption func(*Entity) |
||||
|
|
||||
|
func WithId(id int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.Id = id |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithVideoId(videoId int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.VideoId = videoId |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithUserId(userId int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.UserId = userId |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithConversationId(conversationId int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.ConversationId = conversationId |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithLastId(lastId int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.LastId = lastId |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithToUserId(toUserId int64) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.ToUserId = toUserId |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithContent(content string) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.Content = content |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithTimestamp(timestamp string) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.Timestamp = timestamp |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithStatus(status bool) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.Status = status |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithCreatedAt(createdAt time.Time) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.CreatedAt = createdAt |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithUpdatedAt(updatedAt time.Time) EntityOption { |
||||
|
return func(c *Entity) { |
||||
|
c.UpdatedAt = updatedAt |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package comment_count |
||||
|
|
||||
|
import "errors" |
||||
|
|
||||
|
type EntityCheckOption func(*Entity) error |
||||
|
|
||||
|
func IsIdValid() EntityCheckOption { |
||||
|
return func(c *Entity) error { |
||||
|
if c.Id == 0 { |
||||
|
return errors.New("video id of comment count can't be 0") |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
package comment_count |
||||
|
|
||||
|
import ( |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
) |
||||
|
|
||||
|
type Entity struct { |
||||
|
Id int64 |
||||
|
Number int64 |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
||||
|
|
||||
|
func New(options ...Option) *Entity { |
||||
|
e := &Entity{} |
||||
|
for _, option := range options { |
||||
|
option(e) |
||||
|
} |
||||
|
|
||||
|
return e |
||||
|
} |
||||
|
|
||||
|
func TransformFromModel(model *model.CommentCount) *Entity { |
||||
|
return &Entity{ |
||||
|
Id: model.Id, |
||||
|
Number: model.Number, |
||||
|
CreatedAt: model.CreatedAt, |
||||
|
UpdatedAt: model.UpdatedAt, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) ToModel() *model.CommentCount { |
||||
|
return &model.CommentCount{ |
||||
|
Id: c.Id, |
||||
|
Number: c.Number, |
||||
|
CreatedAt: c.CreatedAt, |
||||
|
UpdatedAt: c.UpdatedAt, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) Check(options ...EntityCheckOption) error { |
||||
|
for _, option := range options { |
||||
|
if err := option(c); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (c *Entity) UpdateNumber(number int64) { |
||||
|
c.Number = number |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package comment_count |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
|
||||
|
type CommentCountList []*Entity |
||||
|
|
||||
|
func NewListFromModels(models []*model.CommentCount) CommentCountList { |
||||
|
var result CommentCountList |
||||
|
for _, model := range models { |
||||
|
result = append(result, &Entity{ |
||||
|
Id: model.Id, |
||||
|
Number: model.Number, |
||||
|
CreatedAt: model.CreatedAt, |
||||
|
UpdatedAt: model.UpdatedAt, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return result |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package comment_count |
||||
|
|
||||
|
type Option func(*Entity) |
||||
|
|
||||
|
func WithId(id int64) Option { |
||||
|
return func(e *Entity) { |
||||
|
e.Id = id |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func WithNumber(number int64) Option { |
||||
|
return func(e *Entity) { |
||||
|
e.Number = number |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package misc |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
|
||||
|
var Config *dtviper.Config |
||||
|
|
||||
|
func InitViperConfig() { |
||||
|
config := dtviper.ConfigInit(ViperConfigEnvPrefix, ViperConfigEnvFilename) |
||||
|
Config = config |
||||
|
} |
||||
|
|
||||
|
func GetConfig(key string) string { |
||||
|
return Config.Viper.GetString(key) |
||||
|
} |
||||
|
|
||||
|
func GetConfigNum(key string) int64 { |
||||
|
return Config.Viper.GetInt64(key) |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
package misc |
||||
|
|
||||
|
const ( |
||||
|
ViperConfigEnvPrefix = "DOUTOK_COMMENT" |
||||
|
ViperConfigEnvFilename = "comment" |
||||
|
|
||||
|
ComCntCache = "comcntcache" |
||||
|
ComTotalCntCache = "comtotalcntcache" |
||||
|
) |
@ -0,0 +1,33 @@ |
|||||
|
package misc |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
|
||||
|
var ( |
||||
|
NilErrCode = -1 |
||||
|
SuccessCode = 0 |
||||
|
ParamsErrCode = 26001 |
||||
|
SystemErrCode = 26002 |
||||
|
BindingErrCode = 26003 |
||||
|
ListEmptyErrCode = 26004 |
||||
|
VideoIdErrCode = 26005 |
||||
|
QueryCommentCountErrCode = 26006 |
||||
|
QueryCommentListInHBErrCode = 26007 |
||||
|
CommentNotBelongToUserErrCode = 26008 |
||||
|
RmDataFromHBErrCode = 26009 |
||||
|
HBDataNotFoundErrCode = 26010 |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
NilErr = errno.NewErrNo(NilErrCode, "Don't care") |
||||
|
Success = errno.NewErrNo(SuccessCode, "Success") |
||||
|
ParamsErr = errno.NewErrNo(ParamsErrCode, "Invalid parameters") |
||||
|
SystemErr = errno.NewErrNo(SystemErrCode, "System error") |
||||
|
BindingErr = errno.NewErrNo(BindingErrCode, "Action type invalid") |
||||
|
ListEmptyErr = errno.NewErrNo(ListEmptyErrCode, "List is empty") |
||||
|
VideoIdErr = errno.NewErrNo(VideoIdErrCode, "Video id invalid") |
||||
|
QueryCommentCountErr = errno.NewErrNo(QueryCommentCountErrCode, "Query comment count error") |
||||
|
QueryCommentListInHBErr = errno.NewErrNo(QueryCommentListInHBErrCode, "Query comment list in HBase error") |
||||
|
CommentNotBelongToUserErr = errno.NewErrNo(CommentNotBelongToUserErrCode, "This comment not belong to the user") |
||||
|
RmDataFromHBErr = errno.NewErrNo(RmDataFromHBErrCode, "Deleta data in HBase error") |
||||
|
HBDataNotFoundErr = errno.NewErrNo(HBDataNotFoundErrCode, "HBase comment data not found") |
||||
|
) |
@ -0,0 +1,19 @@ |
|||||
|
package misc |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
|
||||
|
globalMisc "github.com/TremblingV5/DouTok/pkg/misc" |
||||
|
) |
||||
|
|
||||
|
func EnsureIdLength(id int64) string { |
||||
|
return globalMisc.LFill(fmt.Sprint(id), 20) |
||||
|
} |
||||
|
|
||||
|
func GetCommentRowKey(video_id int64, is_deleted string, conversation_id int64, timestamp string) string { |
||||
|
return EnsureIdLength(video_id) + is_deleted + EnsureIdLength(conversation_id) + timestamp |
||||
|
} |
||||
|
|
||||
|
func GetCommentQueryPrefix(video_id int64) string { |
||||
|
return EnsureIdLength(video_id) + "0" |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package model |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
type Comment struct { |
||||
|
Id int64 `gorm:"primarykey"` |
||||
|
VideoId int64 `gorm:"index:video_id"` |
||||
|
UserId int64 `gorm:"index:user_id"` // 留下评论的id
|
||||
|
ConversationId int64 `gorm:"index:con_id"` |
||||
|
LastId int64 // 二级回复所使用到的上一条回复的id
|
||||
|
ToUserId int64 // 二级回复的用户id
|
||||
|
Content string |
||||
|
Timestamp string |
||||
|
Status bool |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package model |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
type CommentCount struct { |
||||
|
Id int64 `gorm:"index:com_count_id"` // 与Comment表的Id相同
|
||||
|
Number int64 |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
package model |
||||
|
|
||||
|
import ( |
||||
|
"encoding/binary" |
||||
|
"strconv" |
||||
|
) |
||||
|
|
||||
|
type CommentInHB struct { |
||||
|
Id []byte `json:"id"` |
||||
|
VideoId []byte `json:"video_id"` |
||||
|
UserId []byte `json:"user_id"` |
||||
|
ConversationId []byte `json:"conversation_id"` |
||||
|
LastId []byte `json:"last_id"` |
||||
|
ToUserId []byte `json:"to_user_id"` |
||||
|
Content []byte `json:"content"` |
||||
|
Timestamp []byte `json:"timestamp"` |
||||
|
} |
||||
|
|
||||
|
func ToInt64(data []byte) int64 { |
||||
|
return int64(binary.BigEndian.Uint64(data)) |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetId() int64 { |
||||
|
str := string(c.Id) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetVideoId() int64 { |
||||
|
str := string(c.VideoId) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetUserId() int64 { |
||||
|
str := string(c.UserId) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetConversationId() int64 { |
||||
|
str := string(c.ConversationId) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetLastId() int64 { |
||||
|
str := string(c.LastId) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetToUserId() int64 { |
||||
|
str := string(c.ToUserId) |
||||
|
i, _ := strconv.ParseInt(str, 10, 64) |
||||
|
return i |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetContent() string { |
||||
|
return string(c.Content) |
||||
|
} |
||||
|
|
||||
|
func (c *CommentInHB) GetTimestamp() string { |
||||
|
return string(c.Timestamp) |
||||
|
} |
@ -0,0 +1,395 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
"gorm.io/gorm/clause" |
||||
|
"gorm.io/gorm/schema" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
"gorm.io/gen/field" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
) |
||||
|
|
||||
|
func newCommentCount(db *gorm.DB, opts ...gen.DOOption) commentCount { |
||||
|
_commentCount := commentCount{} |
||||
|
|
||||
|
_commentCount.commentCountDo.UseDB(db, opts...) |
||||
|
_commentCount.commentCountDo.UseModel(&model.CommentCount{}) |
||||
|
|
||||
|
tableName := _commentCount.commentCountDo.TableName() |
||||
|
_commentCount.ALL = field.NewAsterisk(tableName) |
||||
|
_commentCount.Id = field.NewInt64(tableName, "id") |
||||
|
_commentCount.Number = field.NewInt64(tableName, "number") |
||||
|
_commentCount.CreatedAt = field.NewTime(tableName, "created_at") |
||||
|
_commentCount.UpdatedAt = field.NewTime(tableName, "updated_at") |
||||
|
|
||||
|
_commentCount.fillFieldMap() |
||||
|
|
||||
|
return _commentCount |
||||
|
} |
||||
|
|
||||
|
type commentCount struct { |
||||
|
commentCountDo |
||||
|
|
||||
|
ALL field.Asterisk |
||||
|
Id field.Int64 |
||||
|
Number field.Int64 |
||||
|
CreatedAt field.Time |
||||
|
UpdatedAt field.Time |
||||
|
|
||||
|
fieldMap map[string]field.Expr |
||||
|
} |
||||
|
|
||||
|
func (c commentCount) Table(newTableName string) *commentCount { |
||||
|
c.commentCountDo.UseTable(newTableName) |
||||
|
return c.updateTableName(newTableName) |
||||
|
} |
||||
|
|
||||
|
func (c commentCount) As(alias string) *commentCount { |
||||
|
c.commentCountDo.DO = *(c.commentCountDo.As(alias).(*gen.DO)) |
||||
|
return c.updateTableName(alias) |
||||
|
} |
||||
|
|
||||
|
func (c *commentCount) updateTableName(table string) *commentCount { |
||||
|
c.ALL = field.NewAsterisk(table) |
||||
|
c.Id = field.NewInt64(table, "id") |
||||
|
c.Number = field.NewInt64(table, "number") |
||||
|
c.CreatedAt = field.NewTime(table, "created_at") |
||||
|
c.UpdatedAt = field.NewTime(table, "updated_at") |
||||
|
|
||||
|
c.fillFieldMap() |
||||
|
|
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
func (c *commentCount) GetFieldByName(fieldName string) (field.OrderExpr, bool) { |
||||
|
_f, ok := c.fieldMap[fieldName] |
||||
|
if !ok || _f == nil { |
||||
|
return nil, false |
||||
|
} |
||||
|
_oe, ok := _f.(field.OrderExpr) |
||||
|
return _oe, ok |
||||
|
} |
||||
|
|
||||
|
func (c *commentCount) fillFieldMap() { |
||||
|
c.fieldMap = make(map[string]field.Expr, 4) |
||||
|
c.fieldMap["id"] = c.Id |
||||
|
c.fieldMap["number"] = c.Number |
||||
|
c.fieldMap["created_at"] = c.CreatedAt |
||||
|
c.fieldMap["updated_at"] = c.UpdatedAt |
||||
|
} |
||||
|
|
||||
|
func (c commentCount) clone(db *gorm.DB) commentCount { |
||||
|
c.commentCountDo.ReplaceConnPool(db.Statement.ConnPool) |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
func (c commentCount) replaceDB(db *gorm.DB) commentCount { |
||||
|
c.commentCountDo.ReplaceDB(db) |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
type commentCountDo struct{ gen.DO } |
||||
|
|
||||
|
type ICommentCountDo interface { |
||||
|
gen.SubQuery |
||||
|
Debug() ICommentCountDo |
||||
|
WithContext(ctx context.Context) ICommentCountDo |
||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo |
||||
|
ReplaceDB(db *gorm.DB) |
||||
|
ReadDB() ICommentCountDo |
||||
|
WriteDB() ICommentCountDo |
||||
|
As(alias string) gen.Dao |
||||
|
Session(config *gorm.Session) ICommentCountDo |
||||
|
Columns(cols ...field.Expr) gen.Columns |
||||
|
Clauses(conds ...clause.Expression) ICommentCountDo |
||||
|
Not(conds ...gen.Condition) ICommentCountDo |
||||
|
Or(conds ...gen.Condition) ICommentCountDo |
||||
|
Select(conds ...field.Expr) ICommentCountDo |
||||
|
Where(conds ...gen.Condition) ICommentCountDo |
||||
|
Order(conds ...field.Expr) ICommentCountDo |
||||
|
Distinct(cols ...field.Expr) ICommentCountDo |
||||
|
Omit(cols ...field.Expr) ICommentCountDo |
||||
|
Join(table schema.Tabler, on ...field.Expr) ICommentCountDo |
||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) ICommentCountDo |
||||
|
RightJoin(table schema.Tabler, on ...field.Expr) ICommentCountDo |
||||
|
Group(cols ...field.Expr) ICommentCountDo |
||||
|
Having(conds ...gen.Condition) ICommentCountDo |
||||
|
Limit(limit int) ICommentCountDo |
||||
|
Offset(offset int) ICommentCountDo |
||||
|
Count() (count int64, err error) |
||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentCountDo |
||||
|
Unscoped() ICommentCountDo |
||||
|
Create(values ...*model.CommentCount) error |
||||
|
CreateInBatches(values []*model.CommentCount, batchSize int) error |
||||
|
Save(values ...*model.CommentCount) error |
||||
|
First() (*model.CommentCount, error) |
||||
|
Take() (*model.CommentCount, error) |
||||
|
Last() (*model.CommentCount, error) |
||||
|
Find() ([]*model.CommentCount, error) |
||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.CommentCount, err error) |
||||
|
FindInBatches(result *[]*model.CommentCount, batchSize int, fc func(tx gen.Dao, batch int) error) error |
||||
|
Pluck(column field.Expr, dest interface{}) error |
||||
|
Delete(...*model.CommentCount) (info gen.ResultInfo, err error) |
||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
Updates(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateFrom(q gen.SubQuery) gen.Dao |
||||
|
Attrs(attrs ...field.AssignExpr) ICommentCountDo |
||||
|
Assign(attrs ...field.AssignExpr) ICommentCountDo |
||||
|
Joins(fields ...field.RelationField) ICommentCountDo |
||||
|
Preload(fields ...field.RelationField) ICommentCountDo |
||||
|
FirstOrInit() (*model.CommentCount, error) |
||||
|
FirstOrCreate() (*model.CommentCount, error) |
||||
|
FindByPage(offset int, limit int) (result []*model.CommentCount, count int64, err error) |
||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error) |
||||
|
Scan(result interface{}) (err error) |
||||
|
Returning(value interface{}, columns ...string) ICommentCountDo |
||||
|
UnderlyingDB() *gorm.DB |
||||
|
schema.Tabler |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Debug() ICommentCountDo { |
||||
|
return c.withDO(c.DO.Debug()) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) WithContext(ctx context.Context) ICommentCountDo { |
||||
|
return c.withDO(c.DO.WithContext(ctx)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) ReadDB() ICommentCountDo { |
||||
|
return c.Clauses(dbresolver.Read) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) WriteDB() ICommentCountDo { |
||||
|
return c.Clauses(dbresolver.Write) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Session(config *gorm.Session) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Session(config)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Clauses(conds ...clause.Expression) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Clauses(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Returning(value interface{}, columns ...string) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Returning(value, columns...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Not(conds ...gen.Condition) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Not(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Or(conds ...gen.Condition) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Or(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Select(conds ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Select(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Where(conds ...gen.Condition) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Where(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) ICommentCountDo { |
||||
|
return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB())) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Order(conds ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Order(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Distinct(cols ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Distinct(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Omit(cols ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Omit(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Join(table schema.Tabler, on ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Join(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) LeftJoin(table schema.Tabler, on ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.LeftJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) RightJoin(table schema.Tabler, on ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.RightJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Group(cols ...field.Expr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Group(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Having(conds ...gen.Condition) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Having(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Limit(limit int) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Limit(limit)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Offset(offset int) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Offset(offset)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Scopes(funcs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Unscoped() ICommentCountDo { |
||||
|
return c.withDO(c.DO.Unscoped()) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Create(values ...*model.CommentCount) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return c.DO.Create(values) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) CreateInBatches(values []*model.CommentCount, batchSize int) error { |
||||
|
return c.DO.CreateInBatches(values, batchSize) |
||||
|
} |
||||
|
|
||||
|
// Save : !!! underlying implementation is different with GORM
|
||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
|
func (c commentCountDo) Save(values ...*model.CommentCount) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return c.DO.Save(values) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) First() (*model.CommentCount, error) { |
||||
|
if result, err := c.DO.First(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.CommentCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Take() (*model.CommentCount, error) { |
||||
|
if result, err := c.DO.Take(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.CommentCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Last() (*model.CommentCount, error) { |
||||
|
if result, err := c.DO.Last(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.CommentCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Find() ([]*model.CommentCount, error) { |
||||
|
result, err := c.DO.Find() |
||||
|
return result.([]*model.CommentCount), err |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.CommentCount, err error) { |
||||
|
buf := make([]*model.CommentCount, 0, batchSize) |
||||
|
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { |
||||
|
defer func() { results = append(results, buf...) }() |
||||
|
return fc(tx, batch) |
||||
|
}) |
||||
|
return results, err |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) FindInBatches(result *[]*model.CommentCount, batchSize int, fc func(tx gen.Dao, batch int) error) error { |
||||
|
return c.DO.FindInBatches(result, batchSize, fc) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Attrs(attrs ...field.AssignExpr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Attrs(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Assign(attrs ...field.AssignExpr) ICommentCountDo { |
||||
|
return c.withDO(c.DO.Assign(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Joins(fields ...field.RelationField) ICommentCountDo { |
||||
|
for _, _f := range fields { |
||||
|
c = *c.withDO(c.DO.Joins(_f)) |
||||
|
} |
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Preload(fields ...field.RelationField) ICommentCountDo { |
||||
|
for _, _f := range fields { |
||||
|
c = *c.withDO(c.DO.Preload(_f)) |
||||
|
} |
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) FirstOrInit() (*model.CommentCount, error) { |
||||
|
if result, err := c.DO.FirstOrInit(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.CommentCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) FirstOrCreate() (*model.CommentCount, error) { |
||||
|
if result, err := c.DO.FirstOrCreate(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.CommentCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) FindByPage(offset int, limit int) (result []*model.CommentCount, count int64, err error) { |
||||
|
result, err = c.Offset(offset).Limit(limit).Find() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if size := len(result); 0 < limit && 0 < size && size < limit { |
||||
|
count = int64(size + offset) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
count, err = c.Offset(-1).Limit(-1).Count() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { |
||||
|
count, err = c.Count() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
err = c.Offset(offset).Limit(limit).Scan(result) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Scan(result interface{}) (err error) { |
||||
|
return c.DO.Scan(result) |
||||
|
} |
||||
|
|
||||
|
func (c commentCountDo) Delete(models ...*model.CommentCount) (result gen.ResultInfo, err error) { |
||||
|
return c.DO.Delete(models) |
||||
|
} |
||||
|
|
||||
|
func (c *commentCountDo) withDO(do gen.Dao) *commentCountDo { |
||||
|
c.DO = *do.(*gen.DO) |
||||
|
return c |
||||
|
} |
@ -0,0 +1,423 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
"gorm.io/gorm/clause" |
||||
|
"gorm.io/gorm/schema" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
"gorm.io/gen/field" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
) |
||||
|
|
||||
|
func newComment(db *gorm.DB, opts ...gen.DOOption) comment { |
||||
|
_comment := comment{} |
||||
|
|
||||
|
_comment.commentDo.UseDB(db, opts...) |
||||
|
_comment.commentDo.UseModel(&model.Comment{}) |
||||
|
|
||||
|
tableName := _comment.commentDo.TableName() |
||||
|
_comment.ALL = field.NewAsterisk(tableName) |
||||
|
_comment.Id = field.NewInt64(tableName, "id") |
||||
|
_comment.VideoId = field.NewInt64(tableName, "video_id") |
||||
|
_comment.UserId = field.NewInt64(tableName, "user_id") |
||||
|
_comment.ConversationId = field.NewInt64(tableName, "conversation_id") |
||||
|
_comment.LastId = field.NewInt64(tableName, "last_id") |
||||
|
_comment.ToUserId = field.NewInt64(tableName, "to_user_id") |
||||
|
_comment.Content = field.NewString(tableName, "content") |
||||
|
_comment.Timestamp = field.NewString(tableName, "timestamp") |
||||
|
_comment.Status = field.NewBool(tableName, "status") |
||||
|
_comment.CreatedAt = field.NewTime(tableName, "created_at") |
||||
|
_comment.UpdatedAt = field.NewTime(tableName, "updated_at") |
||||
|
|
||||
|
_comment.fillFieldMap() |
||||
|
|
||||
|
return _comment |
||||
|
} |
||||
|
|
||||
|
type comment struct { |
||||
|
commentDo |
||||
|
|
||||
|
ALL field.Asterisk |
||||
|
Id field.Int64 |
||||
|
VideoId field.Int64 |
||||
|
UserId field.Int64 |
||||
|
ConversationId field.Int64 |
||||
|
LastId field.Int64 |
||||
|
ToUserId field.Int64 |
||||
|
Content field.String |
||||
|
Timestamp field.String |
||||
|
Status field.Bool |
||||
|
CreatedAt field.Time |
||||
|
UpdatedAt field.Time |
||||
|
|
||||
|
fieldMap map[string]field.Expr |
||||
|
} |
||||
|
|
||||
|
func (c comment) Table(newTableName string) *comment { |
||||
|
c.commentDo.UseTable(newTableName) |
||||
|
return c.updateTableName(newTableName) |
||||
|
} |
||||
|
|
||||
|
func (c comment) As(alias string) *comment { |
||||
|
c.commentDo.DO = *(c.commentDo.As(alias).(*gen.DO)) |
||||
|
return c.updateTableName(alias) |
||||
|
} |
||||
|
|
||||
|
func (c *comment) updateTableName(table string) *comment { |
||||
|
c.ALL = field.NewAsterisk(table) |
||||
|
c.Id = field.NewInt64(table, "id") |
||||
|
c.VideoId = field.NewInt64(table, "video_id") |
||||
|
c.UserId = field.NewInt64(table, "user_id") |
||||
|
c.ConversationId = field.NewInt64(table, "conversation_id") |
||||
|
c.LastId = field.NewInt64(table, "last_id") |
||||
|
c.ToUserId = field.NewInt64(table, "to_user_id") |
||||
|
c.Content = field.NewString(table, "content") |
||||
|
c.Timestamp = field.NewString(table, "timestamp") |
||||
|
c.Status = field.NewBool(table, "status") |
||||
|
c.CreatedAt = field.NewTime(table, "created_at") |
||||
|
c.UpdatedAt = field.NewTime(table, "updated_at") |
||||
|
|
||||
|
c.fillFieldMap() |
||||
|
|
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
func (c *comment) GetFieldByName(fieldName string) (field.OrderExpr, bool) { |
||||
|
_f, ok := c.fieldMap[fieldName] |
||||
|
if !ok || _f == nil { |
||||
|
return nil, false |
||||
|
} |
||||
|
_oe, ok := _f.(field.OrderExpr) |
||||
|
return _oe, ok |
||||
|
} |
||||
|
|
||||
|
func (c *comment) fillFieldMap() { |
||||
|
c.fieldMap = make(map[string]field.Expr, 11) |
||||
|
c.fieldMap["id"] = c.Id |
||||
|
c.fieldMap["video_id"] = c.VideoId |
||||
|
c.fieldMap["user_id"] = c.UserId |
||||
|
c.fieldMap["conversation_id"] = c.ConversationId |
||||
|
c.fieldMap["last_id"] = c.LastId |
||||
|
c.fieldMap["to_user_id"] = c.ToUserId |
||||
|
c.fieldMap["content"] = c.Content |
||||
|
c.fieldMap["timestamp"] = c.Timestamp |
||||
|
c.fieldMap["status"] = c.Status |
||||
|
c.fieldMap["created_at"] = c.CreatedAt |
||||
|
c.fieldMap["updated_at"] = c.UpdatedAt |
||||
|
} |
||||
|
|
||||
|
func (c comment) clone(db *gorm.DB) comment { |
||||
|
c.commentDo.ReplaceConnPool(db.Statement.ConnPool) |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
func (c comment) replaceDB(db *gorm.DB) comment { |
||||
|
c.commentDo.ReplaceDB(db) |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
type commentDo struct{ gen.DO } |
||||
|
|
||||
|
type ICommentDo interface { |
||||
|
gen.SubQuery |
||||
|
Debug() ICommentDo |
||||
|
WithContext(ctx context.Context) ICommentDo |
||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo |
||||
|
ReplaceDB(db *gorm.DB) |
||||
|
ReadDB() ICommentDo |
||||
|
WriteDB() ICommentDo |
||||
|
As(alias string) gen.Dao |
||||
|
Session(config *gorm.Session) ICommentDo |
||||
|
Columns(cols ...field.Expr) gen.Columns |
||||
|
Clauses(conds ...clause.Expression) ICommentDo |
||||
|
Not(conds ...gen.Condition) ICommentDo |
||||
|
Or(conds ...gen.Condition) ICommentDo |
||||
|
Select(conds ...field.Expr) ICommentDo |
||||
|
Where(conds ...gen.Condition) ICommentDo |
||||
|
Order(conds ...field.Expr) ICommentDo |
||||
|
Distinct(cols ...field.Expr) ICommentDo |
||||
|
Omit(cols ...field.Expr) ICommentDo |
||||
|
Join(table schema.Tabler, on ...field.Expr) ICommentDo |
||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) ICommentDo |
||||
|
RightJoin(table schema.Tabler, on ...field.Expr) ICommentDo |
||||
|
Group(cols ...field.Expr) ICommentDo |
||||
|
Having(conds ...gen.Condition) ICommentDo |
||||
|
Limit(limit int) ICommentDo |
||||
|
Offset(offset int) ICommentDo |
||||
|
Count() (count int64, err error) |
||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentDo |
||||
|
Unscoped() ICommentDo |
||||
|
Create(values ...*model.Comment) error |
||||
|
CreateInBatches(values []*model.Comment, batchSize int) error |
||||
|
Save(values ...*model.Comment) error |
||||
|
First() (*model.Comment, error) |
||||
|
Take() (*model.Comment, error) |
||||
|
Last() (*model.Comment, error) |
||||
|
Find() ([]*model.Comment, error) |
||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Comment, err error) |
||||
|
FindInBatches(result *[]*model.Comment, batchSize int, fc func(tx gen.Dao, batch int) error) error |
||||
|
Pluck(column field.Expr, dest interface{}) error |
||||
|
Delete(...*model.Comment) (info gen.ResultInfo, err error) |
||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
Updates(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateFrom(q gen.SubQuery) gen.Dao |
||||
|
Attrs(attrs ...field.AssignExpr) ICommentDo |
||||
|
Assign(attrs ...field.AssignExpr) ICommentDo |
||||
|
Joins(fields ...field.RelationField) ICommentDo |
||||
|
Preload(fields ...field.RelationField) ICommentDo |
||||
|
FirstOrInit() (*model.Comment, error) |
||||
|
FirstOrCreate() (*model.Comment, error) |
||||
|
FindByPage(offset int, limit int) (result []*model.Comment, count int64, err error) |
||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error) |
||||
|
Scan(result interface{}) (err error) |
||||
|
Returning(value interface{}, columns ...string) ICommentDo |
||||
|
UnderlyingDB() *gorm.DB |
||||
|
schema.Tabler |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Debug() ICommentDo { |
||||
|
return c.withDO(c.DO.Debug()) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) WithContext(ctx context.Context) ICommentDo { |
||||
|
return c.withDO(c.DO.WithContext(ctx)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) ReadDB() ICommentDo { |
||||
|
return c.Clauses(dbresolver.Read) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) WriteDB() ICommentDo { |
||||
|
return c.Clauses(dbresolver.Write) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Session(config *gorm.Session) ICommentDo { |
||||
|
return c.withDO(c.DO.Session(config)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Clauses(conds ...clause.Expression) ICommentDo { |
||||
|
return c.withDO(c.DO.Clauses(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Returning(value interface{}, columns ...string) ICommentDo { |
||||
|
return c.withDO(c.DO.Returning(value, columns...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Not(conds ...gen.Condition) ICommentDo { |
||||
|
return c.withDO(c.DO.Not(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Or(conds ...gen.Condition) ICommentDo { |
||||
|
return c.withDO(c.DO.Or(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Select(conds ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Select(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Where(conds ...gen.Condition) ICommentDo { |
||||
|
return c.withDO(c.DO.Where(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) ICommentDo { |
||||
|
return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB())) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Order(conds ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Order(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Distinct(cols ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Distinct(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Omit(cols ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Omit(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Join(table schema.Tabler, on ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Join(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) LeftJoin(table schema.Tabler, on ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.LeftJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) RightJoin(table schema.Tabler, on ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.RightJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Group(cols ...field.Expr) ICommentDo { |
||||
|
return c.withDO(c.DO.Group(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Having(conds ...gen.Condition) ICommentDo { |
||||
|
return c.withDO(c.DO.Having(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Limit(limit int) ICommentDo { |
||||
|
return c.withDO(c.DO.Limit(limit)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Offset(offset int) ICommentDo { |
||||
|
return c.withDO(c.DO.Offset(offset)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Scopes(funcs ...func(gen.Dao) gen.Dao) ICommentDo { |
||||
|
return c.withDO(c.DO.Scopes(funcs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Unscoped() ICommentDo { |
||||
|
return c.withDO(c.DO.Unscoped()) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Create(values ...*model.Comment) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return c.DO.Create(values) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) CreateInBatches(values []*model.Comment, batchSize int) error { |
||||
|
return c.DO.CreateInBatches(values, batchSize) |
||||
|
} |
||||
|
|
||||
|
// Save : !!! underlying implementation is different with GORM
|
||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
|
func (c commentDo) Save(values ...*model.Comment) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return c.DO.Save(values) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) First() (*model.Comment, error) { |
||||
|
if result, err := c.DO.First(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Comment), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Take() (*model.Comment, error) { |
||||
|
if result, err := c.DO.Take(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Comment), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Last() (*model.Comment, error) { |
||||
|
if result, err := c.DO.Last(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Comment), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Find() ([]*model.Comment, error) { |
||||
|
result, err := c.DO.Find() |
||||
|
return result.([]*model.Comment), err |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Comment, err error) { |
||||
|
buf := make([]*model.Comment, 0, batchSize) |
||||
|
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { |
||||
|
defer func() { results = append(results, buf...) }() |
||||
|
return fc(tx, batch) |
||||
|
}) |
||||
|
return results, err |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) FindInBatches(result *[]*model.Comment, batchSize int, fc func(tx gen.Dao, batch int) error) error { |
||||
|
return c.DO.FindInBatches(result, batchSize, fc) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Attrs(attrs ...field.AssignExpr) ICommentDo { |
||||
|
return c.withDO(c.DO.Attrs(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Assign(attrs ...field.AssignExpr) ICommentDo { |
||||
|
return c.withDO(c.DO.Assign(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Joins(fields ...field.RelationField) ICommentDo { |
||||
|
for _, _f := range fields { |
||||
|
c = *c.withDO(c.DO.Joins(_f)) |
||||
|
} |
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Preload(fields ...field.RelationField) ICommentDo { |
||||
|
for _, _f := range fields { |
||||
|
c = *c.withDO(c.DO.Preload(_f)) |
||||
|
} |
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) FirstOrInit() (*model.Comment, error) { |
||||
|
if result, err := c.DO.FirstOrInit(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Comment), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) FirstOrCreate() (*model.Comment, error) { |
||||
|
if result, err := c.DO.FirstOrCreate(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Comment), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) FindByPage(offset int, limit int) (result []*model.Comment, count int64, err error) { |
||||
|
result, err = c.Offset(offset).Limit(limit).Find() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if size := len(result); 0 < limit && 0 < size && size < limit { |
||||
|
count = int64(size + offset) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
count, err = c.Offset(-1).Limit(-1).Count() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { |
||||
|
count, err = c.Count() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
err = c.Offset(offset).Limit(limit).Scan(result) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Scan(result interface{}) (err error) { |
||||
|
return c.DO.Scan(result) |
||||
|
} |
||||
|
|
||||
|
func (c commentDo) Delete(models ...*model.Comment) (result gen.ResultInfo, err error) { |
||||
|
return c.DO.Delete(models) |
||||
|
} |
||||
|
|
||||
|
func (c *commentDo) withDO(do gen.Dao) *commentDo { |
||||
|
c.DO = *do.(*gen.DO) |
||||
|
return c |
||||
|
} |
@ -0,0 +1,107 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"database/sql" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
Q = new(Query) |
||||
|
Comment *comment |
||||
|
CommentCount *commentCount |
||||
|
) |
||||
|
|
||||
|
func SetDefault(db *gorm.DB, opts ...gen.DOOption) { |
||||
|
*Q = *Use(db, opts...) |
||||
|
Comment = &Q.Comment |
||||
|
CommentCount = &Q.CommentCount |
||||
|
} |
||||
|
|
||||
|
func Use(db *gorm.DB, opts ...gen.DOOption) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Comment: newComment(db, opts...), |
||||
|
CommentCount: newCommentCount(db, opts...), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type Query struct { |
||||
|
db *gorm.DB |
||||
|
|
||||
|
Comment comment |
||||
|
CommentCount commentCount |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Available() bool { return q.db != nil } |
||||
|
|
||||
|
func (q *Query) clone(db *gorm.DB) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Comment: q.Comment.clone(db), |
||||
|
CommentCount: q.CommentCount.clone(db), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (q *Query) ReadDB() *Query { |
||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Read)) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) WriteDB() *Query { |
||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Write)) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) ReplaceDB(db *gorm.DB) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Comment: q.Comment.replaceDB(db), |
||||
|
CommentCount: q.CommentCount.replaceDB(db), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type queryCtx struct { |
||||
|
Comment ICommentDo |
||||
|
CommentCount ICommentCountDo |
||||
|
} |
||||
|
|
||||
|
func (q *Query) WithContext(ctx context.Context) *queryCtx { |
||||
|
return &queryCtx{ |
||||
|
Comment: q.Comment.WithContext(ctx), |
||||
|
CommentCount: q.CommentCount.WithContext(ctx), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error { |
||||
|
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx { |
||||
|
return &QueryTx{q.clone(q.db.Begin(opts...))} |
||||
|
} |
||||
|
|
||||
|
type QueryTx struct{ *Query } |
||||
|
|
||||
|
func (q *QueryTx) Commit() error { |
||||
|
return q.db.Commit().Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) Rollback() error { |
||||
|
return q.db.Rollback().Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) SavePoint(name string) error { |
||||
|
return q.db.SavePoint(name).Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) RollbackTo(name string) error { |
||||
|
return q.db.RollbackTo(name).Error |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
package query |
||||
|
|
||||
|
var CommentStruct = &comment{} |
||||
|
var CommentCountStruct = &commentCount{} |
@ -0,0 +1,78 @@ |
|||||
|
package comment_count_repo |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/query" |
||||
|
"github.com/TremblingV5/box/dbtx" |
||||
|
) |
||||
|
|
||||
|
type Repository interface { |
||||
|
Save(ctx context.Context, commentCount *model.CommentCount) error |
||||
|
Update(ctx context.Context, commentCount *model.CommentCount) error |
||||
|
LoadById(ctx context.Context, id int64) (*model.CommentCount, error) |
||||
|
LoadByIdList(ctx context.Context, ids ...int64) ([]*model.CommentCount, error) |
||||
|
UpdateNumber(ctx context.Context, id, number int64) error |
||||
|
} |
||||
|
|
||||
|
type PersistRepository struct{} |
||||
|
|
||||
|
func New() *PersistRepository { |
||||
|
return &PersistRepository{} |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Save(ctx context.Context, commentCount *model.CommentCount) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
return tx.CommentCount.WithContext(ctx).Save(commentCount) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Update(ctx context.Context, commentCount *model.CommentCount) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
_, err := query.CommentCount.WithContext(ctx).Where( |
||||
|
query.CommentCount.Id.Eq(commentCount.Id), |
||||
|
).Updates( |
||||
|
commentCount, |
||||
|
) |
||||
|
|
||||
|
return err |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) LoadById(ctx context.Context, id int64) (commentCount *model.CommentCount, err error) { |
||||
|
err = dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
c, err := tx.CommentCount.WithContext(ctx).Where( |
||||
|
query.CommentCount.Id.Eq(id), |
||||
|
).First() |
||||
|
commentCount = c |
||||
|
return err |
||||
|
}) |
||||
|
|
||||
|
return commentCount, err |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) LoadByIdList(ctx context.Context, ids ...int64) (commentCountList []*model.CommentCount, err error) { |
||||
|
err = dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
c, err := tx.CommentCount.WithContext(ctx).Where( |
||||
|
query.CommentCount.Id.In(ids...), |
||||
|
).Find() |
||||
|
|
||||
|
commentCountList = append(commentCountList, c...) |
||||
|
return err |
||||
|
}) |
||||
|
|
||||
|
return commentCountList, err |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) UpdateNumber(ctx context.Context, id, number int64) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
_, err := query.CommentCount.WithContext(ctx).Where( |
||||
|
query.CommentCount.Id.Eq(id), |
||||
|
).Update( |
||||
|
query.CommentCount.Number, number, |
||||
|
) |
||||
|
return err |
||||
|
}) |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
package comment_hb_repo |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
"github.com/TremblingV5/DouTok/pkg/hbaseHandle" |
||||
|
tools "github.com/TremblingV5/DouTok/pkg/misc" |
||||
|
"github.com/tsuna/gohbase" |
||||
|
"github.com/tsuna/gohbase/hrpc" |
||||
|
) |
||||
|
|
||||
|
type Repository interface { |
||||
|
Save(ctx context.Context, comment *model.CommentInHB) error |
||||
|
ScanByPrefix(ctx context.Context, videoId int64) ([]*model.CommentInHB, error) |
||||
|
Delete(ctx context.Context, rowKey string) error |
||||
|
} |
||||
|
|
||||
|
type PersistRepository struct { |
||||
|
hbClient gohbase.Client |
||||
|
} |
||||
|
|
||||
|
func New(hbClient gohbase.Client) *PersistRepository { |
||||
|
return &PersistRepository{ |
||||
|
hbClient: hbClient, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Save(ctx context.Context, comment *model.CommentInHB) error { |
||||
|
hbData := map[string]map[string][]byte{ |
||||
|
"data": { |
||||
|
"id": comment.Id, |
||||
|
"video_id": comment.VideoId, |
||||
|
"user_id": comment.UserId, |
||||
|
"conversation_id": comment.ConversationId, |
||||
|
"last_id": comment.LastId, |
||||
|
"to_user_id": comment.ToUserId, |
||||
|
"content": comment.Content, |
||||
|
"timestamp": comment.Timestamp, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
if _, err := r.hbClient.Put( |
||||
|
"comment", misc.GetCommentRowKey( |
||||
|
comment.GetVideoId(), "0", |
||||
|
comment.GetConversationId(), |
||||
|
comment.GetTimestamp(), |
||||
|
), hbData, |
||||
|
); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) ScanByPrefix(ctx context.Context, videoId int64) ([]*model.CommentInHB, error) { |
||||
|
result, err := r.hbClient.Scan( |
||||
|
"comment", |
||||
|
hbaseHandle.GetFilterByRowKeyPrefix(misc.GetCommentQueryPrefix(videoId))..., |
||||
|
) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
var commentList []*model.CommentInHB |
||||
|
|
||||
|
for _, v := range result { |
||||
|
temp := model.CommentInHB{} |
||||
|
err := tools.Map2Struct4HB(v, &temp) |
||||
|
if err != nil { |
||||
|
continue |
||||
|
} |
||||
|
commentList = append(commentList, &temp) |
||||
|
} |
||||
|
|
||||
|
return commentList, nil |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Delete(ctx context.Context, rowKey string) error { |
||||
|
rmReq, err := hrpc.NewDelStr( |
||||
|
context.Background(), |
||||
|
"comment", rowKey, make(map[string]map[string][]byte), |
||||
|
) |
||||
|
|
||||
|
if err != nil { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
if _, err := r.hbClient.Client.Delete(rmReq); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
package comment_repo |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/model" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/query" |
||||
|
"github.com/TremblingV5/box/dbtx" |
||||
|
) |
||||
|
|
||||
|
type Repository interface { |
||||
|
Save(ctx context.Context, comment *model.Comment) error |
||||
|
Update(ctx context.Context, comment *model.Comment) error |
||||
|
MarkAsDeleted(ctx context.Context, id int64) error |
||||
|
LoadById(ctx context.Context, id int64) (*model.Comment, error) |
||||
|
} |
||||
|
|
||||
|
type PersistRepository struct { |
||||
|
} |
||||
|
|
||||
|
func New() *PersistRepository { |
||||
|
return &PersistRepository{} |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Save(ctx context.Context, comment *model.Comment) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
return tx.Comment.WithContext(ctx).Save(comment) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) Update(ctx context.Context, comment *model.Comment) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
_, err := tx.Comment.WithContext(ctx).Where( |
||||
|
query.Comment.Id.Eq(comment.Id), |
||||
|
).Updates(comment) |
||||
|
|
||||
|
return err |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) MarkAsDeleted(ctx context.Context, id int64) error { |
||||
|
return dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
_, err := tx.Comment.WithContext(ctx).Where( |
||||
|
query.Comment.Id.Eq(id), |
||||
|
).Update( |
||||
|
query.Comment.Status, false, |
||||
|
) |
||||
|
|
||||
|
return err |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func (r *PersistRepository) LoadById(ctx context.Context, id int64) (comment *model.Comment, err error) { |
||||
|
err = dbtx.TxDo(ctx, func(tx *query.QueryTx) error { |
||||
|
c, err := tx.Comment.WithContext(ctx).Where(query.Comment.Id.Eq(id)).First() |
||||
|
comment = c |
||||
|
return err |
||||
|
}) |
||||
|
|
||||
|
return comment, err |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package rpc |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/user/userservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/constants" |
||||
|
"github.com/TremblingV5/DouTok/pkg/services" |
||||
|
"github.com/cloudwego/kitex/client" |
||||
|
) |
||||
|
|
||||
|
type Clients struct { |
||||
|
User *services.Service[userservice.Client] |
||||
|
} |
||||
|
|
||||
|
func New(options []client.Option) *Clients { |
||||
|
return &Clients{ |
||||
|
User: services.New[userservice.Client](constants.UserServerName, userservice.NewClient, options), |
||||
|
} |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/api/comment_api" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/query" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/repository/comment_hb_repo" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/rpc" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/services/comment_service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/comment/commentservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/cache" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dlog" |
||||
|
"github.com/TremblingV5/DouTok/pkg/hbaseHandle" |
||||
|
"github.com/TremblingV5/DouTok/pkg/initHelper" |
||||
|
"github.com/TremblingV5/box/components/hbasex" |
||||
|
"github.com/TremblingV5/box/components/mysqlx" |
||||
|
"github.com/TremblingV5/box/components/redisx" |
||||
|
"github.com/TremblingV5/box/configx" |
||||
|
"github.com/TremblingV5/box/dbtx" |
||||
|
"github.com/TremblingV5/box/launcher" |
||||
|
"github.com/TremblingV5/box/rpcserver/kitexx" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
Logger = dlog.InitLog(3) |
||||
|
) |
||||
|
|
||||
|
func initHb(host string) hbaseHandle.HBaseClient { |
||||
|
return hbaseHandle.InitHB(host) |
||||
|
} |
||||
|
|
||||
|
func Init() comment.CommentService { |
||||
|
ctx := context.Background() |
||||
|
|
||||
|
misc.InitViperConfig() |
||||
|
|
||||
|
query.SetDefault( |
||||
|
mysqlx.GetDBClient(context.Background(), "default"), |
||||
|
) |
||||
|
dbtx.Init(func() dbtx.TX { |
||||
|
return query.Q.Begin() |
||||
|
}) |
||||
|
|
||||
|
hbaseClient := initHb(misc.GetConfig("HBase.Host")) |
||||
|
|
||||
|
service := comment_service.New( |
||||
|
cache.NewCountMapCache(), |
||||
|
cache.NewCountMapCache(), |
||||
|
comment_hb_repo.New(hbasex.GetClient(ctx, "default")), |
||||
|
redisx.GetClient(ctx, "default", misc.ComCntCache), |
||||
|
redisx.GetClient(ctx, "default", misc.ComTotalCntCache), |
||||
|
) |
||||
|
|
||||
|
go service.UpdateComCountMap() |
||||
|
go service.UpdateComTotalCntMap() |
||||
|
|
||||
|
handle := comment_api.New(service, rpc.New(initHelper.InitRPCClientArgs(misc.Config))) |
||||
|
return handle |
||||
|
} |
||||
|
|
||||
|
func oldMain() { |
||||
|
Init() |
||||
|
|
||||
|
options, shutdown := initHelper.InitRPCServerArgs(misc.Config) |
||||
|
defer shutdown() |
||||
|
|
||||
|
svr := commentservice.NewServer( |
||||
|
Init(), |
||||
|
options..., |
||||
|
) |
||||
|
|
||||
|
if err := svr.Run(); err != nil { |
||||
|
Logger.Fatal(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
l := launcher.New() |
||||
|
|
||||
|
l.AddBeforeConfigInitHandler(func() { |
||||
|
configx.SetRootConfigFilename("comment") |
||||
|
}) |
||||
|
|
||||
|
options, shutdown := initHelper.InitRPCServerArgs(misc.Config) |
||||
|
defer shutdown() |
||||
|
|
||||
|
l.AddBeforeServerStartHandler(func() { |
||||
|
l.AddServer( |
||||
|
kitexx.NewKitexServer( |
||||
|
commentservice.NewServer, Init(), options..., |
||||
|
), |
||||
|
) |
||||
|
}) |
||||
|
|
||||
|
l.Run() |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
#! /usr/bin/env bash |
||||
|
CURDIR=$(cd $(dirname $0); pwd) |
||||
|
|
||||
|
if [ "X$1" != "X" ]; then |
||||
|
RUNTIME_ROOT=$1 |
||||
|
else |
||||
|
RUNTIME_ROOT=${CURDIR} |
||||
|
fi |
||||
|
|
||||
|
export KITEX_RUNTIME_ROOT=$RUNTIME_ROOT |
||||
|
export KITEX_LOG_DIR="$RUNTIME_ROOT/log" |
||||
|
|
||||
|
if [ ! -d "$KITEX_LOG_DIR/app" ]; then |
||||
|
mkdir -p "$KITEX_LOG_DIR/app" |
||||
|
fi |
||||
|
|
||||
|
if [ ! -d "$KITEX_LOG_DIR/rpc" ]; then |
||||
|
mkdir -p "$KITEX_LOG_DIR/rpc" |
||||
|
fi |
||||
|
|
||||
|
exec "$CURDIR/bin/comment" |
@ -0,0 +1,234 @@ |
|||||
|
package comment_service |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
|
||||
|
misc "github.com/TremblingV5/DouTok/applications/comment/infra/misc" |
||||
|
"github.com/TremblingV5/box/dbtx" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/domain/entity/comment" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/domain/entity/comment_count" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/repository/comment_count_repo" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/repository/comment_hb_repo" |
||||
|
"github.com/TremblingV5/DouTok/applications/comment/infra/repository/comment_repo" |
||||
|
"github.com/TremblingV5/DouTok/pkg/cache" |
||||
|
"github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
"github.com/go-redis/redis/v8" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/pkg/utils" |
||||
|
) |
||||
|
|
||||
|
type Service struct { |
||||
|
commentCountCache *cache.CountMapCache |
||||
|
commentTotalCountCache *cache.CountMapCache |
||||
|
commentHBRepository comment_hb_repo.Repository |
||||
|
commentCountRedis *redis.Client |
||||
|
commentTotalCountRedis *redis.Client |
||||
|
commentRepository comment_repo.Repository |
||||
|
commentCountRepository comment_count_repo.Repository |
||||
|
} |
||||
|
|
||||
|
func New( |
||||
|
commentCountCache *cache.CountMapCache, |
||||
|
commentTotalCountCache *cache.CountMapCache, |
||||
|
commentHBRepository comment_hb_repo.Repository, |
||||
|
commentCountRedis *redis.Client, |
||||
|
commentTotalCountRedis *redis.Client, |
||||
|
) *Service { |
||||
|
return &Service{ |
||||
|
commentCountCache: commentCountCache, |
||||
|
commentTotalCountCache: commentTotalCountCache, |
||||
|
commentHBRepository: commentHBRepository, |
||||
|
commentCountRedis: commentCountRedis, |
||||
|
commentTotalCountRedis: commentTotalCountRedis, |
||||
|
commentRepository: comment_repo.New(), |
||||
|
commentCountRepository: comment_count_repo.New(), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *Service) AddComment( |
||||
|
ctx context.Context, |
||||
|
videoId int64, userId int64, conId int64, |
||||
|
lastId int64, toUserId int64, content string, |
||||
|
) (c *comment.Entity, err error) { |
||||
|
ctx, persist := dbtx.WithTXPersist(ctx) |
||||
|
defer func() { |
||||
|
persist(err) |
||||
|
}() |
||||
|
|
||||
|
timestamp := fmt.Sprint(time.Now().Unix()) |
||||
|
|
||||
|
id := utils.GetSnowFlakeId().Int64() |
||||
|
|
||||
|
comment, err := comment.New( |
||||
|
comment.WithId(id), |
||||
|
comment.WithVideoId(videoId), |
||||
|
comment.WithUserId(userId), |
||||
|
comment.WithConversationId(conId), |
||||
|
comment.WithLastId(lastId), |
||||
|
comment.WithToUserId(toUserId), |
||||
|
comment.WithContent(content), |
||||
|
comment.WithTimestamp(timestamp), |
||||
|
) |
||||
|
|
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
if err := s.commentRepository.Save(ctx, comment.ToModel()); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
// TODO: 通过消息队列异步写
|
||||
|
if err := s.commentHBRepository.Save(ctx, comment.ToHBModel()); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
s.updateCacheComCount(videoId, true) |
||||
|
|
||||
|
return comment, nil |
||||
|
} |
||||
|
|
||||
|
func (s *Service) CountComment(ctx context.Context, videoId ...int64) (result map[int64]int64, e *errno.ErrNo, err error) { |
||||
|
ctx, persist := dbtx.WithTXPersist(ctx) |
||||
|
defer func() { |
||||
|
persist(err) |
||||
|
}() |
||||
|
|
||||
|
resMap := make(map[int64]int64) |
||||
|
|
||||
|
// 1. 从内存中查找喜欢数
|
||||
|
var findAgain []int64 |
||||
|
for _, v := range videoId { |
||||
|
cnt, ok := s.readComTotalCount(v) |
||||
|
|
||||
|
if !ok { |
||||
|
findAgain = append(findAgain, v) |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
resMap[v] = cnt |
||||
|
} |
||||
|
|
||||
|
// 2. 从Redis中查找喜欢数
|
||||
|
var findAgainAgain []int64 |
||||
|
for _, v := range findAgain { |
||||
|
cnt, ok, _ := s.readComTotalCountFromCache(fmt.Sprint(v)) |
||||
|
|
||||
|
if !ok { |
||||
|
findAgainAgain = append(findAgainAgain, v) |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
resMap[v] = cnt |
||||
|
s.commentTotalCountCache.Set(v, cnt) |
||||
|
} |
||||
|
|
||||
|
// 3. 从MySQL中查找喜欢数
|
||||
|
commentCountModels, err := s.commentCountRepository.LoadByIdList(ctx, findAgainAgain...) |
||||
|
if err != nil { |
||||
|
return nil, &misc.QueryCommentCountErr, err |
||||
|
} |
||||
|
|
||||
|
commentCounts := comment_count.NewListFromModels(commentCountModels) |
||||
|
for _, v := range commentCounts { |
||||
|
resMap[v.Id] = v.Number |
||||
|
} |
||||
|
|
||||
|
// 4. 如果仍然没有查找到该记录,则置0
|
||||
|
for _, v := range videoId { |
||||
|
if _, ok := resMap[v]; !ok { |
||||
|
resMap[v] = 0 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return resMap, &misc.Success, nil |
||||
|
} |
||||
|
|
||||
|
func (s *Service) readComTotalCount(videoId int64) (int64, bool) { |
||||
|
return s.commentTotalCountCache.Get(videoId) |
||||
|
} |
||||
|
|
||||
|
func (s *Service) readComTotalCountFromCache(videoId string) (int64, bool, error) { |
||||
|
data, err := s.commentTotalCountRedis.Get(context.Background(), videoId).Result() |
||||
|
if errors.Is(err, redis.Nil) { |
||||
|
return 0, false, nil |
||||
|
} else if err != nil { |
||||
|
return 0, false, err |
||||
|
} |
||||
|
|
||||
|
num, _ := strconv.ParseInt(data, 10, 64) |
||||
|
|
||||
|
return num, true, nil |
||||
|
} |
||||
|
|
||||
|
func (s *Service) updateCacheComCount(videoId int64, isAdd bool) { |
||||
|
if isAdd { |
||||
|
s.commentCountCache.Add(videoId, 1) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
s.commentCountCache.Add(videoId, -1) |
||||
|
} |
||||
|
|
||||
|
func (s *Service) ListComment(ctx context.Context, videoId int64) (comment.List, errno.ErrNo, error) { |
||||
|
commentHBModels, err := s.commentHBRepository.ScanByPrefix(ctx, videoId) |
||||
|
if err != nil { |
||||
|
return nil, misc.QueryCommentListInHBErr, err |
||||
|
} |
||||
|
|
||||
|
commentList := comment.NewListFromHBModels(commentHBModels) |
||||
|
return commentList, misc.Success, nil |
||||
|
} |
||||
|
|
||||
|
func (s *Service) RmComment(ctx context.Context, userId, commentId int64) (e errno.ErrNo, err error) { |
||||
|
ctx, persist := dbtx.WithTXPersist(ctx) |
||||
|
defer func() { |
||||
|
persist(err) |
||||
|
}() |
||||
|
|
||||
|
commentModel, err := s.commentRepository.LoadById(ctx, commentId) |
||||
|
if err != nil { |
||||
|
return misc.SystemErr, err |
||||
|
} |
||||
|
|
||||
|
comment, err := comment.New( |
||||
|
comment.WithId(commentModel.Id), |
||||
|
comment.WithVideoId(commentModel.VideoId), |
||||
|
comment.WithUserId(commentModel.UserId), |
||||
|
comment.WithConversationId(commentModel.ConversationId), |
||||
|
comment.WithLastId(commentModel.LastId), |
||||
|
comment.WithToUserId(commentModel.ToUserId), |
||||
|
comment.WithContent(commentModel.Content), |
||||
|
comment.WithTimestamp(commentModel.Timestamp), |
||||
|
comment.WithStatus(commentModel.Status), |
||||
|
comment.WithCreatedAt(commentModel.CreatedAt), |
||||
|
comment.WithUpdatedAt(commentModel.UpdatedAt), |
||||
|
) |
||||
|
if err != nil { |
||||
|
return misc.SystemErr, err |
||||
|
} |
||||
|
|
||||
|
_, err = comment.IsBelongUser(userId) |
||||
|
if err != nil { |
||||
|
return misc.SystemErr, err |
||||
|
} |
||||
|
|
||||
|
comment.MarkAsDelete() |
||||
|
|
||||
|
if err := s.commentRepository.Update(ctx, comment.ToModel()); err != nil { |
||||
|
return misc.SystemErr, err |
||||
|
} |
||||
|
|
||||
|
if err := s.commentHBRepository.Save(ctx, comment.ToHBModel()); err != nil { |
||||
|
return misc.SystemErr, err |
||||
|
} |
||||
|
|
||||
|
s.updateCacheComCount(comment.VideoId, false) |
||||
|
|
||||
|
return misc.Success, nil |
||||
|
} |
@ -0,0 +1,101 @@ |
|||||
|
package comment_service |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/comment/domain/entity/comment_count" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dlog" |
||||
|
) |
||||
|
|
||||
|
var logger = dlog.InitLog(3) |
||||
|
|
||||
|
/* |
||||
|
定时将内存中的局部评论数更新到数据库中,并删除Redis中的评论总数 |
||||
|
*/ |
||||
|
func (s *Service) UpdateComCountMap() { |
||||
|
for { |
||||
|
time.Sleep(time.Duration(5) * time.Second) |
||||
|
logger.Info("Start iter comment cnt map and update on " + fmt.Sprint(time.Now().Unix())) |
||||
|
|
||||
|
var keyList []string |
||||
|
s.commentCountCache.Iter(func(key string, v interface{}) { |
||||
|
keyList = append(keyList, key) |
||||
|
|
||||
|
keyI64, _ := strconv.ParseInt(key, 10, 64) |
||||
|
err := s.updateCount(context.Background(), keyI64, int64(v.(int))) |
||||
|
if err != nil { |
||||
|
dlog.Warn("Write comment count to RDB defeat: " + key + " with count: " + fmt.Sprint(v.(int))) |
||||
|
} |
||||
|
|
||||
|
err = s.delCount2Cache(key) |
||||
|
if err != nil { |
||||
|
dlog.Warn("Delete comment count from third party cache defeat: " + key) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
for _, v := range keyList { |
||||
|
i64, _ := strconv.ParseInt(v, 10, 64) |
||||
|
s.commentCountCache.Set(i64, 0) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
定时将Redis中每个Video的Comment总数更新到内存中的Map |
||||
|
Redis不存在的视频评论数由单独查询时再添加到Redis中 |
||||
|
*/ |
||||
|
func (s *Service) UpdateComTotalCntMap() { |
||||
|
for { |
||||
|
time.Sleep(time.Duration(5) * time.Second) |
||||
|
logger.Info("Start iter comment total cnt map and update on " + fmt.Sprint(time.Now().Unix())) |
||||
|
|
||||
|
keyList := []string{} |
||||
|
|
||||
|
s.commentTotalCountCache.Iter(func(key string, v interface{}) { |
||||
|
keyList = append(keyList, key) |
||||
|
}) |
||||
|
|
||||
|
for _, v := range keyList { |
||||
|
res, err := s.commentTotalCountRedis.Get(context.Background(), v).Result() |
||||
|
if err != nil { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
i, _ := strconv.ParseInt(res, 10, 64) |
||||
|
iKey, _ := strconv.ParseInt(v, 10, 64) |
||||
|
s.commentTotalCountCache.Set(iKey, i) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *Service) updateCount(ctx context.Context, videoId int64, cnt int64) error { |
||||
|
commentModel, err := s.commentCountRepository.LoadById(ctx, videoId) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
|
||||
|
} |
||||
|
|
||||
|
commentCount := comment_count.TransformFromModel(commentModel) |
||||
|
|
||||
|
if err := commentCount.Check(comment_count.IsIdValid()); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
commentCount.UpdateNumber(cnt) |
||||
|
|
||||
|
if err := s.commentCountRepository.Update(ctx, commentCount.ToModel()); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
删除Redis中存储的视频的完整的评论数量 |
||||
|
*/ |
||||
|
func (s *Service) delCount2Cache(videoId string) error { |
||||
|
return s.commentTotalCountRedis.Del(context.Background(), videoId).Err() |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package comment_service |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func GetTimeRecall(timestamp string, current int64) string { |
||||
|
timestampI64, _ := strconv.ParseInt(timestamp, 10, 64) |
||||
|
|
||||
|
diff := current - timestampI64 |
||||
|
|
||||
|
if diff < 60 { |
||||
|
return "刚刚" |
||||
|
} else if diff < 60*60 { |
||||
|
minutes := diff / 60 |
||||
|
return fmt.Sprint(minutes) + "分钟前" |
||||
|
} else if diff < 60*60*24 { |
||||
|
hours := diff / (60 * 60) |
||||
|
return fmt.Sprint(hours) + "小时前" |
||||
|
} else if diff < 60*60*24*14 { |
||||
|
days := diff / (60 * 60 * 24) |
||||
|
return fmt.Sprint(days) + "天前" |
||||
|
} else { |
||||
|
t := time.Unix(timestampI64, 0) |
||||
|
return t.Format("2006/01/02") |
||||
|
} |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
server: |
||||
|
kitex -module github.com/TremblingV5/DouTok -type protobuf -I ../../proto/ -service favorite ../../proto/favorite.proto |
@ -0,0 +1,12 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
RUN_NAME="favorite" |
||||
|
|
||||
|
mkdir -p output/bin |
||||
|
cp script/* output/ |
||||
|
chmod +x output/bootstrap.sh |
||||
|
|
||||
|
if [ "$IS_SYSTEM_TEST_ENV" != "1" ]; then |
||||
|
go build -o output/bin/${RUN_NAME} |
||||
|
else |
||||
|
go test -c -covermode=set -o output/bin/${RUN_NAME} -coverpkg=./... |
||||
|
fi |
@ -0,0 +1,39 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/dal/model" |
||||
|
"github.com/TremblingV5/DouTok/config/configStruct" |
||||
|
"github.com/TremblingV5/DouTok/pkg/configurator" |
||||
|
"github.com/TremblingV5/DouTok/pkg/mysqlIniter" |
||||
|
"gorm.io/gen" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
g := gen.NewGenerator(gen.Config{ |
||||
|
OutPath: "../query", |
||||
|
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, |
||||
|
}) |
||||
|
|
||||
|
var config configStruct.MySQLConfig |
||||
|
configurator.InitConfig( |
||||
|
&config, "mysql.yaml", |
||||
|
) |
||||
|
|
||||
|
db, err := mysqlIniter.InitDb( |
||||
|
config.Username, |
||||
|
config.Password, |
||||
|
config.Host, |
||||
|
config.Port, |
||||
|
config.Database, |
||||
|
) |
||||
|
|
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
|
||||
|
g.UseDB(db) |
||||
|
g.ApplyBasic(model.Favorite{}, model.FavoriteCount{}) |
||||
|
g.ApplyInterface(func() {}, model.Favorite{}, model.FavoriteCount{}) |
||||
|
|
||||
|
g.Execute() |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/dal/model" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
misc.InitViperConfig() |
||||
|
|
||||
|
service.InitDb( |
||||
|
misc.GetConfig("MySQL.Username"), |
||||
|
misc.GetConfig("MySQL.Password"), |
||||
|
misc.GetConfig("MySQL.Host"), |
||||
|
misc.GetConfig("MySQL.Port"), |
||||
|
misc.GetConfig("MySQL.Database"), |
||||
|
) |
||||
|
|
||||
|
service.DB.AutoMigrate(&model.Favorite{}, &model.FavoriteCount{}) |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package model |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
type FavoriteCount struct { |
||||
|
VideoId int64 `gorm:"index:video_id"` |
||||
|
Number int64 |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
package model |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
type Favorite struct { |
||||
|
ID int64 `gorm:"primarykey"` |
||||
|
UserId int64 `gorm:"index:user_id"` |
||||
|
VideoId int64 `gorm:"index:video_id"` |
||||
|
Status int |
||||
|
CreatedAt time.Time |
||||
|
UpdatedAt time.Time |
||||
|
} |
@ -0,0 +1,396 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
"gorm.io/gorm/clause" |
||||
|
"gorm.io/gorm/schema" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
"gorm.io/gen/field" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/dal/model" |
||||
|
) |
||||
|
|
||||
|
func newFavoriteCount(db *gorm.DB, opts ...gen.DOOption) favoriteCount { |
||||
|
_favoriteCount := favoriteCount{} |
||||
|
|
||||
|
_favoriteCount.favoriteCountDo.UseDB(db, opts...) |
||||
|
_favoriteCount.favoriteCountDo.UseModel(&model.FavoriteCount{}) |
||||
|
|
||||
|
tableName := _favoriteCount.favoriteCountDo.TableName() |
||||
|
_favoriteCount.ALL = field.NewAsterisk(tableName) |
||||
|
_favoriteCount.VideoId = field.NewInt64(tableName, "video_id") |
||||
|
_favoriteCount.Number = field.NewInt64(tableName, "number") |
||||
|
_favoriteCount.CreatedAt = field.NewTime(tableName, "created_at") |
||||
|
_favoriteCount.UpdatedAt = field.NewTime(tableName, "updated_at") |
||||
|
|
||||
|
_favoriteCount.fillFieldMap() |
||||
|
|
||||
|
return _favoriteCount |
||||
|
} |
||||
|
|
||||
|
type favoriteCount struct { |
||||
|
favoriteCountDo |
||||
|
|
||||
|
ALL field.Asterisk |
||||
|
VideoId field.Int64 |
||||
|
Number field.Int64 |
||||
|
CreatedAt field.Time |
||||
|
UpdatedAt field.Time |
||||
|
|
||||
|
fieldMap map[string]field.Expr |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCount) Table(newTableName string) *favoriteCount { |
||||
|
f.favoriteCountDo.UseTable(newTableName) |
||||
|
return f.updateTableName(newTableName) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCount) As(alias string) *favoriteCount { |
||||
|
f.favoriteCountDo.DO = *(f.favoriteCountDo.As(alias).(*gen.DO)) |
||||
|
return f.updateTableName(alias) |
||||
|
} |
||||
|
|
||||
|
func (f *favoriteCount) updateTableName(table string) *favoriteCount { |
||||
|
f.ALL = field.NewAsterisk(table) |
||||
|
f.VideoId = field.NewInt64(table, "video_id") |
||||
|
f.Number = field.NewInt64(table, "number") |
||||
|
f.CreatedAt = field.NewTime(table, "created_at") |
||||
|
f.UpdatedAt = field.NewTime(table, "updated_at") |
||||
|
|
||||
|
f.fillFieldMap() |
||||
|
|
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
func (f *favoriteCount) GetFieldByName(fieldName string) (field.OrderExpr, bool) { |
||||
|
_f, ok := f.fieldMap[fieldName] |
||||
|
if !ok || _f == nil { |
||||
|
return nil, false |
||||
|
} |
||||
|
_oe, ok := _f.(field.OrderExpr) |
||||
|
return _oe, ok |
||||
|
} |
||||
|
|
||||
|
func (f *favoriteCount) fillFieldMap() { |
||||
|
f.fieldMap = make(map[string]field.Expr, 4) |
||||
|
f.fieldMap["video_id"] = f.VideoId |
||||
|
f.fieldMap["number"] = f.Number |
||||
|
f.fieldMap["created_at"] = f.CreatedAt |
||||
|
f.fieldMap["updated_at"] = f.UpdatedAt |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCount) clone(db *gorm.DB) favoriteCount { |
||||
|
f.favoriteCountDo.ReplaceConnPool(db.Statement.ConnPool) |
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCount) replaceDB(db *gorm.DB) favoriteCount { |
||||
|
f.favoriteCountDo.ReplaceDB(db) |
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
type favoriteCountDo struct{ gen.DO } |
||||
|
|
||||
|
type IFavoriteCountDo interface { |
||||
|
gen.SubQuery |
||||
|
Debug() IFavoriteCountDo |
||||
|
WithContext(ctx context.Context) IFavoriteCountDo |
||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo |
||||
|
ReplaceDB(db *gorm.DB) |
||||
|
ReadDB() IFavoriteCountDo |
||||
|
WriteDB() IFavoriteCountDo |
||||
|
As(alias string) gen.Dao |
||||
|
Session(config *gorm.Session) IFavoriteCountDo |
||||
|
Columns(cols ...field.Expr) gen.Columns |
||||
|
Clauses(conds ...clause.Expression) IFavoriteCountDo |
||||
|
Not(conds ...gen.Condition) IFavoriteCountDo |
||||
|
Or(conds ...gen.Condition) IFavoriteCountDo |
||||
|
Select(conds ...field.Expr) IFavoriteCountDo |
||||
|
Where(conds ...gen.Condition) IFavoriteCountDo |
||||
|
Order(conds ...field.Expr) IFavoriteCountDo |
||||
|
Distinct(cols ...field.Expr) IFavoriteCountDo |
||||
|
Omit(cols ...field.Expr) IFavoriteCountDo |
||||
|
Join(table schema.Tabler, on ...field.Expr) IFavoriteCountDo |
||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) IFavoriteCountDo |
||||
|
RightJoin(table schema.Tabler, on ...field.Expr) IFavoriteCountDo |
||||
|
Group(cols ...field.Expr) IFavoriteCountDo |
||||
|
Having(conds ...gen.Condition) IFavoriteCountDo |
||||
|
Limit(limit int) IFavoriteCountDo |
||||
|
Offset(offset int) IFavoriteCountDo |
||||
|
Count() (count int64, err error) |
||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) IFavoriteCountDo |
||||
|
Unscoped() IFavoriteCountDo |
||||
|
Create(values ...*model.FavoriteCount) error |
||||
|
CreateInBatches(values []*model.FavoriteCount, batchSize int) error |
||||
|
Save(values ...*model.FavoriteCount) error |
||||
|
First() (*model.FavoriteCount, error) |
||||
|
Take() (*model.FavoriteCount, error) |
||||
|
Last() (*model.FavoriteCount, error) |
||||
|
Find() ([]*model.FavoriteCount, error) |
||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.FavoriteCount, err error) |
||||
|
FindInBatches(result *[]*model.FavoriteCount, batchSize int, fc func(tx gen.Dao, batch int) error) error |
||||
|
Pluck(column field.Expr, dest interface{}) error |
||||
|
Delete(...*model.FavoriteCount) (info gen.ResultInfo, err error) |
||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
Updates(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateFrom(q gen.SubQuery) gen.Dao |
||||
|
Attrs(attrs ...field.AssignExpr) IFavoriteCountDo |
||||
|
Assign(attrs ...field.AssignExpr) IFavoriteCountDo |
||||
|
Joins(fields ...field.RelationField) IFavoriteCountDo |
||||
|
Preload(fields ...field.RelationField) IFavoriteCountDo |
||||
|
FirstOrInit() (*model.FavoriteCount, error) |
||||
|
FirstOrCreate() (*model.FavoriteCount, error) |
||||
|
FindByPage(offset int, limit int) (result []*model.FavoriteCount, count int64, err error) |
||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error) |
||||
|
Scan(result interface{}) (err error) |
||||
|
Returning(value interface{}, columns ...string) IFavoriteCountDo |
||||
|
UnderlyingDB() *gorm.DB |
||||
|
schema.Tabler |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Debug() IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Debug()) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) WithContext(ctx context.Context) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.WithContext(ctx)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) ReadDB() IFavoriteCountDo { |
||||
|
return f.Clauses(dbresolver.Read) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) WriteDB() IFavoriteCountDo { |
||||
|
return f.Clauses(dbresolver.Write) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Session(config *gorm.Session) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Session(config)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Clauses(conds ...clause.Expression) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Clauses(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Returning(value interface{}, columns ...string) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Returning(value, columns...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Not(conds ...gen.Condition) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Not(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Or(conds ...gen.Condition) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Or(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Select(conds ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Select(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Where(conds ...gen.Condition) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Where(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) IFavoriteCountDo { |
||||
|
return f.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB())) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Order(conds ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Order(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Distinct(cols ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Distinct(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Omit(cols ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Omit(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Join(table schema.Tabler, on ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Join(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) LeftJoin(table schema.Tabler, on ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.LeftJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) RightJoin(table schema.Tabler, on ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.RightJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Group(cols ...field.Expr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Group(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Having(conds ...gen.Condition) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Having(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Limit(limit int) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Limit(limit)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Offset(offset int) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Offset(offset)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Scopes(funcs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Unscoped() IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Unscoped()) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Create(values ...*model.FavoriteCount) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return f.DO.Create(values) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) CreateInBatches(values []*model.FavoriteCount, batchSize int) error { |
||||
|
return f.DO.CreateInBatches(values, batchSize) |
||||
|
} |
||||
|
|
||||
|
// Save : !!! underlying implementation is different with GORM
|
||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
|
func (f favoriteCountDo) Save(values ...*model.FavoriteCount) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return f.DO.Save(values) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) First() (*model.FavoriteCount, error) { |
||||
|
if result, err := f.DO.First(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.FavoriteCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Take() (*model.FavoriteCount, error) { |
||||
|
if result, err := f.DO.Take(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.FavoriteCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Last() (*model.FavoriteCount, error) { |
||||
|
if result, err := f.DO.Last(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.FavoriteCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Find() ([]*model.FavoriteCount, error) { |
||||
|
result, err := f.DO.Find() |
||||
|
return result.([]*model.FavoriteCount), err |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.FavoriteCount, err error) { |
||||
|
buf := make([]*model.FavoriteCount, 0, batchSize) |
||||
|
err = f.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { |
||||
|
defer func() { results = append(results, buf...) }() |
||||
|
return fc(tx, batch) |
||||
|
}) |
||||
|
return results, err |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) FindInBatches(result *[]*model.FavoriteCount, batchSize int, fc func(tx gen.Dao, batch int) error) error { |
||||
|
return f.DO.FindInBatches(result, batchSize, fc) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Attrs(attrs ...field.AssignExpr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Attrs(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Assign(attrs ...field.AssignExpr) IFavoriteCountDo { |
||||
|
return f.withDO(f.DO.Assign(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Joins(fields ...field.RelationField) IFavoriteCountDo { |
||||
|
for _, _f := range fields { |
||||
|
f = *f.withDO(f.DO.Joins(_f)) |
||||
|
} |
||||
|
return &f |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Preload(fields ...field.RelationField) IFavoriteCountDo { |
||||
|
for _, _f := range fields { |
||||
|
f = *f.withDO(f.DO.Preload(_f)) |
||||
|
} |
||||
|
return &f |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) FirstOrInit() (*model.FavoriteCount, error) { |
||||
|
if result, err := f.DO.FirstOrInit(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.FavoriteCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) FirstOrCreate() (*model.FavoriteCount, error) { |
||||
|
if result, err := f.DO.FirstOrCreate(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.FavoriteCount), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) FindByPage(offset int, limit int) (result []*model.FavoriteCount, count int64, err error) { |
||||
|
result, err = f.Offset(offset).Limit(limit).Find() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if size := len(result); 0 < limit && 0 < size && size < limit { |
||||
|
count = int64(size + offset) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
count, err = f.Offset(-1).Limit(-1).Count() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { |
||||
|
count, err = f.Count() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
err = f.Offset(offset).Limit(limit).Scan(result) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Scan(result interface{}) (err error) { |
||||
|
return f.DO.Scan(result) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteCountDo) Delete(models ...*model.FavoriteCount) (result gen.ResultInfo, err error) { |
||||
|
return f.DO.Delete(models) |
||||
|
} |
||||
|
|
||||
|
func (f *favoriteCountDo) withDO(do gen.Dao) *favoriteCountDo { |
||||
|
f.DO = *do.(*gen.DO) |
||||
|
return f |
||||
|
} |
@ -0,0 +1,404 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
"gorm.io/gorm/clause" |
||||
|
"gorm.io/gorm/schema" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
"gorm.io/gen/field" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/dal/model" |
||||
|
) |
||||
|
|
||||
|
func newFavorite(db *gorm.DB, opts ...gen.DOOption) favorite { |
||||
|
_favorite := favorite{} |
||||
|
|
||||
|
_favorite.favoriteDo.UseDB(db, opts...) |
||||
|
_favorite.favoriteDo.UseModel(&model.Favorite{}) |
||||
|
|
||||
|
tableName := _favorite.favoriteDo.TableName() |
||||
|
_favorite.ALL = field.NewAsterisk(tableName) |
||||
|
_favorite.ID = field.NewInt64(tableName, "id") |
||||
|
_favorite.UserId = field.NewInt64(tableName, "user_id") |
||||
|
_favorite.VideoId = field.NewInt64(tableName, "video_id") |
||||
|
_favorite.Status = field.NewInt(tableName, "status") |
||||
|
_favorite.CreatedAt = field.NewTime(tableName, "created_at") |
||||
|
_favorite.UpdatedAt = field.NewTime(tableName, "updated_at") |
||||
|
|
||||
|
_favorite.fillFieldMap() |
||||
|
|
||||
|
return _favorite |
||||
|
} |
||||
|
|
||||
|
type favorite struct { |
||||
|
favoriteDo |
||||
|
|
||||
|
ALL field.Asterisk |
||||
|
ID field.Int64 |
||||
|
UserId field.Int64 |
||||
|
VideoId field.Int64 |
||||
|
Status field.Int |
||||
|
CreatedAt field.Time |
||||
|
UpdatedAt field.Time |
||||
|
|
||||
|
fieldMap map[string]field.Expr |
||||
|
} |
||||
|
|
||||
|
func (f favorite) Table(newTableName string) *favorite { |
||||
|
f.favoriteDo.UseTable(newTableName) |
||||
|
return f.updateTableName(newTableName) |
||||
|
} |
||||
|
|
||||
|
func (f favorite) As(alias string) *favorite { |
||||
|
f.favoriteDo.DO = *(f.favoriteDo.As(alias).(*gen.DO)) |
||||
|
return f.updateTableName(alias) |
||||
|
} |
||||
|
|
||||
|
func (f *favorite) updateTableName(table string) *favorite { |
||||
|
f.ALL = field.NewAsterisk(table) |
||||
|
f.ID = field.NewInt64(table, "id") |
||||
|
f.UserId = field.NewInt64(table, "user_id") |
||||
|
f.VideoId = field.NewInt64(table, "video_id") |
||||
|
f.Status = field.NewInt(table, "status") |
||||
|
f.CreatedAt = field.NewTime(table, "created_at") |
||||
|
f.UpdatedAt = field.NewTime(table, "updated_at") |
||||
|
|
||||
|
f.fillFieldMap() |
||||
|
|
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
func (f *favorite) GetFieldByName(fieldName string) (field.OrderExpr, bool) { |
||||
|
_f, ok := f.fieldMap[fieldName] |
||||
|
if !ok || _f == nil { |
||||
|
return nil, false |
||||
|
} |
||||
|
_oe, ok := _f.(field.OrderExpr) |
||||
|
return _oe, ok |
||||
|
} |
||||
|
|
||||
|
func (f *favorite) fillFieldMap() { |
||||
|
f.fieldMap = make(map[string]field.Expr, 6) |
||||
|
f.fieldMap["id"] = f.ID |
||||
|
f.fieldMap["user_id"] = f.UserId |
||||
|
f.fieldMap["video_id"] = f.VideoId |
||||
|
f.fieldMap["status"] = f.Status |
||||
|
f.fieldMap["created_at"] = f.CreatedAt |
||||
|
f.fieldMap["updated_at"] = f.UpdatedAt |
||||
|
} |
||||
|
|
||||
|
func (f favorite) clone(db *gorm.DB) favorite { |
||||
|
f.favoriteDo.ReplaceConnPool(db.Statement.ConnPool) |
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
func (f favorite) replaceDB(db *gorm.DB) favorite { |
||||
|
f.favoriteDo.ReplaceDB(db) |
||||
|
return f |
||||
|
} |
||||
|
|
||||
|
type favoriteDo struct{ gen.DO } |
||||
|
|
||||
|
type IFavoriteDo interface { |
||||
|
gen.SubQuery |
||||
|
Debug() IFavoriteDo |
||||
|
WithContext(ctx context.Context) IFavoriteDo |
||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo |
||||
|
ReplaceDB(db *gorm.DB) |
||||
|
ReadDB() IFavoriteDo |
||||
|
WriteDB() IFavoriteDo |
||||
|
As(alias string) gen.Dao |
||||
|
Session(config *gorm.Session) IFavoriteDo |
||||
|
Columns(cols ...field.Expr) gen.Columns |
||||
|
Clauses(conds ...clause.Expression) IFavoriteDo |
||||
|
Not(conds ...gen.Condition) IFavoriteDo |
||||
|
Or(conds ...gen.Condition) IFavoriteDo |
||||
|
Select(conds ...field.Expr) IFavoriteDo |
||||
|
Where(conds ...gen.Condition) IFavoriteDo |
||||
|
Order(conds ...field.Expr) IFavoriteDo |
||||
|
Distinct(cols ...field.Expr) IFavoriteDo |
||||
|
Omit(cols ...field.Expr) IFavoriteDo |
||||
|
Join(table schema.Tabler, on ...field.Expr) IFavoriteDo |
||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) IFavoriteDo |
||||
|
RightJoin(table schema.Tabler, on ...field.Expr) IFavoriteDo |
||||
|
Group(cols ...field.Expr) IFavoriteDo |
||||
|
Having(conds ...gen.Condition) IFavoriteDo |
||||
|
Limit(limit int) IFavoriteDo |
||||
|
Offset(offset int) IFavoriteDo |
||||
|
Count() (count int64, err error) |
||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) IFavoriteDo |
||||
|
Unscoped() IFavoriteDo |
||||
|
Create(values ...*model.Favorite) error |
||||
|
CreateInBatches(values []*model.Favorite, batchSize int) error |
||||
|
Save(values ...*model.Favorite) error |
||||
|
First() (*model.Favorite, error) |
||||
|
Take() (*model.Favorite, error) |
||||
|
Last() (*model.Favorite, error) |
||||
|
Find() ([]*model.Favorite, error) |
||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Favorite, err error) |
||||
|
FindInBatches(result *[]*model.Favorite, batchSize int, fc func(tx gen.Dao, batch int) error) error |
||||
|
Pluck(column field.Expr, dest interface{}) error |
||||
|
Delete(...*model.Favorite) (info gen.ResultInfo, err error) |
||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
Updates(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) |
||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error) |
||||
|
UpdateFrom(q gen.SubQuery) gen.Dao |
||||
|
Attrs(attrs ...field.AssignExpr) IFavoriteDo |
||||
|
Assign(attrs ...field.AssignExpr) IFavoriteDo |
||||
|
Joins(fields ...field.RelationField) IFavoriteDo |
||||
|
Preload(fields ...field.RelationField) IFavoriteDo |
||||
|
FirstOrInit() (*model.Favorite, error) |
||||
|
FirstOrCreate() (*model.Favorite, error) |
||||
|
FindByPage(offset int, limit int) (result []*model.Favorite, count int64, err error) |
||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error) |
||||
|
Scan(result interface{}) (err error) |
||||
|
Returning(value interface{}, columns ...string) IFavoriteDo |
||||
|
UnderlyingDB() *gorm.DB |
||||
|
schema.Tabler |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Debug() IFavoriteDo { |
||||
|
return f.withDO(f.DO.Debug()) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) WithContext(ctx context.Context) IFavoriteDo { |
||||
|
return f.withDO(f.DO.WithContext(ctx)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) ReadDB() IFavoriteDo { |
||||
|
return f.Clauses(dbresolver.Read) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) WriteDB() IFavoriteDo { |
||||
|
return f.Clauses(dbresolver.Write) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Session(config *gorm.Session) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Session(config)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Clauses(conds ...clause.Expression) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Clauses(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Returning(value interface{}, columns ...string) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Returning(value, columns...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Not(conds ...gen.Condition) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Not(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Or(conds ...gen.Condition) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Or(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Select(conds ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Select(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Where(conds ...gen.Condition) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Where(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) IFavoriteDo { |
||||
|
return f.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB())) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Order(conds ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Order(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Distinct(cols ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Distinct(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Omit(cols ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Omit(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Join(table schema.Tabler, on ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Join(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) LeftJoin(table schema.Tabler, on ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.LeftJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) RightJoin(table schema.Tabler, on ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.RightJoin(table, on...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Group(cols ...field.Expr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Group(cols...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Having(conds ...gen.Condition) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Having(conds...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Limit(limit int) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Limit(limit)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Offset(offset int) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Offset(offset)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Scopes(funcs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Unscoped() IFavoriteDo { |
||||
|
return f.withDO(f.DO.Unscoped()) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Create(values ...*model.Favorite) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return f.DO.Create(values) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) CreateInBatches(values []*model.Favorite, batchSize int) error { |
||||
|
return f.DO.CreateInBatches(values, batchSize) |
||||
|
} |
||||
|
|
||||
|
// Save : !!! underlying implementation is different with GORM
|
||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
|
func (f favoriteDo) Save(values ...*model.Favorite) error { |
||||
|
if len(values) == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return f.DO.Save(values) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) First() (*model.Favorite, error) { |
||||
|
if result, err := f.DO.First(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Favorite), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Take() (*model.Favorite, error) { |
||||
|
if result, err := f.DO.Take(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Favorite), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Last() (*model.Favorite, error) { |
||||
|
if result, err := f.DO.Last(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Favorite), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Find() ([]*model.Favorite, error) { |
||||
|
result, err := f.DO.Find() |
||||
|
return result.([]*model.Favorite), err |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Favorite, err error) { |
||||
|
buf := make([]*model.Favorite, 0, batchSize) |
||||
|
err = f.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { |
||||
|
defer func() { results = append(results, buf...) }() |
||||
|
return fc(tx, batch) |
||||
|
}) |
||||
|
return results, err |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) FindInBatches(result *[]*model.Favorite, batchSize int, fc func(tx gen.Dao, batch int) error) error { |
||||
|
return f.DO.FindInBatches(result, batchSize, fc) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Attrs(attrs ...field.AssignExpr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Attrs(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Assign(attrs ...field.AssignExpr) IFavoriteDo { |
||||
|
return f.withDO(f.DO.Assign(attrs...)) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Joins(fields ...field.RelationField) IFavoriteDo { |
||||
|
for _, _f := range fields { |
||||
|
f = *f.withDO(f.DO.Joins(_f)) |
||||
|
} |
||||
|
return &f |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Preload(fields ...field.RelationField) IFavoriteDo { |
||||
|
for _, _f := range fields { |
||||
|
f = *f.withDO(f.DO.Preload(_f)) |
||||
|
} |
||||
|
return &f |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) FirstOrInit() (*model.Favorite, error) { |
||||
|
if result, err := f.DO.FirstOrInit(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Favorite), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) FirstOrCreate() (*model.Favorite, error) { |
||||
|
if result, err := f.DO.FirstOrCreate(); err != nil { |
||||
|
return nil, err |
||||
|
} else { |
||||
|
return result.(*model.Favorite), nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) FindByPage(offset int, limit int) (result []*model.Favorite, count int64, err error) { |
||||
|
result, err = f.Offset(offset).Limit(limit).Find() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if size := len(result); 0 < limit && 0 < size && size < limit { |
||||
|
count = int64(size + offset) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
count, err = f.Offset(-1).Limit(-1).Count() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { |
||||
|
count, err = f.Count() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
err = f.Offset(offset).Limit(limit).Scan(result) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Scan(result interface{}) (err error) { |
||||
|
return f.DO.Scan(result) |
||||
|
} |
||||
|
|
||||
|
func (f favoriteDo) Delete(models ...*model.Favorite) (result gen.ResultInfo, err error) { |
||||
|
return f.DO.Delete(models) |
||||
|
} |
||||
|
|
||||
|
func (f *favoriteDo) withDO(do gen.Dao) *favoriteDo { |
||||
|
f.DO = *do.(*gen.DO) |
||||
|
return f |
||||
|
} |
@ -0,0 +1,107 @@ |
|||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
|
||||
|
package query |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"database/sql" |
||||
|
|
||||
|
"gorm.io/gorm" |
||||
|
|
||||
|
"gorm.io/gen" |
||||
|
|
||||
|
"gorm.io/plugin/dbresolver" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
Q = new(Query) |
||||
|
Favorite *favorite |
||||
|
FavoriteCount *favoriteCount |
||||
|
) |
||||
|
|
||||
|
func SetDefault(db *gorm.DB, opts ...gen.DOOption) { |
||||
|
*Q = *Use(db, opts...) |
||||
|
Favorite = &Q.Favorite |
||||
|
FavoriteCount = &Q.FavoriteCount |
||||
|
} |
||||
|
|
||||
|
func Use(db *gorm.DB, opts ...gen.DOOption) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Favorite: newFavorite(db, opts...), |
||||
|
FavoriteCount: newFavoriteCount(db, opts...), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type Query struct { |
||||
|
db *gorm.DB |
||||
|
|
||||
|
Favorite favorite |
||||
|
FavoriteCount favoriteCount |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Available() bool { return q.db != nil } |
||||
|
|
||||
|
func (q *Query) clone(db *gorm.DB) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Favorite: q.Favorite.clone(db), |
||||
|
FavoriteCount: q.FavoriteCount.clone(db), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (q *Query) ReadDB() *Query { |
||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Read)) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) WriteDB() *Query { |
||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Write)) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) ReplaceDB(db *gorm.DB) *Query { |
||||
|
return &Query{ |
||||
|
db: db, |
||||
|
Favorite: q.Favorite.replaceDB(db), |
||||
|
FavoriteCount: q.FavoriteCount.replaceDB(db), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type queryCtx struct { |
||||
|
Favorite IFavoriteDo |
||||
|
FavoriteCount IFavoriteCountDo |
||||
|
} |
||||
|
|
||||
|
func (q *Query) WithContext(ctx context.Context) *queryCtx { |
||||
|
return &queryCtx{ |
||||
|
Favorite: q.Favorite.WithContext(ctx), |
||||
|
FavoriteCount: q.FavoriteCount.WithContext(ctx), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error { |
||||
|
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...) |
||||
|
} |
||||
|
|
||||
|
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx { |
||||
|
return &QueryTx{q.clone(q.db.Begin(opts...))} |
||||
|
} |
||||
|
|
||||
|
type QueryTx struct{ *Query } |
||||
|
|
||||
|
func (q *QueryTx) Commit() error { |
||||
|
return q.db.Commit().Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) Rollback() error { |
||||
|
return q.db.Rollback().Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) SavePoint(name string) error { |
||||
|
return q.db.SavePoint(name).Error |
||||
|
} |
||||
|
|
||||
|
func (q *QueryTx) RollbackTo(name string) error { |
||||
|
return q.db.RollbackTo(name).Error |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
package query |
||||
|
|
||||
|
var FavoriteStruct = &favorite{} |
||||
|
var FavoriteCountStruct = &favoriteCount{} |
@ -0,0 +1,24 @@ |
|||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/pack" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
) |
||||
|
|
||||
|
func (s *FavoriteServiceImpl) FavoriteAction(ctx context.Context, req *favorite.DouyinFavoriteActionRequest) (resp *favorite.DouyinFavoriteActionResponse, err error) { |
||||
|
if req.ActionType == 1 { |
||||
|
// 点赞
|
||||
|
errNo, _ := service.ActionFavorite(req.UserId, req.VideoId, true) |
||||
|
return pack.PackFavoriteActionResp(int32(errNo.ErrCode), errNo.ErrMsg) |
||||
|
} else if req.ActionType == 2 { |
||||
|
// 取消点赞
|
||||
|
errNo, _ := service.ActionFavorite(req.UserId, req.VideoId, false) |
||||
|
return pack.PackFavoriteActionResp(int32(errNo.ErrCode), errNo.ErrMsg) |
||||
|
} else { |
||||
|
return pack.PackFavoriteActionResp(int32(misc.BindingInvalidErr.ErrCode), misc.BindingInvalidErr.ErrMsg) |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/pack" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
) |
||||
|
|
||||
|
func (s *FavoriteServiceImpl) FavoriteCount(ctx context.Context, req *favorite.DouyinFavoriteCountRequest) (resp *favorite.DouyinFavoriteCountResponse, err error) { |
||||
|
if len(req.VideoIdList) == 0 { |
||||
|
return pack.PackFavoriteCountResp(int32(misc.EmptyVideoIdListErr.ErrCode), misc.EmptyVideoIdListErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
res, err := service.QueryFavoriteCount(req.VideoIdList) |
||||
|
if err != nil { |
||||
|
return pack.PackFavoriteCountResp(int32(misc.SystemErr.ErrCode), misc.SystemErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
return pack.PackFavoriteCountResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, res) |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/pack" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
) |
||||
|
|
||||
|
func (s *FavoriteServiceImpl) FavoriteList(ctx context.Context, req *favorite.DouyinFavoriteListRequest) (resp *favorite.DouyinFavoriteListResponse, err error) { |
||||
|
// 1. 查缓存
|
||||
|
res, _ := service.QueryFavListInCache(req.UserId) |
||||
|
|
||||
|
// 2. 如果缓存有则直接返回
|
||||
|
if len(res) > 0 { |
||||
|
return pack.PackFavoriteListResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, res) |
||||
|
} |
||||
|
|
||||
|
// 3. 如果缓存没有则查库
|
||||
|
res, err = service.QueryFavListInRDB(req.UserId) |
||||
|
// 4. 将从RDB查询到的数据读入缓存
|
||||
|
for _, v := range res { |
||||
|
if err := service.WriteFavoriteInCache(req.UserId, v, true); err != nil { |
||||
|
continue |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if err != nil { |
||||
|
pack.PackFavoriteListResp(int32(misc.SystemErr.ErrCode), misc.SystemErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
return pack.PackFavoriteListResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, res) |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
package handler |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/pack" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
) |
||||
|
|
||||
|
func (s *FavoriteServiceImpl) IsFavorite(ctx context.Context, req *favorite.DouyinIsFavoriteRequest) (resp *favorite.DouyinIsFavoriteResponse, err error) { |
||||
|
res, err := service.QueryIsFavorite(req.UserId, req.VideoIdList) |
||||
|
|
||||
|
if err != nil { |
||||
|
return pack.PackIsFavoriteResp(int32(misc.SystemErr.ErrCode), misc.SystemErr.ErrMsg, nil) |
||||
|
} |
||||
|
|
||||
|
return pack.PackIsFavoriteResp(int32(misc.Success.ErrCode), misc.Success.ErrMsg, res) |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
package handler |
||||
|
|
||||
|
type FavoriteServiceImpl struct{} |
@ -0,0 +1,43 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/handler" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/misc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/rpc" |
||||
|
"github.com/TremblingV5/DouTok/applications/favorite/service" |
||||
|
"github.com/TremblingV5/DouTok/kitex_gen/favorite/favoriteservice" |
||||
|
"github.com/TremblingV5/DouTok/pkg/dlog" |
||||
|
"github.com/TremblingV5/DouTok/pkg/initHelper" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
Logger = dlog.InitLog(3) |
||||
|
) |
||||
|
|
||||
|
func Init() { |
||||
|
misc.InitViperConfig() |
||||
|
|
||||
|
service.Init() |
||||
|
|
||||
|
rpc.InitPRCClient() |
||||
|
|
||||
|
go service.UpdateFavMap() |
||||
|
go service.UpdateFavCntMap() |
||||
|
go service.Consumer4UpdateCount() |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
Init() |
||||
|
|
||||
|
options, shutdown := initHelper.InitRPCServerArgs(misc.Config) |
||||
|
defer shutdown() |
||||
|
|
||||
|
svr := favoriteservice.NewServer( |
||||
|
new(handler.FavoriteServiceImpl), |
||||
|
options..., |
||||
|
) |
||||
|
|
||||
|
if err := svr.Run(); err != nil { |
||||
|
Logger.Fatal(err) |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package misc |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/pkg/dtviper" |
||||
|
|
||||
|
var Config *dtviper.Config |
||||
|
|
||||
|
func InitViperConfig() { |
||||
|
config := dtviper.ConfigInit(ViperConfigEnvPrefix, ViperConfigEnvFilename) |
||||
|
Config = config |
||||
|
} |
||||
|
|
||||
|
func GetConfig(key string) string { |
||||
|
return Config.Viper.GetString(key) |
||||
|
} |
||||
|
|
||||
|
func GetConfigNum(key string) int64 { |
||||
|
return Config.Viper.GetInt64(key) |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package misc |
||||
|
|
||||
|
var ( |
||||
|
FavCountTopicName = "fav_count" |
||||
|
FavCountGroupName = "fav_count01" |
||||
|
|
||||
|
ViperConfigEnvPrefix = "DOUTOK_FAVORITE" |
||||
|
ViperConfigEnvFilename = "favorite" |
||||
|
|
||||
|
ConfigIndex_MySQLUsername = "MySQL.Username" |
||||
|
ConfigIndex_MySQLPassword = "MySQL.Password" |
||||
|
ConfigIndex_MySQLHost = "MySQL.Host" |
||||
|
ConfigIndex_MySQLPort = "MySQL.Port" |
||||
|
ConfigIndex_MySQLDb = "MySQL.Database" |
||||
|
|
||||
|
ConfigIndex_RedisDest = "Redis.Dest" |
||||
|
ConfigIndex_RedisPassword = "Redis.Password" |
||||
|
ConfigIndex_RedisFavCacheDbNum = "Redis.FavCache.Num" |
||||
|
ConfigIndex_RedisFavCntCacheDbNum = "Redis.FavCntCache.Num" |
||||
|
|
||||
|
ConfigIndex_SnowFlake = "Snowflake.Node" |
||||
|
) |
@ -0,0 +1,27 @@ |
|||||
|
package misc |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/pkg/errno" |
||||
|
|
||||
|
var ( |
||||
|
NilErrCode = -1 |
||||
|
SuccessCode = 0 |
||||
|
ParamsErrCode = 27001 |
||||
|
SystemErrCode = 27002 |
||||
|
EmptyVideoIdListErrCode = 27003 |
||||
|
BindingInvalidErrCode = 27004 |
||||
|
QueryCacheErrCode = 27005 |
||||
|
CreateFavoriteInRDBErrCode = 27006 |
||||
|
WriteRDBErrCode = 27007 |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
NilErr = errno.NewErrNo(NilErrCode, "Don't care") |
||||
|
Success = errno.NewErrNo(SuccessCode, "Success") |
||||
|
ParamsErr = errno.NewErrNo(ParamsErrCode, "Invalid parameters") |
||||
|
SystemErr = errno.NewErrNo(SystemErrCode, "System error") |
||||
|
EmptyVideoIdListErr = errno.NewErrNo(EmptyVideoIdListErrCode, "Empty video id list") |
||||
|
BindingInvalidErr = errno.NewErrNo(BindingInvalidErrCode, "Action type is invalid") |
||||
|
QueryCacheErr = errno.NewErrNo(QueryCacheErrCode, "Query cache defeat") |
||||
|
CreateFavoriteInRDBErr = errno.NewErrNo(CreateFavoriteInRDBErrCode, "Create new favorite relation in rdb defeat") |
||||
|
WriteRDBErr = errno.NewErrNo(WriteRDBErrCode, "Write rdb defeat") |
||||
|
) |
@ -0,0 +1,5 @@ |
|||||
|
package misc |
||||
|
|
||||
|
var FavCache = "favcache" |
||||
|
var FavCntCache = "favcountcache" |
||||
|
var FavTotalCntCache = "favtotalcountcache" |
@ -0,0 +1,10 @@ |
|||||
|
package pack |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
|
||||
|
func PackFavoriteActionResp(code int32, msg string) (resp *favorite.DouyinFavoriteActionResponse, err error) { |
||||
|
return &favorite.DouyinFavoriteActionResponse{ |
||||
|
StatusCode: code, |
||||
|
StatusMsg: msg, |
||||
|
}, nil |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package pack |
||||
|
|
||||
|
import "github.com/TremblingV5/DouTok/kitex_gen/favorite" |
||||
|
|
||||
|
func PackFavoriteCountResp(code int32, msg string, list map[int64]int64) (resp *favorite.DouyinFavoriteCountResponse, err error) { |
||||
|
resp = &favorite.DouyinFavoriteCountResponse{ |
||||
|
StatusCode: code, |
||||
|
StatusMsg: msg, |
||||
|
Result: list, |
||||
|
} |
||||
|
|
||||
|
return resp, nil |
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue