76 Commits

Author SHA1 Message Date
zetaloop d42333e5eb fix(cd): drop matrix in favor of single-job loop
cd / build (push) Failing after 19s
cd / rollout (push) Has been skipped
2026-05-06 20:40:05 +08:00
zetaloop 70d06c9dd1 fix(cd): flatten matrix target
cd / discover (push) Successful in 4s
cd / build (push) Failing after 10s
cd / rollout (push) Has been skipped
2026-05-06 20:22:54 +08:00
zetaloop 3b293d39d3 fix(center): wire act_runner into compose network
cd / discover (push) Successful in 10s
cd / build (push) Failing after 2m25s
cd / rollout (push) Has been skipped
2026-05-06 20:11:32 +08:00
zetaloop 8cf1af8019 feat: add gitea actions cd workflow, drop old harbor one
cd / discover (push) Failing after 39s
cd / build (push) Has been skipped
cd / rollout (push) Has been skipped
2026-05-06 15:12:50 +08:00
zetaloop 2e4454ded3 fix(k01): apply-schema list clusters after wait to avoid race
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 14:21:44 +08:00
zetaloop 92f8344cc2 fix(k01): apply-schema drop owned objects and wait all clusters
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 14:02:53 +08:00
zetaloop 68bdb9797b fix(k01): apply-schema use TCP+PGPASSWORD for CNPG peer-auth bypass
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 13:21:23 +08:00
zetaloop 50f0846e11 fix(k01): raise redpanda memory to 400Mi/500Mi
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 13:17:39 +08:00
zetaloop d6c59b59d4 fix(k01): drop additionalRedpandaCmdFlags to avoid conflict with chart-generated flags
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 12:47:25 +08:00
zetaloop fe744ae6c4 fix(k01): enable redpanda developer_mode to skip 1GB memory minimum check
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 12:22:45 +08:00
zetaloop e43d2467da fix(k01): drop chartRef.chartVersion from Redpanda CR
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 12:13:55 +08:00
zetaloop a25086dcdf fix(k01): relax redpanda operator probes and raise memory limits
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 12:05:16 +08:00
zetaloop 6fc320656b feat(k01): replace strimzi kafka with redpanda
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 11:39:47 +08:00
zetaloop 1deb5dbdb2 fix(k01): resource requests based on actual usage
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 10:24:59 +08:00
zetaloop 6341d746da fix: fuck mongo
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 09:48:02 +08:00
zetaloop 50f079d86c fix(k01): replicate operator shell script and wrap exec with setarch for mongod
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 09:06:04 +08:00
zetaloop 01f8bc1729 fix(k01): wrap mongod entrypoint with setarch uname-2.6 to bypass kernel 6.19+ guard
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 08:32:46 +08:00
zetaloop ed3f80ca73 fix(k01): force glibc pthread rseq for mongo to bypass tcmalloc crash on kernel 6.19+
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 07:41:58 +08:00
zetaloop 4d4a16ba1b feat(k01): bump mongo redis images and workaround mongo tcmalloc segfault on newer kernels
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 07:18:24 +08:00
zetaloop 92822e9da8 fix(k01): rewrite strimzi namespace via sed before applying manifest 2026-05-06 07:17:40 +08:00
zetaloop 4a8e04d444 fix(k01): shrink postgres redis kafka memory requests
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 05:22:32 +08:00
zetaloop b9ff1f043d fix(k01): correct redis wait condition and serialize ratelimit on rl-redis
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-06 04:49:37 +08:00
zetaloop a3174d16d0 fix(k01): scope teardown cleanup to business resources only
build-and-push-harbor / docker-build-push (push) Failing after 32s
2026-05-06 04:38:55 +08:00
zetaloop 4ee866da95 feat(k01): add teardown script for clean reset of data and service layers
build-and-push-harbor / docker-build-push (push) Failing after 34s
2026-05-06 04:32:36 +08:00
zetaloop 513d0dbac2 fix(k01): lower cpu requests so all infra and services fit on 1 vcpu node 2026-05-06 04:32:25 +08:00
zetaloop bc8c5ad152 fix(k01): avoid set -e exit on arithmetic post-increment in apply-infra
build-and-push-harbor / docker-build-push (push) Failing after 36s
2026-05-06 03:52:41 +08:00
zetaloop 8dac0b8d76 fix(k01): apply infra cr documents one by one to avoid scheduler storm
build-and-push-harbor / docker-build-push (push) Failing after 32s
2026-05-06 03:44:54 +08:00
zetaloop da43d9b8f7 fix(k01): set production-grade memory limits across all workloads
build-and-push-harbor / docker-build-push (push) Failing after 35s
2026-05-06 03:24:31 +08:00
zetaloop c575b53843 refactor(k01): flatten directory layout and split deployment into five scripts
build-and-push-harbor / docker-build-push (push) Failing after 33s
2026-05-06 02:37:25 +08:00
zetaloop 8ba8c7ca20 fix(k01): bump kafka crd apiversion to v1 for strimzi 1.0.0
build-and-push-harbor / docker-build-push (push) Failing after 25s
2026-05-06 01:28:07 +08:00
zetaloop 95f3608b4b fix(k01): quote env value with spaces for shell source compatibility
build-and-push-harbor / docker-build-push (push) Failing after 34s
2026-05-06 01:01:24 +08:00
zetaloop 45ade5a6a0 fix(k01): merge secrets.sh into install-k3s.sh and lower operator resource requests
build-and-push-harbor / docker-build-push (push) Failing after 33s
2026-05-06 00:52:10 +08:00
zetaloop 4d93678046 fix(k01): lower operator resource requests to fit single-vcpu node
build-and-push-harbor / docker-build-push (push) Failing after 51s
2026-05-06 00:30:05 +08:00
zetaloop 430cc63eb2 fix(k01): use server-side apply for cnpg and strimzi manifests
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-05 13:35:11 +08:00
zetaloop d9a41c9831 chore: point frontend submodule to new gitea instance
build-and-push-harbor / docker-build-push (push) Has been cancelled
2026-05-05 12:51:39 +08:00
zetaloop e92bdf30d9 feat(k01): add agent join mode to install-k3s.sh 2026-05-05 12:29:56 +08:00
zetaloop c456f3e296 fix(snowflake): support per-replica WorkerId via env for multi-instance StatefulSet 2026-05-05 12:29:47 +08:00
zetaloop cba510c675 docs(k01): fix readme 2026-05-05 12:22:14 +08:00
zetaloop 8697569b81 docs(k01): rewrite readme following center host documentation style 2026-05-05 12:11:30 +08:00
zetaloop 20ca50c127 feat(deploy): add k01 business cluster manifests for k3s with cnpg, strimzi, redis and mongodb operators 2026-05-05 12:08:10 +08:00
zetaloop 2d4dc236e9 fix(center/zot): drop unworkable healthcheck for distroless image 2026-05-05 11:08:04 +08:00
zetaloop f3b12f30f0 feat(center/caddy): add WebTransport reverse-proxy passthrough via PR #7669 fork 2026-05-05 10:54:37 +08:00
zetaloop 2a41969771 feat(deploy): add center host docker compose stack for git, registry and s3 hosting 2026-05-05 08:45:58 +08:00
wwweww d1ff2661d1 fix(k8s): lower cpu/memory requests for dev environment (50m/128Mi) 2026-05-04 13:59:15 +08:00
wwweww 7a12a9e702 fix(k8s): add Harbor registry prefix to all service image references 2026-05-04 13:22:25 +08:00
wwweww fe84f68648 fix(jenkins): use curl --get --data-urlencode to avoid shell glob, no python3 required 2026-05-04 12:53:29 +08:00
wwweww a3c7c013c5 fix(jenkins): replace curl with python3 urllib to avoid shell glob and timeout issues 2026-05-04 12:44:44 +08:00
wwweww c523ebcf89 fix(jenkins): pass URL via shell variable to avoid glob expansion 2026-05-04 12:25:54 +08:00
wwweww bbccb3e05e fix(jenkins): quote URL with query params to prevent shell glob expansion 2026-05-04 12:19:57 +08:00
wwweww 4bdd040e91 fix(jenkins): poll from Harbor API instead of k8s yaml, add FORCE_DEPLOY param 2026-05-04 02:55:26 +08:00
wwweww 590e5b0cd2 Merge pull request '添加jenkins' (#3) from jenkins/init into main
Reviewed-on: http://103.236.53.208:3000/juwan/juwan-backend/pulls/3
2026-05-03 18:52:13 +00:00
wwweww ad5bff534c Merge branch 'main' into jenkins/init 2026-05-03 14:53:31 +00:00
wwweww 13eb299316 添加jenkins 2026-05-03 22:41:40 +08:00
zetaloop a3518d20f1 docs: 在接口文档补全 title 与 desc 并标注 ID 序列化形式 2026-05-03 20:58:28 +08:00
zetaloop 9654147054 chore: 更新前端仓库 2026-05-03 19:03:56 +08:00
zetaloop 44c73e787f docs: 重新生成 swagger 接口文档 2026-05-03 19:03:09 +08:00
zetaloop 164f98cf33 docs: 重写 dev README 对齐 per-domain 拓扑与前端集成 2026-05-03 19:00:58 +08:00
zetaloop 60a3530609 docs: 归档基于旧版 k8s 的 jwt 加密部署文档 2026-05-03 18:59:44 +08:00
zetaloop d19cb53f24 docs: 清理过时的部署文档与模板残留 2026-05-03 18:59:11 +08:00
zetaloop b08a3a51e0 feat: 接入 frontend 子模块并集成 envoy 2026-05-03 09:22:29 +08:00
zetaloop 9a32850030 feat: admin 使用固定 ID 并补全全角色权限和演示数据 2026-05-03 08:21:28 +08:00
zetaloop 776ecc479f fix(users-rpc): 移除未使用的 DataSource 配置字段 2026-05-03 07:57:19 +08:00
zetaloop 631469a713 fix: 给有 FK 依赖的建表脚本加数字前缀以保证字母序就是依赖序 2026-05-03 07:57:19 +08:00
zetaloop 22c7c4e7d9 refactor: 用 per-domain fixture 替代 seed.py 2026-05-03 07:57:19 +08:00
zetaloop d1031f48b3 refactor: 拆分 postgres 为 per-domain 数据库 2026-05-03 07:57:19 +08:00
zetaloop 429a1df32a refactor: 启用 conf.UseEnv 并将 etc 配置统一为 env 占位 2026-05-03 07:57:19 +08:00
zetaloop 87bf86a410 fix: 重命名 objectStorge 为 objectstory 并修复 service ports 缩进 2026-05-03 07:57:19 +08:00
zetaloop 227f5814df feat(player): 新增 GET /players/me 查询当前用户打手资料 2026-05-03 06:18:01 +08:00
zetaloop cf639f1bca fix: int64 ID 字段序列化为 JSON string 2026-05-03 05:58:21 +08:00
wwweww 83fa982749 补齐各个服务的k8s配置清单 2026-05-02 11:57:07 +08:00
zetaloop 41890ddd33 fix: 修复 player 详情 completionRate 和 k8s 公开路由
同步 k8s Envoy 中已放行公开接口的实际路由,避免落到泛用 user API;同时规范 dev API 测试脚本的响应体解析,使新增负向断言通过静态检查。
2026-04-29 23:42:46 +08:00
zetaloop 2341284f6c Merge branch 'main-merge-base-a' 2026-04-29 23:29:12 +08:00
wwweww 585417c07a delete chat rpc service 2026-04-25 10:29:46 +08:00
wwweww fbb4d12f63 add go mod cn proxy 2026-04-25 10:29:08 +08:00
wwweww cdc85ce7dd Modify Configuration 2026-04-25 10:28:42 +08:00
wwweww bd07075cfe add wt test 2026-04-25 10:27:53 +08:00
266 changed files with 16116 additions and 18190 deletions
-150
View File
@@ -1,150 +0,0 @@
name: build-and-push-harbor
on:
push:
branches:
- main
- master
- dev
- "feature/**"
workflow_dispatch:
jobs:
docker-build-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: http://103.236.53.208:3000/actions/checkout@v4
- name: Set image tags
id: vars
run: |
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
echo "date_tag=$(date +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT"
# 调试步骤:检查 Secret 是否正确读取 (只会输出字符长度,不会泄露密码)
- name: Debug Secrets
run: |
echo "Registry: ${{ secrets.HARBOR_REGISTRY }}"
echo "User length: ${#HARBOR_USERNAME}"
echo "Pass length: ${#HARBOR_PASSWORD}"
env:
HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }}
HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }}
- name: Login Harbor
env:
HARBOR_REGISTRY: ${{ secrets.HARBOR_REGISTRY }}
HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }}
HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }}
run: |
# 尝试登录,如果失败会打印详细信息
echo "$HARBOR_PASSWORD" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USERNAME" --password-stdin
- name: Build and Push Monorepo Services
env:
HARBOR_REGISTRY: ${{ secrets.HARBOR_REGISTRY }}
HARBOR_PROJECT: ${{ secrets.HARBOR_PROJECT }}
SHORT_SHA: ${{ steps.vars.outputs.short_sha }}
DATE_TAG: ${{ steps.vars.outputs.date_tag }}
shell: bash
run: |
set -euo pipefail
# 1. 定义要遍历的微服务根目录 (根据你的项目结构)
# 你的结构是 app/<service>/<type>
# 我们只关心 api, rpc, mq 这三种类型
echo "🔍 开始扫描 Go-Zero 微服务..."
# 找到 app 下所有的 api/rpc/mq 目录
find app -mindepth 2 -maxdepth 2 -type d \( -name "api" -o -name "rpc" -o -name "mq" \) | sort | while read -r service_dir; do
# service_dir 举例: app/community/api
service_type=$(basename "$service_dir") # api
parent_dir=$(dirname "$service_dir") # app/community
service_name=$(basename "$parent_dir") # community
# 2. 智能查找入口文件 (main.go 或 service_name.go)
# 在当前目录下查找含有 "package main" 的 .go 文件
entry_file=$(grep -l "package main" "$service_dir"/*.go | head -n 1 || true)
if [[ -z "$entry_file" ]]; then
echo "⚠️ 跳过 $service_dir: 未找到 package main 入口文件"
continue
fi
# 3. 智能查找配置文件 (etc/*.yaml)
config_file=$(ls "$service_dir/etc/"*.yaml 2>/dev/null | head -n 1 || true)
if [[ -z "$config_file" ]]; then
echo "⚠️ 警告 $service_name-$service_type: 未找到 etc/*.yaml 配置文件,容器启动可能失败"
config_name="config.yaml" # fallback
else
config_name=$(basename "$config_file")
fi
# 镜像名称: community-api, user-rpc 等
image_name="${service_name}-${service_type}"
image_ref="$HARBOR_REGISTRY/$HARBOR_PROJECT/$image_name"
echo "----------------------------------------------------"
echo "🚀 构建目标: $image_name"
echo "📂 入口文件: $entry_file"
echo "📄 配置文件: $config_name"
echo "----------------------------------------------------"
# 4. 动态生成 Dockerfile (针对 Monorepo 优化)
# 关键点:COPY . . 把整个根目录拷进去,因为 Go-Zero 项目通常依赖 ../../common
cat <<EOF > Dockerfile.tmp
FROM golang:alpine AS builder
# 优化:使用阿里云 Alpine 源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update --no-cache && apk add --no-cache tzdata
WORKDIR /build
# 优化:利用层缓存,先下载依赖
ENV GOPROXY=https://goproxy.cn,direct
COPY go.mod go.sum ./
RUN go mod download
# 拷贝所有源码 (解决 common 依赖问题)
COPY . .
# 编译
RUN go build -ldflags="-s -w" -o /app/main $entry_file
# 运行时镜像
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ=Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/main /app/main
# 拷贝 etc 配置
COPY $service_dir/etc /app/etc
# 启动命令
CMD ["./main", "-f", "etc/$config_name"]
EOF
# 5. 执行 Docker Build
docker build -f Dockerfile.tmp -t "$image_ref:$SHORT_SHA" .
# 打其他 Tag
docker tag "$image_ref:$SHORT_SHA" "$image_ref:$DATE_TAG"
docker tag "$image_ref:$SHORT_SHA" "$image_ref:latest"
# 6. 推送
echo "📤 推送镜像..."
docker push "$image_ref:$SHORT_SHA"
docker push "$image_ref:$DATE_TAG"
docker push "$image_ref:latest"
echo "✅ $image_name 完成"
rm -f Dockerfile.tmp
done
+144
View File
@@ -0,0 +1,144 @@
name: cd
on:
push:
branches: [main]
workflow_dispatch:
env:
REGISTRY: registry.juwan.xhttp.zip
REPO: juwan
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Buildx
uses: docker/setup-buildx-action@v3
- name: Login registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push all
shell: bash
env:
REGISTRY: ${{ env.REGISTRY }}
REPO: ${{ env.REPO }}
run: |
set -euo pipefail
SHA_TAG="${GITHUB_SHA::7}"
python3 - >/tmp/targets <<'PY'
import os
NAME_OVERRIDE = {
"users": ("users", "user"),
"user_verifications": ("user_verifications", "user-verifications"),
}
STATEFULSETS = {"snowflake-rpc": "snowflake"}
for svc in sorted(os.listdir("app")):
svc_dir = f"app/{svc}"
if not os.path.isdir(svc_dir):
continue
for sub in sorted(os.listdir(svc_dir)):
d = f"{svc_dir}/{sub}"
if not os.path.isdir(d) or sub not in ("api","rpc","mq","adapter"):
continue
img_pre, wl_pre = NAME_OVERRIDE.get(svc, (svc, svc))
image = f"{img_pre}-{sub}"
workload = STATEFULSETS.get(image, f"{wl_pre}-{sub}")
print(f"{image}|{d}|{workload}")
PY
while IFS='|' read -r image dir _workload; do
echo "::group::Build $image"
entry=$(grep -l "package main" "$dir"/*.go | head -n1)
cfg=$(basename "$(find "$dir/etc" -maxdepth 1 -name '*.yaml' | head -n1)" 2>/dev/null || echo config.yaml)
cat > Dockerfile.build <<EOF
FROM golang:1.25-alpine AS builder
WORKDIR /build
ENV CGO_ENABLED=0 GOOS=linux
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -ldflags="-s -w" -o /app/main $entry
FROM alpine:3.21
RUN apk add --no-cache ca-certificates tzdata
ENV TZ=Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/main /app/main
COPY $dir/etc /app/etc
CMD ["./main", "-f", "etc/$cfg"]
EOF
IMAGE="$REGISTRY/$REPO/$image"
CACHE="$REGISTRY/$REPO/buildcache:$image"
docker buildx build \
--file Dockerfile.build \
--tag "$IMAGE:$SHA_TAG" \
--tag "$IMAGE:latest" \
--cache-from "type=registry,ref=$CACHE" \
--cache-to "type=registry,ref=$CACHE,mode=max" \
--push \
.
echo "::endgroup::"
done < /tmp/targets
rollout:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install kubectl
run: |
curl -sLo /usr/local/bin/kubectl \
"https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x /usr/local/bin/kubectl
- name: Rollout k01
env:
REGISTRY: ${{ env.REGISTRY }}
REPO: ${{ env.REPO }}
KUBECONFIG_B64: ${{ secrets.K01_KUBECONFIG }}
shell: bash
run: |
set -euo pipefail
mkdir -p ~/.kube
echo "$KUBECONFIG_B64" | base64 -d > ~/.kube/config
chmod 600 ~/.kube/config
SHA_TAG="${GITHUB_SHA::7}"
python3 - <<PY
import os, subprocess
NAME_OVERRIDE = {
"users": ("users", "user"),
"user_verifications": ("user_verifications", "user-verifications"),
}
STATEFULSETS = {"snowflake-rpc": "snowflake"}
reg = os.environ["REGISTRY"] + "/" + os.environ["REPO"]
sha = "$SHA_TAG"
for svc in sorted(os.listdir("app")):
svc_dir = f"app/{svc}"
if not os.path.isdir(svc_dir):
continue
for sub in sorted(os.listdir(svc_dir)):
d = f"{svc_dir}/{sub}"
if not os.path.isdir(d) or sub not in ("api","rpc","mq","adapter"):
continue
img_pre, wl_pre = NAME_OVERRIDE.get(svc, (svc, svc))
image = f"{img_pre}-{sub}"
workload = STATEFULSETS.get(image, f"{wl_pre}-{sub}")
kind = "statefulset" if workload == "snowflake" else "deployment"
ref = f"{reg}/{image}:{sha}"
cmd = ["kubectl","-n","juwan","set","image",f"{kind}/{workload}",f"{image}={ref}"]
print(" ".join(cmd))
subprocess.run(cmd, check=False)
PY
+5 -1
View File
@@ -119,7 +119,11 @@ dist
# End of https://mrkandreev.name/snippets/gitignore-generator/#Node
DockerFile
/app/*/api/Dockerfile
/app/*/rpc/Dockerfile
/app/*/mq/Dockerfile
/app/*/adapter/Dockerfile
/app/*/test/Dockerfile
.idea
# Go compiled binaries
+3
View File
@@ -0,0 +1,3 @@
[submodule "frontend"]
path = frontend
url = https://git.juwan.xhttp.zip/juwan/juwan-frontend.git
+1 -1
View File
@@ -20,7 +20,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
svcCtx := svc.NewServiceContext(c)
handler := chathandler.NewHandler(svcCtx)
+6 -6
View File
@@ -17,8 +17,8 @@ Hybrid:
Wt:
Addr: :8443
Path: /wt/chat
CertFile: /etc/certs/tls.crt
KeyFile: /etc/certs/tls.key
CertFile: "${CHAT_WT_CERT_FILE}"
KeyFile: "${CHAT_WT_KEY_FILE}"
Auth:
Enabled: true
FallbackStrategy: auto
@@ -29,18 +29,18 @@ Hybrid:
WsHeaderName: x-auth-user-id
WtTokenSource: cookie
WtTokenName: JToken
WtJWTSecret: MGUyMWE3ZDhjMTQ5ZDg1MWViOWU0MGM3OTE2NWVkYTBlOTE5ZWRkZDU1YjYzOGJjOWRiNzM0NTc4NDIyMjlkZQ
WtJWTSecret: "${JWT_SECRET_KEY}"
Stateless:
PollInterval: 100ms
BatchSize: 100
Mongo:
URI: mongodb://mongo:27017
Database: juwan_chat
URI: "${MONGO_URI}"
Database: "${MONGO_DATABASE}"
Redis:
Addr: redis:6379
Addr: "${REDIS_HOST}:${REDIS_PORT}"
Log:
Level: info
-114
View File
@@ -1,114 +0,0 @@
package chatservice
import (
"context"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc"
)
type (
ChatSessions = pb.ChatSessions
AddChatSessionsReq = pb.AddChatSessionsReq
AddChatSessionsResp = pb.AddChatSessionsResp
UpdateChatSessionsReq = pb.UpdateChatSessionsReq
UpdateChatSessionsResp = pb.UpdateChatSessionsResp
DelChatSessionsReq = pb.DelChatSessionsReq
DelChatSessionsResp = pb.DelChatSessionsResp
GetChatSessionsByIdReq = pb.GetChatSessionsByIdReq
GetChatSessionsByIdResp = pb.GetChatSessionsByIdResp
SearchChatSessionsReq = pb.SearchChatSessionsReq
SearchChatSessionsResp = pb.SearchChatSessionsResp
AddParticipantReq = pb.AddParticipantReq
AddParticipantResp = pb.AddParticipantResp
RemoveParticipantReq = pb.RemoveParticipantReq
RemoveParticipantResp = pb.RemoveParticipantResp
ChatMessages = pb.ChatMessages
AddChatMessagesReq = pb.AddChatMessagesReq
AddChatMessagesResp = pb.AddChatMessagesResp
DelChatMessagesReq = pb.DelChatMessagesReq
DelChatMessagesResp = pb.DelChatMessagesResp
GetChatMessagesByIdReq = pb.GetChatMessagesByIdReq
GetChatMessagesByIdResp = pb.GetChatMessagesByIdResp
SearchChatMessagesReq = pb.SearchChatMessagesReq
SearchChatMessagesResp = pb.SearchChatMessagesResp
ChatService interface {
AddChatSessions(ctx context.Context, in *AddChatSessionsReq, opts ...grpc.CallOption) (*AddChatSessionsResp, error)
UpdateChatSessions(ctx context.Context, in *UpdateChatSessionsReq, opts ...grpc.CallOption) (*UpdateChatSessionsResp, error)
DelChatSessions(ctx context.Context, in *DelChatSessionsReq, opts ...grpc.CallOption) (*DelChatSessionsResp, error)
GetChatSessionsById(ctx context.Context, in *GetChatSessionsByIdReq, opts ...grpc.CallOption) (*GetChatSessionsByIdResp, error)
SearchChatSessions(ctx context.Context, in *SearchChatSessionsReq, opts ...grpc.CallOption) (*SearchChatSessionsResp, error)
AddParticipant(ctx context.Context, in *AddParticipantReq, opts ...grpc.CallOption) (*AddParticipantResp, error)
RemoveParticipant(ctx context.Context, in *RemoveParticipantReq, opts ...grpc.CallOption) (*RemoveParticipantResp, error)
AddChatMessages(ctx context.Context, in *AddChatMessagesReq, opts ...grpc.CallOption) (*AddChatMessagesResp, error)
DelChatMessages(ctx context.Context, in *DelChatMessagesReq, opts ...grpc.CallOption) (*DelChatMessagesResp, error)
GetChatMessagesById(ctx context.Context, in *GetChatMessagesByIdReq, opts ...grpc.CallOption) (*GetChatMessagesByIdResp, error)
SearchChatMessages(ctx context.Context, in *SearchChatMessagesReq, opts ...grpc.CallOption) (*SearchChatMessagesResp, error)
}
defaultChatService struct {
cli zrpc.Client
}
)
func NewChatService(cli zrpc.Client) ChatService {
return &defaultChatService{cli: cli}
}
func (m *defaultChatService) AddChatSessions(ctx context.Context, in *AddChatSessionsReq, opts ...grpc.CallOption) (*AddChatSessionsResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.AddChatSessions(ctx, in, opts...)
}
func (m *defaultChatService) UpdateChatSessions(ctx context.Context, in *UpdateChatSessionsReq, opts ...grpc.CallOption) (*UpdateChatSessionsResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.UpdateChatSessions(ctx, in, opts...)
}
func (m *defaultChatService) DelChatSessions(ctx context.Context, in *DelChatSessionsReq, opts ...grpc.CallOption) (*DelChatSessionsResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.DelChatSessions(ctx, in, opts...)
}
func (m *defaultChatService) GetChatSessionsById(ctx context.Context, in *GetChatSessionsByIdReq, opts ...grpc.CallOption) (*GetChatSessionsByIdResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.GetChatSessionsById(ctx, in, opts...)
}
func (m *defaultChatService) SearchChatSessions(ctx context.Context, in *SearchChatSessionsReq, opts ...grpc.CallOption) (*SearchChatSessionsResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.SearchChatSessions(ctx, in, opts...)
}
func (m *defaultChatService) AddParticipant(ctx context.Context, in *AddParticipantReq, opts ...grpc.CallOption) (*AddParticipantResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.AddParticipant(ctx, in, opts...)
}
func (m *defaultChatService) RemoveParticipant(ctx context.Context, in *RemoveParticipantReq, opts ...grpc.CallOption) (*RemoveParticipantResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.RemoveParticipant(ctx, in, opts...)
}
func (m *defaultChatService) AddChatMessages(ctx context.Context, in *AddChatMessagesReq, opts ...grpc.CallOption) (*AddChatMessagesResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.AddChatMessages(ctx, in, opts...)
}
func (m *defaultChatService) DelChatMessages(ctx context.Context, in *DelChatMessagesReq, opts ...grpc.CallOption) (*DelChatMessagesResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.DelChatMessages(ctx, in, opts...)
}
func (m *defaultChatService) GetChatMessagesById(ctx context.Context, in *GetChatMessagesByIdReq, opts ...grpc.CallOption) (*GetChatMessagesByIdResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.GetChatMessagesById(ctx, in, opts...)
}
func (m *defaultChatService) SearchChatMessages(ctx context.Context, in *SearchChatMessagesReq, opts ...grpc.CallOption) (*SearchChatMessagesResp, error) {
client := pb.NewChatServiceClient(m.cli.Conn())
return client.SearchChatMessages(ctx, in, opts...)
}
-5
View File
@@ -1,5 +0,0 @@
Name: pb.rpc
ListenOn: 0.0.0.0:8080
Log:
Level: debug
-7
View File
@@ -1,7 +0,0 @@
package config
import "github.com/zeromicro/go-zero/zrpc"
type Config struct {
zrpc.RpcServerConf
}
@@ -1,69 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type AddChatMessagesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewAddChatMessagesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddChatMessagesLogic {
return &AddChatMessagesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *AddChatMessagesLogic) AddChatMessages(in *pb.AddChatMessagesReq) (*pb.AddChatMessagesResp, error) {
if in.GetSessionId() <= 0 {
return nil, errors.New("sessionId is required")
}
if in.GetSenderId() <= 0 {
return nil, errors.New("senderId is required")
}
if in.GetContent() == "" {
return nil, errors.New("content is required")
}
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
if _, ok := store.Sessions[in.GetSessionId()]; !ok {
return nil, errors.New("session not found")
}
now := nowUnix(0)
msgType := in.GetType()
if msgType == "" {
msgType = "text"
}
msg := &pb.ChatMessages{
Id: store.NextMessage(),
SessionId: in.GetSessionId(),
SenderId: in.GetSenderId(),
Type: msgType,
Content: in.GetContent(),
CreatedAt: now,
}
store.Messages[msg.Id] = msg
store.SessionMessages[in.GetSessionId()] = append(store.SessionMessages[in.GetSessionId()], msg.Id)
session := store.Sessions[in.GetSessionId()]
session.LastMessage = in.GetContent()
session.LastMessageAt = now
session.UpdatedAt = now
return &pb.AddChatMessagesResp{Id: msg.Id}, nil
}
@@ -1,64 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type AddChatSessionsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewAddChatSessionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddChatSessionsLogic {
return &AddChatSessionsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *AddChatSessionsLogic) AddChatSessions(in *pb.AddChatSessionsReq) (*pb.AddChatSessionsResp, error) {
if in.GetType() == "" {
return nil, errors.New("type is required")
}
if in.GetCreatorId() <= 0 {
return nil, errors.New("creatorId is required")
}
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
now := nowUnix(0)
participants := append([]int64(nil), in.GetParticipants()...)
hasCreator := false
for _, p := range participants {
if p == in.GetCreatorId() {
hasCreator = true
break
}
}
if !hasCreator {
participants = append(participants, in.GetCreatorId())
}
session := &pb.ChatSessions{
Id: store.NextSession(),
Type: in.GetType(),
Name: in.GetName(),
CreatorId: in.GetCreatorId(),
Participants: participants,
CreatedAt: now,
UpdatedAt: now,
}
store.Sessions[session.Id] = session
return &pb.AddChatSessionsResp{Id: session.Id}, nil
}
@@ -1,46 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type AddParticipantLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewAddParticipantLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddParticipantLogic {
return &AddParticipantLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *AddParticipantLogic) AddParticipant(in *pb.AddParticipantReq) (*pb.AddParticipantResp, error) {
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
session, ok := store.Sessions[in.GetSessionId()]
if !ok {
return nil, errors.New("session not found")
}
for _, p := range session.Participants {
if p == in.GetUserId() {
return &pb.AddParticipantResp{}, nil
}
}
session.Participants = append(session.Participants, in.GetUserId())
session.UpdatedAt = nowUnix(0)
return &pb.AddParticipantResp{}, nil
}
@@ -1,45 +0,0 @@
package logic
import (
"context"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type DelChatMessagesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewDelChatMessagesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DelChatMessagesLogic {
return &DelChatMessagesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *DelChatMessagesLogic) DelChatMessages(in *pb.DelChatMessagesReq) (*pb.DelChatMessagesResp, error) {
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
msg, ok := store.Messages[in.GetId()]
if ok {
ids := store.SessionMessages[msg.SessionId]
filtered := make([]int64, 0, len(ids))
for _, id := range ids {
if id != in.GetId() {
filtered = append(filtered, id)
}
}
store.SessionMessages[msg.SessionId] = filtered
}
delete(store.Messages, in.GetId())
return &pb.DelChatMessagesResp{}, nil
}
@@ -1,35 +0,0 @@
package logic
import (
"context"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type DelChatSessionsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewDelChatSessionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DelChatSessionsLogic {
return &DelChatSessionsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *DelChatSessionsLogic) DelChatSessions(in *pb.DelChatSessionsReq) (*pb.DelChatSessionsResp, error) {
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
delete(store.Sessions, in.GetId())
delete(store.SessionMessages, in.GetId())
return &pb.DelChatSessionsResp{}, nil
}
@@ -1,38 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type GetChatMessagesByIdLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetChatMessagesByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChatMessagesByIdLogic {
return &GetChatMessagesByIdLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetChatMessagesByIdLogic) GetChatMessagesById(in *pb.GetChatMessagesByIdReq) (*pb.GetChatMessagesByIdResp, error) {
store := l.svcCtx.Store
store.Mu.RLock()
defer store.Mu.RUnlock()
msg, ok := store.Messages[in.GetId()]
if !ok {
return nil, errors.New("message not found")
}
return &pb.GetChatMessagesByIdResp{ChatMessages: msg}, nil
}
@@ -1,38 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type GetChatSessionsByIdLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetChatSessionsByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChatSessionsByIdLogic {
return &GetChatSessionsByIdLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetChatSessionsByIdLogic) GetChatSessionsById(in *pb.GetChatSessionsByIdReq) (*pb.GetChatSessionsByIdResp, error) {
store := l.svcCtx.Store
store.Mu.RLock()
defer store.Mu.RUnlock()
session, ok := store.Sessions[in.GetId()]
if !ok {
return nil, errors.New("session not found")
}
return &pb.GetChatSessionsByIdResp{ChatSessions: session}, nil
}
-10
View File
@@ -1,10 +0,0 @@
package logic
import "time"
func nowUnix(ts int64) int64 {
if ts > 0 {
return ts
}
return time.Now().Unix()
}
@@ -1,47 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type RemoveParticipantLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewRemoveParticipantLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RemoveParticipantLogic {
return &RemoveParticipantLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *RemoveParticipantLogic) RemoveParticipant(in *pb.RemoveParticipantReq) (*pb.RemoveParticipantResp, error) {
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
session, ok := store.Sessions[in.GetSessionId()]
if !ok {
return nil, errors.New("session not found")
}
filtered := make([]int64, 0, len(session.Participants))
for _, p := range session.Participants {
if p != in.GetUserId() {
filtered = append(filtered, p)
}
}
session.Participants = filtered
session.UpdatedAt = nowUnix(0)
return &pb.RemoveParticipantResp{}, nil
}
@@ -1,58 +0,0 @@
package logic
import (
"context"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type SearchChatMessagesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewSearchChatMessagesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchChatMessagesLogic {
return &SearchChatMessagesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *SearchChatMessagesLogic) SearchChatMessages(in *pb.SearchChatMessagesReq) (*pb.SearchChatMessagesResp, error) {
store := l.svcCtx.Store
store.Mu.RLock()
defer store.Mu.RUnlock()
msgIDs := store.SessionMessages[in.GetSessionId()]
var results []*pb.ChatMessages
for _, id := range msgIDs {
msg, ok := store.Messages[id]
if !ok {
continue
}
if in.SenderId != nil && msg.SenderId != *in.SenderId {
continue
}
results = append(results, msg)
}
limit := in.GetLimit()
if limit <= 0 {
limit = 20
}
offset := in.GetPage() * limit
if offset >= int64(len(results)) {
return &pb.SearchChatMessagesResp{}, nil
}
end := offset + limit
if end > int64(len(results)) {
end = int64(len(results))
}
return &pb.SearchChatMessagesResp{ChatMessages: results[offset:end]}, nil
}
@@ -1,65 +0,0 @@
package logic
import (
"context"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type SearchChatSessionsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewSearchChatSessionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchChatSessionsLogic {
return &SearchChatSessionsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *SearchChatSessionsLogic) SearchChatSessions(in *pb.SearchChatSessionsReq) (*pb.SearchChatSessionsResp, error) {
store := l.svcCtx.Store
store.Mu.RLock()
defer store.Mu.RUnlock()
var results []*pb.ChatSessions
for _, s := range store.Sessions {
if in.Type != nil && s.Type != *in.Type {
continue
}
if in.UserId != nil {
found := false
for _, p := range s.Participants {
if p == *in.UserId {
found = true
break
}
}
if !found {
continue
}
}
results = append(results, s)
}
limit := in.GetLimit()
if limit <= 0 {
limit = 20
}
offset := in.GetPage() * limit
if offset >= int64(len(results)) {
return &pb.SearchChatSessionsResp{}, nil
}
end := offset + limit
if end > int64(len(results)) {
end = int64(len(results))
}
return &pb.SearchChatSessionsResp{ChatSessions: results[offset:end]}, nil
}
@@ -1,49 +0,0 @@
package logic
import (
"context"
"errors"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateChatSessionsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewUpdateChatSessionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateChatSessionsLogic {
return &UpdateChatSessionsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *UpdateChatSessionsLogic) UpdateChatSessions(in *pb.UpdateChatSessionsReq) (*pb.UpdateChatSessionsResp, error) {
store := l.svcCtx.Store
store.Mu.Lock()
defer store.Mu.Unlock()
session, ok := store.Sessions[in.GetId()]
if !ok {
return nil, errors.New("session not found")
}
if in.Name != nil {
session.Name = *in.Name
}
if in.LastMessage != nil {
session.LastMessage = *in.LastMessage
}
if in.LastMessageAt != nil {
session.LastMessageAt = *in.LastMessageAt
}
session.UpdatedAt = nowUnix(0)
return &pb.UpdateChatSessionsResp{}, nil
}
@@ -1,75 +0,0 @@
package server
import (
"context"
"juwan-backend/app/chat/rpc/internal/logic"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
)
type ChatServiceServer struct {
svcCtx *svc.ServiceContext
pb.UnimplementedChatServiceServer
}
func NewChatServiceServer(svcCtx *svc.ServiceContext) *ChatServiceServer {
return &ChatServiceServer{
svcCtx: svcCtx,
}
}
func (s *ChatServiceServer) AddChatSessions(ctx context.Context, in *pb.AddChatSessionsReq) (*pb.AddChatSessionsResp, error) {
l := logic.NewAddChatSessionsLogic(ctx, s.svcCtx)
return l.AddChatSessions(in)
}
func (s *ChatServiceServer) UpdateChatSessions(ctx context.Context, in *pb.UpdateChatSessionsReq) (*pb.UpdateChatSessionsResp, error) {
l := logic.NewUpdateChatSessionsLogic(ctx, s.svcCtx)
return l.UpdateChatSessions(in)
}
func (s *ChatServiceServer) DelChatSessions(ctx context.Context, in *pb.DelChatSessionsReq) (*pb.DelChatSessionsResp, error) {
l := logic.NewDelChatSessionsLogic(ctx, s.svcCtx)
return l.DelChatSessions(in)
}
func (s *ChatServiceServer) GetChatSessionsById(ctx context.Context, in *pb.GetChatSessionsByIdReq) (*pb.GetChatSessionsByIdResp, error) {
l := logic.NewGetChatSessionsByIdLogic(ctx, s.svcCtx)
return l.GetChatSessionsById(in)
}
func (s *ChatServiceServer) SearchChatSessions(ctx context.Context, in *pb.SearchChatSessionsReq) (*pb.SearchChatSessionsResp, error) {
l := logic.NewSearchChatSessionsLogic(ctx, s.svcCtx)
return l.SearchChatSessions(in)
}
func (s *ChatServiceServer) AddParticipant(ctx context.Context, in *pb.AddParticipantReq) (*pb.AddParticipantResp, error) {
l := logic.NewAddParticipantLogic(ctx, s.svcCtx)
return l.AddParticipant(in)
}
func (s *ChatServiceServer) RemoveParticipant(ctx context.Context, in *pb.RemoveParticipantReq) (*pb.RemoveParticipantResp, error) {
l := logic.NewRemoveParticipantLogic(ctx, s.svcCtx)
return l.RemoveParticipant(in)
}
func (s *ChatServiceServer) AddChatMessages(ctx context.Context, in *pb.AddChatMessagesReq) (*pb.AddChatMessagesResp, error) {
l := logic.NewAddChatMessagesLogic(ctx, s.svcCtx)
return l.AddChatMessages(in)
}
func (s *ChatServiceServer) DelChatMessages(ctx context.Context, in *pb.DelChatMessagesReq) (*pb.DelChatMessagesResp, error) {
l := logic.NewDelChatMessagesLogic(ctx, s.svcCtx)
return l.DelChatMessages(in)
}
func (s *ChatServiceServer) GetChatMessagesById(ctx context.Context, in *pb.GetChatMessagesByIdReq) (*pb.GetChatMessagesByIdResp, error) {
l := logic.NewGetChatMessagesByIdLogic(ctx, s.svcCtx)
return l.GetChatMessagesById(in)
}
func (s *ChatServiceServer) SearchChatMessages(ctx context.Context, in *pb.SearchChatMessagesReq) (*pb.SearchChatMessagesResp, error) {
l := logic.NewSearchChatMessagesLogic(ctx, s.svcCtx)
return l.SearchChatMessages(in)
}
@@ -1,15 +0,0 @@
package svc
import "juwan-backend/app/chat/rpc/internal/config"
type ServiceContext struct {
Config config.Config
Store *ChatStore
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
Store: NewChatStore(),
}
}
-38
View File
@@ -1,38 +0,0 @@
package svc
import (
"sync"
"juwan-backend/app/chat/rpc/pb"
)
type ChatStore struct {
Mu sync.RWMutex
nextSessionID int64
nextMessageID int64
Sessions map[int64]*pb.ChatSessions
Messages map[int64]*pb.ChatMessages
SessionMessages map[int64][]int64
}
func NewChatStore() *ChatStore {
return &ChatStore{
nextSessionID: 1000,
nextMessageID: 1000,
Sessions: make(map[int64]*pb.ChatSessions),
Messages: make(map[int64]*pb.ChatMessages),
SessionMessages: make(map[int64][]int64),
}
}
func (s *ChatStore) NextSession() int64 {
s.nextSessionID++
return s.nextSessionID
}
func (s *ChatStore) NextMessage() int64 {
s.nextMessageID++
return s.nextMessageID
}
-39
View File
@@ -1,39 +0,0 @@
package main
import (
"flag"
"fmt"
"juwan-backend/app/chat/rpc/internal/config"
"juwan-backend/app/chat/rpc/internal/server"
"juwan-backend/app/chat/rpc/internal/svc"
"juwan-backend/app/chat/rpc/pb"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/service"
"github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
var configFile = flag.String("f", "etc/pb.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
ctx := svc.NewServiceContext(c)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
pb.RegisterChatServiceServer(grpcServer, server.NewChatServiceServer(ctx))
if c.Mode == service.DevMode || c.Mode == service.TestMode {
reflection.Register(grpcServer)
}
})
defer s.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
s.Start()
}
-175
View File
@@ -1,175 +0,0 @@
package pb
import (
"context"
"google.golang.org/grpc"
)
type ChatServiceServer interface {
AddChatSessions(context.Context, *AddChatSessionsReq) (*AddChatSessionsResp, error)
UpdateChatSessions(context.Context, *UpdateChatSessionsReq) (*UpdateChatSessionsResp, error)
DelChatSessions(context.Context, *DelChatSessionsReq) (*DelChatSessionsResp, error)
GetChatSessionsById(context.Context, *GetChatSessionsByIdReq) (*GetChatSessionsByIdResp, error)
SearchChatSessions(context.Context, *SearchChatSessionsReq) (*SearchChatSessionsResp, error)
AddParticipant(context.Context, *AddParticipantReq) (*AddParticipantResp, error)
RemoveParticipant(context.Context, *RemoveParticipantReq) (*RemoveParticipantResp, error)
AddChatMessages(context.Context, *AddChatMessagesReq) (*AddChatMessagesResp, error)
DelChatMessages(context.Context, *DelChatMessagesReq) (*DelChatMessagesResp, error)
GetChatMessagesById(context.Context, *GetChatMessagesByIdReq) (*GetChatMessagesByIdResp, error)
SearchChatMessages(context.Context, *SearchChatMessagesReq) (*SearchChatMessagesResp, error)
mustEmbedUnimplementedChatServiceServer()
}
type UnimplementedChatServiceServer struct{}
func (UnimplementedChatServiceServer) AddChatSessions(context.Context, *AddChatSessionsReq) (*AddChatSessionsResp, error) {
return nil, grpc.Errorf(12, "method AddChatSessions not implemented")
}
func (UnimplementedChatServiceServer) UpdateChatSessions(context.Context, *UpdateChatSessionsReq) (*UpdateChatSessionsResp, error) {
return nil, grpc.Errorf(12, "method UpdateChatSessions not implemented")
}
func (UnimplementedChatServiceServer) DelChatSessions(context.Context, *DelChatSessionsReq) (*DelChatSessionsResp, error) {
return nil, grpc.Errorf(12, "method DelChatSessions not implemented")
}
func (UnimplementedChatServiceServer) GetChatSessionsById(context.Context, *GetChatSessionsByIdReq) (*GetChatSessionsByIdResp, error) {
return nil, grpc.Errorf(12, "method GetChatSessionsById not implemented")
}
func (UnimplementedChatServiceServer) SearchChatSessions(context.Context, *SearchChatSessionsReq) (*SearchChatSessionsResp, error) {
return nil, grpc.Errorf(12, "method SearchChatSessions not implemented")
}
func (UnimplementedChatServiceServer) AddParticipant(context.Context, *AddParticipantReq) (*AddParticipantResp, error) {
return nil, grpc.Errorf(12, "method AddParticipant not implemented")
}
func (UnimplementedChatServiceServer) RemoveParticipant(context.Context, *RemoveParticipantReq) (*RemoveParticipantResp, error) {
return nil, grpc.Errorf(12, "method RemoveParticipant not implemented")
}
func (UnimplementedChatServiceServer) AddChatMessages(context.Context, *AddChatMessagesReq) (*AddChatMessagesResp, error) {
return nil, grpc.Errorf(12, "method AddChatMessages not implemented")
}
func (UnimplementedChatServiceServer) DelChatMessages(context.Context, *DelChatMessagesReq) (*DelChatMessagesResp, error) {
return nil, grpc.Errorf(12, "method DelChatMessages not implemented")
}
func (UnimplementedChatServiceServer) GetChatMessagesById(context.Context, *GetChatMessagesByIdReq) (*GetChatMessagesByIdResp, error) {
return nil, grpc.Errorf(12, "method GetChatMessagesById not implemented")
}
func (UnimplementedChatServiceServer) SearchChatMessages(context.Context, *SearchChatMessagesReq) (*SearchChatMessagesResp, error) {
return nil, grpc.Errorf(12, "method SearchChatMessages not implemented")
}
func (UnimplementedChatServiceServer) mustEmbedUnimplementedChatServiceServer() {}
type UnsafeChatServiceServer interface {
mustEmbedUnimplementedChatServiceServer()
}
type ChatServiceClient interface {
AddChatSessions(ctx context.Context, in *AddChatSessionsReq, opts ...grpc.CallOption) (*AddChatSessionsResp, error)
UpdateChatSessions(ctx context.Context, in *UpdateChatSessionsReq, opts ...grpc.CallOption) (*UpdateChatSessionsResp, error)
DelChatSessions(ctx context.Context, in *DelChatSessionsReq, opts ...grpc.CallOption) (*DelChatSessionsResp, error)
GetChatSessionsById(ctx context.Context, in *GetChatSessionsByIdReq, opts ...grpc.CallOption) (*GetChatSessionsByIdResp, error)
SearchChatSessions(ctx context.Context, in *SearchChatSessionsReq, opts ...grpc.CallOption) (*SearchChatSessionsResp, error)
AddParticipant(ctx context.Context, in *AddParticipantReq, opts ...grpc.CallOption) (*AddParticipantResp, error)
RemoveParticipant(ctx context.Context, in *RemoveParticipantReq, opts ...grpc.CallOption) (*RemoveParticipantResp, error)
AddChatMessages(ctx context.Context, in *AddChatMessagesReq, opts ...grpc.CallOption) (*AddChatMessagesResp, error)
DelChatMessages(ctx context.Context, in *DelChatMessagesReq, opts ...grpc.CallOption) (*DelChatMessagesResp, error)
GetChatMessagesById(ctx context.Context, in *GetChatMessagesByIdReq, opts ...grpc.CallOption) (*GetChatMessagesByIdResp, error)
SearchChatMessages(ctx context.Context, in *SearchChatMessagesReq, opts ...grpc.CallOption) (*SearchChatMessagesResp, error)
}
type chatServiceClient struct {
cc grpc.ClientConnInterface
}
func NewChatServiceClient(cc grpc.ClientConnInterface) ChatServiceClient {
return &chatServiceClient{cc}
}
func (c *chatServiceClient) AddChatSessions(ctx context.Context, in *AddChatSessionsReq, opts ...grpc.CallOption) (*AddChatSessionsResp, error) {
out := new(AddChatSessionsResp)
err := c.cc.Invoke(ctx, "/pb.chatService/AddChatSessions", in, out, opts...)
return out, err
}
func (c *chatServiceClient) UpdateChatSessions(ctx context.Context, in *UpdateChatSessionsReq, opts ...grpc.CallOption) (*UpdateChatSessionsResp, error) {
out := new(UpdateChatSessionsResp)
err := c.cc.Invoke(ctx, "/pb.chatService/UpdateChatSessions", in, out, opts...)
return out, err
}
func (c *chatServiceClient) DelChatSessions(ctx context.Context, in *DelChatSessionsReq, opts ...grpc.CallOption) (*DelChatSessionsResp, error) {
out := new(DelChatSessionsResp)
err := c.cc.Invoke(ctx, "/pb.chatService/DelChatSessions", in, out, opts...)
return out, err
}
func (c *chatServiceClient) GetChatSessionsById(ctx context.Context, in *GetChatSessionsByIdReq, opts ...grpc.CallOption) (*GetChatSessionsByIdResp, error) {
out := new(GetChatSessionsByIdResp)
err := c.cc.Invoke(ctx, "/pb.chatService/GetChatSessionsById", in, out, opts...)
return out, err
}
func (c *chatServiceClient) SearchChatSessions(ctx context.Context, in *SearchChatSessionsReq, opts ...grpc.CallOption) (*SearchChatSessionsResp, error) {
out := new(SearchChatSessionsResp)
err := c.cc.Invoke(ctx, "/pb.chatService/SearchChatSessions", in, out, opts...)
return out, err
}
func (c *chatServiceClient) AddParticipant(ctx context.Context, in *AddParticipantReq, opts ...grpc.CallOption) (*AddParticipantResp, error) {
out := new(AddParticipantResp)
err := c.cc.Invoke(ctx, "/pb.chatService/AddParticipant", in, out, opts...)
return out, err
}
func (c *chatServiceClient) RemoveParticipant(ctx context.Context, in *RemoveParticipantReq, opts ...grpc.CallOption) (*RemoveParticipantResp, error) {
out := new(RemoveParticipantResp)
err := c.cc.Invoke(ctx, "/pb.chatService/RemoveParticipant", in, out, opts...)
return out, err
}
func (c *chatServiceClient) AddChatMessages(ctx context.Context, in *AddChatMessagesReq, opts ...grpc.CallOption) (*AddChatMessagesResp, error) {
out := new(AddChatMessagesResp)
err := c.cc.Invoke(ctx, "/pb.chatService/AddChatMessages", in, out, opts...)
return out, err
}
func (c *chatServiceClient) DelChatMessages(ctx context.Context, in *DelChatMessagesReq, opts ...grpc.CallOption) (*DelChatMessagesResp, error) {
out := new(DelChatMessagesResp)
err := c.cc.Invoke(ctx, "/pb.chatService/DelChatMessages", in, out, opts...)
return out, err
}
func (c *chatServiceClient) GetChatMessagesById(ctx context.Context, in *GetChatMessagesByIdReq, opts ...grpc.CallOption) (*GetChatMessagesByIdResp, error) {
out := new(GetChatMessagesByIdResp)
err := c.cc.Invoke(ctx, "/pb.chatService/GetChatMessagesById", in, out, opts...)
return out, err
}
func (c *chatServiceClient) SearchChatMessages(ctx context.Context, in *SearchChatMessagesReq, opts ...grpc.CallOption) (*SearchChatMessagesResp, error) {
out := new(SearchChatMessagesResp)
err := c.cc.Invoke(ctx, "/pb.chatService/SearchChatMessages", in, out, opts...)
return out, err
}
var ChatService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pb.chatService",
HandlerType: (*ChatServiceServer)(nil),
Methods: []grpc.MethodDesc{
{MethodName: "AddChatSessions", Handler: _ChatService_AddChatSessions_Handler},
{MethodName: "UpdateChatSessions", Handler: _ChatService_UpdateChatSessions_Handler},
{MethodName: "DelChatSessions", Handler: _ChatService_DelChatSessions_Handler},
{MethodName: "GetChatSessionsById", Handler: _ChatService_GetChatSessionsById_Handler},
{MethodName: "SearchChatSessions", Handler: _ChatService_SearchChatSessions_Handler},
{MethodName: "AddParticipant", Handler: _ChatService_AddParticipant_Handler},
{MethodName: "RemoveParticipant", Handler: _ChatService_RemoveParticipant_Handler},
{MethodName: "AddChatMessages", Handler: _ChatService_AddChatMessages_Handler},
{MethodName: "DelChatMessages", Handler: _ChatService_DelChatMessages_Handler},
{MethodName: "GetChatMessagesById", Handler: _ChatService_GetChatMessagesById_Handler},
{MethodName: "SearchChatMessages", Handler: _ChatService_SearchChatMessages_Handler},
},
Streams: []grpc.StreamDesc{},
Metadata: "chat.proto",
}
func RegisterChatServiceServer(s grpc.ServiceRegistrar, srv ChatServiceServer) {
s.RegisterService(&ChatService_ServiceDesc, srv)
}
-161
View File
@@ -1,161 +0,0 @@
package pb
import (
"context"
"google.golang.org/grpc"
)
func _ChatService_AddChatSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddChatSessionsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).AddChatSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/AddChatSessions"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).AddChatSessions(ctx, req.(*AddChatSessionsReq))
})
}
func _ChatService_UpdateChatSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateChatSessionsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).UpdateChatSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/UpdateChatSessions"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).UpdateChatSessions(ctx, req.(*UpdateChatSessionsReq))
})
}
func _ChatService_DelChatSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DelChatSessionsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).DelChatSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/DelChatSessions"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).DelChatSessions(ctx, req.(*DelChatSessionsReq))
})
}
func _ChatService_GetChatSessionsById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetChatSessionsByIdReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).GetChatSessionsById(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/GetChatSessionsById"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).GetChatSessionsById(ctx, req.(*GetChatSessionsByIdReq))
})
}
func _ChatService_SearchChatSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchChatSessionsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).SearchChatSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/SearchChatSessions"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).SearchChatSessions(ctx, req.(*SearchChatSessionsReq))
})
}
func _ChatService_AddParticipant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddParticipantReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).AddParticipant(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/AddParticipant"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).AddParticipant(ctx, req.(*AddParticipantReq))
})
}
func _ChatService_RemoveParticipant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveParticipantReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).RemoveParticipant(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/RemoveParticipant"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).RemoveParticipant(ctx, req.(*RemoveParticipantReq))
})
}
func _ChatService_AddChatMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddChatMessagesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).AddChatMessages(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/AddChatMessages"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).AddChatMessages(ctx, req.(*AddChatMessagesReq))
})
}
func _ChatService_DelChatMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DelChatMessagesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).DelChatMessages(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/DelChatMessages"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).DelChatMessages(ctx, req.(*DelChatMessagesReq))
})
}
func _ChatService_GetChatMessagesById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetChatMessagesByIdReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).GetChatMessagesById(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/GetChatMessagesById"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).GetChatMessagesById(ctx, req.(*GetChatMessagesByIdReq))
})
}
func _ChatService_SearchChatMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchChatMessagesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChatServiceServer).SearchChatMessages(ctx, in)
}
info := &grpc.UnaryServerInfo{Server: srv, FullMethod: "/pb.chatService/SearchChatMessages"}
return interceptor(ctx, in, info, func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChatServiceServer).SearchChatMessages(ctx, req.(*SearchChatMessagesReq))
})
}
-179
View File
@@ -1,179 +0,0 @@
package pb
type ChatMessages struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
SessionId int64 `protobuf:"varint,2,opt,name=sessionId,proto3" json:"sessionId,omitempty"`
SenderId int64 `protobuf:"varint,3,opt,name=senderId,proto3" json:"senderId,omitempty"`
Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"`
Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"`
CreatedAt int64 `protobuf:"varint,6,opt,name=createdAt,proto3" json:"createdAt,omitempty"`
}
func (x *ChatMessages) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ChatMessages) GetSessionId() int64 {
if x != nil {
return x.SessionId
}
return 0
}
func (x *ChatMessages) GetSenderId() int64 {
if x != nil {
return x.SenderId
}
return 0
}
func (x *ChatMessages) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ChatMessages) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *ChatMessages) GetCreatedAt() int64 {
if x != nil {
return x.CreatedAt
}
return 0
}
type AddChatMessagesReq struct {
SessionId int64 `protobuf:"varint,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"`
SenderId int64 `protobuf:"varint,2,opt,name=senderId,proto3" json:"senderId,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
}
func (x *AddChatMessagesReq) GetSessionId() int64 {
if x != nil {
return x.SessionId
}
return 0
}
func (x *AddChatMessagesReq) GetSenderId() int64 {
if x != nil {
return x.SenderId
}
return 0
}
func (x *AddChatMessagesReq) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *AddChatMessagesReq) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
type AddChatMessagesResp struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *AddChatMessagesResp) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type DelChatMessagesReq struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DelChatMessagesReq) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type DelChatMessagesResp struct{}
type GetChatMessagesByIdReq struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *GetChatMessagesByIdReq) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type GetChatMessagesByIdResp struct {
ChatMessages *ChatMessages `protobuf:"bytes,1,opt,name=chatMessages,proto3" json:"chatMessages,omitempty"`
}
func (x *GetChatMessagesByIdResp) GetChatMessages() *ChatMessages {
if x != nil {
return x.ChatMessages
}
return nil
}
type SearchChatMessagesReq struct {
Page int64 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"`
SessionId int64 `protobuf:"varint,3,opt,name=sessionId,proto3" json:"sessionId,omitempty"`
SenderId *int64 `protobuf:"varint,4,opt,name=senderId,proto3,oneof" json:"senderId,omitempty"`
}
func (x *SearchChatMessagesReq) GetPage() int64 {
if x != nil {
return x.Page
}
return 0
}
func (x *SearchChatMessagesReq) GetLimit() int64 {
if x != nil {
return x.Limit
}
return 0
}
func (x *SearchChatMessagesReq) GetSessionId() int64 {
if x != nil {
return x.SessionId
}
return 0
}
func (x *SearchChatMessagesReq) GetSenderId() *int64 {
if x != nil {
return x.SenderId
}
return nil
}
type SearchChatMessagesResp struct {
ChatMessages []*ChatMessages `protobuf:"bytes,1,rep,name=chatMessages,proto3" json:"chatMessages,omitempty"`
}
func (x *SearchChatMessagesResp) GetChatMessages() []*ChatMessages {
if x != nil {
return x.ChatMessages
}
return nil
}
-282
View File
@@ -1,282 +0,0 @@
package pb
type ChatSessions struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
CreatorId int64 `protobuf:"varint,4,opt,name=creatorId,proto3" json:"creatorId,omitempty"`
Participants []int64 `protobuf:"varint,5,rep,packed,name=participants,proto3" json:"participants,omitempty"`
LastMessage string `protobuf:"bytes,6,opt,name=lastMessage,proto3" json:"lastMessage,omitempty"`
LastMessageAt int64 `protobuf:"varint,7,opt,name=lastMessageAt,proto3" json:"lastMessageAt,omitempty"`
CreatedAt int64 `protobuf:"varint,8,opt,name=createdAt,proto3" json:"createdAt,omitempty"`
UpdatedAt int64 `protobuf:"varint,9,opt,name=updatedAt,proto3" json:"updatedAt,omitempty"`
}
func (x *ChatSessions) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ChatSessions) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ChatSessions) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *ChatSessions) GetCreatorId() int64 {
if x != nil {
return x.CreatorId
}
return 0
}
func (x *ChatSessions) GetParticipants() []int64 {
if x != nil {
return x.Participants
}
return nil
}
func (x *ChatSessions) GetLastMessage() string {
if x != nil {
return x.LastMessage
}
return ""
}
func (x *ChatSessions) GetLastMessageAt() int64 {
if x != nil {
return x.LastMessageAt
}
return 0
}
func (x *ChatSessions) GetCreatedAt() int64 {
if x != nil {
return x.CreatedAt
}
return 0
}
func (x *ChatSessions) GetUpdatedAt() int64 {
if x != nil {
return x.UpdatedAt
}
return 0
}
type AddChatSessionsReq struct {
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
CreatorId int64 `protobuf:"varint,3,opt,name=creatorId,proto3" json:"creatorId,omitempty"`
Participants []int64 `protobuf:"varint,4,rep,packed,name=participants,proto3" json:"participants,omitempty"`
}
func (x *AddChatSessionsReq) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *AddChatSessionsReq) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *AddChatSessionsReq) GetCreatorId() int64 {
if x != nil {
return x.CreatorId
}
return 0
}
func (x *AddChatSessionsReq) GetParticipants() []int64 {
if x != nil {
return x.Participants
}
return nil
}
type AddChatSessionsResp struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *AddChatSessionsResp) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type UpdateChatSessionsReq struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Name *string `protobuf:"bytes,2,opt,name=name,proto3,oneof" json:"name,omitempty"`
LastMessage *string `protobuf:"bytes,3,opt,name=lastMessage,proto3,oneof" json:"lastMessage,omitempty"`
LastMessageAt *int64 `protobuf:"varint,4,opt,name=lastMessageAt,proto3,oneof" json:"lastMessageAt,omitempty"`
}
func (x *UpdateChatSessionsReq) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *UpdateChatSessionsReq) GetName() *string {
if x != nil {
return x.Name
}
return nil
}
func (x *UpdateChatSessionsReq) GetLastMessage() *string {
if x != nil {
return x.LastMessage
}
return nil
}
func (x *UpdateChatSessionsReq) GetLastMessageAt() *int64 {
if x != nil {
return x.LastMessageAt
}
return nil
}
type UpdateChatSessionsResp struct{}
type DelChatSessionsReq struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DelChatSessionsReq) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type DelChatSessionsResp struct{}
type GetChatSessionsByIdReq struct {
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *GetChatSessionsByIdReq) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
type GetChatSessionsByIdResp struct {
ChatSessions *ChatSessions `protobuf:"bytes,1,opt,name=chatSessions,proto3" json:"chatSessions,omitempty"`
}
func (x *GetChatSessionsByIdResp) GetChatSessions() *ChatSessions {
if x != nil {
return x.ChatSessions
}
return nil
}
type SearchChatSessionsReq struct {
Page int64 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"`
UserId *int64 `protobuf:"varint,3,opt,name=userId,proto3,oneof" json:"userId,omitempty"`
Type *string `protobuf:"bytes,4,opt,name=type,proto3,oneof" json:"type,omitempty"`
}
func (x *SearchChatSessionsReq) GetPage() int64 {
if x != nil {
return x.Page
}
return 0
}
func (x *SearchChatSessionsReq) GetLimit() int64 {
if x != nil {
return x.Limit
}
return 0
}
func (x *SearchChatSessionsReq) GetUserId() *int64 {
if x != nil {
return x.UserId
}
return nil
}
func (x *SearchChatSessionsReq) GetType() *string {
if x != nil {
return x.Type
}
return nil
}
type SearchChatSessionsResp struct {
ChatSessions []*ChatSessions `protobuf:"bytes,1,rep,name=chatSessions,proto3" json:"chatSessions,omitempty"`
}
func (x *SearchChatSessionsResp) GetChatSessions() []*ChatSessions {
if x != nil {
return x.ChatSessions
}
return nil
}
type AddParticipantReq struct {
SessionId int64 `protobuf:"varint,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"`
UserId int64 `protobuf:"varint,2,opt,name=userId,proto3" json:"userId,omitempty"`
}
func (x *AddParticipantReq) GetSessionId() int64 {
if x != nil {
return x.SessionId
}
return 0
}
func (x *AddParticipantReq) GetUserId() int64 {
if x != nil {
return x.UserId
}
return 0
}
type AddParticipantResp struct{}
type RemoveParticipantReq struct {
SessionId int64 `protobuf:"varint,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"`
UserId int64 `protobuf:"varint,2,opt,name=userId,proto3" json:"userId,omitempty"`
}
func (x *RemoveParticipantReq) GetSessionId() int64 {
if x != nil {
return x.SessionId
}
return 0
}
func (x *RemoveParticipantReq) GetUserId() int64 {
if x != nil {
return x.UserId
}
return 0
}
type RemoveParticipantResp struct{}
+2
View File
@@ -3,6 +3,8 @@ FROM golang:1.25-alpine AS builder
RUN apk add --no-cache git
WORKDIR /build
ENV GOTOOLCHAIN=auto
ENV GOPROXY=https://goproxy.cn,direct
COPY go-wst/ go-wst/
COPY juwan-backend/go.mod juwan-backend/go.sum juwan-backend/
-18
View File
@@ -1,18 +0,0 @@
FROM golang:1.25-alpine AS builder
RUN apk add --no-cache git
WORKDIR /build
COPY go-wst/ go-wst/
COPY juwan-backend/go.mod juwan-backend/go.sum juwan-backend/
WORKDIR /build/juwan-backend
RUN go mod download
COPY juwan-backend/ /build/juwan-backend/
RUN CGO_ENABLED=0 go build -o /chat-rpc ./app/chat/rpc/
FROM alpine:latest
COPY --from=builder /chat-rpc /chat-rpc
COPY juwan-backend/app/chat/rpc/etc/pb.yaml /etc/pb.yaml
CMD ["/chat-rpc", "-f", "/etc/pb.yaml"]
+8 -1
View File
@@ -7,13 +7,20 @@ Hybrid:
Protocol: auto
Ws:
Name: chat-ws
Addr: :28888
Addr: :28889
Path: /ws/chat
MaxConnections: 10000
Auth:
Enabled: true
Source: envoy-header
HeaderName: x-auth-user-id
Wt:
Addr: :28443
Path: /wt/chat
CertFile: /Users/asadz/code/juwan/juwan-backend/app/chat/test/certs/tls.crt
KeyFile: /Users/asadz/code/juwan/juwan-backend/app/chat/test/certs/tls.key
Auth:
Enabled: true
FallbackStrategy: auto
MaxRetries: 3
MaxConnections: 10000
+2
View File
@@ -21,6 +21,8 @@ Hybrid:
KeyFile: /etc/certs/tls.key
Auth:
Enabled: true
Auth:
Enabled: true
FallbackStrategy: auto
MaxRetries: 3
MaxConnections: 10000
-5
View File
@@ -1,5 +0,0 @@
Name: pb.rpc
ListenOn: 0.0.0.0:28080
Log:
Level: debug
+35 -7
View File
@@ -12,7 +12,6 @@ echo ""
cleanup() {
echo ""
echo "=== Collecting container logs ==="
docker compose -f "$SCRIPT_DIR/docker-compose.yml" logs chat-rpc > "$LOG_DIR/chat-rpc.log" 2>&1 || true
docker compose -f "$SCRIPT_DIR/docker-compose.yml" logs chat-api > "$LOG_DIR/chat-api.log" 2>&1 || true
echo "=== Stopping containers ==="
docker compose -f "$SCRIPT_DIR/docker-compose.yml" down --remove-orphans 2>/dev/null || true
@@ -23,6 +22,22 @@ echo "=== Step 1: Building Docker images ==="
docker compose -f "$SCRIPT_DIR/docker-compose.yml" build 2>&1 | tee "$LOG_DIR/build.log"
echo ""
echo "=== Step 1.5: Building test tools ==="
(cd "$SCRIPT_DIR" && GOTOOLCHAIN=local GOPROXY=https://goproxy.cn,direct go build -o "$SCRIPT_DIR/wt_client" ./wt_client.go 2>&1) | tee -a "$LOG_DIR/build.log"
(cd "$SCRIPT_DIR" && GOTOOLCHAIN=local GOPROXY=https://goproxy.cn,direct go build -o "$SCRIPT_DIR/gen_token" ./gen_token.go 2>&1) | tee -a "$LOG_DIR/build.log"
echo ""
echo "=== Step 1.6: Generating JWT tokens ==="
JWT_SECRET="test-secret"
TOKEN_1001=$("$SCRIPT_DIR/gen_token" "$JWT_SECRET" 1001)
TOKEN_1002=$("$SCRIPT_DIR/gen_token" "$JWT_SECRET" 1002)
TOKEN_2001=$("$SCRIPT_DIR/gen_token" "$JWT_SECRET" 2001)
TOKEN_2002=$("$SCRIPT_DIR/gen_token" "$JWT_SECRET" 2002)
TOKEN_9001=$("$SCRIPT_DIR/gen_token" "$JWT_SECRET" 9001)
echo " user 1001 token: ${TOKEN_1001:0:30}..."
echo " user 1002 token: ${TOKEN_1002:0:30}..."
echo ""
echo "=== Step 2: Starting services ==="
docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d 2>&1 | tee -a "$LOG_DIR/build.log"
echo ""
@@ -39,24 +54,37 @@ sleep 3
echo "Services should be ready."
echo ""
VENV_PYTHON="$SCRIPT_DIR/.venv/bin/python3"
if [ ! -f "$VENV_PYTHON" ]; then
echo "=== Creating Python venv ==="
python3 -m venv "$SCRIPT_DIR/.venv"
"$VENV_PYTHON" -m pip install websockets -q
fi
echo "=== Step 4: Running WebSocket tests ==="
cd "$SCRIPT_DIR"
python3 test_ws.py 2>&1 | tee "$LOG_DIR/ws_test_stdout.log"
ALL_PROXY= HTTP_PROXY= HTTPS_PROXY= NO_PROXY=* "$VENV_PYTHON" test_ws.py 2>&1 | tee "$LOG_DIR/ws_test_stdout.log"
WS_RC=${PIPESTATUS[0]}
echo ""
echo "=== Step 5: Running WebTransport fallback tests ==="
python3 test_wt.py 2>&1 | tee "$LOG_DIR/wt_test_stdout.log"
WT_RC=${PIPESTATUS[0]}
echo "=== Step 5: Running WebTransport fallback tests (WS) ==="
ALL_PROXY= HTTP_PROXY= HTTPS_PROXY= NO_PROXY=* "$VENV_PYTHON" test_wt.py 2>&1 | tee "$LOG_DIR/wt_test_stdout.log"
WT_FALLBACK_RC=${PIPESTATUS[0]}
echo ""
echo "=== Step 6: Running WebTransport native tests (QUIC) ==="
ALL_PROXY= HTTP_PROXY= HTTPS_PROXY= NO_PROXY=* "$SCRIPT_DIR/wt_client" "https://localhost:28443/wt/chat?token=${TOKEN_9001}" 2>&1 | tee "$LOG_DIR/wt_native_stdout.log"
WT_NATIVE_RC=${PIPESTATUS[0]}
echo ""
echo "=== Test Summary ==="
echo "WebSocket test: $([ $WS_RC -eq 0 ] && echo 'PASSED' || echo 'FAILED')"
echo "WebTransport test: $([ $WT_RC -eq 0 ] && echo 'PASSED' || echo 'FAILED')"
echo "WT fallback test (WS): $([ $WT_FALLBACK_RC -eq 0 ] && echo 'PASSED' || echo 'FAILED')"
echo "WT native test (QUIC): $([ $WT_NATIVE_RC -eq 0 ] && echo 'PASSED' || echo 'FAILED')"
echo ""
echo "Logs saved to: $LOG_DIR/"
ls -la "$LOG_DIR/"
if [ $WS_RC -ne 0 ] || [ $WT_RC -ne 0 ]; then
if [ $WS_RC -ne 0 ] || [ $WT_FALLBACK_RC -ne 0 ] || [ $WT_NATIVE_RC -ne 0 ]; then
exit 1
fi
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+6 -9
View File
@@ -7,16 +7,13 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONFIG =====
#CommunityRpcConf:
# Target: k8s://juwan/community-rpc-svc.juwan:8080
#UsercenterRpcConf:
# Target: k8s://juwan/users-rpc-svc.juwan:8080
# ===== DEV CONFIG =====
CommunityRpcConf:
Endpoints:
- community-rpc:8080
- "${COMMUNITY_RPC_TARGET}"
UsercenterRpcConf:
Endpoints:
- user-rpc:8080
- "${USER_RPC_TARGET}"
Log:
Level: debug
+3 -3
View File
@@ -4,7 +4,7 @@
package types
type Comment struct {
Id int64 `json:"id"`
Id int64 `json:"id,string"`
Content string `json:"content"`
Author UserProfile `json:"author"`
LikeCount int64 `json:"likeCount"`
@@ -54,12 +54,12 @@ type PathId struct {
}
type Post struct {
Id int64 `json:"id"`
Id int64 `json:"id,string"`
Title string `json:"title"`
Content string `json:"content"`
Images []string `json:"images"`
Tags []string `json:"tags"`
LinkedOrderId int64 `json:"linkedOrderId,optional"`
LinkedOrderId int64 `json:"linkedOrderId,string,optional"`
Pinned bool `json:"pinned"`
LikeCount int64 `json:"likeCount"`
CommentCount int64 `json:"commentCount"`
+4 -22
View File
@@ -6,36 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+8 -4
View File
@@ -7,13 +7,17 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONFIG =====
DisputeRpcConf:
Endpoints:
- dispute-rpc:8080
- "${DISPUTE_RPC_TARGET}"
OrderRpcConf:
Endpoints:
- order-rpc:8080
- "${ORDER_RPC_TARGET}"
PlayerRpcConf:
Endpoints:
- player-rpc:8080
- "${PLAYER_RPC_TARGET}"
Log:
Level: debug
+5 -5
View File
@@ -15,11 +15,11 @@ type CreateDisputeReq struct {
}
type Dispute struct {
Id int64 `json:"id"`
OrderId int64 `json:"orderId"`
InitiatorId int64 `json:"initiatorId"`
Id int64 `json:"id,string"`
OrderId int64 `json:"orderId,string"`
InitiatorId int64 `json:"initiatorId,string"`
InitiatorName string `json:"initiatorName"`
RespondentId int64 `json:"respondentId"`
RespondentId int64 `json:"respondentId,string"`
Reason string `json:"reason"`
Evidence []string `json:"evidence"`
Status string `json:"status"`
@@ -28,7 +28,7 @@ type Dispute struct {
RespondentEvidence []string `json:"respondentEvidence"`
AppealReason string `json:"appealReason,optional"`
AppealedAt string `json:"appealedAt,optional"`
ResolvedBy int64 `json:"resolvedBy,optional"`
ResolvedBy int64 `json:"resolvedBy,string,optional"`
ResolvedAt string `json:"resolvedAt,optional"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
+4 -4
View File
@@ -6,18 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+4 -12
View File
@@ -7,21 +7,10 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONFIG =====
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# ===== DEV CONFIG =====
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Kmq:
Name: email-api
@@ -29,3 +18,6 @@ Kmq:
- "${KAFKA_BROKER}"
Group: "email-api-group"
Topic: "email-task"
Log:
Level: debug
+2 -12
View File
@@ -30,15 +30,5 @@ Mail:
InsecureSkipVerify: false
ReplyTo: "${EMAIL_REPLY_TO}"
# Mail:
# Enabled: true
# Host: "smtp.163.com"
# Port: 465
# Username: "churong2646@163.com"
# Password: "GTv6C6qNbv5urAiD"
# FromAddress: "churong2646@163.com"
# FromName: "聚玩"
# UseSSL: true
# UseStartTLS: false
# InsecureSkipVerify: false
# ReplyTo: ""
Log:
Level: debug
+1 -6
View File
@@ -7,14 +7,9 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#GameRpcConf:
# Target: k8s://juwan/game-rpc-svc:8080
# ===== DEV CONF =====
GameRpcConf:
Endpoints:
- game-rpc:8080
- "${GAME_RPC_TARGET}"
Log:
Level: debug
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewRequestMiddleware().Handle)
+1 -1
View File
@@ -1,5 +1,5 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.9.2
// goctl 1.10.1
package handler
+1 -1
View File
@@ -7,7 +7,7 @@ type EmptyResp struct {
}
type Game struct {
Id int64 `json:"id,optional"`
Id int64 `json:"id,string,optional"`
Name string `json:"name"`
Icon string `json:"icon"`
Category string `json:"category"`
+4 -26
View File
@@ -6,40 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Log:
# Level: info
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+4 -2
View File
@@ -7,7 +7,9 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONFIG =====
NotificationRpcConf:
Endpoints:
- notification-rpc:8080
- "${NOTIFICATION_RPC_TARGET}"
Log:
Level: debug
+1 -1
View File
@@ -7,7 +7,7 @@ type EmptyResp struct {
}
type Notification struct {
Id int64 `json:"id"`
Id int64 `json:"id,string"`
Type string `json:"type"`
Title string `json:"title"`
Content string `json:"content"`
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+4 -4
View File
@@ -6,18 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+1 -13
View File
@@ -7,21 +7,9 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#FileRpcConf:
# Target: k8s://juwan/objectstory-rpc-svc:8080
#
#Log:
# Level: info
# ===== DEV CONF =====
FileRpcConf:
Endpoints:
- objectstory-rpc:8080
- "${OBJECTSTORY_RPC_TARGET}"
Log:
Level: debug
# k8s://juwan/<service name>:8080
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewRequestMiddleware().Handle)
+5 -28
View File
@@ -6,36 +6,13 @@ Prometheus:
Port: 4001
Path: /metrics
# Target: k8s://juwan/<service name>.<namespace>:8080
#S3Conf:
# Endpoint: "${S3_ENDPOINT}"
# AccessKey: "${S3_ACCESS_KEY}"
# SecretKey: "${S3_SECRET_KEY}"
# Bucket: "${S3_BUCKET_NAME}"
# Region: "${S3_REGION}"
S3Conf:
Endpoint: "https://cn-nb1.rains3.com"
AccessKey: "mfgGnaAcUDP2zYAi"
SecretKey: "ZfKkbhUvsAchiKlxzIXrDHrSyskyRj"
Bucket: "juwan-dev-image-zj"
Region: auto
Endpoint: "${S3_ENDPOINT}"
AccessKey: "${S3_ACCESS_KEY}"
SecretKey: "${S3_SECRET_KEY}"
Bucket: "${S3_BUCKET_NAME}"
Region: "${S3_REGION}"
UsePathStyle: true
Log:
Level: debug
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
ctx := svc.NewServiceContext(c)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
+6 -15
View File
@@ -7,26 +7,17 @@ Prometheus:
Port: 4001
Path: /metrics
# k8s://juwan/<service name>:8080
# ===== PROC CONF =====
#OrderRpcConf:
# Target: k8s://juwan/order-rpc-svc:8080
#
#PlayerRpcConf:
# Target: k8s://juwan/player-rpc-svc:8080
#
#ShopRpcConf:
# Target: k8s://juwan/shop-rpc-svc:8080
# ===== DEV CONF ====
OrderRpcConf:
Endpoints:
- order-rpc:8080
- "${ORDER_RPC_TARGET}"
PlayerRpcConf:
Endpoints:
- player-rpc:8080
- "${PLAYER_RPC_TARGET}"
ShopRpcConf:
Endpoints:
- shop-rpc:8080
- "${SHOP_RPC_TARGET}"
Log:
Level: debug
+9 -9
View File
@@ -4,9 +4,9 @@
package types
type CreateOrderReq struct {
PlayerId int64 `json:"playerId"`
ShopId int64 `json:"shopId,optional"`
ServiceId int64 `json:"serviceId"`
PlayerId int64 `json:"playerId,string"`
ShopId int64 `json:"shopId,string,optional"`
ServiceId int64 `json:"serviceId,string"`
Quantity int `json:"quantity"`
Note string `json:"note,optional"`
}
@@ -20,10 +20,10 @@ type EmptyResp struct {
}
type Order struct {
Id int64 `json:"id"`
ConsumerId int64 `json:"consumerId"`
Id int64 `json:"id,string"`
ConsumerId int64 `json:"consumerId,string"`
PlayerId string `json:"playerId"`
ShopId int64 `json:"shopId,optional"`
ShopId int64 `json:"shopId,string,optional"`
Service PlayerService `json:"service"`
Status string `json:"status"`
TotalPrice float64 `json:"totalPrice"`
@@ -60,9 +60,9 @@ type PathId struct {
}
type PlayerService struct {
Id int64 `json:"id"`
PlayerId int64 `json:"playerId"`
GameId int64 `json:"gameId"`
Id int64 `json:"id,string"`
PlayerId int64 `json:"playerId,string"`
GameId int64 `json:"gameId,string"`
GameName string `json:"gameName"`
Title string `json:"title"`
Description string `json:"description"`
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewRequestMiddleware().Handle)
+4 -35
View File
@@ -1,54 +1,23 @@
Name: pb.rpc
ListenOn: 0.0.0.0:8080
Prometheus:
Host: 0.0.0.0
Port: 4001
Path: /metrics
# tcd:
# Hosts:
# - 127.0.0.1:2379
# Key: pb.rpc
# Target: k8s://juwan/<service name>.<namespace>:8080
# ==== PROC CONF ====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#
#
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Log:
# Level: info
# ==== DEV CONF ====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+6 -8
View File
@@ -7,15 +7,13 @@ Prometheus:
Port: 4001
Path: /metrics
# k8s://juwan/<service name>:8080
# ===== PROC CONF =====
#PlayerRpcConf:
# Target: k8s://juwan/player-rpc-svc:8080
# ===== DEV CONF ====
PlayerRpcConf:
Endpoints:
- player-rpc:8080
- "${PLAYER_RPC_TARGET}"
UsercenterRpcConf:
Endpoints:
- user-rpc:8080
- "${USER_RPC_TARGET}"
Log:
Level: debug
@@ -0,0 +1,32 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package player
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"juwan-backend/app/player/api/internal/logic/player"
"juwan-backend/app/player/api/internal/svc"
"juwan-backend/app/player/api/internal/types"
)
// 获取当前用户的打手资料
func GetMyPlayerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.EmptyResp
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := player.NewGetMyPlayerLogic(r.Context(), svcCtx)
resp, err := l.GetMyPlayer(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
@@ -57,6 +57,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/players/me",
Handler: player.InitPlayerHandler(serverCtx),
},
{
// 获取当前用户的打手资料
Method: http.MethodGet,
Path: "/players/me",
Handler: player.GetMyPlayerHandler(serverCtx),
},
{
// 更新接单状态
Method: http.MethodPut,
@@ -45,11 +45,16 @@ func (l *GetPlayerLogic) GetPlayer(req *types.GetPlayerReq) (resp *types.PlayerP
if player == nil {
return nil, errors.New("player not found")
}
completionRate := 0.0
if player.TotalOrders > 0 {
completionRate = float64(player.CompletedOrders) / float64(player.TotalOrders)
}
resp = &types.PlayerProfile{
Id: player.Id,
Rating: player.Rating,
TotalOrders: player.TotalOrders,
CompletionRate: completionRate,
Status: player.Status,
Gender: player.Gender,
Services: []types.PlayerService{},
@@ -0,0 +1,126 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package player
import (
"context"
"encoding/json"
"errors"
"strconv"
"time"
"juwan-backend/app/player/api/internal/svc"
"juwan-backend/app/player/api/internal/types"
"juwan-backend/app/player/rpc/pb"
"juwan-backend/app/player/rpc/playerservice"
"juwan-backend/app/users/rpc/usercenter"
"juwan-backend/common/utils/contextj"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type GetMyPlayerLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 获取当前用户的打手资料
func NewGetMyPlayerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMyPlayerLogic {
return &GetMyPlayerLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetMyPlayerLogic) GetMyPlayer(req *types.EmptyResp) (resp *types.PlayerProfile, err error) {
userID, err := contextj.UserIDFrom(l.ctx)
if err != nil {
return nil, err
}
playerResp, err := l.svcCtx.PlayerRpc.GetPlayerByUserId(l.ctx, &playerservice.SearchPlayersReq{UserId: &userID})
if err != nil {
st, _ := status.FromError(err)
if st.Code().String() == "NotFound" {
return nil, errors.New("player not found")
}
return nil, err
}
player := playerResp.GetPlayers()
if player == nil {
return nil, errors.New("player not found")
}
userResp, err := l.svcCtx.UserRpc.GetUsersById(l.ctx, &usercenter.GetUsersByIdReq{Id: userID})
if err != nil {
return nil, err
}
user := userResp.GetUsers()
if user == nil {
return nil, errors.New("user not found")
}
games := make([]string, 0, len(player.Games))
for _, gameID := range player.Games {
games = append(games, strconv.FormatInt(gameID, 10))
}
verificationStatus := map[string]string{}
if user.VerificationStatus != "" {
_ = json.Unmarshal([]byte(user.VerificationStatus), &verificationStatus)
}
resp = &types.PlayerProfile{
Id: player.Id,
User: types.UserProfile{
Id: strconv.FormatInt(user.Id, 10),
Username: user.Username,
Nickname: user.Nickname,
Avatar: user.Avatar,
Role: user.CurrentRole,
VerifiedRoles: append([]string{}, user.VerifiedRoles...),
VerificationStatus: verificationStatus,
Phone: user.Phone,
Bio: user.Bio,
CreatedAt: time.Unix(user.CreatedAt, 0).Format(time.DateTime),
},
Rating: player.Rating,
TotalOrders: player.TotalOrders,
Status: player.Status,
Games: games,
Services: []types.PlayerService{},
Gender: player.Gender,
Tags: append([]string{}, player.Tags...),
}
if player.ShopId != 0 {
resp.ShopId = strconv.FormatInt(player.ShopId, 10)
}
svcResp, svcErr := l.svcCtx.PlayerRpc.SearchPlayerServices(l.ctx, &pb.SearchPlayerServicesReq{
PlayerId: player.Id,
Limit: 100,
})
if svcErr != nil {
logx.Errorf("GetMyPlayer SearchPlayerServices player=%d err: %v", player.Id, svcErr)
} else {
for _, s := range svcResp.PlayerServices {
resp.Services = append(resp.Services, types.PlayerService{
Id: s.Id,
PlayerId: s.PlayerId,
GameId: s.GameId,
Title: s.Title,
Description: s.Description,
Price: s.Price,
Unit: s.Unit,
RankRange: s.RankRange,
Availability: s.Availability,
})
}
}
return resp, nil
}
+6 -6
View File
@@ -4,7 +4,7 @@
package types
type CreateServiceReq struct {
GameId int64 `json:"gameId,optional"`
GameId int64 `json:"gameId,string,optional"`
Title string `json:"title,optional"`
Description string `json:"description,optional"`
Price float64 `json:"price"`
@@ -56,7 +56,7 @@ type PlayerListResp struct {
}
type PlayerProfile struct {
Id int64 `json:"id"`
Id int64 `json:"id,string"`
User UserProfile `json:"user"`
Rating float64 `json:"rating"`
TotalOrders int64 `json:"totalOrders"`
@@ -71,9 +71,9 @@ type PlayerProfile struct {
}
type PlayerService struct {
Id int64 `json:"id,optional"`
PlayerId int64 `json:"playerId"`
GameId int64 `json:"gameId"`
Id int64 `json:"id,string,optional"`
PlayerId int64 `json:"playerId,string"`
GameId int64 `json:"gameId,string"`
GameName string `json:"gameName"`
Title string `json:"title"`
Description string `json:"description"`
@@ -100,7 +100,7 @@ type UpdatePlayerStatusReq struct {
type UpdateServiceReq struct {
Id int64 `path:"id"`
GameId *int64 `json:"gameId,optional"`
GameId *int64 `json:"gameId,string,optional"`
Title *string `json:"title,optional"`
Description *string `json:"description,optional"`
Price *float64 `json:"price,optional"`
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+4 -29
View File
@@ -1,48 +1,23 @@
Name: pb.rpc
ListenOn: 0.0.0.0:8080
Prometheus:
Host: 0.0.0.0
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Log:
# Level: info
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+8 -4
View File
@@ -7,13 +7,17 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONFIG =====
ReviewRpcConf:
Endpoints:
- review-rpc:8080
- "${REVIEW_RPC_TARGET}"
OrderRpcConf:
Endpoints:
- order-rpc:8080
- "${ORDER_RPC_TARGET}"
PlayerRpcConf:
Endpoints:
- player-rpc:8080
- "${PLAYER_RPC_TARGET}"
Log:
Level: debug
+3 -3
View File
@@ -27,9 +27,9 @@ type PageReq struct {
}
type Review struct {
Id int64 `json:"id"`
OrderId int64 `json:"orderId"`
FromUserId int64 `json:"fromUserId"`
Id int64 `json:"id,string"`
OrderId int64 `json:"orderId,string"`
FromUserId int64 `json:"fromUserId,string"`
FromUserName string `json:"fromUserName"`
Rating int `json:"rating"`
Content string `json:"content"`
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+4 -4
View File
@@ -6,18 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+4 -2
View File
@@ -7,7 +7,9 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONFIG =====
SearchRpcConf:
Endpoints:
- search-rpc:8080
- "${SEARCH_RPC_TARGET}"
Log:
Level: debug
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+4 -4
View File
@@ -6,18 +6,18 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== DEV CONF =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+6 -10
View File
@@ -7,17 +7,13 @@ Prometheus:
Port: 4001
Path: /metrics
# k8s://juwan/<service name>:8080
# ===== PROC CONFIG =====
#ShopRpcConf:
# Target: k8s://juwan/shop-rpc-svc.juwan:8080
# ===== DEV CONFIG ====
ShopRpcConf:
Endpoints:
- shop-rpc:8080
- "${SHOP_RPC_TARGET}"
PlayerRpcConf:
Endpoints:
- player-rpc:8080
- "${PLAYER_RPC_TARGET}"
Log:
Level: debug
+5 -5
View File
@@ -37,7 +37,7 @@ type IncomeStatsResp struct {
type InvitationReq struct {
Id int64 `path:"id"`
PlayerId int64 `json:"playerId"`
PlayerId int64 `json:"playerId,string"`
}
type PageMeta struct {
@@ -61,11 +61,11 @@ type ShopIdReq struct {
}
type ShopInvitation struct {
Id int64 `json:"id"`
ShopId int64 `json:"shopId"`
PlayerId int64 `json:"playerId"`
Id int64 `json:"id,string"`
ShopId int64 `json:"shopId,string"`
PlayerId int64 `json:"playerId,string"`
Status string `json:"status"`
InvitedBy int64 `json:"invitedBy"`
InvitedBy int64 `json:"invitedBy,string"`
CreatedAt int64 `json:"createdAt"`
RespondedAt int64 `json:"respondedAt,optional"`
}
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+7 -38
View File
@@ -6,53 +6,22 @@ Prometheus:
Port: 4001
Path: /metrics
# tcd:
# Hosts:
# - 127.0.0.1:2379
# Key: pb.rpc
# ===== PROC Config =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#UsersRpcConf:
# Target: k8s://juwan/user-rpc-svc:8080
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@{DB_HOST_RW}.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@{BD_HOST_RO}.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# ===== DEV Config =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
UsersRpcConf:
Endpoints:
- user-rpc:8080
- "${USER_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: info
# Target: k8s://juwan/<service name>.<namespace>:8080
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
Level: debug
+2 -2
View File
@@ -2,5 +2,5 @@ Name: snowflake.rpc
ListenOn: 0.0.0.0:8080
Snowflake:
DatacenterId: 1
WorkerId: 0
DatacenterId: ${SNOWFLAKE_DATACENTER_ID}
WorkerId: ${SNOWFLAKE_WORKER_ID}
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
ctx := svc.NewServiceContext(c)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
+10 -28
View File
@@ -1,45 +1,27 @@
Name: pb.rpc
ListenOn: 0.0.0.0:8080
Prometheus:
Host: 0.0.0.0
Port: 4001
Path: /metrics
# ===== PROC Config =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc.juwan:8080
#UserRpcConf:
# Target: k8s://juwan/user-rpc-svc.juwan:8080
#
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Log:
# Level: info
# ===== DEV Config =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
UserRpcConf:
Endpoints:
- user-rpc:8080
- "${USER_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+3 -9
View File
@@ -7,19 +7,13 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONFIG =====
#UsercenterRpcConf:
# Target: k8s://juwan/user-rpc-svc:8080
#UserVerificationRpc:
# Target: k8s://juwan/user_verifications-svc:8080
# ===== DEV CONFIG ====
UserVerificationRpc:
Endpoints:
- user-verifications-rpc:8080
- "${USER_VERIFICATIONS_RPC_TARGET}"
UsercenterRpcConf:
Endpoints:
- user-rpc:8080
- "${USER_RPC_TARGET}"
Log:
Level: debug
+2 -2
View File
@@ -125,8 +125,8 @@ type VerificationIdReq struct {
}
type VerificationItem struct {
Id int64 `json:"id"` // 认证记录ID (主键,用于管理员操作)
UserId int64 `json:"userId"` // 申请人ID (外键)
Id int64 `json:"id,string"` // 认证记录ID (主键,用于管理员操作)
UserId int64 `json:"userId,string"` // 申请人ID (外键)
UserNickname string `json:"userNickname"` // 冗余显示,方便前端展示
Role string `json:"role"` // 申请角色: player, owner
Status string `json:"status"` // pending, approved, rejected
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewHeaderExtractorMiddleware().Handle)
+35 -11
View File
@@ -6,14 +6,28 @@ import (
"strings"
"time"
"juwan-backend/app/snowflake/rpc/snowflake"
"juwan-backend/app/users/rpc/internal/models/schema"
"juwan-backend/app/users/rpc/internal/models/users"
"juwan-backend/app/users/rpc/internal/svc"
"juwan-backend/common/utils/pwdUtils"
"juwan-backend/pkg/types"
"github.com/zeromicro/go-zero/core/logx"
)
const adminUserID int64 = 100000
var adminVerifiedRoles = types.TextArray{
Elements: []string{"consumer", "player", "owner", "admin"},
Valid: true,
}
var adminVerificationStatus = schema.VerificationStatusStruct{
Consumer: "approved",
Player: "approved",
Owner: "approved",
}
func initAdmin(svcCtx *svc.ServiceContext) {
username := strings.TrimSpace(os.Getenv("ADMIN_USERNAME"))
password := strings.TrimSpace(os.Getenv("ADMIN_PASSWORD"))
@@ -24,8 +38,9 @@ func initAdmin(svcCtx *svc.ServiceContext) {
go func() {
ctx := context.Background()
var existing bool
for i := range 30 {
exists, err := svcCtx.UsersModelRW.Users.Query().Where(users.UsernameEQ(username)).Exist(ctx)
ok, err := svcCtx.UsersModelRW.Users.Query().Where(users.UsernameEQ(username)).Exist(ctx)
if err != nil {
if i < 29 {
time.Sleep(time.Second)
@@ -34,10 +49,23 @@ func initAdmin(svcCtx *svc.ServiceContext) {
logx.Errorf("check admin user: %v", err)
return
}
if exists {
existing = ok
break
}
if existing {
err := svcCtx.UsersModelRW.Users.Update().
Where(users.UsernameEQ(username)).
SetIsAdmin(true).
SetVerifiedRoles(adminVerifiedRoles).
SetVerificationStatus(adminVerificationStatus).
Exec(ctx)
if err != nil {
logx.Errorf("reconcile admin user: %v", err)
return
}
break
logx.Infof("reconciled admin user: %s", username)
return
}
hashedPassword, err := pwdUtils.HashPassword(password)
@@ -46,14 +74,8 @@ func initAdmin(svcCtx *svc.ServiceContext) {
return
}
resp, err := svcCtx.Snowflake.NextId(ctx, &snowflake.NextIdReq{})
if err != nil {
logx.Errorf("generate admin user ID: %v", err)
return
}
_, err = svcCtx.UsersModelRW.Users.Create().
SetID(resp.Id).
SetID(adminUserID).
SetUsername(username).
SetPasswordHash(hashedPassword).
SetEmail(email).
@@ -63,6 +85,8 @@ func initAdmin(svcCtx *svc.ServiceContext) {
SetCurrentRole("consumer").
SetNickname(username).
SetIsAdmin(true).
SetVerifiedRoles(adminVerifiedRoles).
SetVerificationStatus(adminVerificationStatus).
Save(ctx)
if err != nil {
logx.Errorf("create admin user: %v", err)
+5 -30
View File
@@ -6,46 +6,21 @@ Prometheus:
Port: 4001
Path: /metrics
DataSource: "${DB_URI}?sslmode=disable"
# ===== PROC CONFIG =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Jwt:
# SecretKey: "${JWT_SECRET_KEY}"
# Issuer: "juwan-user-rpc"
# ===== DEV CONFIG =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slave: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Jwt:
SecretKey: "MGUyMWE3ZDhjMTQ5ZDg1MWViOWU0MGM3OTE2NWVkYTBlOTE5ZWRkZDU1YjYzOGJjOWRiNzM0NTc4NDIyMjlkZQ"
SecretKey: "${JWT_SECRET_KEY}"
Issuer: "juwan-user-rpc"
Log:
-1
View File
@@ -12,7 +12,6 @@ type JwtConfig struct {
type Config struct {
zrpc.RpcServerConf
DataSource string `json:"dataSource"`
DB struct {
Master string
Slave string
+3 -10
View File
@@ -7,16 +7,9 @@ Prometheus:
Port: 4001
Path: /metrics
# ===== PROC CONF =====
#WalletRpcConf:
# Target: k8s://juwan/wallet-rpc:8080
# ===== DEV CONF =====
WalletRpcConf:
Endpoints:
- wallet-rpc:8080
# k8s://juwan/<service name>:8080
- "${WALLET_RPC_TARGET}"
Log:
Level: debug
+1 -1
View File
@@ -1,5 +1,5 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.9.2
// goctl 1.10.1
package handler
+2 -2
View File
@@ -1,5 +1,5 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.9.2
// goctl 1.10.1
package types
@@ -29,7 +29,7 @@ type TopupReq struct {
}
type Transaction struct {
Id int64 `json:"id"`
Id int64 `json:"id,string"`
Type string `json:"type"`
Amount string `json:"amount"`
Description string `json:"description"`
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
conf.MustLoad(*configFile, &c, conf.UseEnv())
server := rest.MustNewServer(c.RestConf)
server.Use(middlewares.NewRequestMiddleware().Handle)
+4 -36
View File
@@ -1,55 +1,23 @@
Name: pb.rpc
ListenOn: 0.0.0.0:8080
Prometheus:
Host: 0.0.0.0
Port: 4001
Path: /metrics
# tcd:
# Hosts:
# - 127.0.0.1:2379
# Key: pb.rpc
# Target: k8s://juwan/<service name>.<namespace>:8080
# ===== PROC CONF =====
#SnowflakeRpcConf:
# Target: k8s://juwan/snowflake-svc:8080
#
#
#DB:
# Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-rw.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
# Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@user-db-ro.juwan:${DB_PORT}/${DB_NAME}?sslmode=disable"
#
#
#CacheConf:
# - Host: "${REDIS_M_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
# - Host: "${REDIS_S_HOST}"
# Type: node
# Pass: "${REDIS_PASSWORD}"
# User: "default"
#
#Log:
# Level: info
# ===== DEV CONFIG =====
SnowflakeRpcConf:
Endpoints:
- snowflake:8080
- "${SNOWFLAKE_RPC_TARGET}"
DB:
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@postgres:${DB_PORT}/${DB_NAME}?sslmode=disable"
Master: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Slaves: "postgresql://${PD_USERNAME}:${DB_PASSWORD}@${DB_HOST_RO}:${DB_PORT}/${DB_NAME}?sslmode=disable"
CacheConf:
- Host: "${REDIS_HOST}:${REDIS_PORT}"
Type: node
Pass: "${REDIS_PASSWORD}"
Log:
Level: debug
+2
View File
@@ -0,0 +1,2 @@
GITEA_DOMAIN=git.juwan.xhttp.zip
RUNNER_TOKEN=
+4
View File
@@ -0,0 +1,4 @@
/secrets/
/garage/garage.toml
/zot/htpasswd
/.env
+100
View File
@@ -0,0 +1,100 @@
# 管理机部署
Zot(容器仓库)、Garage(对象存储)、Gitea(代码 + Actions Runner)、CaddyHTTPS 反代 + 业务入口),全部在同一台 center 机器上以 Docker Compose 运行。业务服务部署在另一台 k01 机器上,公网流量经由 center 的 Caddy 反代到 k01 上的 envoy-gateway NodePort。
部署机参考:centerVultr High Frequency / 1 vCPU / 1 GB RAM / 32 GB NVMe)。
## 前置条件
- Docker Engine 与 compose v2
- `apache2-utils`(提供 `htpasswd` 命令,用于给 Zot 生成 bcrypt 密码)
- DNS`git` / `registry` / `s3` / `juwan` 四条 A 记录全部指向 66.135.5.101,灰云直连
- 防火墙入站规则允许 TCP 80、443、UDP 443
## 首次部署
```bash
cd deploy/center
# 生成所有随机密码与 token,渲染 garage.toml / zot.htpasswd / .env
bash init.sh
# 启动 Caddy + Zot + Garage + Gitea
docker compose up -d caddy zot garage gitea
# 创建 Gitea 管理员
docker compose exec -u git gitea gitea admin user create \
--username admin \
--email admin@juwan.xhttp.zip \
--password "$(cat secrets/gitea-admin-password)" \
--admin --must-change-password=false
# 在浏览器打开 https://git.juwan.xhttp.zip
# → Site Administration → Actions → Runners → 生成 runner token
# → 把 token 写入 .env 的 RUNNER_TOKEN
# → 回到终端执行:
docker compose up -d runner
# 初始化 Garage:创建 layout、两个 bucket、生成 access key
bash garage/bootstrap.sh
```
`bootstrap.sh` 最后会打印 S3 连接信息,其中 `S3_ACCESS_KEY` / `S3_SECRET_KEY` 留给 k01 的 `objectstory-rpc` 和 CNPG backup 配置。
## 访问入口
| 子域 | 内容 |
| -------------------------- | ------------------------------------------------- |
| `git.juwan.xhttp.zip` | Gitea 代码仓库 |
| `registry.juwan.xhttp.zip` | Zot 镜像仓库 + 内置 zui 浏览器 |
| `s3.juwan.xhttp.zip` | Garage S3 API |
| `juwan.xhttp.zip` | 业务前端,Caddy 反代至 k01 envoy-gateway NodePort |
## 凭据与认证
`init.sh` 会把所有密码写入 `secrets/` 目录(权限 600`.gitignore` 已排除)。`garage/garage.toml``zot/htpasswd` 由模板渲染生成,同样不在仓库中跟踪。
### Zot
匿名用户可浏览 zui、`docker pull` 镜像。推送或删除需要登录:
```bash
docker login registry.juwan.xhttp.zip -u admin -p "$(cat secrets/zot-admin-password)"
```
### Gitea
注册链接默认关闭。管理员登录后通过以下方式创建新用户:
```bash
docker compose exec -u git gitea gitea admin user create \
--username NAME --email MAIL --password PASS
```
## Runner
通过宿主 `/var/run/docker.sock` 启动 job 容器。Workflow 里写 `runs-on: ubuntu-latest` 时,runner 会拉取 `gitea/runner-images:ubuntu-latest-slim` 作为临时工作环境。`docker build` 命令在此容器内调用宿主的 dockerd,生成的镜像可直接推送到本机 Zot。
## 日常维护
```bash
docker compose restart # 全部重启
docker compose logs -f caddy # 查看 Caddy 日志(含 ACME 信息)
docker compose logs -f runner # 查看 Runner 日志(含 job 输出)
# 彻底重置:删除所有 Compose 卷与 init.sh 生成的本地文件
docker compose down -v
rm -rf secrets garage/garage.toml zot/htpasswd
```
持久化数据所在的 Docker 卷:
| 卷 | 内容 |
| -------------------- | ------------------------ |
| `juwan-caddy-data` | ACME 证书 |
| `juwan-caddy-config` | Caddy 自动配置 |
| `juwan-zot-data` | 容器镜像层 |
| `juwan-garage-meta` | Garage 元数据 |
| `juwan-garage-data` | S3 对象数据 |
| `juwan-gitea-data` | Git 仓库与 SQLite 数据库 |
| `juwan-runner-data` | Runner 注册信息 |
+78
View File
@@ -0,0 +1,78 @@
{
email admin@juwan.xhttp.zip
servers {
enable_webtransport
}
}
(common_log) {
log {
output stdout
format console {
time_format common_log
time_local
}
}
}
(stream_proxy) {
flush_interval -1
transport http {
read_timeout 0
write_timeout 0
response_header_timeout 0
}
}
git.juwan.xhttp.zip {
import common_log
request_body {
max_size 2GB
}
reverse_proxy http://gitea:3000 {
import stream_proxy
}
}
registry.juwan.xhttp.zip {
import common_log
request_body {
max_size 2GB
}
reverse_proxy http://zot:5000 {
import stream_proxy
}
}
s3.juwan.xhttp.zip {
import common_log
request_body {
max_size 5GB
}
reverse_proxy http://garage:3900 {
import stream_proxy
}
}
juwan.xhttp.zip {
import common_log
handle /wt/* {
reverse_proxy https://140.82.15.92:8443 {
transport http {
versions 3
tls_insecure_skip_verify
}
}
}
handle {
reverse_proxy http://140.82.15.92:30080 {
lb_policy round_robin
health_uri /healthz
health_interval 10s
fail_duration 30s
import stream_proxy
}
}
}
+10
View File
@@ -0,0 +1,10 @@
FROM caddy:2.11.2-builder-alpine AS builder
# 编译带 PR #7669experimental WebTransport reverse-proxy passthrough
# 的 Caddy。来源是 tomholford 的 fork 分支 webtransport-reverse-proxy。
RUN xcaddy build \
--with github.com/caddyserver/caddy/v2=github.com/tomholford/caddy/v2@webtransport-reverse-proxy
FROM caddy:2.11.2-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Some files were not shown because too many files have changed in this diff Show More