diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b52db57 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Ignore files and directories starting with a dot + +# Ignore specific files +.dockerignore + +# Ignore build artifacts +logs/ +_output/ + +# Ignore non-essential documentation +README.md +README-zh_CN.md +CONTRIBUTING.md +CHANGELOG/ +# LICENSE + +# Ignore testing and linting configuration +.golangci.yml + + +# Ignore assets +assets/ + +# Ignore components +components/ + +# Ignore tools and scripts +.github/ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfdb8b7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/.gitea/deployments/deploy/openim-admin-api-deployment.yml b/.gitea/deployments/deploy/openim-admin-api-deployment.yml new file mode 100644 index 0000000..70e3a8d --- /dev/null +++ b/.gitea/deployments/deploy/openim-admin-api-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-api-server + template: + metadata: + labels: + app: admin-api-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-admin-api-container + image: openim/openim-admin-api:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10009 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/.gitea/deployments/deploy/openim-admin-api-service.yml b/.gitea/deployments/deploy/openim-admin-api-service.yml new file mode 100644 index 0000000..dcb723b --- /dev/null +++ b/.gitea/deployments/deploy/openim-admin-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-api-service +spec: + selector: + app: admin-api-server + ports: + - name: http-10009 + protocol: TCP + port: 10009 + targetPort: 10009 + type: NodePort diff --git a/.gitea/deployments/deploy/openim-admin-rpc-deployment.yml b/.gitea/deployments/deploy/openim-admin-rpc-deployment.yml new file mode 100644 index 0000000..bea0d48 --- /dev/null +++ b/.gitea/deployments/deploy/openim-admin-rpc-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-rpc-server + template: + metadata: + labels: + app: admin-rpc-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-admin-rpc-container + image: openim/openim-admin-rpc:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30200 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/.gitea/deployments/deploy/openim-admin-rpc-service.yml b/.gitea/deployments/deploy/openim-admin-rpc-service.yml new file mode 100644 index 0000000..100e431 --- /dev/null +++ b/.gitea/deployments/deploy/openim-admin-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-rpc-service +spec: + selector: + app: admin-rpc-server + ports: + - name: rpc-30200 + protocol: TCP + port: 30200 + targetPort: 30200 + type: ClusterIP diff --git a/.gitea/deployments/deploy/openim-chat-api-deployment.yml b/.gitea/deployments/deploy/openim-chat-api-deployment.yml new file mode 100644 index 0000000..45ec618 --- /dev/null +++ b/.gitea/deployments/deploy/openim-chat-api-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-api-server + template: + metadata: + labels: + app: chat-api-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-chat-api-container + image: openim/openim-chat-api:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10008 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/.gitea/deployments/deploy/openim-chat-api-service.yml b/.gitea/deployments/deploy/openim-chat-api-service.yml new file mode 100644 index 0000000..43a777e --- /dev/null +++ b/.gitea/deployments/deploy/openim-chat-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-api-service +spec: + selector: + app: chat-api-server + ports: + - name: http-10008 + protocol: TCP + port: 10008 + targetPort: 10008 + type: NodePort diff --git a/.gitea/deployments/deploy/openim-chat-rpc-deployment.yml b/.gitea/deployments/deploy/openim-chat-rpc-deployment.yml new file mode 100644 index 0000000..05c94c5 --- /dev/null +++ b/.gitea/deployments/deploy/openim-chat-rpc-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-rpc-server + template: + metadata: + labels: + app: chat-rpc-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-chat-rpc-container + image: openim/openim-chat-rpc:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30300 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/.gitea/deployments/deploy/openim-chat-rpc-service.yml b/.gitea/deployments/deploy/openim-chat-rpc-service.yml new file mode 100644 index 0000000..e245e45 --- /dev/null +++ b/.gitea/deployments/deploy/openim-chat-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-rpc-service +spec: + selector: + app: chat-rpc-server + ports: + - name: rpc-30300 + protocol: TCP + port: 30300 + targetPort: 30300 + type: ClusterIP diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..4055b2d --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,604 @@ +name: OpenIM Chat 构建和发布 + +on: + push: + branches: [ main,wallet, master, develop, release-* ] + paths: + - '**' + pull_request: + branches: [ main,wallet, master ] + paths: + - '**' + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + default: "prod" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + REGISTRY: docker.io + DOCKER_USER: ${{ secrets.DOCKER_USERNAME || 'openim' }} + GO_VERSION: "1.24" + +jobs: + build-and-push: + runs-on: openim + permissions: + contents: read + packages: write + + steps: + - name: 检出代码 + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: 设置 SSH 密钥 + run: | + echo "🔑 配置 SSH 密钥..." + # 创建 .ssh 目录 + mkdir -p ~/.ssh + chmod 700 ~/.ssh + + # 解码 base64 编码的 SSH 私钥 + echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_rsa + + # 验证解码是否成功 + if [ ! -s ~/.ssh/id_rsa ]; then + echo "❌ SSH 私钥解码失败或为空" + exit 1 + fi + + # 设置权限 + chmod 600 ~/.ssh/id_rsa + + # 配置 SSH 主机密钥验证(可选,根据需要调整) + ssh-keyscan git.imall.cloud >> ~/.ssh/known_hosts 2>/dev/null || true + chmod 644 ~/.ssh/known_hosts + + echo "✅ SSH 密钥配置完成" + + - name: 检出 protocol 仓库 + run: | + # 克隆 protocol 仓库到当前目录的 protocol 子目录(使用 SSH) + git clone git@git.imall.cloud:openim/protocol.git ./protocol || true + cd ./protocol + git fetch --all + git checkout v1.0.4 + + - name: 设置 Go 缓存 + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: 设置 Go 环境 + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: 设置 Docker Buildx + uses: docker/setup-buildx-action@v3.8.0 + with: + platforms: linux/amd64 + + - name: 登录到 Docker Hub + uses: docker/login-action@v3.1.0 + with: + username: ${{ env.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: 构建和推送 Docker 镜像 + run: | + set -e + + # 设置版本标签 - 默认使用 prod + if [ "${{ github.event_name }}" = "release" ]; then + VERSION_TAG="${{ github.event.release.tag_name }}" + elif [ -n "${{ github.event.inputs.tag }}" ]; then + VERSION_TAG="${{ github.event.inputs.tag }}" + elif [ "${{ github.ref }}" = "refs/heads/main" ] || [ "${{ github.ref }}" = "refs/heads/master" ]; then + VERSION_TAG="prod" + else + VERSION_TAG="prod" # 所有分支默认都使用 prod + fi + + echo "版本标签: $VERSION_TAG" + echo "Docker用户: $DOCKER_USER" + + # 获取CPU核心数 + CPU_CORES=$(nproc) + echo "CPU核心数: $CPU_CORES" + + # 定义服务列表 + API_SERVICES=( + "openim-chat-api" + ) + + RPC_SERVICES=( + "openim-chat-rpc" + ) + + ADMIN_SERVICES=( + "openim-admin-api" + "openim-admin-rpc" + ) + + # 合并所有服务 + ALL_SERVICES=("${API_SERVICES[@]}" "${RPC_SERVICES[@]}" "${ADMIN_SERVICES[@]}") + + # 资源监控函数 + monitor_resources() { + local cpu_usage=0 + local mem_usage=0 + local load_1min=0 + + # 获取CPU使用率 + if command -v top >/dev/null 2>&1; then + cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//' | cut -d. -f1) + elif [ -f /proc/stat ]; then + local prev_idle=$(cat /tmp/cpu_idle 2>/dev/null || echo "0") + local prev_total=$(cat /tmp/cpu_total 2>/dev/null || echo "0") + + local curr_cpu=($(cat /proc/stat | head -1)) + local curr_idle=${curr_cpu[4]} + local curr_total=0 + for val in "${curr_cpu[@]:1}"; do + curr_total=$((curr_total + val)) + done + + local diff_idle=$((curr_idle - prev_idle)) + local diff_total=$((curr_total - prev_total)) + local diff_usage=$((diff_total - diff_idle)) + + if [ $diff_total -gt 0 ]; then + cpu_usage=$((diff_usage * 100 / diff_total)) + fi + + echo "$curr_idle" > /tmp/cpu_idle + echo "$curr_total" > /tmp/cpu_total + fi + + # 限制CPU使用率在0-100%之间 + if [ "$cpu_usage" -gt 100 ]; then + cpu_usage=100 + elif [ "$cpu_usage" -lt 0 ]; then + cpu_usage=0 + fi + + # 获取内存使用率 + if command -v free >/dev/null 2>&1; then + mem_usage=$(free | awk 'NR==2{printf "%.0f", $3*100/$2}') + fi + + # 获取1分钟负载 + if [ -f /proc/loadavg ]; then + load_1min=$(cat /proc/loadavg | awk '{print $1}' | cut -d. -f1) + fi + + echo "CPU: ${cpu_usage}%, 内存: ${mem_usage}%, 负载: ${load_1min}" + } + + # 检查资源状态 + check_resources() { + local cpu_usage=$(monitor_resources | awk '{print $1}' | sed 's/CPU://' | sed 's/%//') + local mem_usage=$(monitor_resources | awk '{print $2}' | sed 's/内存://' | sed 's/%//') + local load_1min=$(monitor_resources | awk '{print $3}' | sed 's/负载://') + + # 如果CPU使用率超过90%或内存使用率超过85%,等待资源释放 + if [ "$cpu_usage" -gt 90 ] || [ "$mem_usage" -gt 85 ]; then + echo "资源使用率过高,等待释放..." + local wait_count=0 + local max_wait=20 + + while [ $wait_count -lt $max_wait ]; do + sleep 5 + wait_count=$((wait_count + 1)) + + # 清理Docker缓存 + if [ $((wait_count % 5)) -eq 0 ]; then + docker system prune -f >/dev/null 2>&1 || true + docker builder prune -f >/dev/null 2>&1 || true + fi + + cpu_usage=$(monitor_resources | awk '{print $1}' | sed 's/CPU://' | sed 's/%//') + mem_usage=$(monitor_resources | awk '{print $2}' | sed 's/内存://' | sed 's/%//') + + if [ "$cpu_usage" -le 90 ] && [ "$mem_usage" -le 85 ]; then + echo "资源已释放,继续构建" + break + fi + + echo "等待资源释放... ($wait_count/$max_wait)" + done + + if [ $wait_count -eq $max_wait ]; then + echo "警告:等待超时,继续执行构建" + fi + fi + } + + # 构建服务函数 + build_service() { + local service=$1 + local dockerfile="build/images/$service/Dockerfile" + + echo "检查服务: $service" + echo " Dockerfile 路径: $dockerfile" + echo " Dockerfile 是否存在: $([ -f "$dockerfile" ] && echo "是" || echo "否")" + + # 检查资源状态 + check_resources + + if [ -f "$dockerfile" ]; then + echo "📦 开始构建 Docker 镜像: $service" + echo " 📁 Dockerfile: $dockerfile" + echo " 🏷️ 版本标签: $VERSION_TAG" + echo " 👤 Docker用户: $DOCKER_USER" + # 降低日志噪音:不打印 buildx 状态 + + # 构建和推送 Docker 镜像 + echo " 尝试使用 buildx 构建..." + # 降低日志噪音:省略上下文验证输出 + + local start_time=$(date +%s) + + # 尝试使用 buildx 构建 + # 使用 git commit SHA 作为构建参数,确保代码变化时缓存失效 + BUILD_SHA=$(git rev-parse --short HEAD) + BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + + if docker buildx build \ + --platform linux/amd64 \ + --file "$dockerfile" \ + --tag "$DOCKER_USER/$service:$VERSION_TAG" \ + --push \ + --cache-from type=gha,scope=openim-chat-build-${{ github.ref_name }}-$service \ + --cache-to type=gha,mode=max,scope=openim-chat-build-${{ github.ref_name }}-$service \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --build-arg GOCACHE=/go-cache \ + --build-arg GOMAXPROCS=$CPU_CORES \ + --build-arg BUILD_SHA=$BUILD_SHA \ + --build-arg BUILD_TIME=$BUILD_TIME \ + --provenance=false \ + --sbom=false \ + . > "/tmp/build_${service}.log" 2>&1; then + + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + echo "" + echo "✅ 构建成功: $service" + echo " ⏱️ 耗时: ${duration}秒" + echo " 🏷️ 镜像: $DOCKER_USER/$service:$VERSION_TAG" + echo " 📤 推送状态: 已完成" + else + echo " buildx 构建失败,查看详细错误日志..." + echo " Buildx 构建日志:" + if [ -f "/tmp/build_${service}.log" ]; then + cat "/tmp/build_${service}.log" + fi + + echo " 尝试使用传统 docker build..." + + # 回退到传统 docker build + local build_cmd="docker build --file $dockerfile --tag $DOCKER_USER/$service:$VERSION_TAG --build-arg BUILDKIT_INLINE_CACHE=1 --build-arg GOCACHE=/go-cache --build-arg GOMAXPROCS=$CPU_CORES ." + echo " 传统构建命令: $build_cmd" + + if eval "$build_cmd" > "/tmp/traditional_build_${service}.log" 2>&1; then + echo " 传统构建成功,推送镜像..." + docker push "$DOCKER_USER/$service:$VERSION_TAG" || echo "推送 $VERSION_TAG 失败" + + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + echo "" + echo "✅ 构建成功: $service (传统构建)" + echo " ⏱️ 耗时: ${duration}秒" + echo " 🏷️ 镜像: $DOCKER_USER/$service:$VERSION_TAG" + echo " 📤 推送状态: 已完成" + else + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + echo "" + echo "❌ 构建失败: $service" + echo " ⏱️ 耗时: ${duration}秒" + echo " 🔍 查看详细错误日志:" + echo "=== 详细错误日志 ===" + echo "服务: $service" + echo "Dockerfile: $dockerfile" + echo "构建命令:" + echo "docker buildx build --platform linux/amd64 --file $dockerfile --tag $DOCKER_USER/$service:$VERSION_TAG --push --quiet --cache-from type=gha,scope=openim-chat-build-${{ github.ref_name }}-$service --cache-to type=gha,mode=max,scope=openim-chat-build-${{ github.ref_name }}-$service --build-arg BUILDKIT_INLINE_CACHE=1 --build-arg GOCACHE=/go-cache --build-arg GOMAXPROCS=$CPU_CORES --provenance=false --sbom=false ." + echo "" + echo "Buildx 构建日志:" + if [ -f "/tmp/build_${service}.log" ]; then + cat "/tmp/build_${service}.log" + fi + echo "" + echo "传统构建日志:" + if [ -f "/tmp/traditional_build_${service}.log" ]; then + cat "/tmp/traditional_build_${service}.log" + fi + echo "=== 错误日志结束 ===" + return 1 + fi + fi + else + echo "❌ 错误: 找不到 Dockerfile: $dockerfile" + echo " 当前目录: $(pwd)" + echo " 目录内容: $(ls -la build/images/ 2>/dev/null || echo 'build/images 目录不存在')" + echo " 查找所有 Dockerfile: $(find . -name "Dockerfile" -type f 2>/dev/null | head -5)" + return 1 + fi + } + + # 初始化构建统计 + failed_services=() + successful_services=() + + # 计算总服务数 + total_services=$((${#API_SERVICES[@]} + ${#RPC_SERVICES[@]} + ${#ADMIN_SERVICES[@]})) + echo "" + echo "🎯 开始构建 OpenIM Chat 镜像" + echo "📊 构建统计:" + echo " 📦 API服务: ${#API_SERVICES[@]} 个" + echo " 🔧 RPC服务: ${#RPC_SERVICES[@]} 个" + echo " 👑 管理服务: ${#ADMIN_SERVICES[@]} 个" + echo " 📈 总计: $total_services 个服务" + echo " 🏷️ 版本标签: $VERSION_TAG" + echo " 👤 Docker用户: $DOCKER_USER" + echo "" + + # 先构建API服务 + echo "API服务构建:" + echo "总服务数: ${#API_SERVICES[@]}" + echo "==========================================" + + for i in "${!API_SERVICES[@]}"; do + service="${API_SERVICES[$i]}" + current=$((i + 1)) + total=${#API_SERVICES[@]} + + echo "" + echo "🚀 [${current}/${total}] 开始构建: $service" + echo "⏰ 开始时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + + if build_service "$service"; then + successful_services+=("$service") + echo "✅ [${current}/${total}] 构建完成: $service" + else + failed_services+=("$service") + echo "❌ [${current}/${total}] 构建失败: $service" + fi + + echo "⏰ 完成时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + done + + # 构建RPC服务 + echo "RPC服务构建:" + echo "总服务数: ${#RPC_SERVICES[@]}" + echo "==========================================" + + for i in "${!RPC_SERVICES[@]}"; do + service="${RPC_SERVICES[$i]}" + current=$((i + 1)) + total=${#RPC_SERVICES[@]} + + echo "" + echo "🚀 [${current}/${total}] 开始构建: $service" + echo "⏰ 开始时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + + if build_service "$service"; then + successful_services+=("$service") + echo "✅ [${current}/${total}] 构建完成: $service" + else + failed_services+=("$service") + echo "❌ [${current}/${total}] 构建失败: $service" + fi + + echo "⏰ 完成时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + done + + # 构建管理服务 + echo "管理服务构建:" + echo "总服务数: ${#ADMIN_SERVICES[@]}" + echo "==========================================" + + for i in "${!ADMIN_SERVICES[@]}"; do + service="${ADMIN_SERVICES[$i]}" + current=$((i + 1)) + total=${#ADMIN_SERVICES[@]} + + echo "" + echo "🚀 [${current}/${total}] 开始构建: $service" + echo "⏰ 开始时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + + if build_service "$service"; then + successful_services+=("$service") + echo "✅ [${current}/${total}] 构建完成: $service" + else + failed_services+=("$service") + echo "❌ [${current}/${total}] 构建失败: $service" + fi + + echo "⏰ 完成时间: $(date '+%H:%M:%S')" + echo "------------------------------------------" + done + + + # 输出构建结果统计 + echo "" + echo "🎉 构建完成总结" + echo "==========================================" + echo "✅ 成功构建: ${#successful_services[@]} 个服务" + echo "❌ 构建失败: ${#failed_services[@]} 个服务" + echo "📊 成功率: $(( ${#successful_services[@]} * 100 / total_services ))%" + echo "" + + if [ ${#successful_services[@]} -gt 0 ]; then + echo "✅ 成功构建的服务:" + for service in "${successful_services[@]}"; do + echo " - $service" + done + echo "" + fi + + if [ ${#failed_services[@]} -gt 0 ]; then + echo "❌ 构建失败的服务:" + for service in "${failed_services[@]}"; do + echo " - $service" + done + echo "" + fi + + if [ ${#failed_services[@]} -gt 0 ]; then + echo "" + echo "失败服务错误日志:" + for service in "${failed_services[@]}"; do + echo "=== $service 错误日志 ===" + if [ -f "/tmp/build_${service}.log" ]; then + echo "Buildx 构建日志:" + cat "/tmp/build_${service}.log" + fi + if [ -f "/tmp/traditional_build_${service}.log" ]; then + echo "传统构建日志:" + cat "/tmp/traditional_build_${service}.log" + fi + echo "=== $service 错误日志结束 ===" + echo "" + done + fi + + # 如果有失败的服务,退出码为1 + if [ ${#failed_services[@]} -gt 0 ]; then + echo "❌ 构建失败,有 ${#failed_services[@]} 个服务构建失败" + exit 1 + else + echo "🎉 所有服务构建成功!" + fi + + - name: 配置 kubectl + if: success() + run: | + echo "🔧 配置 kubectl 连接到阿里云 ACK..." + # 创建 kubeconfig 目录 + mkdir -p ~/.kube + + # 直接解码 base64 内容 + echo "解码 KUBECONFIG..." + echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config + + # 验证解码是否成功 + if [ ! -s ~/.kube/config ]; then + echo "❌ KUBECONFIG 解码失败或为空" + exit 1 + fi + + # 设置权限 + chmod 600 ~/.kube/config + echo "✅ kubeconfig 配置完成" + + # 降低日志噪音:不输出 kubeconfig 内容 + + - name: 部署到阿里云 ACK + if: success() + run: | + echo "🚀 开始部署到阿里云 ACK..." + + # 简单验证 kubectl + if ! kubectl version --client >/dev/null 2>&1; then + echo "❌ kubectl 不可用,跳过部署步骤" + exit 0 + fi + + echo "✅ kubectl 可用,尝试部署..." + + # 获取版本标签 + if [ "${{ github.event_name }}" = "release" ]; then + VERSION_TAG="${{ github.event.release.tag_name }}" + else + VERSION_TAG="${{ github.event.inputs.tag || github.ref_name || 'prod' }}" + fi + + DOCKER_USER="${{ env.DOCKER_USER }}" + NS=${NS:-default} + + echo "部署参数:" + echo "版本标签: $VERSION_TAG" + echo "Docker用户: $DOCKER_USER" + + # 检查部署文件是否存在 + DEPLOY_DIR=".gitea/deployments/deploy" + if [ ! -d "$DEPLOY_DIR" ]; then + echo "❌ 部署目录不存在: $DEPLOY_DIR" + echo "📁 当前目录内容:" + ls -la + exit 1 + fi + + echo "📁 部署目录: $DEPLOY_DIR" + echo "使用命名空间: $NS" + + # 创建命名空间(如果不存在) + kubectl get ns "$NS" >/dev/null 2>&1 || kubectl create ns "$NS" + kubectl config set-context --current --namespace="$NS" + + # 尝试部署,如果失败则继续 + echo "🚀 开始部署 Chat 服务..." + + # 定义所有部署文件 + DEPLOY_FILES=( + "openim-chat-api-deployment.yml" + "openim-chat-api-service.yml" + "openim-chat-rpc-deployment.yml" + "openim-chat-rpc-service.yml" + "openim-admin-api-deployment.yml" + "openim-admin-api-service.yml" + "openim-admin-rpc-deployment.yml" + "openim-admin-rpc-service.yml" + ) + + # 部署所有文件 + for file in "${DEPLOY_FILES[@]}"; do + if [ -f "$DEPLOY_DIR/$file" ]; then + echo "📄 部署文件: $file" + # 更新镜像标签 + sed -i "s|image: .*/openim-|image: $DOCKER_USER/openim-|g" "$DEPLOY_DIR/$file" + sed -i "s|:latest|:$VERSION_TAG|g" "$DEPLOY_DIR/$file" + # 应用文件 + kubectl apply -f "$DEPLOY_DIR/$file" || echo "⚠️ $file 部署失败,但继续" + else + echo "⚠️ $file 不存在,跳过" + fi + done + + echo "" + echo "🔍 验证部署状态..." + + # 简单检查,如果失败也不阻塞流程 + kubectl get pods -l app=openim-chat-api || echo "⚠️ 无法获取 chat-api Pod 状态" + kubectl get pods -l app=openim-chat-rpc || echo "⚠️ 无法获取 chat-rpc Pod 状态" + + echo "✅ 验证完成" + + - name: 清理 + if: always() + run: | + echo "🧹 清理临时文件..." + rm -f /tmp/build_*.log + echo "✅ 清理完成" \ No newline at end of file diff --git a/.github/.codecov.yml b/.github/.codecov.yml new file mode 100644 index 0000000..25b77e5 --- /dev/null +++ b/.github/.codecov.yml @@ -0,0 +1,22 @@ +# Copyright © 2023 OpenIM. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +coverage: + status: + project: + default: false # disable the default status that measures entire project + pkg: # declare a new status context "pkg" + paths: + - pkg/* # only include coverage in "pkg/" folder + informational: true # Always pass check + patch: off # disable the commit only checks \ No newline at end of file diff --git a/.github/sync-release.yml b/.github/sync-release.yml new file mode 100644 index 0000000..1472ba5 --- /dev/null +++ b/.github/sync-release.yml @@ -0,0 +1,10 @@ +openim-sigs/openim-docker: + - source: ./config + dest: ./openim-chat/release/config + replace: true + - source: ./docs + dest: ./openim-chat/release/docs + replace: true + - source: ./scripts + dest: ./openim-chat/release/scripts + replace: true diff --git a/.github/sync.yml b/.github/sync.yml new file mode 100644 index 0000000..8664e83 --- /dev/null +++ b/.github/sync.yml @@ -0,0 +1,26 @@ +# Copyright © 2023 OpenIM. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# https://github.com/BetaHuhn/repo-file-sync-action +# Synchronization for the.github repository +openim-sigs/openim-docker: + - source: ./config + dest: ./openim-chat/main/config + replace: true + - source: ./docs + dest: ./openim-chat/main/docs + replace: true + - source: ./scripts + dest: ./openim-chat/main/scripts + replace: true diff --git a/.github/workflows/auto-assign-issue.yml b/.github/workflows/auto-assign-issue.yml new file mode 100644 index 0000000..320174d --- /dev/null +++ b/.github/workflows/auto-assign-issue.yml @@ -0,0 +1,29 @@ +name: Assign issue to comment author +on: + issue_comment: + types: [created] +jobs: + assign-issue: + if: | + contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept') && + !contains(github.event.comment.user.login, 'openim-robot') + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Assign the issue + run: | + export LETASE_MILESTONES=$(curl 'https://api.github.com/repos/$OWNER/$PEPO/milestones' | jq -r 'last(.[]).title') + gh issue edit ${{ github.event.issue.number }} --add-assignee "${{ github.event.comment.user.login }}" + gh issue edit ${{ github.event.issue.number }} --add-label "accepted" + gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LETASE_MILESTONES](https://github.com/$OWNER/$PEPO/milestones), We are looking forward to your PR!" + + # gh issue edit ${{ github.event.issue.number }} --milestone "$LETASE_MILESTONES" + env: + GH_TOKEN: ${{ secrets.BOT_TOKEN }} + ISSUE: ${{ github.event.issue.html_url }} + OWNER: ${{ github.repository_owner }} + REPO: ${{ github.event.repository.name }} diff --git a/.github/workflows/auto-invite-comment.yml b/.github/workflows/auto-invite-comment.yml new file mode 100644 index 0000000..dde36ea --- /dev/null +++ b/.github/workflows/auto-invite-comment.yml @@ -0,0 +1,38 @@ +name: Invite users to join OpenIM Community. +on: + issue_comment: + types: + - created +jobs: + issue_comment: + name: Invite users to join OpenIM Community + if: ${{ github.event.comment.body == '/invite' || github.event.comment.body == '/close' || github.event.comment.body == '/comment' }} + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Invite user to join OpenIM Community + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.BOT_GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. + + Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server. + + In addition to Slack, we also offer the following ways to get in touch: + + + We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) team channel. + + Get in touch with us on [Gmail](https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=winxu81@gmail.com). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email. + + Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information. + + Add [Wechat](https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible. + + # - name: Close Issue + # uses: peter-evans/close-issue@v3 + # with: + # token: ${{ secrets.BOT_GITHUB_TOKEN }} + # issue-number: ${{ github.event.issue.number }} + # comment: 🤖 Auto-closing issue, if you still need help please reopen the issue or ask for help in the community above + # labels: | + # accepted diff --git a/.github/workflows/auto-invite.yml b/.github/workflows/auto-invite.yml new file mode 100644 index 0000000..f8bcfc4 --- /dev/null +++ b/.github/workflows/auto-invite.yml @@ -0,0 +1,52 @@ +# Copyright © 2023 OpenIM open source community. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Invite users to join our group +on: + issue_comment: + types: + - created +jobs: + issue_comment: + name: Invite users to join our group + if: ${{ github.event.comment.body == '/invite' || github.event.comment.body == '/close' || github.event.comment.body == '/comment' }} + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Invite user to join our group + uses: peter-evans/create-or-update-comment@v3 + with: + token: ${{ secrets.BOT_GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. + + Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server. + + In addition to Slack, we also offer the following ways to get in touch: + + + We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) team channel. + + Get in touch with us on [Gmail](https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=winxu81@gmail.com). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email. + + Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information. + + Add [Wechat](https://github.com/openimsdk/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible. + + - name: Close Issue + uses: peter-evans/close-issue@v3 + with: + token: ${{ secrets.BOT_GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + comment: 🤖 Auto-closing issue, if you still need help please reopen the issue or ask for help in the community above + labels: | + triage/accepted diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml new file mode 100644 index 0000000..56f9f54 --- /dev/null +++ b/.github/workflows/build-docker-image.yml @@ -0,0 +1,102 @@ +name: Publish Docker image + +on: + push: + branches: + # - main + - release-* + # tags: + # - v* + release: + types: [published] + + workflow_dispatch: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + default: "v3.8.0" + +env: + GO_VERSION: "1.22" + +jobs: + build-image: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.8.0 + + - name: Log in to Docker Hub + uses: docker/login-action@v3.3.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3.3.0 + with: + registry: registry.cn-hangzhou.aliyuncs.com + username: ${{ secrets.ALIREGISTRY_USERNAME }} + password: ${{ secrets.ALIREGISTRY_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5.6.0 + with: + images: | + openim/openim-chat + ghcr.io/openimsdk/openim-chat + registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat + tags: | + type=ref,event=tag + type=schedule + type=ref,event=branch + # type=ref,event=pr + # type=semver,pattern={{version}} + type=semver,pattern=v{{version}} + type=semver,pattern=release-{{raw}} + type=sha + type=raw,value=${{ github.event.inputs.tag }} + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Verify multi-platform support + run: | + images=("openim/openim-chat" "ghcr.io/openimsdk/openim-chat" "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat") + for image in "${images[@]}"; do + for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n'); do + manifest=$(docker manifest inspect "$image:$tag" || echo "error") + if [[ "$manifest" == "error" ]]; then + echo "Manifest not found for $image:$tag" + exit 1 + fi + amd64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "amd64")') + arm64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "arm64")') + if [[ -z "$amd64_found" ]]; then + echo "Multi-platform support check failed for $image:$tag - missing amd64" + exit 1 + fi + if [[ -z "$arm64_found" ]]; then + echo "Multi-platform support check failed for $image:$tag - missing arm64" + exit 1 + fi + done + done diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..b97036d --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,78 @@ +name: Release Changelog + +on: + release: + types: [released] + +permissions: + contents: write + pull-requests: write + +jobs: + update-changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Go Changelog Generator + run: | + # Run the Go changelog generator, passing the release tag if available + if [ "${{ github.event.release.tag_name }}" = "latest" ]; then + go run tools/changelog/changelog.go > "${{ github.event.release.tag_name }}-changelog.md" + else + go run tools/changelog/changelog.go "${{ github.event.release.tag_name }}" > "${{ github.event.release.tag_name }}-changelog.md" + fi + + - name: Handle changelog files + run: | + # Ensure that the CHANGELOG directory exists + mkdir -p CHANGELOG + + # Extract Major.Minor version by removing the 'v' prefix from the tag name + TAG_NAME=${{ github.event.release.tag_name }} + CHANGELOG_VERSION_NUMBER=$(echo "$TAG_NAME" | sed 's/^v//' | grep -oP '^\d+\.\d+') + + # Define the new changelog file path + CHANGELOG_FILENAME="CHANGELOG-$CHANGELOG_VERSION_NUMBER.md" + CHANGELOG_PATH="CHANGELOG/$CHANGELOG_FILENAME" + + # Check if the changelog file for the current release already exists + if [ -f "$CHANGELOG_PATH" ]; then + # If the file exists, append the new changelog to the existing one + cat "$CHANGELOG_PATH" >> "${TAG_NAME}-changelog.md" + # Overwrite the existing changelog with the updated content + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + else + # If the changelog file doesn't exist, rename the temp changelog file to the new changelog file + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + + # Ensure that README.md exists + if [ ! -f "CHANGELOG/README.md" ]; then + echo -e "# CHANGELOGs\n\n" > CHANGELOG/README.md + fi + + # Add the new changelog entry at the top of the README.md + if ! grep -q "\[$CHANGELOG_FILENAME\]" CHANGELOG/README.md; then + sed -i "3i- [$CHANGELOG_FILENAME](./$CHANGELOG_FILENAME)" CHANGELOG/README.md + # Remove the extra newline character added by sed + # sed -i '4d' CHANGELOG/README.md + fi + fi + + - name: Clean up + run: | + # Remove any temporary files that were created during the process + rm -f "${{ github.event.release.tag_name }}-changelog.md" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + title: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + body: "This PR updates the CHANGELOG files for release ${{ github.event.release.tag_name }}" + branch: changelog-${{ github.event.release.tag_name }} + base: main + delete-branch: true + labels: changelog diff --git a/.github/workflows/chat-build-test.yml b/.github/workflows/chat-build-test.yml new file mode 100644 index 0000000..c2946fa --- /dev/null +++ b/.github/workflows/chat-build-test.yml @@ -0,0 +1,165 @@ +name: OpenIM Chat Build Test + +on: + push: + branches: + - main + - release-* + paths-ignore: + - "docs/**" + - "README.md" + - "README_zh-CN.md" + - "**.md" + - "docs/**" + - "CONTRIBUTING.md" + pull_request: + branches: + - main + - release-* + paths-ignore: + - "README.md" + - "README_zh-CN.md" + - "CONTRIBUTING/**" + - "**.md" + - "docs/**" + workflow_dispatch: + +jobs: + build-linux: + name: Execute OpenIM Script On Linux + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + # environment: + # name: openim + strategy: + matrix: + arch: [amd64] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.22" + + - name: init + run: sudo bash bootstrap.sh + timeout-minutes: 20 + + - name: Checkout chat repository + uses: actions/checkout@v4 + with: + repository: "openimsdk/chat-deploy" + path: "server-repo" + + - name: Set up Docker for Linux + run: | + cd ${{ github.workspace }}/server-repo + sudo docker compose up -d + sudo sleep 30 # Increased sleep time for better stability + timeout-minutes: 30 # Increased timeout for Docker setup + + - name: Modify Server Configuration + run: | + yq e '.secret = 123456' -i ${{ github.workspace }}/server-repo/config/share.yml + + - name: Build and Start IM Serevr Services + run: | + cd ${{ github.workspace }}/server-repo + sudo mage + sudo mage start + sudo mage check + + - name: Modify Chat Configuration + run: | + yq e '.openIM.secret = 123456' -i config/share.yml + + - name: Build, Start, Check Services and Print Logs for Linux + run: | + sudo mage + sudo mage start + sudo mage check + + - name: Restart Services and Print Logs + run: | + sudo mage stop + sudo mage start + sudo mage check + + - name: Test Chat + run: | + check_error() { + echo "Response: $1" + errCode=$(echo $1 | jq -r '.errCode') + if [ "$errCode" != "0" ]; then + errMsg=$(echo $1 | jq -r '.errMsg') + echo "Error: $errMsg" + exit 1 + fi + } + + # Test register + response1=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "verifyCode": "666666", + "platform": 3, + "autoLogin": true, + "user":{ + "nickname": "test12312", + "areaCode":"+86", + "phoneNumber": "12345678190", + "password":"test123456" + } + }' http://127.0.0.1:10008/account/register) + check_error "$response1" + userID1=$(echo $response1 | jq -r '.data.userID') + echo "userID1: $userID1" + + response2=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "verifyCode": "666666", + "platform": 3, + "autoLogin": true, + "user":{ + "nickname": "test22312", + "areaCode":"+86", + "phoneNumber": "12345678290", + "password":"test123456" + } + }' http://127.0.0.1:10008/account/register) + check_error "$response2" + userID2=$(echo $response2 | jq -r '.data.userID') + echo "userID2: $userID2" + + # Test login + login_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "platform": 3, + "areaCode":"+86", + "phoneNumber": "12345678190", + "password":"test123456" + }' http://localhost:10008/account/login) + check_error "$login_response" + + # Test get admin token + get_admin_token_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "secret": "123456", + "platformID": 2, + "userID": "imAdmin" + }' http://127.0.0.1:10002/auth/get_admin_token) + check_error "$get_admin_token_response" + adminToken=$(echo $get_admin_token_response | jq -r '.data.token') + echo "adminToken: $adminToken" + + # Test send message + send_msg_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -H "token: $adminToken" -d '{ + "sendID": "'$userID1'", + "recvID": "'$userID2'", + "senderPlatformID": 3, + "content": { + "content": "hello!!" + }, + "contentType": 101, + "sessionType": 1 + }' http://127.0.0.1:10002/msg/send_msg) + check_error "$send_msg_response" diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.yml new file mode 100644 index 0000000..8c8d441 --- /dev/null +++ b/.github/workflows/check-coverage.yml @@ -0,0 +1,45 @@ +name: Check-Coverage + +on: + workflow_dispatch: + push: + branches: [ "main" ] + paths-ignore: + - "docs/**" + - "**/*.md" + - "**/*.yaml" + - "CONTRIBUTORS" + - "CHANGELOG/**" + pull_request: + branches: [ "*" ] + paths-ignore: + - "docs/**" + - "**/*.md" + - "**/*.yaml" + - "CONTRIBUTORS" + - "CHANGELOG/**" +env: + # Common versions + GO_VERSION: "1.20" + +jobs: + coverage: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Golang with cache + uses: magnetikonline/action-golang-cache@v4 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Dependencies + run: sudo apt update && sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev + + - name: Run Cover + run: make cover + continue-on-error: true + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/cla-assistant.yml b/.github/workflows/cla-assistant.yml new file mode 100644 index 0000000..4aaa4e2 --- /dev/null +++ b/.github/workflows/cla-assistant.yml @@ -0,0 +1,40 @@ +name: CLA Assistant +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened,closed,synchronize] + +# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings +permissions: + actions: write + contents: write # this can be 'read' if the signatures are in remote repository + pull-requests: write + statuses: write + +jobs: + CLA-Assistant: + runs-on: ubuntu-latest + steps: + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@v2.4.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.BOT_TOKEN }} + with: + path-to-signatures: 'signatures/cla.json' + path-to-document: 'https://github.com/OpenIM-Robot/cla/blob/main/README.md' # e.g. a CLA or a DCO document + branch: 'main' + allowlist: 'bot*,*bot,OpenIM-Robot' + + # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken + remote-organization-name: OpenIM-Robot + remote-repository-name: cla + create-file-commit-message: 'Creating file for storing CLA Signatures' + # signed-commit-message: '$contributorName has signed the CLA in $owner/$repo#$pullRequestNo' + custom-notsigned-prcomment: '💕 Thank you for your contribution and please kindly read and sign our CLA. [CLA Docs](https://github.com/OpenIM-Robot/cla/blob/main/README.md)' + custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' + custom-allsigned-prcomment: '🤖 All Contributors have signed the [CLA](https://github.com/OpenIM-Robot/cla/blob/main/README.md).
The signed information is recorded [**here**](https://github.com/OpenIM-Robot/cla/blob/main/signatures/cla.json)' + #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) + #use-dco-flag: true - If you are using DCO instead of CLA \ No newline at end of file diff --git a/.github/workflows/cleanup-after-milestone-prs-merged.yml b/.github/workflows/cleanup-after-milestone-prs-merged.yml new file mode 100644 index 0000000..8a3e381 --- /dev/null +++ b/.github/workflows/cleanup-after-milestone-prs-merged.yml @@ -0,0 +1,65 @@ +name: Cleanup After Milestone PRs Merged + +on: + pull_request: + types: + - closed + +jobs: + handle_pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.0 + + - name: Get the PR title and extract PR numbers + id: extract_pr_numbers + run: | + # Get the PR title + PR_TITLE="${{ github.event.pull_request.title }}" + + echo "PR Title: $PR_TITLE" + + # Extract PR numbers from the title + PR_NUMBERS=$(echo "$PR_TITLE" | grep -oE "#[0-9]+" | tr -d '#' | tr '\n' ' ') + echo "Extracted PR Numbers: $PR_NUMBERS" + + # Save PR numbers to a file + echo "$PR_NUMBERS" > pr_numbers.txt + echo "Saved PR Numbers to pr_numbers.txt" + + # Check if the title matches a specific pattern + if echo "$PR_TITLE" | grep -qE "^deps: Merge( #[0-9]+)+ PRs into .+"; then + echo "proceed=true" >> $GITHUB_OUTPUT + else + echo "proceed=false" >> $GITHUB_OUTPUT + fi + + - name: Use extracted PR numbers and label PRs + if: (steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge')) && github.event.pull_request.merged == true + run: | + # Read the previously saved PR numbers + PR_NUMBERS=$(cat pr_numbers.txt) + echo "Using extracted PR Numbers: $PR_NUMBERS" + + # Loop through each PR number and add label + for PR_NUMBER in $PR_NUMBERS; do + echo "Adding 'cherry-picked' label to PR #$PR_NUMBER" + curl -X POST \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels \ + -d '{"labels":["cherry-picked"]}' + done + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Delete branch after PR close + if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge') + run: | + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + echo "Branch to delete: $BRANCH_NAME" + git push origin --delete "$BRANCH_NAME" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..fd871e2 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. + +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '18 19 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 \ No newline at end of file diff --git a/.github/workflows/comment-check.yml b/.github/workflows/comment-check.yml new file mode 100644 index 0000000..1609355 --- /dev/null +++ b/.github/workflows/comment-check.yml @@ -0,0 +1,51 @@ +name: Non-English Comments Check + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + non-english-comments-check: + runs-on: ubuntu-latest + + env: + # need ignore Dirs + EXCLUDE_DIRS: ".git docs tests scripts assets node_modules build" + # need ignore Files + EXCLUDE_FILES: "*.md *.txt *.html *.css *.min.js *.mdx" + + steps: + - uses: actions/checkout@v4 + + - name: Search for Non-English comments + run: | + set -e + # Define the regex pattern to match Chinese characters + pattern='[\p{Han}]' + + # Process the directories to be excluded + exclude_dirs="" + for dir in $EXCLUDE_DIRS; do + exclude_dirs="$exclude_dirs --exclude-dir=$dir" + done + + # Process the file types to be excluded + exclude_files="" + for file in $EXCLUDE_FILES; do + exclude_files="$exclude_files --exclude=$file" + done + + # Use grep to find all comments containing Non-English characters and save to file + grep -Pnr "$pattern" . $exclude_dirs $exclude_files > non_english_comments.txt || true + + - name: Output non-English comments are found + run: | + if [ -s non_english_comments.txt ]; then + echo "Non-English comments found in the following locations:" + cat non_english_comments.txt + exit 1 # terminate the workflow + else + echo "No Non_English comments found." + fi \ No newline at end of file diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml new file mode 100644 index 0000000..bfb018e --- /dev/null +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -0,0 +1,90 @@ +name: Build and release services Docker Images + +on: + push: + branches: + - release-* + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + default: "v3.8.3" + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.8.0 + + - name: Log in to Docker Hub + uses: docker/login-action@v3.3.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3.3.0 + with: + registry: registry.cn-hangzhou.aliyuncs.com + username: ${{ secrets.ALIREGISTRY_USERNAME }} + password: ${{ secrets.ALIREGISTRY_TOKEN }} + + - name: Extract metadata for Docker (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + tags: | + type=ref,event=tag + type=schedule + type=ref,event=branch + type=semver,pattern=v{{version}} + type=semver,pattern=release-{{raw}} + type=sha + type=raw,value=${{ github.event.inputs.tag }} + + - name: Build and push Docker images + run: | + IMG_DIR="build/images" + for dir in "$IMG_DIR"/*/; do + # Find Dockerfile or *.dockerfile in a case-insensitive manner + dockerfile=$(find "$dir" -maxdepth 1 -type f \( -iname 'dockerfile' -o -iname '*.dockerfile' \) | head -n 1) + + if [ -n "$dockerfile" ] && [ -f "$dockerfile" ]; then + IMAGE_NAME=$(basename "$dir") + echo "Building Docker image for $IMAGE_NAME with tags:" + + # Initialize tag arguments + tag_args=() + + # Read each tag and append --tag arguments + while IFS= read -r tag; do + tag_args+=(--tag "${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME:$tag") + tag_args+=(--tag "ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$tag") + tag_args+=(--tag "registry.cn-hangzhou.aliyuncs.com/openimsdk/$IMAGE_NAME:$tag") + done <<< "${{ steps.meta.outputs.tags }}" + + # Build and push the Docker image with all tags + docker buildx build --platform linux/amd64,linux/arm64 \ + --file "$dockerfile" \ + "${tag_args[@]}" \ + --push \ + "." + else + echo "No valid Dockerfile found in $dir" + fi + done diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml new file mode 100644 index 0000000..43fba5c --- /dev/null +++ b/.github/workflows/gosec.yml @@ -0,0 +1,31 @@ +name: OpenIM Run Gosec + +# gosec is a source code security audit tool for the Go language. It performs a static +# analysis of the Go code, looking for potential security problems. The main functions of gosec are: +# 1. Find common security vulnerabilities, such as SQL injection, command injection, and cross-site scripting (XSS). +# 2. Audit codes according to common security standards and find non-standard codes. +# 3. Assist the Go language engineer to write safe and reliable code. +# https://github.com/securego/gosec/ +on: + push: + branches: "*" + pull_request: + branches: "*" + paths-ignore: + - '*.md' + - '*.yml' + - '.github' + +jobs: + golang-security-action: + runs-on: ubuntu-latest + env: + GO111MODULE: on + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Run Gosec Security Scanner + uses: securego/gosec@master + with: + args: ./... + continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml new file mode 100644 index 0000000..65b2e99 --- /dev/null +++ b/.github/workflows/help-comment-issue.yml @@ -0,0 +1,22 @@ +name: Good frist issue add comment +on: + issues: + types: + - labeled + +jobs: + add-comment: + if: github.event.label.name == 'help wanted' || github.event.label.name == 'good first issue' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@v4 + with: + issue-number: ${{ github.event.issue.number }} + token: ${{ secrets.BOT_TOKEN }} + body: | + This issue is available for anyone to work on. **Make sure to reference this issue in your pull request.** :sparkles: Thank you for your contribution! :sparkles: + [Join slack 🤖](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) to connect and communicate with our developers. + If you wish to accept this assignment, please leave a comment in the comments section: `/accept`.🎯 diff --git a/.github/workflows/issue-translator.yml b/.github/workflows/issue-translator.yml new file mode 100644 index 0000000..6a8528a --- /dev/null +++ b/.github/workflows/issue-translator.yml @@ -0,0 +1,19 @@ +name: 'issue-translator' +on: + issue_comment: + types: [created] + issues: + types: [opened] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: usthe/issues-translate-action@v2.7 + with: + BOT_GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} + IS_MODIFY_TITLE: true + # not require, default false, . Decide whether to modify the issue title + # if true, the robot account @Issues-translate-bot must have modification permissions, invite @Issues-translate-bot to your project or use your custom bot. + CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿 + # not require. Customize the translation robot prefix message. \ No newline at end of file diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml new file mode 100644 index 0000000..a5e3852 --- /dev/null +++ b/.github/workflows/merge-from-milestone.yml @@ -0,0 +1,181 @@ +name: Create Individual PRs from Milestone + +permissions: + contents: write + pull-requests: write + issues: write + +on: + workflow_dispatch: + inputs: + milestone_name: + description: "Milestone name to collect closed PRs from" + required: true + default: "v1.8.5" + target_branch: + description: "Target branch to merge the consolidated PR" + required: true + default: "pre-release-v1.8.5" + +env: + MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v1.8.5' }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v1.8.5' }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + LABEL_NAME: cherry-picked + TEMP_DIR: /tmp + +jobs: + merge_milestone_prs: + runs-on: ubuntu-latest + steps: + - name: Setup temp directory + run: | + # Create the temporary directory and initialize necessary files + mkdir -p ${{ env.TEMP_DIR }} + touch ${{ env.TEMP_DIR }}/pr_numbers.txt + touch ${{ env.TEMP_DIR }}/commit_hashes.txt + touch ${{ env.TEMP_DIR }}/pr_title.txt + touch ${{ env.TEMP_DIR }}/pr_body.txt + touch ${{ env.TEMP_DIR }}/created_pr_number.txt + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_TOKEN }} + + - name: Setup Git User for OpenIM-Robot + run: | + git config --global user.email "OpenIM-Robot@users.noreply.github.com" + git config --global user.name "OpenIM-Robot" + + - name: Fetch Milestone ID and Filter PR Numbers + env: + MILESTONE_NAME: ${{ env.MILESTONE_NAME }} + run: | + # Fetch milestone details and extract milestone ID + milestones=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/milestones") + milestone_id=$(echo "$milestones" | grep -B3 "\"title\": \"$MILESTONE_NAME\"" | grep '"number":' | head -n1 | grep -o '[0-9]\+') + if [ -z "$milestone_id" ]; then + echo "Milestone '$MILESTONE_NAME' not found. Exiting." + exit 1 + fi + echo "Milestone ID: $milestone_id" + echo "MILESTONE_ID=$milestone_id" >> $GITHUB_ENV + + # Fetch issues for the milestone + issues=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues?milestone=$milestone_id&state=closed&per_page=100") + + > ${{ env.TEMP_DIR }}/pr_numbers.txt + + # Filter PRs that do not have the 'cherry-picked' label + for pr_number in $(echo "$issues" | jq -r '.[] | select(.pull_request != null) | .number'); do + labels=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" | jq -r '.[].name') + + if ! echo "$labels" | grep -q "${LABEL_NAME}"; then + echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list." + echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt + fi + done + + sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt + + - name: Create Individual PRs + run: | + for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do + pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number") + pr_title=$(echo "$pr_details" | jq -r '.title') + pr_body=$(echo "$pr_details" | jq -r '.body') + pr_creator=$(echo "$pr_details" | jq -r '.user.login') + merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha') + short_commit_hash=$(echo "$merge_commit" | cut -c 1-7) + + if [ "$merge_commit" != "null" ]; then + git fetch origin + + echo "Checking out target branch: $TARGET_BRANCH" + git checkout $TARGET_BRANCH + + echo "Pulling latest changes from target branch: $TARGET_BRANCH" + git pull origin $TARGET_BRANCH + + cherry_pick_branch="cherry-pick-${short_commit_hash}" + git checkout -b $cherry_pick_branch + + echo "Cherry-picking commit: $merge_commit" + if ! git cherry-pick "$merge_commit" --strategy=recursive -X theirs; then + echo "Conflict detected for $merge_commit. Resolving with incoming changes." + conflict_files=$(git diff --name-only --diff-filter=U) + echo "Conflicting files:" + echo "$conflict_files" + + for file in $conflict_files; do + if [ -f "$file" ]; then + echo "Resolving conflict for $file" + git add "$file" + else + echo "File $file has been deleted. Skipping." + git rm "$file" + fi + done + + echo "Conflicts resolved. Continuing cherry-pick." + git cherry-pick --continue || { echo "Cherry-pick failed, but continuing to create PR."; } + else + echo "Cherry-pick successful for commit $merge_commit." + fi + + git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" + + echo "Pushing branch: $cherry_pick_branch" + if ! git push origin $cherry_pick_branch --force; then + echo "Push failed, but continuing to create PR..." + fi + + new_pr_title="$pr_title [Created by @$pr_creator from #$pr_number]" + new_pr_body="$pr_body + > This PR is created from original PR #$pr_number." + + response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pulls \ + -d "$(jq -n --arg title "$new_pr_title" \ + --arg head "$cherry_pick_branch" \ + --arg base "$TARGET_BRANCH" \ + --arg body "$new_pr_body" \ + '{title: $title, head: $head, base: $base, body: $body}')") + + new_pr_number=$(echo "$response" | jq -r '.number') + + if [[ "$new_pr_number" == "null" || -z "$new_pr_number" ]]; then + echo "Failed to create PR. Response: $response" + + git checkout $TARGET_BRANCH + + git branch -D $cherry_pick_branch + + echo "Deleted branch: $cherry_pick_branch" + git push origin --delete $cherry_pick_branch + else + echo "Created PR #$new_pr_number" + + curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -d '{"labels": ["milestone-merge"]}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/$new_pr_number/labels" + fi + + echo "" + echo "----------------------------------------" + echo "" + fi + done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a46b1c8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,99 @@ +name: OpenIM chat release + +on: + push: + # run only against tags + tags: + - '*' + +permissions: + contents: write + packages: write + issues: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + env: + DOCKER_CLI_EXPERIMENTAL: "enabled" + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: setup-snapcraft + # FIXME: the mkdirs are a hack for https://github.com/goreleaser/goreleaser/issues/1715 + run: | + sudo apt-get update + sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft + mkdir -p $HOME/.cache/snapcraft/download + mkdir -p $HOME/.cache/snapcraft/stage-packages + + - uses: actions/setup-go@v4 + with: + go-version: stable + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to AliYun Docker Hub + uses: docker/login-action@v2 + with: + registry: registry.cn-hangzhou.aliyuncs.com + username: ${{ secrets.ALIREGISTRY_USERNAME }} + password: ${{ secrets.ALIREGISTRY_TOKEN }} + + - name: set action env cache + uses: actions/cache@v3 + with: + path: | + ./_output/dist/*.deb + ./_output/dist/*.rpm + ./_output/dist/*.apk + key: ${{ github.ref }} + + - uses: sigstore/cosign-installer@v3.1.1 + - uses: anchore/sbom-action/download-syft@v0.14.3 + - uses: crazy-max/ghaction-upx@v2 + with: + install-only: true + - uses: cachix/install-nix-action@v22 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + # - name: snapcraft-login + # if: startsWith(github.ref, 'refs/tags/v') + # run: snapcraft login --with <(echo "${{ secrets.SNAPCRAFT_TOKEN }}") + # More assembly might be required: Docker logins, GPG, etc. It all depends + # on your needs. + + - uses: goreleaser/goreleaser-action@v4 + with: + # either 'goreleaser' (default) or 'goreleaser-pro': + distribution: goreleaser + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} + USERNAME: ${{ github.repository_owner }} + # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' + # distribution: + # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} + FURY_TOKEN: ${{ secrets.FURY_TOKEN }} + diff --git a/.github/workflows/remove-unused-labels.yml b/.github/workflows/remove-unused-labels.yml new file mode 100644 index 0000000..a2259d7 --- /dev/null +++ b/.github/workflows/remove-unused-labels.yml @@ -0,0 +1,75 @@ +name: Remove Unused Labels +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + contents: read + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Fetch All Issues and PRs + id: fetch_issues_prs + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'all', + per_page: 100 + }); + + const labelsInUse = new Set(); + issues.forEach(issue => { + issue.labels.forEach(label => { + labelsInUse.add(label.name); + }); + }); + + return JSON.stringify(Array.from(labelsInUse)); + result-encoding: string + + - name: Fetch All Labels + id: fetch_labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = await github.paginate(github.rest.issues.listLabelsForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + return JSON.stringify(labels.map(label => label.name)); + result-encoding: string + + - name: Remove Unused Labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labelsInUse = new Set(JSON.parse(process.env.LABELS_IN_USE)); + const allLabels = JSON.parse(process.env.ALL_LABELS); + + const unusedLabels = allLabels.filter(label => !labelsInUse.has(label)); + + for (const label of unusedLabels) { + await github.rest.issues.deleteLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label + }); + console.log(`Deleted label: ${label}`); + } + + env: + LABELS_IN_USE: ${{ steps.fetch_issues_prs.outputs.result }} + ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} \ No newline at end of file diff --git a/.github/workflows/reopen-issue.yml b/.github/workflows/reopen-issue.yml new file mode 100644 index 0000000..d12e2c3 --- /dev/null +++ b/.github/workflows/reopen-issue.yml @@ -0,0 +1,78 @@ +name: Reopen and Update Stale Issues + +on: + workflow_dispatch: + +jobs: + reopen_stale_issues: + runs-on: ubuntu-latest + permissions: + issues: write + contents: read + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Fetch Closed Issues with lifecycle/stale Label + id: fetch_issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'closed', + labels: 'lifecycle/stale', + per_page: 100 + }); + const issueNumbers = issues + .filter(issue => !issue.pull_request) + .map(issue => issue.number); + console.log(`Fetched issues: ${issueNumbers}`); + return issueNumbers; + + - name: Set issue numbers + id: set_issue_numbers + run: | + echo "ISSUE_NUMBERS=${{ steps.fetch_issues.outputs.result }}" >> $GITHUB_ENV + echo "Issue numbers: ${{ steps.fetch_issues.outputs.result }}" + + - name: Reopen Issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = JSON.parse(process.env.ISSUE_NUMBERS); + console.log(`Reopening issues: ${issueNumbers}`); + + for (const issue_number of issueNumbers) { + // Reopen the issue + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + state: 'open' + }); + console.log(`Reopened issue #${issue_number}`); + } + + - name: Remove lifecycle/stale Label + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = JSON.parse(process.env.ISSUE_NUMBERS); + console.log(`Removing 'lifecycle/stale' label from issues: ${issueNumbers}`); + + for (const issue_number of issueNumbers) { + // Remove the lifecycle/stale label + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + name: 'lifecycle/stale' + }); + console.log(`Removed label 'lifecycle/stale' from issue #${issue_number}`); + } diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml new file mode 100644 index 0000000..b7e2a44 --- /dev/null +++ b/.github/workflows/update-version-file-on-release.yml @@ -0,0 +1,119 @@ +name: Update Version File on Release + +on: + release: + types: [created] + +jobs: + update-version: + runs-on: ubuntu-latest + env: + TAG_VERSION: ${{ github.event.release.tag_name }} + steps: + # Step 1: Checkout the original repository's code + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + # submodules: "recursive" + + - name: Safe submodule initialization + run: | + echo "Checking for submodules..." + if [ -f .gitmodules ]; then + if [ -s .gitmodules ]; then + echo "Initializing submodules..." + if git submodule sync --recursive 2>/dev/null; then + git submodule update --init --force --recursive || { + echo "Warning: Some submodules failed to initialize, continuing anyway..." + } + else + echo "Warning: Submodule sync failed, continuing without submodules..." + fi + else + echo ".gitmodules exists but is empty, skipping submodule initialization" + fi + else + echo "No .gitmodules file found, no submodules to initialize" + fi + + # Step 2: Set up Git with official account + - name: Set up Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + # Step 3: Check and delete existing tag + - name: Check and delete existing tag + run: | + if git rev-parse ${{ env.TAG_VERSION }} >/dev/null 2>&1; then + git tag -d ${{ env.TAG_VERSION }} + git push --delete origin ${{ env.TAG_VERSION }} + fi + + # Step 4: Update version file + - name: Update version file + run: | + mkdir -p version + echo -n "${{ env.TAG_VERSION }}" > version/version + + # Step 5: Commit and push changes + - name: Commit and push changes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git add version/version + git commit -m "Update version to ${{ env.TAG_VERSION }}" + + # Step 6: Update tag + - name: Update tag + run: | + git tag -fa ${{ env.TAG_VERSION }} -m "Update version to ${{ env.TAG_VERSION }}" + git push origin ${{ env.TAG_VERSION }} --force + + # Step 7: Find and Publish Draft Release + - name: Find and Publish Draft Release + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo } = context.repo; + const tagName = process.env.TAG_VERSION; + + try { + let release; + try { + const response = await github.rest.repos.getReleaseByTag({ + owner, + repo, + tag: tagName + }); + release = response.data; + } catch (tagError) { + core.info(`Release not found by tag, searching all releases...`); + const releases = await github.rest.repos.listReleases({ + owner, + repo, + per_page: 100 + }); + + release = releases.data.find(r => r.draft && r.tag_name === tagName); + if (!release) { + throw new Error(`No release found with tag ${tagName}`); + } + } + + await github.rest.repos.updateRelease({ + owner, + repo, + release_id: release.id, + draft: false, + prerelease: release.prerelease + }); + + const status = release.draft ? "was draft" : "was already published"; + core.info(`Release ${tagName} ensured to be published (${status}).`); + + } catch (error) { + core.warning(`Could not find or update release for tag ${tagName}: ${error.message}`); + } diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8117158 --- /dev/null +++ b/.gitignore @@ -0,0 +1,376 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +.idea/ +bin/ +components/ +logs + +# Created by https://www.toptal.com/developers/gitignore/api/vim,jetbrains,vscode,git,go,tags,backup,test,emacs +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,jetbrains,vscode,git,go,tags,backup,test,emacs + +### Backup ### +*.bak +*.gho +*.ori +*.orig +*.tmp + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +_output/ +bin/ + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Go Patch ### +/vendor/ +/Godeps/ + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +.idea + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### Tags ### +# Ignore tags created by etags, ctags, gtags (GNU global) and cscope +TAGS +.TAGS +!TAGS/ +tags +.tags +!tags/ +gtags.files +GTAGS +GRTAGS +GPATH +GSYMS +cscope.files +cscope.out +cscope.in.out +cscope.po.out + + +### Test ### +### Ignore all files that could be used to test your code and +### you wouldn't want to push + +# Reference https://en.wikipedia.org/wiki/Metasyntactic_variable + +# Most common +*foo +*bar +*fubar +*foobar +*baz + +# Less common +*qux +*quux +*bongo +*bazola +*ztesch + +# UK, Australia +*wibble +*wobble +*wubble +*flob +*blep +*blah +*boop +*beep + +# Japanese +*hoge +*piyo +*fuga +*hogera +*hogehoge + +# Portugal, Spain +*fulano +*sicrano +*beltrano +*mengano +*perengano +*zutano + +# France, Italy, the Netherlands +*toto +*titi +*tata +*tutu +*pipppo +*pluto +*paperino +*aap +*noot +*mies + +# Other names that would make sense +*tests +*testsdir +*testsfile +*testsfiles +*testdir +*testfile +*testfiles +*testing +*testingdir +*testingfile +*testingfiles +*temp +*tempdir +*tempfile +*tempfiles +*tmp +*tmpdir +*tmpfile +*tmpfiles +*lol + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +# Persistent undo +[._]*.un~ + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive +ltximg/** + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + +### vscode ### +.vscode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# End of https://www.toptal.com/developers/gitignore/api/vim,jetbrains,vscode,git,go,tags,backup,test + +# Start by kubecub + +# log +*.log + +# Output of backend and frontend +/_output +/_debug + +# Misc +.DS_Store +# *.env +# .env +dist + +# files used by the developer +.idea.md +.todo.md +.note.md + +# config files, may contain sensitive informatio +config/config.yaml + diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..a80d2c0 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,934 @@ +# Copyright © 2023 OpenIMSDK open source community. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains all available configuration options +# with their default values. + +# options for analysis running +run: + # default concurrency is a available CPU number + concurrency: 4 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 5m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + + # include test files or not, default is true + tests: true + + # list of build tags, all linters use it. Default is empty list. + build-tags: + - mytag + + # which dirs to skip: issues from them won't be reported; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but default dirs are skipped independently + # from this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + skip-dirs: + - util + - .*~ + - api/swagger/docs + - server/docs + + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: true + + # which files to skip: they will be analyzed, but issues from them + # won't be reported. Default value is empty list, but there is + # no need to include all autogenerated files, we confidently recognize + # autogenerated files. If it's not please let us know. + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + skip-files: + - ".*\\.my\\.go$" + - _test.go + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + #modules-download-mode: release|readonly|vendor + + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: true + + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + + # make issues output unique by line, default is true + uniq-by-line: true + + # add a prefix to the output file references; default is no prefix + path-prefix: "" + + # sorts results by: filepath, line and column + sort-results: true + +# all available settings of specific linters +linters-settings: + bidichk: + # The following configurations check for all mentioned invisible unicode + # runes. It can be omitted because all runes are enabled by default. + left-to-right-embedding: true + right-to-left-embedding: true + pop-directional-formatting: true + left-to-right-override: true + right-to-left-override: true + left-to-right-isolate: true + right-to-left-isolate: true + first-strong-isolate: true + pop-directional-isolate: true + dogsled: + # checks assignments with too many blank identifiers; default is 2 + max-blank-identifiers: 2 + dupl: + # tokens count to trigger issue, 150 by default + threshold: 200 + errcheck: + # report about not checking of errors in type assertions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + + # [deprecated] comma-separated list of pairs of the form pkg:regex + # the regex is used to ignore names within pkg. (default "fmt:.*"). + # see https://github.com/kisielk/errcheck#the-deprecated-method for details + #ignore: GenMarkdownTree,os:.*,BindPFlags,WriteTo,Help + #ignore: (os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv + + # path to a file containing a list of functions to exclude from checking + # see https://github.com/kisielk/errcheck#excluding-functions for details + #exclude: errcheck.txt + + errorlint: + # Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats + errorf: true + # Check for plain type assertions and type switches + asserts: true + # Check for plain error comparisons + comparison: true + + exhaustive: + # check switch statements in generated files also + check-generated: false + # indicates that switch statements are to be considered exhaustive if a + # 'default' case is present, even if all enum members aren't listed in the + # switch + default-signifies-exhaustive: false + # enum members matching the supplied regex do not have to be listed in + # switch statements to satisfy exhaustiveness + ignore-enum-members: "" + # consider enums only in package scopes, not in inner scopes + package-scope-only: false + exhaustivestruct: + struct-patterns: + - '*.Test' + - '*.Test2' + - '*.Embedded' + - '*.External' + + # forbidigo: + # # Forbid the following identifiers (identifiers are written using regexp): + # forbid: + # - ^print.*$ + # - 'fmt\.Print.*' + # - fmt.Println.* # too much log noise + # - ginkgo\\.F.* # these are used just for local development + # # Exclude godoc examples from forbidigo checks. Default is true. + # exclude_godoc_examples: false + funlen: + lines: 150 + statements: 50 + gci: + # put imports beginning with prefix after 3rd-party packages; + # only support one prefix + # if not set, use goimports.local-prefixes + prefix: github.com/openimsdk/OpenKF + gocognit: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 30 + goconst: + # minimal length of string constant, 3 by default + min-len: 3 + # minimal occurrences count to trigger, 3 by default + min-occurrences: 3 + # ignore test files, false by default + ignore-tests: false + # look for existing constants matching the values, true by default + match-constant: true + # search also for duplicated numbers, false by default + numbers: false + # minimum value, only works with goconst.numbers, 3 by default + min: 3 + # maximum value, only works with goconst.numbers, 3 by default + max: 3 + # ignore when constant is not used as function argument, true by default + ignore-calls: true + + gocritic: + # Which checks should be enabled; can't be combined with 'disabled-checks'; + # See https://go-critic.github.io/overview#checks-overview + # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` + # By default list of stable checks is used. + enabled-checks: + #- rangeValCopy + - nestingreduce + - truncatecmp + - unnamedresult + - ruleguard + + # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty + disabled-checks: + - regexpMust + - ifElseChain + #- exitAfterDefer + + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - performance + disabled-tags: + - experimental + + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: + captLocal: # must be valid enabled check name + # whether to restrict checker to params only (default true) + paramsOnly: true + elseif: + # whether to skip balanced if-else pairs (default true) + skipBalanced: true + hugeParam: + # size in bytes that makes the warning trigger (default 80) + sizeThreshold: 80 + nestingReduce: + # min number of statements inside a branch to trigger a warning (default 5) + bodyWidth: 5 + rangeExprCopy: + # size in bytes that makes the warning trigger (default 512) + sizeThreshold: 512 + # whether to check test functions (default true) + skipTestFuncs: true + rangeValCopy: + # size in bytes that makes the warning trigger (default 128) + sizeThreshold: 32 + # whether to check test functions (default true) + skipTestFuncs: true + ruleguard: + # path to a gorules file for the ruleguard checker + rules: '' + truncateCmp: + # whether to skip int/uint/uintptr types (default true) + skipArchDependent: true + underef: + # whether to skip (*x).method() calls where x is a pointer receiver (default true) + skipRecvDeref: true + unnamedResult: + # whether to check exported functions + checkExported: true + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 30 + cyclop: + # the maximal code complexity to report + max-complexity: 50 + # the maximal average package complexity. If it's higher than 0.0 (float) the check is enabled (default 0.0) + package-average: 0.0 + # should ignore tests (default false) + skip-tests: false + godot: + # comments to be checked: `declarations`, `toplevel`, or `all` + scope: declarations + # list of regexps for excluding particular comment lines from check + exclude: + # example: exclude comments which contain numbers + # - '[0-9]+' + # check that each sentence starts with a capital letter + capital: false + godox: + # report any comments starting with keywords, this is useful for TODO or FIXME comments that + # might be left in the code accidentally and should be resolved before merging + keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting + #- TODO + - BUG + - FIXME + #- NOTE + - OPTIMIZE # marks code that should be optimized before merging + - HACK # marks hack-arounds that should be removed before merging + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + + gofumpt: + # Select the Go version to target. The default is `1.18`. + lang-version: "1.20" + + # Choose whether or not to use the extra rules that are disabled + # by default + extra-rules: false + + goheader: + values: + const: + # define here const type values in format k:v, for example: + # COMPANY: MY COMPANY + regexp: + # define here regexp type values, for example + # AUTHOR: .*@mycompany\.com + template: # |- + # put here copyright header template for source code files, for example: + # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time. + # + # {{ AUTHOR }} {{ COMPANY }} {{ YEAR }} + # SPDX-License-Identifier: Apache-2.0 + + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at: + + # http://www.apache.org/licenses/LICENSE-2.0 + + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + template-path: + # also as alternative of directive 'template' you may put the path to file with the template source + goimports: + # put imports beginning with prefix after 3rd-party packages; + # it's a comma-separated list of prefixes + local-prefixes: github.com/openimsdk/OpenKF + golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.9 + gomnd: + settings: + mnd: + # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + checks: argument,case,condition,operation,return,assign + # ignored-numbers: 1000 + # ignored-files: magic_.*.go + # ignored-functions: math.* + gomoddirectives: + # Allow local `replace` directives. Default is false. + replace-local: true + # List of allowed `replace` directives. Default is empty. + replace-allow-list: + - google.golang.org/grpc + + # Allow to not explain why the version has been retracted in the `retract` directives. Default is false. + retract-allow-no-explanation: false + # Forbid the use of the `exclude` directives. Default is false. + exclude-forbidden: false + gomodguard: + allowed: + modules: + - gorm.io/gen # List of allowed modules + - gorm.io/gorm + - gorm.io/driver/mysql + - k8s.io/klog + # - gopkg.in/yaml.v2 + domains: # List of allowed module domains + - google.golang.org + - gopkg.in + - golang.org + - github.com + - go.uber.org + - go.etcd.io + blocked: + versions: + - github.com/MakeNowJust/heredoc: + version: "> 2.0.9" + reason: "use the latest version" + local_replace_directives: false # Set to true to raise lint issues for packages that are loaded from a local path via replace directive + + gosec: + # To select a subset of rules to run. + # Available rules: https://github.com/securego/gosec#available-rules + includes: + - G401 + - G306 + - G101 + # To specify a set of rules to explicitly exclude. + # Available rules: https://github.com/securego/gosec#available-rules + excludes: + - G204 + # Exclude generated files + exclude-generated: true + # Filter out the issues with a lower severity than the given value. Valid options are: low, medium, high. + severity: "low" + # Filter out the issues with a lower confidence than the given value. Valid options are: low, medium, high. + confidence: "low" + # To specify the configuration of rules. + # The configuration of rules is not fully documented by gosec: + # https://github.com/securego/gosec#configuration + # https://github.com/securego/gosec/blob/569328eade2ccbad4ce2d0f21ee158ab5356a5cf/rules/rulelist.go#L60-L102 + config: + G306: "0600" + G101: + pattern: "(?i)example" + ignore_entropy: false + entropy_threshold: "80.0" + per_char_threshold: "3.0" + truncate: "32" + + gosimple: + # Select the Go version to target. The default is '1.13'. + go: "1.20" + # https://staticcheck.io/docs/options#checks + checks: [ "all" ] + + govet: + # report about shadowed variables + check-shadowing: true + + # settings per analyzer + settings: + printf: # analyzer name, run `go tool vet help` to see all analyzers + funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + + # enable or disable analyzers by name + enable: + - atomicalign + enable-all: false + disable: + - shadow + disable-all: false + # depguard: + # list-type: blacklist + # include-go-root: false + # packages: + # - github.com/Sirupsen/logrus + # packages-with-error-message: + # # specify an error message to output when a blacklisted package is used + # - github.com/Sirupsen/logrus: "logging is allowed only by logutils.Log" + ifshort: + # Maximum length of variable declaration measured in number of lines, after which linter won't suggest using short syntax. + # Has higher priority than max-decl-chars. + max-decl-lines: 1 + # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax. + max-decl-chars: 30 + + importas: + # if set to `true`, force to use alias. + no-unaliased: true + # List of aliases + alias: + # using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package + - pkg: knative.dev/serving/pkg/apis/serving/v1 + alias: servingv1 + # using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package + - pkg: knative.dev/serving/pkg/apis/autoscaling/v1alpha1 + alias: autoscalingv1alpha1 + # You can specify the package path by regular expression, + # and alias by regular expression expansion syntax like below. + # see https://github.com/julz/importas#use-regular-expression for details + - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+) + alias: $1$2 + # using `jwt` alias for `github.com/appleboy/gin-jwt/v2` package + jwt: github.com/appleboy/gin-jwt/v2 + + ireturn: + # ireturn allows using `allow` and `reject` settings at the same time. + # Both settings are lists of the keywords and regular expressions matched to interface or package names. + # keywords: + # - `empty` for `interface{}` + # - `error` for errors + # - `stdlib` for standard library + # - `anon` for anonymous interfaces + + # By default, it allows using errors, empty interfaces, anonymous interfaces, + # and interfaces provided by the standard library. + allow: + - anon + - error + - empty + - stdlib + # You can specify idiomatic endings for interface + - (or|er)$ + + # Reject patterns + reject: + - github.com\/user\/package\/v4\.Type + + lll: + # max line length, lines longer will be reported. Default is 120. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option + line-length: 240 + # tab width in spaces. Default to 1. + tab-width: 4 + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + locale: US + ignore-words: + - someword + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 + + nestif: + # minimal complexity of if statements to report, 5 by default + min-complexity: 4 + + nilnil: + # By default, nilnil checks all returned types below. + checked-types: + - ptr + - func + - iface + - map + - chan + + nlreturn: + # size of the block (including return statement that is still "OK") + # so no return split required. + block-size: 1 + + nolintlint: + # Disable to ensure that all nolint directives actually have an effect. Default is true. + allow-unused: false + # Disable to ensure that nolint directives don't have a leading space. Default is true. + allow-leading-space: true + # Exclude following linters from requiring an explanation. Default is []. + allow-no-explanation: [ ] + # Enable to require an explanation of nonzero length after each nolint directive. Default is false. + require-explanation: false + # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. + require-specific: true + + prealloc: + # XXX: we don't recommend using this linter before doing performance profiling. + # For most programs usage of prealloc will be a premature optimization. + + # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # True by default. + simple: true + range-loops: true # Report preallocation suggestions on range loops, true by default + for-loops: false # Report preallocation suggestions on for loops, false by default + + promlinter: + # Promlinter cannot infer all metrics name in static analysis. + # Enable strict mode will also include the errors caused by failing to parse the args. + strict: false + # Please refer to https://github.com/yeya24/promlinter#usage for detailed usage. + disabled-linters: + # - "Help" + # - "MetricUnits" + # - "Counter" + # - "HistogramSummaryReserved" + # - "MetricTypeInName" + # - "ReservedChars" + # - "CamelCase" + # - "lintUnitAbbreviations" + + predeclared: + # comma-separated list of predeclared identifiers to not report on + ignore: "" + # include method names and field names (i.e., qualified names) in checks + q: false + rowserrcheck: + packages: + - github.com/jmoiron/sqlx + revive: + # see https://github.com/mgechev/revive#available-rules for details. + ignore-generated-header: true + severity: warning + rules: + - name: indent-error-flow + severity: warning + staticcheck: + # Select the Go version to target. The default is '1.13'. + go: "1.16" + # https://staticcheck.io/docs/options#checks + checks: [ "all" ] + + stylecheck: + # Select the Go version to target. The default is '1.13'. + go: "1.16" + + # https://staticcheck.io/docs/options#checks + checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022" ] + # https://staticcheck.io/docs/options#dot_import_whitelist + dot-import-whitelist: + - fmt + # https://staticcheck.io/docs/options#initialisms + initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS" ] + # https://staticcheck.io/docs/options#http_status_code_whitelist + http-status-code-whitelist: [ "200", "400", "404", "500" ] + + + tagliatelle: + # check the struck tag name case + case: + # use the struct field name to check the name of the struct tag + use-field-name: true + rules: + # any struct tag type can be used. + # support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower` + json: camel + yaml: camel + xml: camel + bson: camel + avro: snake + mapstructure: kebab + + testpackage: + # regexp pattern to skip files + skip-regexp: (id|export|internal)_test\.go + thelper: + # The following configurations enable all checks. It can be omitted because all checks are enabled by default. + # You can enable only required checks deleting unnecessary checks. + test: + first: true + name: true + begin: true + benchmark: + first: true + name: true + begin: true + tb: + first: true + name: true + begin: true + + tenv: + # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. + # By default, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. + all: false + + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + unused: + # treat code as a program (not a library) and report unused exported identifiers; default is false. + # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find funcs usages. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + whitespace: + multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-func: false # Enforces newlines (or comments) after every multi-line function signature + + wrapcheck: + # An array of strings that specify substrings of signatures to ignore. + # If this set, it will override the default set of ignored signatures. + # See https://github.com/tomarrell/wrapcheck#configuration for more information. + ignoreSigs: + - .Errorf( + - errors.New( + - errors.Unwrap( + - .Wrap( + - .Wrapf( + - .WithMessage( + - .WithMessagef( + - .WithStack( + ignorePackageGlobs: + - encoding/* + - github.com/pkg/* + + wsl: + # If true append is only allowed to be cuddled if appending value is + # matching variables, fields or types on line above. Default is true. + strict-append: true + # Allow calls and assignments to be cuddled as long as the lines have any + # matching variables, fields or types. Default is true. + allow-assign-and-call: true + # Allow assignments to be cuddled with anything. Default is false. + allow-assign-and-anything: false + # Allow multiline assignments to be cuddled. Default is true. + allow-multiline-assign: true + # Allow declarations (var) to be cuddled. + allow-cuddle-declarations: false + # Allow trailing comments in ending of blocks + allow-trailing-comment: false + # Force newlines in end of case at this limit (0 = never). + force-case-trailing-whitespace: 0 + # Force cuddling of err checks with err var assignment + force-err-cuddling: false + # Allow leading comments to be separated with empty liens + allow-separated-leading-comment: false + makezero: + # Allow only slices initialized with a length of zero. Default is false. + always: false + + + # The custom section can be used to define linter plugins to be loaded at runtime. See README doc + # for more info. + #custom: + # Each custom linter should have a unique name. + #example: + # The path to the plugin *.so. Can be absolute or local. Required for each custom linter + #path: /path/to/example.so + # The description of the linter. Optional, just for documentation purposes. + #description: This is an example usage of a plugin linter. + # Intended to point to the repo location of the linter. Optional, just for documentation purposes. + #original-url: github.com/golangci/example-linter + +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + # enable-all: true + disable-all: true + enable: + - typecheck + - asciicheck + - bodyclose + - cyclop + - deadcode + # - depguard + - dogsled + - dupl + - durationcheck + - errcheck + - errorlint + - exhaustive + - exportloopref + # - forbidigo + - funlen + # - gci + # - gochecknoinits + - gocognit + - goconst + - gocyclo + - godot + - godox + - gofmt + - gofumpt + - goheader + - goimports + - gomoddirectives + - gomodguard + - goprintffuncname + - gosec + - gosimple + - govet + - ifshort + - importas + - ineffassign + - lll + - makezero + - misspell + - nakedret + - nestif + - nilerr + - nlreturn + - noctx + - nolintlint + - paralleltest + - prealloc + - predeclared + - promlinter + - revive + - rowserrcheck + - sqlclosecheck + - staticcheck + - structcheck + - stylecheck + - thelper + - tparallel + - unconvert + - unparam + - unused + - varcheck + - wastedassign + - whitespace + - bidichk + - wastedassign + - golint + - execinquery + - nosprintfhostport + - grouper + - decorder + - errchkjson + - maintidx + #- containedctx + #- tagliatelle + #- nonamedreturns + #- nilnil + #- tenv + #- varnamelen + #- contextcheck + #- errname + #- ForceTypeAssert + #- nilassign + fast: false + +issues: + # List of regexps of issue texts to exclude, empty list by default. + # But independently from this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. To list all + # excluded by default patterns execute `golangci-lint run --help` + exclude: + - tools/.* + - test/.* + - third_party/.* + + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - linters: + - golint + path: (internal/api/.*)\.go # exclude golint for internal/api/... files + + - linters: + - revive + path: (log/.*)\.go + + - linters: + - wrapcheck + path: (cmd/.*|pkg/.*)\.go + + - linters: + - typecheck + #path: (pkg/storage/.*)\.go + path: (internal/.*|pkg/.*)\.go + + - path: (cmd/.*|test/.*|tools/.*|internal/pump/pumps/.*)\.go + linters: + - forbidigo + + - path: (cmd/[a-z]*/.*|store/.*)\.go + linters: + - dupl + + - linters: + - gocritic + text: (hugeParam:|rangeValCopy:) + + - path: (cmd/[a-z]*/.*)\.go + linters: + - lll + + - path: (validator/.*|code/.*|validator/.*|watcher/watcher/.*) + linters: + - gochecknoinits + + - path: (internal/.*/options|internal/pump|pkg/log/options.go|internal/authzserver|tools/) + linters: + - tagliatelle + + - path: (pkg/app/.*)\.go + linters: + - deadcode + - unused + - varcheck + - forbidigo + + # Exclude some staticcheck messages + - linters: + - staticcheck + text: "SA9003:" + + # Exclude lll issues for long lines with go:generate + - linters: + - lll + source: "^//go:generate " + + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: true + + # The default value is false. If set to true exclude and exclude-rules + # regular expressions become case sensitive. + exclude-case-sensitive: false + + # The list of ids of default excludes to include or disable. By default it's empty. + include: + - EXC0002 # disable excluding of issues about comments from golint + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-issues-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 + + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing + # large codebase. It's not practical to fix all existing issues at the moment + # of integration: much better don't allow issues in new code. + # Default is false. + new: false + + # Show only new issues created after git revision `REV` + # new-from-rev: REV + + # Show only new issues created in git patch with set file path. + #new-from-patch: path/to/patch/file + + # Fix found issues (if it's supported by the linter) + fix: true + +severity: + # Default value is empty string. + # Set the default severity for issues. If severity rules are defined and the issues + # do not match or no severity is provided to the rule this will be the default + # severity applied. Severities should match the supported severity names of the + # selected out format. + # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity + # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + default-severity: error + + # The default value is false. + # If set to true severity-rules regular expressions become case sensitive. + case-sensitive: false + + # Default value is empty list. + # When a list of severity rules are provided, severity information will be added to lint + # issues. Severity rules have the same filtering capability as exclude rules except you + # are allowed to specify one matcher per severity rule. + # Only affects out formats that support setting severity information. + rules: + - linters: + - dupl + severity: info \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..2106ed5 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,493 @@ +# Copyright © 2023 OpenIM open source community. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This is an example .goreleaser.yml file with some sensible defaults. +# Make sure to check the documentation at https://goreleaser.com + +before: + hooks: + - make clean + # You may remove this if you don't use go modules. + - go mod tidy + # you may remove this if you don't need go generate + - go generate ./... + +git: + # What should be used to sort tags when gathering the current and previous + # tags if there are more than one tag in the same commit. + # + # Default: '-version:refname' + tag_sort: -version:creatordate + + # What should be used to specify prerelease suffix while sorting tags when gathering + # the current and previous tags if there are more than one tag in the same commit. + # + # Since: v1.17 + prerelease_suffix: "-" + + # Tags to be ignored by GoReleaser. + # This means that GoReleaser will not pick up tags that match any of the + # provided values as either previous or current tags. + # + # Templates: allowed. + # Since: v1.21. + ignore_tags: + - nightly + # - "{{.Env.IGNORE_TAG}}" + +report_sizes: true + +builds: + - binary: chat-api + id: chat-api + main: ./cmd/api/chat-api/main.go + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - s390x + - arm64 + - ppc64le + goarm: + - "6" + - "7" + ignore: + - goos: darwin + goarch: s390x + - goos: darwin + goarch: ppc64le + - goos: windows + goarch: s390x + - goos: windows + goarch: arm64 + - goos: windows + goarch: ppc64le + + - binary: admin-api + id: admin-api + main: ./cmd/api/admin-api/main.go + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - s390x + - arm64 + - ppc64le + goarm: + - "6" + - "7" + ignore: + - goos: darwin + goarch: s390x + - goos: darwin + goarch: ppc64le + - goos: windows + goarch: s390x + - goos: windows + goarch: arm64 + - goos: windows + goarch: ppc64le + + - binary: chat-rpc + id: chat-rpc + main: ./cmd/rpc/chat-rpc/main.go + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - s390x + - arm64 + - ppc64le + goarm: + - "6" + - "7" + ignore: + - goos: darwin + goarch: s390x + - goos: darwin + goarch: ppc64le + - goos: windows + goarch: s390x + - goos: windows + goarch: arm64 + - goos: windows + goarch: ppc64le + + - binary: admin-rpc + id: admin-rpc + main: ./cmd/rpc/admin-rpc/main.go + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - s390x + - arm64 + - ppc64le + goarm: + - "6" + - "7" + ignore: + - goos: darwin + goarch: s390x + - goos: darwin + goarch: ppc64le + - goos: windows + goarch: s390x + - goos: windows + goarch: arm64 + - goos: windows + goarch: ppc64le + +archives: + - format: tar.gz + # this name template makes the OS and Arch compatible with the results of uname. + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + # use zip for windows archives + files: + - LICENSE + - README.md + - docs/* + # a more complete example, check the globbing deep dive below + - src: "*.md" + dst: docs + + # Strip parent folders when adding files to the archive. + strip_parent: true + + # File info. + # Not all fields are supported by all formats available formats. + # + # Default: copied from the source file + info: + # Templates: allowed (since v1.14) + owner: root + + # Templates: allowed (since v1.14) + group: root + + # Must be in time.RFC3339Nano format. + # + # Templates: allowed (since v1.14) + mtime: "{{ .CommitDate }}" + + # File mode. + mode: 0644 + + format_overrides: + - goos: windows + format: zip + +changelog: + sort: asc + use: github + filters: + exclude: + - "^test:" + - "^chore" + - "merge conflict" + - Merge pull request + - Merge remote-tracking branch + - Merge branch + - go mod tidy + groups: + - title: Dependency updates + regexp: '^.*?(feat|fix)\(deps\)!?:.+$' + order: 300 + - title: "New Features" + regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' + order: 100 + - title: "Security updates" + regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$' + order: 150 + - title: "Bug fixes" + regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' + order: 200 + - title: "Documentation updates" + regexp: ^.*?doc(\([[:word:]]+\))??!?:.+$ + order: 400 + - title: "Build process updates" + regexp: ^.*?build(\([[:word:]]+\))??!?:.+$ + order: 400 + - title: Other work + order: 9999 + +# dockers: +# - image_templates: +# - "openim/openim-chat-api-chat:{{ .Tag }}-amd64" +# - "ghcr.io/openimsdk/openim-chat-api-chat:{{ .Tag }}-amd64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-chat:{{ .Tag }}-amd64" +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/chat/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://git.imall.cloud/openim/chat/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/amd64" +# goos: linux +# goarch: amd64 +# dockerfile: ./build/images/api-chat/Dockerfile +# use: buildx + +# - image_templates: +# - "openim/openim-chat-api-chat:{{ .Tag }}-arm64" +# - "ghcr.io/openimsdk/openim-chat-api-chat:{{ .Tag }}-arm64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-chat:{{ .Tag }}-arm64" +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/chat/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://git.imall.cloud/openim/chat/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/arm64" +# goos: linux +# goarch: arm64 +# dockerfile: ./build/images/api-chat/Dockerfile +# use: buildx + +# - image_templates: +# - "openim/openim-chat-api-admin:{{ .Tag }}-amd64" +# - "ghcr.io/openimsdk/openim-chat-api-admin:{{ .Tag }}-amd64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-admin:{{ .Tag }}-amd64" +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/chat/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://git.imall.cloud/openim/chat/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/amd64" +# goos: linux +# goarch: amd64 +# dockerfile: ./build/images/api-admin/Dockerfile +# use: buildx + +# - image_templates: +# - "openim/openim-chat-api-admin:{{ .Tag }}-arm64" +# - "ghcr.io/openimsdk/openim-chat-api-admin:{{ .Tag }}-arm64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-admin:{{ .Tag }}-arm64" +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/chat/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://git.imall.cloud/openim/chat/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/arm64" +# goos: linux +# goarch: arm64 +# dockerfile: ./build/images/api-admin/Dockerfile +# use: buildx + +# docker_manifests: +# - name_template: "openim/openim-chat-api-admin:{{ .Tag }}" +# image_templates: +# - "openim/openim-chat-api-admin:{{ .Tag }}-amd64" +# - "openim/openim-chat-api-admin:{{ .Tag }}-arm64" +# - name_template: "ghcr.io/openimsdk/openim-chat:{{ .Tag }}" +# image_templates: +# - "ghcr.io/openimsdk/openim-chat:{{ .Tag }}-amd64" +# - "ghcr.io/openimsdk/openim-chat:{{ .Tag }}-arm64" +# - name_template: "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-admin:{{ .Tag }}" +# image_templates: +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-admin:{{ .Tag }}-amd64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-admin:{{ .Tag }}-arm64" +# - name_template: "openim/openim-chat-api-admin:latest" +# image_templates: +# - "openim/openim-chat-api-chat:{{ .Tag }}-amd64" +# - "openim/openim-chat-api-chat:{{ .Tag }}-arm64" +# - name_template: "ghcr.io/openimsdk/openim-chat-api-chat:latest" +# image_templates: +# - "ghcr.io/openimsdk/openim-chat-api-chat:{{ .Tag }}-amd64" +# - "ghcr.io/openimsdk/openim-chat-api-chat:{{ .Tag }}-arm64" +# - name_template: "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-chat:latest" +# image_templates: +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-chat:{{ .Tag }}-amd64" +# - "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat-api-chat:{{ .Tag }}-arm64" + +nfpms: + - id: packages + builds: + - admin-api + - chat-api + - chat-rpc + - admin-rpc + # Your app's vendor. + vendor: OpenIMSDK + homepage: https://git.imall.cloud/openim/chat + maintainer: kubbot + description: |- + Auto sync github labels + kubbot && openimbot + license: MIT + formats: + - apk + - deb + - rpm + - termux.deb # Since: v1.11 + - archlinux # Since: v1.13 + dependencies: + - git + recommends: + - golang + +# The lines beneath this are called `modelines`. See `:help modeline` +# Feel free to remove those if you don't want/use them. +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj + +# Default: './dist' +dist: ./_output/dist + +# # .goreleaser.yaml +# milestones: +# # You can have multiple milestone configs +# - +# # Repository for the milestone +# # Default is extracted from the origin remote URL +# repo: +# owner: OpenIMSDK +# name: chat + +# # Whether to close the milestone +# close: true + +# # Fail release on errors, such as missing milestone. +# fail_on_error: false + +# # Name of the milestone +# # +# Default: '{{ .Tag }}' +# name_template: "Current Release" + +publishers: + - name: "fury.io" + ids: + - packages + dir: "{{ dir .ArtifactPath }}" + cmd: | + bash -c ' + if [[ "{{ .Tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + curl -F package=@{{ .ArtifactName }} https://{{ .Env.FURY_TOKEN }}@push.fury.io/openim/ + else + echo "Skipping deployment: Non-production release detected" + fi' + +# snapcrafts: +# - name_template: "{{ .ProjectName }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" +# summary: openim is open source instant messaging +# description: | +# OpenIM yyds +# grade: stable +# confinement: classic +# publish: true + +checksum: + name_template: "{{ .ProjectName }}_checksums.txt" + algorithm: sha256 + +snapshot: + name_template: "{{ .Tag }}-next" + +release: + prerelease: auto + footer: | + + ## Welcome to the {{ .Tag }} release of [chat](https://git.imall.cloud/openim/chat)!🎉🎉! + + **Full Changelog**: https://git.imall.cloud/openim/chat/compare/{{ .PreviousTag }}...{{ .Tag }} + + ## Helping out + + + We release logs are recorded on [✨ CHANGELOG](https://github.com/openimsdk/Open-IM-Server/blob/main/CHANGELOG/CHANGELOG.md) + + + For information on versions of OpenIM and how to maintain branches, read [📚this article](https://github.com/openimsdk/Open-IM-Server/blob/main/docs/conversions/version.md) + + + If you wish to use mirroring, read OpenIM's [image management policy](https://github.com/openimsdk/Open-IM-Server/blob/main/docs/conversions/images.md) + + **Want to be one of them 😘?** + +

+ + + + + + + + + +

+ + > **Note** + > @openimbot and @kubbot have made great contributions to the community as community 🤖robots(@openimsdk/bot), respectively. + > Thanks to the @openimsdk/openim team for all their hard work on this release. + > Thank you to all the [💕developers and contributors](https://git.imall.cloud/openim/chat/graphs/contributors), people from all over the world, OpenIM brings us together + > Contributions to this project are welcome! Please see [CONTRIBUTING.md](https://github.com/openimsdk/Open-IM-Server/blob/main/CONTRIBUTING.md) for details. + + + ## Get Involved with OpenIM! + + **Here are some ways to get involved with the OpenIM community:** + + 📢 **Slack Channel**: Join our Slack channels for discussions, communication, and support. Click [here](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) to join the chat Slack team channel. + + 📧 **Gmail Contact**: If you have any questions, suggestions, or feedback for our open-source projects, please feel free to [contact us via email](https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=winxu81@gmail.com). + + 📖 **Blog**: Stay up-to-date with OpenIM-Server projects and trends by reading our [blog](https://doc.rentsoft.cn/). We share the latest developments, tech trends, and other interesting information related to OpenIM. + + 📱 **WeChat**: Add us on WeChat (QR Code) and indicate that you are a user or developer of chat. We'll process your request as soon as possible. + + Remember, your contributions play a vital role in making OpenIM successful, and we look forward to your active participation in our community! 🙌 + +# webhook +# announce: +# slack: +# enabled: false +# message_template: "slack {{ .Tag }} is out! Check it out: https://github.com/openimsdk/Open-IM-Server/releases/tag/{{ .Tag }}" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c5e93d7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +3293172751nss@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b45c107 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,371 @@ +# Contributing to Open-IM-Server + +So, you want to hack on Open-IM-Server? Yay! + +First of all, thank you for considering contributing to our project! We appreciate your time and effort, and we value any contribution, whether it's reporting a bug, suggesting a new feature, or submitting a pull request. + +This document provides guidelines and best practices to help you contribute effectively. + +## 📇Topics + +- [Contributing to Open-IM-Server](#contributing-to-chat-deploy) + - [📇Topics](#topics) + - [What we expect of you](#what-we-expect-of-you) + - [Code of ConductCode of Conduct](#code-of-conductcode-of-conduct) + - [Code and doc contribution](#code-and-doc-contribution) + - [Where should I start?](#where-should-i-start) + - [Design documents](#design-documents) + - [Getting Started](#getting-started) + - [Style and Specification](#style-and-specification) + - [Reporting security issues](#reporting-security-issues) + - [Reporting general issues](#reporting-general-issues) + - [Commit Rules](#commit-rules) + - [PR Description](#pr-description) + - [Docs Contribution](#docs-contribution) + - [Engage to help anything](#engage-to-help-anything) + - [Release version](#release-version) + - [Contact Us](#contact-us) + +## What we expect of you + +We hope that anyone can join Open-IM-Server , even if you are a student, writer, translator + +Please meet the minimum version of the Go language published in [go.mod](./go.mod). If you want to manage the Go language version, we provide tools to install [gvm](https://github.com/moovweb/gvm) in our [Makefile](./Makefile) + +You'd better use Linux OR WSL as the development environment, Linux with [Makefile](./Makefile) can help you quickly build and test Open-IM-Server project. + +If you are familiar with [Makefile](./Makefile) , you can easily see the clever design of the Open-IM-Server Makefile. Storing the necessary tools such as golangci in the `/tools` directory can avoid some tool version issues. + +The [Makefile](./Makefile) is for every developer, even if you don't know how to use the Makefile tool, don't worry, we provide two great commands to get you up to speed with the Makefile architecture, `make help` and `make help-all`, it can reduce problems of the developing environment. + +## Code of ConductCode of Conduct + +#### Code and doc contribution + +Every action to make project Open-IM-Server better is encouraged. On GitHub, every improvement for Open-IM-Server could be via a [PR](https://github.com/openimsdk/Open-IM-Server/pulls) (short for pull request). + +- If you find a typo, try to fix it! +- If you find a bug, try to fix it! +- If you find some redundant codes, try to remove them! +- If you find some test cases missing, try to add them! +- If you could enhance a feature, please **DO NOT** hesitate! +- If you find code implicit, try to add comments to make it clear! +- If you find code ugly, try to refactor that! +- If you can help to improve documents, it could not be better! +- If you find document incorrect, just do it and fix that! +- ... + +#### Where should I start? + +- If you are new to the project, don't know how to contribute Open-IM-Server, please check out the [good first issue](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aopen+label%3A"good+first+issue"+sort%3Aupdated-desc) label. +- You should be good at filtering the Open-IM-Server issue tags and finding the ones you like, such as [RFC](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) for big initiatives, features for [feature](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+label%3Afeature) proposals, and [bug](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+label%3Abug+) fixes. +- If you are looking for something to work on, check out our [open issues](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). +- If you have an idea for a new feature, please [open an issue](https://github.com/openimsdk/Open-IM-Server/issues/new/choose), and we can discuss it. + +#### Design documents + +For any substantial design, there should be a well-crafted design document. This document is not just a simple record, but also a detailed description and manifestation, which can help team members better understand the design thinking and grasp the design direction. In the process of writing the design document, we can choose to use tools such as `Google Docs` or `Notion`, and even mark RFC in [issues](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) or [discussions](https://github.com/openimsdk/Open-IM-Server/discussions) for better collaboration. Of course, after completing the design document, we should also add it to our [Shared Drive](https://drive.google.com/drive/) and notify the appropriate working group to let everyone know of its existence. Only by doing so can we maximize the effectiveness of the design document and provide strong support for the smooth progress of the project. + +Anybody can access the shared Drive for reading. To get access to comment. Once you've done that, head to the [shared Drive](https://drive.google.com/) and behold all the docs. + +In addition to that, we'd love to invite you to [join our Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) where you can play with your imagination, tell us what you're working on, and get a quick response. + +When documenting a new design, we recommend a 2-step approach: + +1. Use the short-form RFC template to outline your ideas and get early feedback. +2. Once you have received sufficient feedback and consensus, you may use the longer-form design doc template to specify and discuss your design in more details. + +In order to contribute a feature to Open-IM-Server you'll need to go through the following steps: + +- Discuss your idea with the appropriate [working groups](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) on the working group's Slack channel. +- Once there is general agreement that the feature is useful, create a GitHub issue to track the discussion. The issue should include information about the requirements and use cases that it is trying to address. +- Include a discussion of the proposed design and technical details of the implementation in the issue. + +But keep in mind that there is no guarantee of it being accepted and so it is usually best to get agreement on the idea/design before time is spent coding it. However, sometimes seeing the exact code change can help focus discussions, so the choice is up to you. + +## Getting Started + +To propose PR for the Open-IM-Server item, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: + +1. Fork the repository(Open-IM-Server) + +2. **CLONE** your own repository to main locally. Use `git clone https://github.com//Open-IM-Server.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. + +3. **Set Remote** upstream to be `https://github.com/openimsdk/Open-IM-Server.git` using the following two commands: + + ```bash + ❯ git remote add upstream https://github.com/openimsdk/Open-IM-Server.git + ❯ git remote set-url --push upstream no-pushing + ``` + + With this remote setting, you can check your git remote configuration like this: + + ```bash + ❯ git remote -v + origin https://github.com//Open-IM-Server.git (fetch) + origin https://github.com//Open-IM-Server.git (push) + upstream https://github.com/openimsdk/Open-IM-Server.git (fetch) + upstream no-pushing (push) + ``` + + Adding this, we can easily synchronize local branches with upstream branches. + +4. Create a new branch for your changes (use a descriptive name, such as `fix-bug-123` or `add-new-feature`). + + ```bash + ❯ cd Open-IM-Server + ❯ git fetch upstream + ❯ git checkout upstream/main + ``` + + Create a new branch: + + ```bash + ❯ git checkout -b + ``` + + Make any change on the `new-branch` then use [Makefile](./Makefile) build and test your codes. + +5. **Commit your changes** to your local branch, lint before committing and commit with sign-off + + ```bash + ❯ git rebase upstream/main + ❯ make lint # golangci-lint run -c .golangci.yml + ❯ git add -A # add changes to staging + ❯ git commit -a -s -m "message for your changes" # -s adds a Signed-off-by trailer + ``` + +6. **Push your branch** to your forked repository, it is recommended to have only one commit for a PR. + + ```bash + # sync up with upstream + ❯ git fetch upstream main + ❯ git rebase upstream/main + ❯ + ❯ git rebase -i # rebase with interactive mode to squash your commits into a single one + ❯ git push # push to the remote repository, if it's a first time push, run git push --set-upstream origin # sync up with upstream + ❯ git fetch upstream main + git rebase upstream/main + + ❯ git rebase -i # rebase with interactive mode to squash your commits into a single one + ❯ git push # push to the remote repository, if it's a first time push, run git push --set-upstream origin + ``` + + You can also use `git commit -s --amend && git push -f` to update modifications on the previous commit. + + If you have developed multiple features in the same branch, you should create PR separately by rebasing to the main branch between each push: + + ```bash + # create new branch, for example git checkout -b feature/infra + ❯ git checkout -b + # update some code, feature1 + ❯ git add -A + ❯ git commit -m -s "feat: feature one" + ❯ git push # if it's first time push, run git push --set-upstream origin + # then create pull request, and merge + # update some new feature, feature2, rebase main branch first. + ❯ git rebase upstream/main # rebase the current branch to upstream/main branch + ❯ git add -A + ❯ git commit -m -s "feat: feature two" + # then create pull request, and merge + ``` + +7. **Open a pull request** to `OpenIMSDK/Open-IM-Server:main` + + It is recommended to review your changes before filing a pull request. Check if your code doesn't conflict with the main branch and no redundant code is included. + +## Style and Specification + +We divide the problem into security and general problems: + +#### Reporting security issues + +Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of Open-IM-Server, please do not discuss it in public and even do not open a public issue. + +Instead we encourage you to send us a private email to winxu81@gmail.com to report this. + +#### Reporting general issues + +To be honest, we regard every user of Open-IM-Serveras a very kind contributor. After experiencing Open-IM-Server, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/openimsdk/Open-IM-Server/issues/new/choose). + +Since we collaborate project Open-IM-Server in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. + +To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](https://github.com/openimsdk/.github/tree/main/.github/ISSUE_TEMPLATE) for issue reporters. You can find three kinds of issue templates there: question, bug report and feature request. Please **BE SURE** to follow the instructions to fill fields in template. + +**There are a lot of cases when you could open an issue:** + +- bug report +- feature request +- Open-IM-Server performance issues +- feature proposal +- feature design +- help wanted +- doc incomplete +- test improvement +- any questions on Open-IM-Server project +- and so on + +Also, we must be reminded when submitting a new question about Open-IM-Server, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. + +#### Commit Rules + +Actually in Open-IM-Server, we take two rules serious when committing: + +**🥇 Commit Message:** + +Commit message could help reviewers better understand what the purpose of submitted PR is. It could help accelerate the code review procedure as well. We encourage contributors to use **EXPLICIT** commit message rather than ambiguous message. In general, we advocate the following commit message type: + +We use [Semantic Commits](https://www.conventionalcommits.org/en/v1.0.0/) to make it easier to understand what a commit does and to build pretty changelogs. Please use the following prefixes for your commits: + +- `docs: xxxx`. For example, "docs: add docs about storage installation". +- `feature: xxxx`.For example, "feature: make result show in sorted order". +- `bugfix: xxxx`. For example, "bugfix: fix panic when input nil parameter". +- `style: xxxx`. For example, "style: format the code style of Constants.java". +- `refactor: xxxx.` For example, "refactor: simplify to make codes more readable". +- `test: xxx`. For example, "test: add unit test case for func InsertIntoArray". +- `chore: xxx.` For example, "chore: integrate travis-ci". It's the type of mantainance change. +- other readable and explicit expression ways. + +On the other side, we discourage contributors from committing message like the following ways: + +- ~~fix bug~~ +- ~~update~~ +- ~~add doc~~ + +**🥈 Commit Content:** + +Commit content represents all content changes included in one commit. We had better include things in one single commit which could support reviewer's complete review without any other commits' help. + +In another word, contents in one single commit can pass the CI to avoid code mess. In brief, there are two minor rules for us to keep in mind: + +1. avoid very large change in a commit. +2. complete and reviewable for each commit. +3. words are written in lowercase English, not uppercase English or other languages such as Chinese. + +No matter what the commit message, or commit content is, we do take more emphasis on code review. + +An example for this could be: + +```bash +❯ git commit -a -s -m "docs: add a new section to the README" +``` + +#### PR Description + +PR is the only way to make change to Open-IM-Server project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](https://github.com/openimsdk/.github/tree/main/.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request. + +You can find some very formal PR in [RFC](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+is%3Aopen+RFC+label%3ARFC) issues and learn about them. + +**📖 Opening PRs:** + +- As long as you are working on your PR, please mark it as a draft +- Please make sure that your PR is up-to-date with the latest changes in `main` +- Mention the issue that your PR is addressing (Fix: #{ID_1}, #{ID_2}) +- Make sure that your PR passes all checks + +**🈴 Reviewing PRs:** + +- Be respectful and constructive +- Assign yourself to the PR +- Check if all checks are passing +- Suggest changes instead of simply commenting on found issues +- If you are unsure about something, ask the author +- If you are not sure if the changes work, try them out +- Reach out to other reviewers if you are unsure about something +- If you are happy with the changes, approve the PR +- Merge the PR once it has all approvals and the checks are passing + +**⚠️ DCO check:** + +We have a DCO check that runs on every pull request to ensure code quality and maintainability. This check verifies that the commit has been signed off, indicating that you have read and agreed to the provisions of the Developer Certificate of Origin. If you have not yet signed off on the commit, you can use the following command to sign off on the last commit you made: + +```bash +❯ git commit --amend --signoff +``` + +Please note that signing off on a commit is a commitment that you have read and agreed to the provisions of the Developer Certificate of Origin. If you have not yet read this document, we strongly recommend that you take some time to read it carefully. If you have any questions about the content of this document, or if you need further assistance, please contact an administrator or relevant personnel. + +You can also automate signing off your commits by adding the following to your `.zshrc` or `.bashrc`: + +```go +git() { + if [ $# -gt 0 ] && [[ "$1" == "commit" ]] ; then + shift + command git commit --signoff "$@" + else + command git "$@" + fi +} +``` + +#### Docs Contribution + +The documentation for Open-IM-Server includes: + +- [README.md](https://github.com/openimsdk/Open-IM-Server/blob/main/README.md): This file includes the basic information and instructions for getting started with Open-IM-Server. +- [CONTRIBUTING.md](https://github.com/openimsdk/Open-IM-Server/blob/main/CONTRIBUTING.md): This file contains guidelines for contributing to Open-IM-Server's codebase, such as how to submit issues, pull requests, and code reviews. +- [Official Documentation](https://doc.rentsoft.cn/): This is the official documentation for Open-IM-Server, which includes comprehensive information on all of its features, configuration options, and troubleshooting tips. + +Please obey the following rules to better format the docs, which would greatly improve the reading experience. + +1. Please do not use Chinese punctuations in English docs, and vice versa. +2. Please use upper case letters where applicable, like the first letter of sentences / headings, etc. +3. Please specify a language for each Markdown code blocks, unless there's no associated languages. +4. Please insert a whitespace between Chinese and English words. +5. Please use the correct case for technical terms, such as using `HTTP` instead of http, `MySQL` rather than mysql, `Kubernetes` instead of kubernetes, etc. +6. Please check if there's any typos in the docs before submitting PRs. + +## Engage to help anything + +We choose GitHub as the primary place for Open-IM-Server to collaborate. So the latest updates of Open-IM-Server are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. + +- reply to other's [issues](https://github.com/openimsdk/Open-IM-Server/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) if you could; +- help solve other user's problems; +- help review other's [PR](https://github.com/openimsdk/Open-IM-Server/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) design; +- discuss about Open-IM-Server to make things clearer; +- advocate [Open-IM-Server](https://google.com/search?q=Open-IM-Server) technology beyond GitHub; +- write blogs on Open-IM-Server and so on. + +In a word, **ANY HELP IS CONTRIBUTION.** + +## Release version + +Releases of Open-IM-Server are done using [Release Please](https://github.com/googleapis/release-please) and [GoReleaser](https://goreleaser.com/). The workflow looks like this: + +🎯 A PR is merged to the `main` branch: + +- Release please is triggered, creates or updates a new release PR +- This is done with every merge to main, the current release PR is updated every time + +🎯 Merging the 'release please' PR to `main`: + +- Release please is triggered, creates a new release and updates the changelog based on the commit messages +- GoReleaser is triggered, builds the binaries and attaches them to the release +- Containers are created and pushed to the container registry + +With the next relevant merge, a new release PR will be created and the process starts again + +**👀 Manually setting the version:** + +If you want to manually set the version, you can create a PR with an empty commit message that contains the version number in the commit message. For example: + +Such a commit can get produced as follows: + +```bash +❯ git commit --allow-empty -m "chore: release 0.0.3" -m "Release-As: 0.0.3 +``` + +## Contact Us + +We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. + +Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server. + +In addition to Slack, we also offer the following ways to get in touch: + +- : We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) team channel. +- : Get in touch with us on [Gmail](winxu81@gmail.com). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email. +- : Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information. +- : Add [Wechat](https://github.com/openimsdk/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible. + +Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dd10380 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +# Use Go 1.21 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Define the base directory for the application as an environment variable +ENV SERVER_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $SERVER_DIR + +# Set the Go proxy to improve dependency resolution speed +# ENV GOPROXY=https://goproxy.io,direct + +COPY go.mod go.sum ./ + +RUN go mod download + +# Copy all files from the current directory into the container +COPY . . + + +# Install Mage to use for building the application +RUN go install github.com/magefile/mage@v1.15.0 + +# Optionally build your application if needed +RUN mage build + +# Using Alpine Linux with Go environment for the final image +FROM golang:1.22-alpine + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV SERVER_DIR=/openim-chat +WORKDIR $SERVER_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $SERVER_DIR/_output $SERVER_DIR/_output +COPY --from=builder $SERVER_DIR/config $SERVER_DIR/config +COPY --from=builder /go/bin/mage /usr/local/bin/mage +COPY --from=builder $SERVER_DIR/magefile_windows.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/magefile_unix.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/magefile.go $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/start-config.yml $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/go.mod $SERVER_DIR/ +COPY --from=builder $SERVER_DIR/go.sum $SERVER_DIR/ + +RUN go get github.com/openimsdk/gomake@v0.0.14-alpha.5 + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] diff --git a/HOW_TO_ADD_REST_RPC_API.md b/HOW_TO_ADD_REST_RPC_API.md new file mode 100644 index 0000000..05cf942 --- /dev/null +++ b/HOW_TO_ADD_REST_RPC_API.md @@ -0,0 +1,157 @@ +# How to add REST RPC API for OpenIM Chat +
+ +OpenIM Chat server works with the OpenIM Server to offer the powerfull IM service. It has many REST APIs which are called by the OpenIM Server, works as an Application Server to fullfill your system demands. + +You can add your business extensions to the OpenIM Chat server by adding REST APIs and let the OpenIM Server call these extend APIs to fulfill your system demands. The following will show you how to add a REST API for it. + +## Protobuf source file modifications + +First, your should add the REST API request and response message declarations, and RPC method declarations to the '.proto' protobuf source code, then call 'protoc' command to generate '.pb.go' go protobuf implementation codes. + +For example, to add a REST API to generate login token for video meeting, you may want to add a request message named GetTokenForVideoMeetingReq and a response message named GetTokenForVideoMeetingResp. This can be done by adding this two messages to '/pkg/proto/chat/chat.proto'. You also should add a RPC method named GetTokenForVideoMeeting() fors the chat service. + +### chat.proto: + +```proto +syntax = "proto3"; +package OpenIMChat.chat; +import "pub/wrapperspb.proto"; +import "pub/sdkws.proto"; +import "common/common.proto"; +option go_package = "git.imall.cloud/openim/chat/pkg/protocol/chat"; + +... + +message GetTokenForVideoMeetingReq { + string room = 1; + string identity = 2; +} + +message GetTokenForVideoMeetingResp { + string serverUrl = 1; + string token = 2; +} + +service chat { + ... + // Audio/video call and video meeting + rpc GetTokenForVideoMeeting(GetTokenForVideoMeetingReq) returns (GetTokenForVideoMeetingResp); +} +``` + +## Generate protobuf implementations +
+ +Then, we start a terminal to run 'pkg/proto/gen.sh' shell script, which will call protoc command to regenerate chat.pb.go with protobuf implementation codes for your add messages. + + +## Add Check() method for the request message +
+ +To check the parameters in the request message, we should add a Check() method for newly added Request message. Take chat.proto as an example, we add the a Check() member method for GetTokenForVideoMeetingReq class in 'pkg/proto/chat/chat.go'. + +```go +func (x *GetTokenForVideoMeetingReq) Check() error { + if x.Room == "" { + errs.ErrArgs.WrapMsg("Room is empty") + } + if x.Identity == "" { + errs.ErrArgs.WrapMsg("User Identity is empty") + } + return nil +} +``` + + +## Add the URL for REST RPC API +
+ +Now, we should add a URL for REST RPC API. + +For example, to add a REST API to generate login token for video meeting, you may want to add a RPC API named 'get_token', which is a member of the 'user' group, the REST URL can be '/user/rtc/get_token'. + +This URL should be add to NewChatRoute() method in 'internal/api/router.go'. + +```go +func NewChatRoute(router gin.IRouter, discov discoveryregistry.SvcDiscoveryRegistry) { + ... + + user := router.Group("/user", mw.CheckToken) + user.POST("/update", chat.UpdateUserInfo) // Edit personal information + user.POST("/find/public", chat.FindUserPublicInfo) // Get user's public information + user.POST("/find/full", chat.FindUserFullInfo) // Get all information of the user + user.POST("/search/full", chat.SearchUserFullInfo) // Search user's public information + user.POST("/search/public", chat.SearchUserPublicInfo) // Search all information of the user + + // your added code begins here + user.POST("/rtc/get_token", chat.GetTokenForVideoMeeting) // Get token for video meeting + + ... +} +``` + +## Implement the REST service + +### Implement the REST Service Api + +We add REST RPC API implementation to the corresponding service implementation go file located in '/internal/api/'. For the chat service, we add codes to '/internal/api/chat.go'. + +```go +... +func (o *ChatApi) GetTokenForVideoMeeting(c *gin.Context) +{ + a2r.Call(chat.ChatClient.GetTokenForVideoMeeting, o.chatClient, c) +} +... +``` + +### Implement the REST Service logic + +We implement the REST Service logic in go files of the path '/internal/rpc/service_name/group_name.go'. For the user group of chat service, the implementation logic should be added to '/internal/rpc/chat/user.go'. + +Here we call the GetLiveKitServerUrl() and GetLiveKitToken() func in the rtc package to allocate a new GetTokenForVideoMeetingResp message and return it to the RPC caller. + +```go +package chat + +import ( + ... + "git.imall.cloud/openim/chat/pkg/common/rtc" + ... +) + +... + +func (o *chatSvr) GetTokenForVideoMeeting(ctx context.Context, req *chat.GetTokenForVideoMeetingReq) (*chat.GetTokenForVideoMeetingResp, error) +{ + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + serverUrl := rtc.GetLiveKitServerUrl() + token, err := rtc.GetLiveKitToken(req.Room, req.Identity) + if err != nil { + return nil, err + } + return &chat.GetTokenForVideoMeetingResp{ + ServerUrl: serverUrl, + Token: token, + }, err +} +``` + +## Done + +Now we have finished all the works to add an REST RPC API for OpenIM Chat. We may call + +```shell +make build +``` +to re-compile the chat project and call + +```shell +make start +``` +to start the OpenIM Chat server and test the chat service's new REST RPC API. + +### \ No newline at end of file diff --git a/HOW_TO_SETUP_LIVEKIT_SERVER.md b/HOW_TO_SETUP_LIVEKIT_SERVER.md new file mode 100644 index 0000000..511f19c --- /dev/null +++ b/HOW_TO_SETUP_LIVEKIT_SERVER.md @@ -0,0 +1,57 @@ +# Setting Up LiveKit Server for OpenIM Chat + +OpenIM Chat uses the LiveKit server as the media server to support video calls and video meeting services. + +## About LiveKit + +[LiveKit](https://github.com/livekit/livekit-server) is an open-source WebRTC SFU written in Go, built on top of the excellent [Pion](https://github.com/pion) project. For more information, visit the [LiveKit website](https://livekit.io/). + +## Quick Start + +To self-host LiveKit, start the server with the following Docker command: +> replace `your-server-ip` with your server IP address + +```bash +docker run -d \ + -p 7880:7880 \ + -p 7881:7881 \ + -p 7882:7882/udp \ + -v $PWD/livekit/livekit.yaml:/livekit.yaml \ + livekit/livekit-server \ + --config /livekit.yaml \ + --bind 0.0.0.0 \ + --node-ip=your-server-ip +``` + +## Viewing Logs + +To check the server logs and ensure everything is running correctly, use the following command: + +```bash +docker logs livekit/livekit-server +``` + +## Configuring the LiveKit Address in OpenIM Chat + +- **If Chat is deployed from source code**, update the `config/chat-rpc-chat.yml` file to configure the LiveKit server address: + +```yaml +liveKit: + url: "ws://127.0.0.1:7880" # ws://your-server-ip:7880 or wss://your-domain/path +``` + +- **If Chat is deployed via Docker**, add the following environment variable to the `docker-compose.yaml` file: + +```yaml +CHATENV_CHAT_RPC_CHAT_LIVEKIT_URL="ws://your-server-ip:7880" # or wss://your-domain/path +``` + +Open the following ports: TCP: 7880-7881, UDP: 7882, and UDP: 50000-60000. + +By following these steps, you can set up and configure the LiveKit server for use with OpenIM Chat. + + + +## More about Deploying LiveKi + +For detailed instructions on deploying LiveKit, refer to the self-hosting [deployment documentation](https://docs.livekit.io/realtime/self-hosting/deployment/). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index e69de29..d791c57 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,89 @@ +# openim-chat + +## 🧩 Feature Overview + +1. This repository implements a business system, which consists of two parts: User System and Backend Management System. +2. The system relies on the [chat-deploy repository](https://github.com/openimsdk/chat-deploy) and implements various business functions by calling the APIs of the instant messaging system. +3. The User System includes regular functions such as user login, user registration, user information update, etc. +4. The Backend Management System includes APIs for managing users, groups, and messages. + +## :busts_in_silhouette: Community + +- 💬 [Follow our Twitter account](https://twitter.com/founder_im63606) +- 🚀 [Join our Slack community](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) +- :eyes: [Join our WeChat group](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## 🛫 Quick Start + +> :warning: **Note**: This project works on Linux/Windows/Mac platforms and both ARM and AMD architectures. + +### 📦 Clone + +```bash +git clone https://git.imall.cloud/openim/chat openim-chat +cd openim-chat +``` + +### 🛠 Initialization + +:computer: Before the first compilation, execute on Linux/Mac platforms: + +``` +sh bootstrap.sh +``` + +:computer: On Windows execute: + +``` +bootstrap.bat +``` + +### 🏗 Build + +```bash +mage +``` + +### 🚀 Start + +```bash +mage start +``` + +### :floppy_disk: Or start in the background and collect logs + +``` +nohup mage start >> _output/logs/chat.log 2>&1 & +``` + +### :mag_right: Check + +```bash +mage check +``` + +### 🛑 Stop + +```bash +mage stop +``` + +### 🚀 Start Sequence + +1. Successfully start [chat-deploy](https://github.com/openimsdk/chat-deploy). +2. Compile chat `mage`. +3. Start chat `mage start`. + +## 📞 If you want to enable audio and video calls, please configure LiveKit + +:link: Please refer to "[How to set up LiveKit server](./HOW_TO_SETUP_LIVEKIT_SERVER.md)". + +## :handshake: Contributing + +:heart: Contributions to this project are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for details. + +## 🚨 License + +This software is licensed under the Apache License 2.0 + + diff --git a/README_zh_CN.md b/README_zh_CN.md new file mode 100644 index 0000000..edb0167 --- /dev/null +++ b/README_zh_CN.md @@ -0,0 +1,89 @@ +# openim-chat + + + +## 🧩 功能简介 + +1. 该仓库实现了业务系统,包括两部分:用户系统和后台管理系统。 +2. 该系统依赖于 [chat-deploy 仓库](https://github.com/openimsdk/chat-deploy),通过调用即时消息系统的 API 实现丰富的业务功能。 +3. 用户系统包括一些常规功能,如用户登录、用户注册、用户信息更新等。 +4. 后台管理系统包括提供了 API 管理用户、群组和消息等。 + +## :busts_in_silhouette: 社区 + +- 💬 [关注我们的 Twitter 账户](https://twitter.com/founder_im63606) +- 🚀 [加入我们的 Slack 社区](https://join.slack.com/t/openimsdk/shared_invite/zt-2ijy1ys1f-O0aEDCr7ExRZ7mwsHAVg9A) +- :eyes: [加入我们的微信群](https://openim-1253691595.cos.ap-nanjing.myqcloud.com/WechatIMG20.jpeg) + +## 🛫 快速开始 + +> :warning: **注意**:本项目在 Linux/Windows/Mac 平台以及 ARM 和 AMD 架构下均可正常使用 + +### 📦 克隆 + +```bash +git clone https://git.imall.cloud/openim/chat openim-chat +cd openim-chat +``` + +### 🛠 初始化 + +:computer: 第一次编译前,Linux/Mac 平台下执行: + +``` +sh bootstrap.sh +``` + +:computer: Windows 执行: + +``` +bootstrap.bat +``` + +### 🏗 编译 + +```bash +mage +``` + +### 🚀 启动 + +```bash +mage start +``` + +### :floppy_disk: 或后台启动 收集日志 + +``` +nohup mage start >> _output/logs/chat.log 2>&1 & +``` + +### :mag_right: 检测 + +```bash +mage check +``` + +### 🛑 停止 + +```bash +mage stop +``` + +### 🚀 启动顺序 + +1. 成功启动 [chat-deploy](https://github.com/openimsdk/chat-deploy)。 +2. 编译 chat `mage`。 +3. 启动 chat `mage start`。 + +## 📞 如果您想启用音视频通话,请配置 LiveKit + +:link: 请参考 "[如何设置 LiveKit 服务器](./HOW_TO_SETUP_LIVEKIT_SERVER.md)"。 + +## :handshake: 贡献 + +:heart: 欢迎对该项目做出贡献!请查看 [CONTRIBUTING.md](./CONTRIBUTING.md) 了解详情。 + +## 🚨 许可 + +This software is licensed under the Apache License 2.0 diff --git a/bootstrap.bat b/bootstrap.bat new file mode 100644 index 0000000..819f19c --- /dev/null +++ b/bootstrap.bat @@ -0,0 +1,31 @@ +@echo off +SETLOCAL + +mage -version >nul 2>&1 +IF %ERRORLEVEL% EQU 0 ( + echo Mage is already installed. + GOTO DOWNLOAD +) + +go version >nul 2>&1 +IF NOT %ERRORLEVEL% EQU 0 ( + echo Go is not installed. Please install Go and try again. + exit /b 1 +) + +echo Installing Mage... +go install github.com/magefile/mage@latest + +mage -version >nul 2>&1 +IF NOT %ERRORLEVEL% EQU 0 ( + echo Mage installation failed. + echo Please ensure that %GOPATH%/bin is in your PATH. + exit /b 1 +) + +echo Mage installed successfully. + +:DOWNLOAD +go mod download + +ENDLOCAL diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..f79cd1f --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [[ ":$PATH:" == *":$HOME/.local/bin:"* ]]; then + TARGET_DIR="$HOME/.local/bin" +else + TARGET_DIR="/usr/local/bin" + echo "Using /usr/local/bin as the installation directory. Might require sudo permissions." +fi + +if ! command -v mage &> /dev/null; then + echo "Installing Mage to $TARGET_DIR ..." + GOBIN=$TARGET_DIR go install github.com/magefile/mage@latest +fi + +if ! command -v mage &> /dev/null; then + echo "Mage installation failed." + echo "Please ensure that $TARGET_DIR is in your \$PATH." + exit 1 +fi + +echo "Mage installed successfully." + +go mod download diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..edd419a --- /dev/null +++ b/build/README.md @@ -0,0 +1,65 @@ +# Building OpenIM + +Building OpenIM is easy if you take advantage of the containerized build environment. This document will help guide you through understanding this build process. + +## Requirements + +1. Docker, using one of the following configurations: + * **macOS** Install Docker for Mac. See installation instructions [here](https://docs.docker.com/docker-for-mac/). + **Note**: You will want to set the Docker VM to have at least 4GB of initial memory or building will likely fail. + * **Linux with local Docker** Install Docker according to the [instructions](https://docs.docker.com/installation/#installation) for your OS. + * **Windows with Docker Desktop WSL2 backend** Install Docker according to the [instructions](https://docs.docker.com/docker-for-windows/wsl-tech-preview/). Be sure to store your sources in the local Linux file system, not the Windows remote mount at `/mnt/c`. + + **Note**: You will need to check if Docker CLI plugin buildx is properly installed (`docker-buildx` file should be present in `~/.docker/cli-plugins`). You can install buildx according to the [instructions](https://github.com/docker/buildx/blob/master/README.md#installing). + +2. **Optional** [Google Cloud SDK](https://developers.google.com/cloud/sdk/) + +You must install and configure Google Cloud SDK if you want to upload your release to Google Cloud Storage and may safely omit this otherwise. + +## Actions + +About [Images packages](https://github.com/orgs/OpenIMSDK/packages?repo_name=Open-IM-Server) + +All files in the `build/images` directory are not templated and are instead rendered by Github Actions, which is an automated process. + +Trigger condition: +1. create a new tag with the format `vX.Y.Z` (e.g. `v1.0.0`) +2. push the tag to the remote repository +3. wait for the build to finish +4. download the artifacts from the release page + +## Make images + +**help info:** + +```bash +$ make image.help +``` + +**build images:** + +```bash +$ make image +``` + +## Overview + +While it is possible to build OpenIM using a local golang installation, we have a build process that runs in a Docker container. This simplifies initial set up and provides for a very consistent build and test environment. + + +## Basic Flow + +The scripts directly under [`build/`](.) are used to build and test. They will ensure that the `openim-build` Docker image is built (based on [`build/build-image/Dockerfile`](../Dockerfile) and after base image's `OPENIM_BUILD_IMAGE_CROSS_TAG` from Dockerfile is replaced with one of those actual tags of the base image, like `v1.13.9-2`) and then execute the appropriate command in that container. These scripts will both ensure that the right data is cached from run to run for incremental builds and will copy the results back out of the container. You can specify a different registry/name and version for `openim-cross` by setting `OPENIM_CROSS_IMAGE` and `OPENIM_CROSS_VERSION`, see [`common.sh`](common.sh) for more details. + +The `openim-build` container image is built by first creating a "context" directory in `_output/images/build-image`. It is done there instead of at the root of the OpenIM repo to minimize the amount of data we need to package up when building the image. + +There are 3 different containers instances that are run from this image. The first is a "data" container to store all data that needs to persist across to support incremental builds. Next there is an "rsync" container that is used to transfer data in and out to the data container. Lastly there is a "build" container that is used for actually doing build actions. The data container persists across runs while the rsync and build containers are deleted after each use. + +`rsync` is used transparently behind the scenes to efficiently move data in and out of the container. This will use an ephemeral port picked by Docker. You can modify this by setting the `OPENIM_RSYNC_PORT` env variable. + +All Docker names are suffixed with a hash derived from the file path (to allow concurrent usage on things like CI machines) and a version number. When the version number changes all state is cleared and clean build is started. This allows the build infrastructure to be changed and signal to CI systems that old artifacts need to be deleted. + +## Build artifacts +The build system output all its products to a top level directory in the source repository named `_output`. +These include the binary compiled packages (e.g. imctl, openim-api etc.) and archived Docker images. +If you intend to run a component with a docker image you will need to import it from this directory with diff --git a/build/images/Dockerfile b/build/images/Dockerfile new file mode 100644 index 0000000..2b78e8a --- /dev/null +++ b/build/images/Dockerfile @@ -0,0 +1,24 @@ +# Copyright © 2023 OpenIM open source community. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM BASE_IMAGE + +WORKDIR ${SERVER_WORKDIR} + +# Set HTTP proxy +ARG BINARY_NAME + +COPY BINARY_NAME ./bin/BINARY_NAME + +ENTRYPOINT ["./bin/BINARY_NAME"] \ No newline at end of file diff --git a/build/images/openim-admin-api/Dockerfile b/build/images/openim-admin-api/Dockerfile new file mode 100644 index 0000000..2d71a7d --- /dev/null +++ b/build/images/openim-admin-api/Dockerfile @@ -0,0 +1,39 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Install git for repository access +RUN apk add --no-cache git ca-certificates + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Copy protocol directory +COPY protocol /protocol + +# Copy current directory +COPY . . + +# Use container's existing SSH configuration for private repositories +RUN go mod tidy +RUN go build -o _output/admin-api ./cmd/api/admin-api + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/admin-api"] \ No newline at end of file diff --git a/build/images/openim-admin-rpc/Dockerfile b/build/images/openim-admin-rpc/Dockerfile new file mode 100644 index 0000000..1293558 --- /dev/null +++ b/build/images/openim-admin-rpc/Dockerfile @@ -0,0 +1,39 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Install git for repository access +RUN apk add --no-cache git ca-certificates + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Copy protocol directory +COPY protocol /protocol + +# Copy current directory +COPY . . + +# Use container's existing SSH configuration for private repositories +RUN go mod tidy +RUN go build -o _output/admin-rpc ./cmd/rpc/admin-rpc + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/admin-rpc"] \ No newline at end of file diff --git a/build/images/openim-chat-api/Dockerfile b/build/images/openim-chat-api/Dockerfile new file mode 100644 index 0000000..6f8a028 --- /dev/null +++ b/build/images/openim-chat-api/Dockerfile @@ -0,0 +1,51 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Install git for repository access +RUN apk add --no-cache git ca-certificates + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Build arguments to invalidate cache when code changes +ARG BUILD_SHA +ARG BUILD_TIME +ENV BUILD_SHA=$BUILD_SHA +ENV BUILD_TIME=$BUILD_TIME + +# Copy protocol directory +COPY protocol /protocol + +# Copy go mod files first for better caching +COPY go.mod go.sum ./ + +# Download dependencies (this layer will be cached if go.mod/go.sum don't change) +RUN go mod download + +# Copy current directory (this will invalidate cache when code changes) +COPY . . + +# Use container's existing SSH configuration for private repositories +RUN go mod tidy +RUN go build -o _output/chat-api ./cmd/api/chat-api + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/chat-api"] \ No newline at end of file diff --git a/build/images/openim-chat-rpc/Dockerfile b/build/images/openim-chat-rpc/Dockerfile new file mode 100644 index 0000000..1305d09 --- /dev/null +++ b/build/images/openim-chat-rpc/Dockerfile @@ -0,0 +1,39 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Install git for repository access +RUN apk add --no-cache git ca-certificates + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Copy protocol directory +COPY protocol /protocol + +# Copy current directory +COPY . . + +# Use container's existing SSH configuration for private repositories +RUN go mod tidy +RUN go build -o _output/chat-rpc ./cmd/rpc/chat-rpc + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/chat-rpc"] \ No newline at end of file diff --git a/cmd/api/admin-api/main.go b/cmd/api/admin-api/main.go new file mode 100644 index 0000000..f117ba2 --- /dev/null +++ b/cmd/api/admin-api/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewAdminApiCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/api/bot-api/main.go b/cmd/api/bot-api/main.go new file mode 100644 index 0000000..4dde656 --- /dev/null +++ b/cmd/api/bot-api/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewBotApiCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/api/chat-api/main.go b/cmd/api/chat-api/main.go new file mode 100644 index 0000000..dd3074c --- /dev/null +++ b/cmd/api/chat-api/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewChatApiCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/rpc/admin-rpc/main.go b/cmd/rpc/admin-rpc/main.go new file mode 100644 index 0000000..c9b61e0 --- /dev/null +++ b/cmd/rpc/admin-rpc/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewAdminRpcCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/rpc/bot-rpc/main.go b/cmd/rpc/bot-rpc/main.go new file mode 100644 index 0000000..69e59dc --- /dev/null +++ b/cmd/rpc/bot-rpc/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewBotRpcCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/rpc/chat-rpc/main.go b/cmd/rpc/chat-rpc/main.go new file mode 100644 index 0000000..5147cd0 --- /dev/null +++ b/cmd/rpc/chat-rpc/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "git.imall.cloud/openim/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewChatRpcCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..089831b --- /dev/null +++ b/config/README.md @@ -0,0 +1,44 @@ +# OpenIM Chat Configuration Files and Common Configuration Item Modifications Guide + +## Configuration Files Explanation + +| Configuration File | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| **redis.yml** | Configurations for Redis password, address, etc. | +| **mongodb.yml** | Configurations for MongoDB username, password, address, etc. | +| **share.yml** | Common configurations needed by various OpenIM services, such as secret. | +| **discovery.yml** | Service discovery account, password, service name and other configurations. | +| **chat-api-chat.yml** | Configurations for listening IP, port, etc., in chat-api-chat service. | +| **chat-api-admin.yml** | Configurations for listening IP, port, etc., in chat-api-admin service. | +| **chat-rpc-chat.yml** | Configurations for listening IP, port, login registration verification code, registration allowance, and livekit in chat-rpc-chat service. | +| **chat-rpc-admin.yml** | Configurations for listening IP, port, chat backend token expiration policy, and chat backend Secret in chat-rpc-admin service. | + +## Common Configuration Item Modifications + +| Configuration Item to Modify | Configuration File | +| ----------------------------------------- | -------------------- | +| Modify OpenIM secret | `share.yml` | +| Production environment logs | `log.yml` | +| Modify chat Admin username and password | `share.yml` | +| Modify verification code | `chat-rpc-chat.yml` | +| Allow user registration | `chat-rpc-chat.yml` | +| Modify chat Admin token expiration policy | `chat-rpc-admin.yml` | +| Modify chat Admin Secret | `chat-rpc-admin.yml` | + +## Starting Multiple Instances of an OpenIM Service + +To launch multiple instances of an OpenIM service, you just need to increase the corresponding number of ports and modify the `start-config.yml` file in the project's root directory, then restart the service for the changes to take effect. For example, the configuration for launching 2 instances of `chat-rpc` is as follows: + +```yaml +rpc: + registerIP: "" + listenIP: 0.0.0.0 + ports: [30300, 30301] +``` + +Modify `start-config.yml`: + +```yaml +serviceBinaries: + chat-rpc: 2 +``` diff --git a/config/README_zh_CN.md b/config/README_zh_CN.md new file mode 100644 index 0000000..ecf66e9 --- /dev/null +++ b/config/README_zh_CN.md @@ -0,0 +1,45 @@ +# OpenIM Chat 配置文件说明以及常用配置修改说明 + +## 配置文件说明 + +| Configuration File | Description | +| ---------------------- | ----------------------------------------------------------------------------------------- | +| **redis.yml** | Redis 密码、地址等配置 | +| **mongodb.yml** | MongoDB 用户名、密码、地址等配置 | +| **log.yml** | 日志级别及存储目录等配置 | +| **share.yml** | OpenIM 各服务所需的公共配置,如 secret、Admin 后台密码等 | +| **discovery.yml** | 服务发现对应的账号密码和服务名等配置 | +| **chat-api-chat.yml** | chat-api-chat 服务的监听 IP、端口等配置 | +| **chat-api-admin.yml** | chat-api-admin 服务的监听 IP、端口等配置 | +| **chat-rpc-chat.yml** | chat-rpc-chat.yml 服务的监听 IP、端口以及登录注册验证码、是否允许注册和 livekit 等配置 | +| **chat-rpc-admin.yml** | chat-rpc-admin 服务的监听 IP、端口以及 chat 后台 token 过期策略和 chat 后台 Secret 等配置 | + +## 常用配置修改 + +| 修改配置项 | 配置文件 | +| ----------------------------- | -------------------- | +| 修改 OpenIM secret | `share.yml` | +| 生产环境日志调整 | `log.yml` | +| 修改 chat Admin | `share.yml` | +| 修改验证码相关配置 | `chat-rpc-chat.yml` | +| 允许用户注册 | `chat-rpc-chat.yml` | +| 修改 chat 后台 token 过期策略 | `chat-rpc-admin.yml` | +| 修改 chat 后台 Secret | `chat-rpc-admin.yml` | + +## 启动某个 OpenIM 服务的多个实例 + +若要启动某个 OpenIM 的多个实例,只需增加对应的端口数,并修改项目根目录下的`start-config.yml`文件,重启服务即可生效。例如,启动 2 个`chat-rpc`实例的配置如下: + +```yaml +rpc: + registerIP: "" + listenIP: 0.0.0.0 + ports: [30300, 30301] +``` + +Modify start-config.yml: + +```yaml +serviceBinaries: + chat-rpc: 2 +``` diff --git a/config/chat-api-admin.yml b/config/chat-api-admin.yml new file mode 100644 index 0000000..e03ee18 --- /dev/null +++ b/config/chat-api-admin.yml @@ -0,0 +1,6 @@ +api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10009 ] + diff --git a/config/chat-api-bot.yml b/config/chat-api-bot.yml new file mode 100644 index 0000000..cc401af --- /dev/null +++ b/config/chat-api-bot.yml @@ -0,0 +1,6 @@ +api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10010 ] + diff --git a/config/chat-api-chat.yml b/config/chat-api-chat.yml new file mode 100644 index 0000000..c563647 --- /dev/null +++ b/config/chat-api-chat.yml @@ -0,0 +1,6 @@ +api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10008 ] + diff --git a/config/chat-rpc-admin.yml b/config/chat-rpc-admin.yml new file mode 100644 index 0000000..7494356 --- /dev/null +++ b/config/chat-rpc-admin.yml @@ -0,0 +1,12 @@ +rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30200 ] + +tokenPolicy: + expire: 90 + +secret: chat123 \ No newline at end of file diff --git a/config/chat-rpc-bot.yml b/config/chat-rpc-bot.yml new file mode 100644 index 0000000..3d8d8c6 --- /dev/null +++ b/config/chat-rpc-bot.yml @@ -0,0 +1,10 @@ +rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30400 ] + +# Model request timeout. Unit: s +timeout: 20 diff --git a/config/chat-rpc-chat.yml b/config/chat-rpc-chat.yml new file mode 100644 index 0000000..a0ef445 --- /dev/null +++ b/config/chat-rpc-chat.yml @@ -0,0 +1,44 @@ +rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30300 ] + +verifyCode: + validTime: 300 + validCount: 5 + uintTime: 86400 + maxCount: 10 + superCode: "666666" + len: 6 + phone: + use: "superCode" # superCode: user superCode; ali: use ali verify code; bao: use bao verify code; + ali: + endpoint: "" + accessKeyId: "" + accessKeySecret: "" + signName: "" + verificationCodeTemplateCode: "" + bao: + endpoint: "http://127.0.0.1:18080" + accessKeyId: "local" + accessKeySecret: "local" + signName: "local" + verificationCodeTemplateCode: "" + mail: + use: "superCode" # superCode: user superCode; mail: use mail verify code; + title: "" + senderMail: "" + senderAuthorizationCode: "" + smtpAddr: "" + smtpPort: + +liveKit: + url: "ws://127.0.0.1:7880" # LIVEKIT_URL, LiveKit server address and port + key: "devkey" + secret: "devsecret" + +allowRegister: true +allowVerifyCodeLogin: false # 是否允许验证码登录,设置为false则隐藏验证码登录功能 diff --git a/config/discovery.yml b/config/discovery.yml new file mode 100644 index 0000000..5022a6a --- /dev/null +++ b/config/discovery.yml @@ -0,0 +1,14 @@ +enable: "etcd" +etcd: + rootDirectory: openim + address: [ localhost:12379 ] + username: '' + password: '' + +kubernetes: + namespace: default + +rpcService: + chat: chat-rpc-service + admin: admin-rpc-service + bot: bot-rpc-service diff --git a/config/log.yml b/config/log.yml new file mode 100644 index 0000000..443fa1e --- /dev/null +++ b/config/log.yml @@ -0,0 +1,14 @@ +# Log storage path, default is acceptable, change to a full path if modification is needed +storageLocation: ../../../../logs/ +# Log rotation period (in hours), default is acceptable +rotationTime: 24 +# Number of log files to retain, default is acceptable +remainRotationCount: 2 +# Log level settings: 3 for production environment; 6 for more verbose logging in debugging environments +remainLogLevel: 6 +# Whether to output to standard output, default is acceptable +isStdout: true +# Whether to log in JSON format, default is acceptable +isJson: false +# output simplify log when KeyAndValues's value len is bigger than 50 in rpc method log +isSimplify: true diff --git a/config/mongodb.yml b/config/mongodb.yml new file mode 100644 index 0000000..d3553ed --- /dev/null +++ b/config/mongodb.yml @@ -0,0 +1,16 @@ +# URI for database connection, leave empty if using address and credential settings directly +uri: "" +# List of MongoDB server addresses +address: [localhost:37017] +# Name of the database +database: openim_v3 +# Username for database authentication +username: openIM +# Password for database authentication +password: openIM123 +# Authentication source for database authentication, if use root user, set it to admin +authSource: openim_v3 +# Maximum number of connections in the connection pool +maxPoolSize: 100 +# Maximum number of retry attempts for a failed database connection +maxRetry: 10 diff --git a/config/redis.yml b/config/redis.yml new file mode 100644 index 0000000..27361ba --- /dev/null +++ b/config/redis.yml @@ -0,0 +1,14 @@ +# List of Redis server addresses +address: [ localhost:16379 ] +# Username for Redis authentication (leave blank if not used) +username: '' +# Password for Redis authentication +password: openIM123 +# Enable or disable pipeline processing +enablePipeline: false +# Enable or disable cluster mode +clusterMode: false +# Database index to be used +db: 0 +# Maximum number of retry attempts for a failed connection +maxRetry: 10 diff --git a/config/share.yml b/config/share.yml new file mode 100644 index 0000000..20ea77b --- /dev/null +++ b/config/share.yml @@ -0,0 +1,13 @@ +openIM: + # OpenIM API address + apiURL: http://127.0.0.1:10002 + # OpenIM secret key, must be consistent with OpenIM + secret: openIM123 + # OpenIM administrator userID, must be consistent with OpenIM + adminUserID: imAdmin + # Refresh OpenIM token interval + tokenRefreshInterval: 120 # unit: minute + +chatAdmin: + # Default username and password for the admin + - "chatAdmin" diff --git a/deployments/README.md b/deployments/README.md new file mode 100644 index 0000000..09b9e42 --- /dev/null +++ b/deployments/README.md @@ -0,0 +1,122 @@ +# OpenIM Chat Deployment + +## Preconditions + +- Ensure deployed OpenIM Server and its dependencies. + - Redis + - MongoDB + - Kafka + - MinIO +- Expose the corresponding Services and ports of OpenIM Server. + +## Deploy OpenIM Chat + +**Chat depends on OpenIM Server, so you need to deploy OpenIM Server first.** + +enter the target directory + +```shell +cd deployments/deploy +``` + +### Modify ConfigMap + +You need to modify the `chat-config.yml` file to match your environment. Focus on the following fields: +**discovery.yml** + +- `kubernetes.namespace`: default is `default`, you can change it to your namespace. + +**mongodb.yml** + +- `address`: set to your already mongodb address or mongo Service name and port in your deployed. +- `database`: set to your mongodb database name.(Need have a created database.) +- `authSource`: et to your mongodb authSource. (authSource is specify the database name associated with the user's credentials, user need create in this database.) + +**redis.yml** + +- `address`: set to your already redis address or redis Service name and port in your deployed. + +**share.yml** + +- `openIM.apiURL`: modify to your already API address or use your `openim-api` service name and port +- `openIM.secret`: same to IM Server `share.secret` value. + +### Set the secret + +A Secret is an object that contains a small amount of sensitive data. Such as password and secret. Secret is similar to ConfigMaps. + +#### Redis: + +Update the `redis-password` value in `redis-secret.yml` to your Redis password encoded in base64. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: openim-redis-secret +type: Opaque +data: + redis-password: b3BlbklNMTIz # update to your redis password encoded in base64, if need empty, you can set to "" +``` + +#### Mongo: + +Update the `mongo_openim_username`, `mongo_openim_password` value in `mongo-secret.yml` to your Mongo username and password encoded in base64. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: openim-mongo-secret +type: Opaque +data: + mongo_openim_username: b3BlbklN # update to your mongo username encoded in base64, if need empty, you can set to "" (this user credentials need in authSource database) + mongo_openim_password: b3BlbklNMTIz # update to your mongo password encoded in base64, if need empty, you can set to "" +``` + +### Apply the secret. + +```shell +kubectl apply -f redis-secret.yml -f mongo-secret.yml +``` + +### Apply Config and Services + +deploy the config and services + +```shell +kubectl apply -f chat-config.yml -f openim-admin-api-service.yml -f openim-chat-api-service.yml -f openim-admin-rpc-service.yml -f openim-chat-rpc-service.yml +``` + +### Start Chat Deployments + +```shell +kubectl apply -f openim-chat-api-deployment.yml -f openim-admin-api-deployment.yml -f openim-chat-rpc-deployment.yml -f openim-admin-rpc-deployment.yml +``` + +## Verify + +After the deployment is complete, you can verify the deployment status. + +```shell +# Check the status of all pods +kubectl get pods + +# Check the status of services +kubectl get svc + +# Check the status of deployments +kubectl get deployments + +# View all resources +kubectl get all + +``` + +## clean all + +`kubectl delete -f ./` + +## Notes: + +- If you use a specific namespace for your deployment, be sure to append the -n flag to your kubectl commands. diff --git a/deployments/deploy/chat-config.yml b/deployments/deploy/chat-config.yml new file mode 100644 index 0000000..330d691 --- /dev/null +++ b/deployments/deploy/chat-config.yml @@ -0,0 +1,148 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: openim-chat-config +data: + discovery.yml: | + enable: kubernetes + kubernetes: + namespace: default + etcd: + rootDirectory: openim + address: [ localhost:12379 ] + username: '' + password: '' + + rpcService: + chat: chat-rpc-service + admin: admin-rpc-service + + log.yml: | + # Log storage path, default is acceptable, change to a full path if modification is needed + # storageLocation: ../../../../logs/ + storageLocation: ./logs/ + # Log rotation period (in hours), default is acceptable + rotationTime: 24 + # Number of log files to retain, default is acceptable + remainRotationCount: 2 + # Log level settings: 3 for production environment; 6 for more verbose logging in debugging environments + remainLogLevel: 6 + # Whether to output to standard output, default is acceptable + isStdout: true + # Whether to log in JSON format, default is acceptable + isJson: false + # output simplify log when KeyAndValues's value len is bigger than 50 in rpc method log + isSimplify: true + + mongodb.yml: | + # URI for database connection, leave empty if using address and credential settings directly + uri: '' + # List of MongoDB server addresses + address: [ mongo-service:37017 ] + # Name of the database + database: openim_v3 + # Username for database authentication + username: openIM + # Password for database authentication + password: # openIM123 + # Authentication source for database authentication, if use root user, set it to admin + authSource: openim_v3 + # Maximum number of connections in the connection pool + maxPoolSize: 100 + # Maximum number of retry attempts for a failed database connection + maxRetry: 10 + + redis.yml: | + # List of Redis server addresses + address: [ redis-service:16379 ] + # Username for Redis authentication (leave blank if not used) + username: '' + # Password for Redis authentication + password: # openIM123 + # Enable or disable pipeline processing + enablePipeline: false + # Enable or disable cluster mode + clusterMode: false + # Database index to be used + db: 0 + # Maximum number of retry attempts for a failed connection + maxRetry: 10 + + share.yml: | + openIM: + # OpenIM API address + apiURL: http://openim-api-service:10002 + # OpenIM secret key, must be consistent with OpenIM + secret: openIM123 + # OpenIM administrator userID, must be consistent with OpenIM + adminUserID: imAdmin + + chatAdmin: + # Default username and password for the admin + - "chatAdmin" + + chat-api-admin.yml: | + api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10009 ] + + chat-rpc-admin.yml: | + rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30200 ] + + tokenPolicy: + expire: 90 + + secret: chat123 + chat-api-chat.yml: | + api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10008 ] + + chat-rpc-chat.yml: | + rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30300 ] + + verifyCode: + validTime: 300 + validCount: 5 + uintTime: 86400 + maxCount: 10 + superCode: "666666" + len: 6 + phone: + use: "" + ali: + endpoint: "" + accessKeyId: "" + accessKeySecret: "" + signName: "" + verificationCodeTemplateCode: "" + mail: + enable: false + title: "" + senderMail: "" + senderAuthorizationCode: "" + smtpAddr: "" + smtpPort: + + liveKit: + url: "ws://127.0.0.1:7880" # LIVEKIT_URL, LiveKit server address and port + key: "APIGPW3gnFTzqHH" + secret: "23ztfSqsfQ8hKkHzHTl3Z4bvaxro0snjk5jwbp5p6Q3" + + allowRegister: true diff --git a/deployments/deploy/mongo-secret.yml b/deployments/deploy/mongo-secret.yml new file mode 100644 index 0000000..c3c10af --- /dev/null +++ b/deployments/deploy/mongo-secret.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openim-mongo-secret +type: Opaque +data: + mongo_openim_username: b3BlbklN # base64 for "openIM", this user credentials need in authSource database. + mongo_openim_password: b3BlbklNMTIz # base64 for "openIM123" diff --git a/deployments/deploy/openim-admin-api-deployment.yml b/deployments/deploy/openim-admin-api-deployment.yml new file mode 100644 index 0000000..74be145 --- /dev/null +++ b/deployments/deploy/openim-admin-api-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-api-server + template: + metadata: + labels: + app: admin-api-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-admin-api-container + image: mag1666888/openim-admin-api:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10009 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-admin-api-service.yml b/deployments/deploy/openim-admin-api-service.yml new file mode 100644 index 0000000..dcb723b --- /dev/null +++ b/deployments/deploy/openim-admin-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-api-service +spec: + selector: + app: admin-api-server + ports: + - name: http-10009 + protocol: TCP + port: 10009 + targetPort: 10009 + type: NodePort diff --git a/deployments/deploy/openim-admin-rpc-deployment.yml b/deployments/deploy/openim-admin-rpc-deployment.yml new file mode 100644 index 0000000..f9f5a15 --- /dev/null +++ b/deployments/deploy/openim-admin-rpc-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-rpc-server + template: + metadata: + labels: + app: admin-rpc-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-admin-rpc-container + image: mag1666888/openim-admin-rpc:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30200 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-admin-rpc-service.yml b/deployments/deploy/openim-admin-rpc-service.yml new file mode 100644 index 0000000..100e431 --- /dev/null +++ b/deployments/deploy/openim-admin-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-rpc-service +spec: + selector: + app: admin-rpc-server + ports: + - name: rpc-30200 + protocol: TCP + port: 30200 + targetPort: 30200 + type: ClusterIP diff --git a/deployments/deploy/openim-chat-api-deployment.yml b/deployments/deploy/openim-chat-api-deployment.yml new file mode 100644 index 0000000..557081f --- /dev/null +++ b/deployments/deploy/openim-chat-api-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-api-server + template: + metadata: + labels: + app: chat-api-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-chat-api-container + image: mag1666888/openim-chat-api:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10008 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-chat-api-service.yml b/deployments/deploy/openim-chat-api-service.yml new file mode 100644 index 0000000..43a777e --- /dev/null +++ b/deployments/deploy/openim-chat-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-api-service +spec: + selector: + app: chat-api-server + ports: + - name: http-10008 + protocol: TCP + port: 10008 + targetPort: 10008 + type: NodePort diff --git a/deployments/deploy/openim-chat-rpc-deployment.yml b/deployments/deploy/openim-chat-rpc-deployment.yml new file mode 100644 index 0000000..c85ab86 --- /dev/null +++ b/deployments/deploy/openim-chat-rpc-deployment.yml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-rpc-server + template: + metadata: + labels: + app: chat-rpc-server + spec: + imagePullSecrets: + - name: dockerhub-secret + containers: + - name: openim-chat-rpc-container + image: mag1666888/openim-chat-rpc:prod + imagePullPolicy: Always + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: openim-redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30300 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-chat-rpc-service.yml b/deployments/deploy/openim-chat-rpc-service.yml new file mode 100644 index 0000000..e245e45 --- /dev/null +++ b/deployments/deploy/openim-chat-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-rpc-service +spec: + selector: + app: chat-rpc-server + ports: + - name: rpc-30300 + protocol: TCP + port: 30300 + targetPort: 30300 + type: ClusterIP diff --git a/deployments/deploy/redis-secret.yml b/deployments/deploy/redis-secret.yml new file mode 100644 index 0000000..463ec95 --- /dev/null +++ b/deployments/deploy/redis-secret.yml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openim-redis-secret +type: Opaque +data: + redis-password: b3BlbklNMTIz # "openIM123" in base64 diff --git a/docs/.generated_docs b/docs/.generated_docs new file mode 100644 index 0000000..4145ed5 --- /dev/null +++ b/docs/.generated_docs @@ -0,0 +1,84 @@ +docs/.generated_docs +docs/guide/en-US/cmd/iam-apiserver.md +docs/guide/en-US/cmd/iam-authz-server.md +docs/guide/en-US/cmd/iam-pump.md +docs/guide/en-US/cmd/iam-watcher.md +docs/guide/en-US/cmd/openim/openim.md +docs/guide/en-US/cmd/openim/openim_color.md +docs/guide/en-US/cmd/openim/openim_completion.md +docs/guide/en-US/cmd/openim/openim_info.md +docs/guide/en-US/cmd/openim/openim_jwt.md +docs/guide/en-US/cmd/openim/openim_jwt_show.md +docs/guide/en-US/cmd/openim/openim_jwt_sign.md +docs/guide/en-US/cmd/openim/openim_jwt_verify.md +docs/guide/en-US/cmd/openim/openim_new.md +docs/guide/en-US/cmd/openim/openim_options.md +docs/guide/en-US/cmd/openim/openim_policy.md +docs/guide/en-US/cmd/openim/openim_policy_create.md +docs/guide/en-US/cmd/openim/openim_policy_delete.md +docs/guide/en-US/cmd/openim/openim_policy_get.md +docs/guide/en-US/cmd/openim/openim_policy_list.md +docs/guide/en-US/cmd/openim/openim_policy_update.md +docs/guide/en-US/cmd/openim/openim_secret.md +docs/guide/en-US/cmd/openim/openim_secret_create.md +docs/guide/en-US/cmd/openim/openim_secret_delete.md +docs/guide/en-US/cmd/openim/openim_secret_get.md +docs/guide/en-US/cmd/openim/openim_secret_list.md +docs/guide/en-US/cmd/openim/openim_secret_update.md +docs/guide/en-US/cmd/openim/openim_set.md +docs/guide/en-US/cmd/openim/openim-rpc-user.md +docs/guide/en-US/cmd/openim/openim-rpc-user_create.md +docs/guide/en-US/cmd/openim/openim-rpc-user_delete.md +docs/guide/en-US/cmd/openim/openim-rpc-user_get.md +docs/guide/en-US/cmd/openim/openim-rpc-user_list.md +docs/guide/en-US/cmd/openim/openim-rpc-user_update.md +docs/guide/en-US/cmd/openim/openim_validate.md +docs/guide/en-US/cmd/openim/openim_version.md +docs/guide/en-US/yaml/openim/openim.yaml +docs/guide/en-US/yaml/openim/openim_color.yaml +docs/guide/en-US/yaml/openim/openim_completion.yaml +docs/guide/en-US/yaml/openim/openim_info.yaml +docs/guide/en-US/yaml/openim/openim_jwt.yaml +docs/guide/en-US/yaml/openim/openim_new.yaml +docs/guide/en-US/yaml/openim/openim_options.yaml +docs/guide/en-US/yaml/openim/openim_policy.yaml +docs/guide/en-US/yaml/openim/openim_secret.yaml +docs/guide/en-US/yaml/openim/openim_set.yaml +docs/guide/en-US/yaml/openim/openim-rpc-user.yaml +docs/guide/en-US/yaml/openim/openim_validate.yaml +docs/guide/en-US/yaml/openim/openim_version.yaml +docs/man/man1/iam-apiserver.1 +docs/man/man1/iam-authz-server.1 +docs/man/man1/iam-pump.1 +docs/man/man1/iam-watcher.1 +docs/man/man1/openim-color.1 +docs/man/man1/openim-completion.1 +docs/man/man1/openim-info.1 +docs/man/man1/openim-jwt-show.1 +docs/man/man1/openim-jwt-sign.1 +docs/man/man1/openim-jwt-verify.1 +docs/man/man1/openim-jwt.1 +docs/man/man1/openim-new.1 +docs/man/man1/openim-options.1 +docs/man/man1/openim-policy-create.1 +docs/man/man1/openim-policy-delete.1 +docs/man/man1/openim-policy-get.1 +docs/man/man1/openim-policy-list.1 +docs/man/man1/openim-policy-update.1 +docs/man/man1/openim-policy.1 +docs/man/man1/openim-secret-create.1 +docs/man/man1/openim-secret-delete.1 +docs/man/man1/openim-secret-get.1 +docs/man/man1/openim-secret-list.1 +docs/man/man1/openim-secret-update.1 +docs/man/man1/openim-secret.1 +docs/man/man1/openim-set.1 +docs/man/man1/openim-user-create.1 +docs/man/man1/openim-user-delete.1 +docs/man/man1/openim-user-get.1 +docs/man/man1/openim-user-list.1 +docs/man/man1/openim-user-update.1 +docs/man/man1/openim-user.1 +docs/man/man1/openim-validate.1 +docs/man/man1/openim-version.1 +docs/man/man1/openim.1 diff --git a/docs/API_SCHEDULED_TASK.md b/docs/API_SCHEDULED_TASK.md new file mode 100644 index 0000000..014b41a --- /dev/null +++ b/docs/API_SCHEDULED_TASK.md @@ -0,0 +1,340 @@ +# 定时任务 API 接口文档 + +## 基础信息 + +- **基础路径**: `/scheduled_task` +- **认证方式**: 所有接口都需要在请求头中携带 `token`(通过 `mw.CheckToken` 中间件验证) +- **请求方法**: 所有接口均为 `POST` + +## 公共数据结构 + +### ScheduledTaskMessage(消息内容) + +```json +{ + "type": 1, // 消息类型:1-文本,2-图片,3-视频 + "content": "string", // 消息内容(文本内容、图片URL、视频URL等) + "thumbnail": "string", // 缩略图URL(用于图片和视频,可选) + "duration": 0, // 时长(秒,用于视频,可选) + "fileSize": 0 // 文件大小(字节,用于图片和视频,可选) +} +``` + +### ScheduledTaskInfo(定时任务信息) + +```json +{ + "id": "string", // 任务ID + "userID": "string", // 用户ID + "name": "string", // 任务名称 + "cronExpression": "string", // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + "messages": [ // 消息列表(支持多条消息一起发送) + { + "type": 1, + "content": "string", + "thumbnail": "string", + "duration": 0, + "fileSize": 0 + } + ], + "recvIDs": ["string"], // 接收者ID列表(单聊,可以多个) + "groupIDs": ["string"], // 群组ID列表(群聊,可以多个) + "status": 1, // 状态:0-已禁用,1-已启用 + "createTime": 1234567890123, // 创建时间(毫秒时间戳) + "updateTime": 1234567890123 // 更新时间(毫秒时间戳) +} +``` + +### RequestPagination(分页信息) + +```json +{ + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 +} +``` + +## Crontab 表达式说明 + +格式:`分 时 日 月 周` + +- **分**: 0-59 +- **时**: 0-23 +- **日**: 1-31 +- **月**: 1-12 +- **周**: 0-7(0和7都表示周日) + +### 示例 + +- `"0 9 * * *"` - 每天9点执行 +- `"*/5 * * * *"` - 每5分钟执行 +- `"0 0 * * 1"` - 每周一0点执行 +- `"0 12 * * 1-5"` - 周一到周五每天12点执行 +- `"0 0 1 * *"` - 每月1号0点执行 + +--- + +## 1. 创建定时任务 + +**接口地址**: `POST /scheduled_task/create` + +**请求参数**: + +```json +{ + "name": "string", // 必填:任务名称 + "cronExpression": "string", // 必填:Crontab表达式 + "messages": [ // 必填:消息列表(至少一条) + { + "type": 1, // 必填:消息类型:1-文本,2-图片,3-视频 + "content": "string", // 必填:消息内容 + "thumbnail": "string", // 可选:缩略图URL + "duration": 0, // 可选:时长(秒) + "fileSize": 0 // 可选:文件大小(字节) + } + ], + "recvIDs": ["string"], // 可选:接收者ID列表(单聊,可以多个) + "groupIDs": ["string"], // 可选:群组ID列表(群聊,可以多个) + "status": 1 // 可选:状态:0-已禁用,1-已启用(默认为1) +} +``` + +**注意**: `recvIDs` 和 `groupIDs` 至少需要提供一个,不能同时为空。 + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "taskID": "string" // 创建的任务ID + } +} +``` + +**请求示例**: + +```json +{ + "name": "每日问候", + "cronExpression": "0 9 * * *", + "messages": [ + { + "type": 1, + "content": "早上好!" + }, + { + "type": 2, + "content": "https://example.com/image.jpg", + "thumbnail": "https://example.com/thumb.jpg", + "fileSize": 102400 + } + ], + "recvIDs": ["user1", "user2"], + "groupIDs": ["group1"], + "status": 1 +} +``` + +--- + +## 2. 获取定时任务详情 + +**接口地址**: `POST /scheduled_task/get` + +**请求参数**: + +```json +{ + "taskID": "string" // 必填:任务ID +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "task": { // 定时任务信息 + "id": "string", + "userID": "string", + "name": "string", + "cronExpression": "string", + "messages": [ + { + "type": 1, + "content": "string", + "thumbnail": "string", + "duration": 0, + "fileSize": 0 + } + ], + "recvIDs": ["string"], + "groupIDs": ["string"], + "status": 1, + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + } +} +``` + +--- + +## 3. 获取定时任务列表 + +**接口地址**: `POST /scheduled_task/list` + +**请求参数**: + +```json +{ + "pagination": { // 必填:分页信息 + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 + } +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 100, // 总数 + "tasks": [ // 任务列表 + { + "id": "string", + "userID": "string", + "name": "string", + "cronExpression": "string", + "messages": [ + { + "type": 1, + "content": "string", + "thumbnail": "string", + "duration": 0, + "fileSize": 0 + } + ], + "recvIDs": ["string"], + "groupIDs": ["string"], + "status": 1, + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + ] + } +} +``` + +--- + +## 4. 更新定时任务 + +**接口地址**: `POST /scheduled_task/update` + +**请求参数**: + +```json +{ + "taskID": "string", // 必填:任务ID + "name": "string", // 可选:任务名称 + "cronExpression": "string", // 可选:Crontab表达式 + "messages": [ // 可选:消息列表 + { + "type": 1, + "content": "string", + "thumbnail": "string", + "duration": 0, + "fileSize": 0 + } + ], + "recvIDs": ["string"], // 可选:接收者ID列表 + "groupIDs": ["string"], // 可选:群组ID列表 + "status": 1 // 可选:状态:0-已禁用,1-已启用 +} +``` + +**注意**: +- 所有字段都是可选的,只更新提供的字段 +- 如果更新 `recvIDs` 和 `groupIDs`,确保至少有一个不为空 + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +```json +{ + "taskID": "task123", + "name": "更新后的任务名称", + "status": 0 +} +``` + +--- + +## 5. 删除定时任务 + +**接口地址**: `POST /scheduled_task/delete` + +**请求参数**: + +```json +{ + "taskIDs": ["string"] // 必填:任务ID列表(支持批量删除) +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +```json +{ + "taskIDs": ["task1", "task2", "task3"] +} +``` + +--- + +## 错误码说明 + +- `0`: 成功 +- 其他错误码请参考系统错误码定义 + +## 注意事项 + +1. 所有接口都需要在请求头中携带有效的 `token` +2. 用户只能操作自己创建的定时任务 +3. `recvIDs` 和 `groupIDs` 可以同时提供,表示同时发送到多个单聊和群聊 +4. `messages` 数组支持多条消息,会按顺序发送 +5. Crontab 表达式需要符合标准格式,客户端负责解析和执行 +6. 服务端只负责存储配置,不执行定时任务 + diff --git a/docs/API_SYSTEM_CONFIG.md b/docs/API_SYSTEM_CONFIG.md new file mode 100644 index 0000000..8cc7170 --- /dev/null +++ b/docs/API_SYSTEM_CONFIG.md @@ -0,0 +1,739 @@ +# 系统配置管理 API 接口文档 + +## 基础信息 + +- **基础路径**: `/system_config` +- **认证方式**: 所有接口都需要在请求头中携带 `token`(通过 `mw.CheckAdmin` 中间件验证,需要管理员权限) +- **请求方法**: 所有接口均为 `POST` + +## 响应格式说明 + +所有接口的响应格式统一为: + +```json +{ + "errCode": 0, // 错误码,0 表示成功 + "errMsg": "", // 错误消息 + "errDlt": "", // 错误详情 + "data": {} // 响应数据 +} +``` + +**注意**: 为了兼容 Ant Design Pro Table,前端在 `request` 函数中需要将响应格式转换为 ProTable 期望的格式: + +```typescript +const request = async (params) => { + const response = await request('/system_config/list', { + method: 'POST', + data: params, + }); + + // 将 errCode 格式转换为 ProTable 期望的格式 + return { + success: response.errCode === 0, + data: response.data?.list || [], + total: response.data?.total || 0, + }; +}; +``` + +## 公共数据结构 + +### SystemConfigInfo(系统配置信息) + +```json +{ + "key": "string", // 配置键(唯一标识) + "title": "string", // 配置标题 + "value": "string", // 配置值(字符串形式存储,根据ValueType解析) + "valueType": 1, // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + "description": "string", // 配置描述 + "enabled": true, // 是否启用(用于开关类配置) + "showInApp": false, // 是否在APP端展示(默认为false) + "createTime": 1234567890123, // 创建时间(毫秒时间戳) + "updateTime": 1234567890123 // 更新时间(毫秒时间戳) +} +``` + +### RequestPagination(分页信息) + +```json +{ + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 +} +``` + +### StringValue(可选字符串值) + +```json +{ + "value": "string" // 字符串值,如果为 null 或未设置则表示不更新该字段 +} +``` + +### Int32Value(可选整数值) + +```json +{ + "value": 1 // 整数值,如果为 null 或未设置则表示不更新该字段 +} +``` + +### BoolValue(可选布尔值) + +```json +{ + "value": true // 布尔值,如果为 null 或未设置则表示不更新该字段 +} +``` + +## 配置值类型说明 + +- **1 - 字符串类型 (ConfigValueTypeString)**: 普通文本字符串 +- **2 - 数字类型 (ConfigValueTypeNumber)**: 数值字符串,需要转换为数字使用 +- **3 - 布尔类型 (ConfigValueTypeBool)**: 布尔值字符串("true"/"false"),需要转换为布尔值使用 +- **4 - JSON类型 (ConfigValueTypeJSON)**: JSON 格式字符串,需要解析为 JSON 对象使用 + +## 常用配置键 + +- `wallet.enabled`: 是否开启钱包功能(布尔类型) +- `register.phone.verify_code.enabled`: 手机号注册验证码功能是否开启(布尔类型) + +--- + +## 1. 创建系统配置 + +**接口地址**: `POST /system_config/create` + +**请求参数**: + +```json +{ + "key": "string", // 必填:配置键(唯一标识) + "title": "string", // 可选:配置标题 + "value": "string|number|boolean|object", // 可选:配置值(支持多种类型,会根据 valueType 自动转换为字符串存储) + "valueType": 1, // 可选:配置值类型:1-字符串,2-数字,3-布尔,4-JSON(默认为1) + "description": "string", // 可选:配置描述 + "enabled": true, // 可选:是否启用(默认为true) + "showInApp": false // 可选:是否在APP端展示(默认为false) +} +``` + +**注意**: `value` 字段支持多种类型传参,系统会根据 `valueType` 自动转换并验证: +- **字符串类型 (valueType=1)**: 可以传字符串,如 `"value": "hello"` +- **数字类型 (valueType=2)**: 可以传数字,如 `"value": 100` 或 `"value": 3.14`,会自动转换为字符串存储 +- **布尔类型 (valueType=3)**: 可以传布尔值,如 `"value": true` 或 `"value": false`,会自动转换为 `"true"` 或 `"false"` 字符串存储 +- **JSON类型 (valueType=4)**: 可以传 JSON 对象,如 `"value": {"key": "value"}`,会自动序列化为 JSON 字符串存储 + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +**示例1: 布尔类型配置(推荐直接传布尔值)** +```json +{ + "key": "wallet.enabled", + "title": "钱包功能开关", + "value": true, // ✅ 直接传布尔值,不需要传字符串 "true" + "valueType": 3, + "description": "控制是否开启钱包功能", + "enabled": true, + "showInApp": true // 在APP端展示此配置 +} +``` + +**示例2: 数字类型配置(推荐直接传数字)** +```json +{ + "key": "wallet.min_withdraw_amount", + "title": "最小提现金额", + "value": 100, // ✅ 直接传数字,会自动转换为字符串 "100" 存储 + "valueType": 2, + "description": "用户提现的最小金额(单位:分)", + "enabled": true +} +``` + +**示例3: JSON类型配置(推荐直接传对象)** +```json +{ + "key": "wallet.withdraw_config", + "title": "提现配置", + "value": { // ✅ 直接传 JSON 对象,会自动序列化为字符串存储 + "dailyLimit": 10000, + "monthlyLimit": 100000, + "feeRate": 0.01 + }, + "valueType": 4, + "description": "提现相关配置(JSON格式)", + "enabled": true +} +``` + +**示例4: 字符串类型配置** +```json +{ + "key": "wallet.welcome_message", + "title": "欢迎消息", + "value": "欢迎使用钱包功能", // ✅ 字符串类型直接传字符串 + "valueType": 1, + "description": "钱包功能欢迎消息", + "enabled": true +} +``` + +**错误码**: +- `ErrArgs`: 配置键为空 +- `ErrDuplicateKey`: 配置键已存在 + +--- + +## 2. 获取系统配置详情 + +**接口地址**: `POST /system_config/get` + +**请求参数**: + +```json +{ + "key": "string" // 必填:配置键 +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "config": { // 系统配置信息 + "key": "string", + "title": "string", + "value": "string", + "valueType": 1, + "description": "string", + "enabled": true, + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + } +} +``` + +**请求示例**: + +```json +{ + "key": "wallet.enabled" +} +``` + +**错误码**: +- `ErrNotFound`: 配置不存在 + +--- + +## 3. 获取所有系统配置(分页) + +**接口地址**: `POST /system_config/list` + +**请求参数**: + +```json +{ + "pagination": { // 必填:分页信息 + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 + } +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 100, // 总数 + "list": [ // 配置列表(Ant Design Pro 标准格式) + { + "key": "string", + "title": "string", + "value": "string|number|boolean|object", // 根据 valueType 自动转换为对应类型 + "valueType": 1, + "description": "string", + "enabled": true, + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + ] + } +} +``` + +**注意**: 返回的 `value` 字段会根据 `valueType` 自动转换为对应类型(详见"2. 获取系统配置详情"的说明)。 + +**请求示例**: + +```json +{ + "pagination": { + "pageNumber": 1, + "showNumber": 20 + } +} +``` + +--- + +## 4. 更新系统配置 + +**接口地址**: `POST /system_config/update` + +**请求参数**: + +```json +{ + "key": "string", // 必填:配置键 + "title": "string", // 可选:配置标题(如果为 null 则不更新) + "value": "string|number|boolean|object", // 可选:配置值(支持多种类型,会根据 valueType 自动转换) + "valueType": 1, // 可选:配置值类型(如果为 null 则不更新) + "description": "string", // 可选:配置描述(如果为 null 则不更新) + "enabled": true, // 可选:是否启用(如果为 null 则不更新) + "showInApp": false // 可选:是否在APP端展示(如果为 null 则不更新) +} +``` + +**注意**: +- `value` 字段支持多种类型传参,系统会根据当前的 `valueType`(或新设置的 `valueType`)自动转换并验证 +- 如果同时更新 `value` 和 `valueType`,系统会验证新值是否符合新的类型要求 +- 如果只更新 `valueType`,系统会验证当前值是否符合新的类型要求 + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +**示例1: 更新布尔类型配置的值** +```json +{ + "key": "wallet.enabled", + "value": false, // ✅ 直接传布尔值 + "description": "已关闭钱包功能" +} +``` + +**示例2: 更新数字类型配置的值** +```json +{ + "key": "wallet.min_withdraw_amount", + "value": 200 // ✅ 直接传数字 +} +``` + +**示例3: 同时更新值和类型** +```json +{ + "key": "wallet.min_amount", + "value": 150, // ✅ 新值 + "valueType": 2 // 更新为数字类型 +} +``` + +**注意**: 只有提供的字段才会被更新,未提供的字段保持不变。 + +**错误码**: +- `ErrNotFound`: 配置不存在 + +--- + +## 5. 更新系统配置值 + +**接口地址**: `POST /system_config/update_value` + +**请求参数**: + +```json +{ + "key": "string", // 必填:配置键 + "value": "string" // 必填:新的配置值 +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +**示例1: 更新布尔类型配置** +```json +{ + "key": "wallet.enabled", + "value": false // ✅ 直接传布尔值,不需要传字符串 "false" +} +``` + +**示例2: 更新数字类型配置** +```json +{ + "key": "wallet.min_withdraw_amount", + "value": 200 // ✅ 直接传数字 +} +``` + +**示例3: 更新 JSON 类型配置** +```json +{ + "key": "wallet.withdraw_config", + "value": { // ✅ 直接传 JSON 对象 + "dailyLimit": 20000, + "monthlyLimit": 200000 + } +} +``` + +**错误码**: +- `ErrNotFound`: 配置不存在 + +--- + +## 6. 更新系统配置启用状态 + +**接口地址**: `POST /system_config/update_enabled` + +**请求参数**: + +```json +{ + "key": "string", // 必填:配置键 + "enabled": true // 必填:是否启用 +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +```json +{ + "key": "wallet.enabled", + "enabled": false +} +``` + +**错误码**: +- `ErrNotFound`: 配置不存在 + +--- + +## 7. 删除系统配置 + +**接口地址**: `POST /system_config/delete` + +**请求参数**: + +```json +{ + "keys": ["string"] // 必填:配置键列表(支持批量删除) +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**请求示例**: + +```json +{ + "keys": ["wallet.enabled", "register.phone.verify_code.enabled"] +} +``` + +--- + +## 8. 获取所有已启用的配置 + +**接口地址**: `POST /system_config/get_enabled` + +**请求参数**: + +```json +{} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "list": [ // 已启用的配置列表(Ant Design Pro 标准格式) + { + "key": "string", + "title": "string", + "value": "string|number|boolean|object", // 根据 valueType 自动转换为对应类型 + "valueType": 1, + "description": "string", + "enabled": true, + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + ] + } +} +``` + +**注意**: 返回的 `value` 字段会根据 `valueType` 自动转换为对应类型(详见"2. 获取系统配置详情"的说明)。 + +**请求示例**: + +```json +{} +``` + +**说明**: 此接口用于获取所有已启用(enabled=true)的配置,通常用于前端展示或业务逻辑判断。 + +--- + +## 使用场景示例 + +### 场景1: 开启/关闭钱包功能 + +1. **创建钱包功能配置**(推荐直接传布尔值): +```json +POST /system_config/create +{ + "key": "wallet.enabled", + "title": "钱包功能开关", + "value": true, // ✅ 直接传布尔值,更直观 + "valueType": 3, + "description": "控制是否开启钱包功能", + "enabled": true +} +``` + +2. **关闭钱包功能**(两种方式): + +方式1: 更新 enabled 字段 +```json +POST /system_config/update_enabled +{ + "key": "wallet.enabled", + "enabled": false +} +``` + +方式2: 更新 value 字段 +```json +POST /system_config/update_value +{ + "key": "wallet.enabled", + "value": false // ✅ 直接传布尔值 +} +``` + +3. **业务代码中检查钱包功能是否开启**: +```go +config, err := db.GetSystemConfig(ctx, "wallet.enabled") +if err != nil || !config.Enabled { + return errors.New("钱包功能未开启") +} +``` + +### 场景2: 配置手机号注册验证码功能 + +1. **创建验证码功能配置**(推荐直接传布尔值): +```json +POST /system_config/create +{ + "key": "register.phone.verify_code.enabled", + "title": "手机号注册验证码功能", + "value": true, // ✅ 直接传布尔值 + "valueType": 3, + "description": "控制手机号注册时是否需要验证码", + "enabled": true +} +``` + +### 场景3: 配置数字类型的参数(推荐直接传数字) + +**创建配置**: +```json +POST /system_config/create +{ + "key": "wallet.min_withdraw_amount", + "title": "最小提现金额", + "value": 100, // ✅ 直接传数字,会自动转换为字符串存储 + "valueType": 2, + "description": "用户提现的最小金额(单位:分)", + "enabled": true +} +``` + +**获取配置**(返回时会自动转换为数字): +```json +GET /system_config/get +{ + "key": "wallet.min_withdraw_amount" +} + +// 响应 +{ + "data": { + "config": { + "key": "wallet.min_withdraw_amount", + "value": 100, // ✅ 返回数字类型,不是字符串 "100" + "valueType": 2 + } + } +} +``` + +**后端使用**(如果直接使用数据库模型,需要手动转换): +```go +config, _ := db.GetSystemConfig(ctx, "wallet.min_withdraw_amount") +minAmount, _ := strconv.ParseInt(config.Value, 10, 64) +``` + +### 场景4: 配置 JSON 类型的复杂参数(推荐直接传对象) + +**创建配置**: +```json +POST /system_config/create +{ + "key": "wallet.withdraw_config", + "title": "提现配置", + "value": { // ✅ 直接传 JSON 对象,会自动序列化为字符串存储 + "dailyLimit": 10000, + "monthlyLimit": 100000, + "feeRate": 0.01 + }, + "valueType": 4, + "description": "提现相关配置(JSON格式)", + "enabled": true +} +``` + +**获取配置**(返回时会自动解析为对象): +```json +GET /system_config/get +{ + "key": "wallet.withdraw_config" +} + +// 响应 +{ + "data": { + "config": { + "key": "wallet.withdraw_config", + "value": { // ✅ 返回 JSON 对象,不是字符串 + "dailyLimit": 10000, + "monthlyLimit": 100000, + "feeRate": 0.01 + }, + "valueType": 4 + } + } +} +``` + +**后端使用**(如果直接使用数据库模型,需要手动解析): +```go +config, _ := db.GetSystemConfig(ctx, "wallet.withdraw_config") +var withdrawConfig map[string]interface{} +json.Unmarshal([]byte(config.Value), &withdrawConfig) +``` + +--- + +## 错误码说明 + +- `ErrArgs`: 参数错误(如必填字段为空) +- `ErrNotFound`: 资源不存在(如配置键不存在) +- `ErrDuplicateKey`: 重复键(如创建配置时键已存在) +- `ErrNoPermission`: 无权限(非管理员用户) + +--- + +## 注意事项 + +1. **配置键唯一性**: 配置键(key)在整个系统中必须唯一,不能重复。 + +2. **配置值类型转换**: + - **传参时**: `value` 字段支持多种类型(字符串、数字、布尔、JSON对象),系统会根据 `valueType` 自动转换为字符串存储 + - **返回时**: `value` 字段会根据 `valueType` 自动转换为对应类型返回(数字返回数字,布尔返回布尔,JSON返回对象) + - **数据库存储**: 所有值都以字符串形式存储在数据库中 + - **后端使用**: 如果直接使用数据库模型,需要根据 `valueType` 手动转换: + - 字符串类型:直接使用 + - 数字类型:使用 `strconv.ParseInt` 或 `strconv.ParseFloat` 转换 + - 布尔类型:使用 `strconv.ParseBool` 转换 + - JSON类型:使用 `json.Unmarshal` 解析 + +3. **类型验证**: 系统会在创建和更新时自动验证 `value` 是否符合 `valueType` 的要求: + - 数字类型:必须是有效的数字 + - 布尔类型:必须是 `true` 或 `false` + - JSON类型:必须是有效的 JSON + +4. **可选字段更新**: 在 `UpdateSystemConfig` 接口中,如果字段为 `null` 或未设置,则不会更新该字段。 + +5. **启用状态**: `enabled` 字段用于控制配置是否生效。即使配置存在,如果 `enabled` 为 `false`,业务代码也应该认为该功能未开启。 + +6. **APP端展示**: `showInApp` 字段用于控制配置是否在APP端展示。只有 `showInApp` 为 `true` 的配置才会在APP端显示给用户。此字段默认为 `false`。 + +7. **推荐用法**: + - 创建/更新布尔类型配置时,推荐直接传布尔值:`"value": true` 而不是 `"value": "true"` + - 创建/更新数字类型配置时,推荐直接传数字:`"value": 100` 而不是 `"value": "100"` + - 创建/更新 JSON 类型配置时,推荐直接传对象:`"value": {"key": "value"}` 而不是 `"value": "{\"key\":\"value\"}"` + +5. **管理员权限**: 所有接口都需要管理员权限,普通用户无法访问。 + +6. **请求头**: 所有请求都需要在请求头中携带 `token` 和 `operationid`。 diff --git a/docs/API_WALLET_SUMMARY.md b/docs/API_WALLET_SUMMARY.md new file mode 100644 index 0000000..0cc88e0 --- /dev/null +++ b/docs/API_WALLET_SUMMARY.md @@ -0,0 +1,453 @@ +# 钱包相关接口汇总 + +## 基础信息 + +- **基础路径**: `/wallet` +- **认证方式**: 所有接口都需要在请求头中携带 `token`(通过 `mw.CheckToken` 中间件验证) +- **请求方法**: 所有接口均为 `POST` +- **Content-Type**: `application/json` + +--- + +## 接口列表 + +### 1. 获取钱包余额 + +**接口地址**: `POST /wallet/balance` + +**请求参数**: 无 + +**响应参数**: +```json +{ + "errCode": 0, + "data": { + "balance": 10000 // 余额(单位:分) + } +} +``` + +--- + +### 2. 获取钱包详细信息 + +**接口地址**: `POST /wallet/info` + +**请求参数**: 无 + +**响应参数**: +```json +{ + "errCode": 0, + "data": { + "balance": 10000, // 余额(单位:分) + "withdrawAccount": "string", // 提现账号 + "withdrawAccountType": 1, // 提现账号类型:1-支付宝,2-微信,3-银行卡 + "withdrawReceiveAccount": "string", // 提现收款账号 + "hasPaymentPassword": true, // 是否已设置支付密码 + "realNameAuth": { // 实名认证信息(可选) + "idCard": "string", + "idCardPhotoFront": "string", + "idCardPhotoBack": "string", + "name": "string" + } + } +} +``` + +--- + +### 3. 获取余额明细 + +**接口地址**: `POST /wallet/balance_records` + +**请求参数**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| pagination | object | 是 | 分页参数 | +| pagination.pageNumber | int32 | 是 | 页码(从1开始) | +| pagination.showNumber | int32 | 是 | 每页显示数量 | +| type | int32 | 否 | 变动类型(可选,0表示查询所有类型):1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 | + +**响应参数**: +```json +{ + "errCode": 0, + "data": { + "total": 100, + "records": [ + { + "id": "string", + "userID": "string", + "amount": 10000, + "type": 1, + "beforeBalance": 0, + "afterBalance": 10000, + "orderID": "string", + "transactionID": "string", + "redPacketID": "string", + "remark": "string", + "createTime": 1234567890123 + } + ] + } +} +``` + +**变动类型说明**: + +| 类型值 | 类型名称 | 说明 | +|--------|---------|------| +| 1 | 充值 | 用户充值 | +| 2 | 提现/提款 | 提现申请 | +| 3 | 消费 | 消费支出 | +| 4 | 退款 | 退款收入 | +| 5 | 奖励 | 奖励收入 | +| 6 | 后台充值 | 管理员后台充值 | +| 7 | 发红包 | 发红包(减少余额) | +| 8 | 抢红包 | 抢红包(增加余额) | +| 99 | 其他 | 其他类型 | + +**业务逻辑**: + +1. 从 token 中获取当前用户ID +2. 如果指定了 type,按类型查询;否则查询所有类型 +3. 按创建时间倒序排列 +4. 支持分页查询 + +**请求示例**: + +查询所有记录: +```json +{ + "pagination": { + "pageNumber": 1, + "showNumber": 10 + } +} +``` + +按类型查询(只查询充值记录): +```json +{ + "pagination": { + "pageNumber": 1, + "showNumber": 10 + }, + "type": 1 +} +``` + +--- + +### 4. 设置支付密码 + +**接口地址**: `POST /wallet/payment_password/set` + +**请求参数**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| newPassword | string | 是 | 新支付密码 | +| oldPassword | string | 条件必填 | 旧支付密码(修改时必填,首次设置时不需要) | + +**响应参数**: +```json +{ + "errCode": 0, + "data": {} +} +``` + +**业务逻辑**: + +1. **首次设置支付密码**: + - 钱包不存在或未设置支付密码 + - 不需要提供 `oldPassword` + - 如果提供了 `oldPassword`,会返回错误 + - 如果钱包不存在,会自动创建钱包并设置支付密码 + +2. **修改支付密码**: + - 已设置支付密码 + - 必须提供 `oldPassword` + - 验证旧密码是否正确 + - 验证新密码不能与旧密码相同 + +**错误码说明**: + +| 错误信息 | 说明 | +|---------|------| +| 新支付密码不能为空 | newPassword 为空 | +| 修改支付密码需要提供旧密码 | 已设置密码但未提供 oldPassword | +| 首次设置支付密码不需要提供旧密码 | 未设置密码但提供了 oldPassword | +| 旧支付密码错误 | oldPassword 验证失败 | +| 新密码不能与旧密码相同 | newPassword == oldPassword | + +**请求示例**: + +首次设置: +```json +{ + "newPassword": "123456" +} +``` + +修改密码: +```json +{ + "newPassword": "654321", + "oldPassword": "123456" +} +``` + +--- + +### 4. 设置提现账号 + +**接口地址**: `POST /wallet/withdraw_account/set` + +**请求参数**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| account | string | 是 | 提现账号 | +| accountType | int32 | 是 | 账号类型:1-支付宝,2-微信,3-银行卡 | + +**响应参数**: +```json +{ + "errCode": 0, + "data": {} +} +``` + +**账号类型说明**: + +| 类型值 | 类型名称 | 说明 | +|--------|---------|------| +| 1 | 支付宝 | 支付宝账号 | +| 2 | 微信 | 微信账号 | +| 3 | 银行卡 | 银行卡号 | + +**错误码说明**: + +| 错误信息 | 说明 | +|---------|------| +| 提现账号不能为空 | account 为空 | +| 账号类型无效,必须是1-支付宝,2-微信,3-银行卡 | accountType 不在有效范围内 | + +**请求示例**: + +设置支付宝账号: +```json +{ + "account": "13800138000", + "accountType": 1 +} +``` + +设置银行卡: +```json +{ + "account": "6222021234567890123", + "accountType": 3 +} +``` + +--- + +### 5. 申请提现 + +**接口地址**: `POST /wallet/withdraw/apply` + +**请求参数**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| amount | int64 | 是 | 提现金额(单位:分,必须 > 0) | +| paymentPassword | string | 是 | 支付密码 | +| ip | string | 否 | 申请IP | +| deviceID | string | 否 | 设备ID | +| platform | string | 否 | 平台(iOS、Android、Web等) | +| deviceModel | string | 否 | 设备型号 | +| deviceBrand | string | 否 | 设备品牌 | +| osVersion | string | 否 | 操作系统版本 | +| appVersion | string | 否 | 应用版本 | + +**注意**: +- 提现账号从用户钱包中自动获取,不需要在请求中提供 +- 如果钱包中未设置提现账号,会返回错误提示"请先在钱包中设置提现账号" +- 备注(remark)由后台管理员在审核时填写,用户申请时不需要提供 + +**响应参数**: +```json +{ + "errCode": 0, + "data": { + "applicationID": "uuid-string" // 申请ID + } +} +``` + +**错误码说明**: + +| 错误信息 | 说明 | +|---------|------| +| 提现金额必须大于0 | amount <= 0 | +| 支付密码不能为空 | paymentPassword 为空 | +| 钱包不存在,无法申请提现 | 用户钱包不存在 | +| 请先设置支付密码 | 用户未设置支付密码 | +| 支付密码错误 | 支付密码验证失败 | +| 余额不足,无法申请提现 | 钱包余额 < 提现金额 | +| 请先在钱包中设置提现账号 | 钱包中未设置提现账号 | + +--- + +### 6. 获取提现申请列表 + +**接口地址**: `POST /wallet/withdraw/list` + +**请求参数**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| pagination | object | 是 | 分页参数 | +| pagination.pageNumber | int32 | 是 | 页码(从1开始) | +| pagination.showNumber | int32 | 是 | 每页显示数量 | + +**响应参数**: +```json +{ + "errCode": 0, + "data": { + "total": 100, + "applications": [ + { + "id": "string", + "userID": "string", + "amount": 10000, + "withdrawAccount": "string", + "withdrawAccountType": 1, + "status": 1, + "auditorID": "string", + "auditTime": 1234567890123, + "auditRemark": "string", + "ip": "string", + "deviceID": "string", + "platform": "string", + "deviceModel": "string", + "deviceBrand": "string", + "osVersion": "string", + "appVersion": "string", + "remark": "string", + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + ] + } +} +``` + +**状态值说明**: + +| 状态值 | 状态名称 | 说明 | +|--------|---------|------| +| 1 | 待审核 | 用户已提交,等待管理员审核 | +| 2 | 已通过 | 管理员审核通过 | +| 3 | 已拒绝 | 管理员审核拒绝 | +| 4 | 处理中 | 审核通过后,正在处理提现 | +| 5 | 已完成 | 提现已完成 | + +--- + +## RPC 接口对应关系 + +| HTTP 接口 | RPC 方法 | 请求消息 | 响应消息 | +|----------|---------|---------|---------| +| `/wallet/balance` | `GetWalletBalance` | `GetWalletBalanceReq` | `GetWalletBalanceResp` | +| `/wallet/info` | `GetWalletInfo` | `GetWalletInfoReq` | `GetWalletInfoResp` | +| `/wallet/balance_records` | `GetWalletBalanceRecords` | `GetWalletBalanceRecordsReq` | `GetWalletBalanceRecordsResp` | +| `/wallet/payment_password/set` | `SetPaymentPassword` | `SetPaymentPasswordReq` | `SetPaymentPasswordResp` | +| `/wallet/withdraw_account/set` | `SetWithdrawAccount` | `SetWithdrawAccountReq` | `SetWithdrawAccountResp` | +| `/wallet/withdraw/apply` | `CreateWithdrawApplication` | `CreateWithdrawApplicationReq` | `CreateWithdrawApplicationResp` | +| `/wallet/withdraw/list` | `GetWithdrawApplications` | `GetWithdrawApplicationsReq` | `GetWithdrawApplicationsResp` | + +--- + +## 使用流程示例 + +### 1. 首次使用钱包 + +```bash +# 1. 获取钱包信息(检查是否已设置支付密码) +POST /wallet/info + +# 2. 如果 hasPaymentPassword 为 false,设置支付密码 +POST /wallet/payment_password/set +{ + "newPassword": "123456" +} + +# 3. 设置提现账号 +POST /wallet/withdraw_account/set +{ + "account": "13800138000", + "accountType": 1 // 1-支付宝,2-微信,3-银行卡 +} + +# 4. 申请提现(提现账号从钱包中自动获取) +POST /wallet/withdraw/apply +{ + "amount": 10000, + "paymentPassword": "123456" +} +``` + +### 2. 修改支付密码 + +```bash +# 修改支付密码 +POST /wallet/payment_password/set +{ + "newPassword": "654321", + "oldPassword": "123456" +} +``` + +### 3. 查看提现记录 + +```bash +# 获取提现申请列表 +POST /wallet/withdraw/list +{ + "pagination": { + "pageNumber": 1, + "showNumber": 10 + } +} +``` + +--- + +## 注意事项 + +1. **支付密码设置**: + - 首次设置不需要旧密码 + - 修改时必须提供正确的旧密码 + - 新密码不能与旧密码相同 + +2. **提现申请**: + - 必须已设置支付密码 + - 必须验证支付密码 + - 余额必须足够 + - 需要设置提现账号 + +3. **权限控制**: + - 所有接口都需要 token 认证 + - 用户只能操作自己的钱包 + - 用户只能查看自己的提现申请列表 + +4. **数据单位**: + - 所有金额单位均为"分"(1元 = 100分) + - 时间戳单位为毫秒 diff --git a/docs/API_WITHDRAW_ADMIN.md b/docs/API_WITHDRAW_ADMIN.md new file mode 100644 index 0000000..cacdab7 --- /dev/null +++ b/docs/API_WITHDRAW_ADMIN.md @@ -0,0 +1,486 @@ +# 提现管理后台接口文档 + +## 接口列表 + +| 接口地址 | 请求方法 | 说明 | +|---------|---------|------| +| `/withdraw/get` | POST | 获取提现申请详情 | +| `/withdraw/list` | POST | 获取提现申请列表(支持按状态筛选) | +| `/withdraw/user_list` | POST | 获取用户的提现申请列表 | +| `/withdraw/audit` | POST | 审核提现申请 | + +**注意:** +- 所有接口都需要管理员权限(需要 `mw.CheckAdmin` 中间件验证) +- 这些接口操作的是 `withdraw_applications` 集合(用户申请的提现) +- 用户在前端申请提现后,后台管理员通过这些接口进行审核 + +--- + +## 1. 获取提现申请详情 + +**接口地址**: `/withdraw/get` + +**请求方法**: `POST` + +**请求参数**: + +```json +{ + "withdrawID": "string" // 提现申请ID(必填) +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "withdraw": { + "id": "string", // 提现申请ID + "userID": "string", // 用户ID + "amount": 10000, // 提现金额(单位:分) + "withdrawAccount": "string", // 提现账号 + "status": 1, // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + "auditorID": "string", // 审核人ID(管理员ID) + "auditTime": 1699000000000, // 审核时间(毫秒时间戳) + "auditRemark": "string", // 审核备注 + "ip": "string", // 申请IP + "deviceID": "string", // 设备ID + "platform": "string", // 平台(iOS、Android、Web等) + "deviceModel": "string", // 设备型号 + "deviceBrand": "string", // 设备品牌 + "osVersion": "string", // 操作系统版本 + "appVersion": "string", // 应用版本 + "createTime": 1699000000000, // 创建时间(毫秒时间戳) + "updateTime": 1699000000000 // 更新时间(毫秒时间戳) + } + } +} +``` + +**状态说明**: + +| 状态值 | 状态名称 | 说明 | +|--------|---------|------| +| 1 | 待审核 | 用户已提交申请,等待审核 | +| 2 | 已通过 | 审核通过,提现成功(余额已在申请时扣除) | +| 3 | 已拒绝 | 审核拒绝,余额已退回 | +| 4 | 处理中 | 审核通过后,正在处理中 | +| 5 | 已完成 | 提现已完成 | + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | applicationID is required | 提现申请ID不能为空 | +| 404 | 记录不存在 | 提现申请不存在 | +| 401 | 无权限 | 需要管理员权限 | + +--- + +## 2. 获取提现申请列表(支持按状态筛选) + +**接口地址**: `/withdraw/list` + +**请求方法**: `POST` + +**请求参数**: + +```json +{ + "status": 1, // 状态筛选(可选):0-全部,1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成。默认为0(全部) + "pagination": { + "pageNumber": 1, // 页码(必填,从1开始) + "showNumber": 10 // 每页数量(必填) + } +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 100, // 总数 + "list": [ + { + "id": "string", // 提现申请ID + "userID": "string", // 用户ID + "amount": 10000, // 提现金额(单位:分) + "withdrawAccount": "string", // 提现账号 + "status": 1, // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + "auditorID": "string", // 审核人ID(管理员ID) + "auditTime": 1699000000000, // 审核时间(毫秒时间戳) + "auditRemark": "string", // 审核备注 + "ip": "string", // 申请IP + "deviceID": "string", // 设备ID + "platform": "string", // 平台(iOS、Android、Web等) + "deviceModel": "string", // 设备型号 + "deviceBrand": "string", // 设备品牌 + "osVersion": "string", // 操作系统版本 + "appVersion": "string", // 应用版本 + "createTime": 1699000000000, // 创建时间(毫秒时间戳) + "updateTime": 1699000000000 // 更新时间(毫秒时间戳) + } + ] + } +} +``` + +**请求示例**: + +```json +// 获取所有提现申请 +{ + "status": 0, + "pagination": { + "pageNumber": 1, + "showNumber": 20 + } +} + +// 获取待审核的提现申请 +{ + "status": 1, + "pagination": { + "pageNumber": 1, + "showNumber": 20 + } +} + +// 获取已通过的提现申请 +{ + "status": 2, + "pagination": { + "pageNumber": 1, + "showNumber": 20 + } +} +``` + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | invalid request | 请求参数格式错误 | +| 401 | 无权限 | 需要管理员权限 | + +--- + +## 3. 获取用户的提现申请列表 + +**接口地址**: `/withdraw/user_list` + +**请求方法**: `POST` + +**请求参数**: + +```json +{ + "userID": "string", // 用户ID(必填) + "pagination": { + "pageNumber": 1, // 页码(必填,从1开始) + "showNumber": 10 // 每页数量(必填) + } +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 10, // 总数 + "list": [ + { + "id": "string", // 提现申请ID + "userID": "string", // 用户ID + "amount": 10000, // 提现金额(单位:分) + "withdrawAccount": "string", // 提现账号 + "status": 1, // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + "auditorID": "string", // 审核人ID(管理员ID) + "auditTime": 1699000000000, // 审核时间(毫秒时间戳) + "auditRemark": "string", // 审核备注 + "ip": "string", // 申请IP + "deviceID": "string", // 设备ID + "platform": "string", // 平台(iOS、Android、Web等) + "deviceModel": "string", // 设备型号 + "deviceBrand": "string", // 设备品牌 + "osVersion": "string", // 操作系统版本 + "appVersion": "string", // 应用版本 + "createTime": 1699000000000, // 创建时间(毫秒时间戳) + "updateTime": 1699000000000 // 更新时间(毫秒时间戳) + } + ] + } +} +``` + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | userID is required | 用户ID不能为空 | +| 400 | invalid request | 请求参数格式错误 | +| 401 | 无权限 | 需要管理员权限 | + +--- + +## 4. 批量审核提现申请 + +**接口地址**: `/withdraw/audit` + +**请求方法**: `POST` + +**请求参数**: + +```json +{ + "withdrawIDs": ["string", "string"], // 提现申请ID列表(必填,支持批量审核) + "status": 2, // 审核状态(必填):2-已通过,3-已拒绝 + "auditRemark": "string" // 审核备注(可选) +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "successCount": 5, // 成功审核的数量 + "failCount": 2, // 失败审核的数量 + "failedIDs": ["id1", "id2"] // 失败的提现申请ID列表 + } +} +``` + +**状态说明**: + +| 状态值 | 状态名称 | 说明 | +|--------|---------|------| +| 2 | 已通过 | 审核通过,提现成功(余额已在用户申请时扣除,无需额外操作) | +| 3 | 已拒绝 | 审核拒绝,系统会自动将余额退回用户钱包,并创建退款记录 | + +**业务逻辑**: + +1. 验证必填字段(提现申请ID列表、审核状态) +2. 验证审核状态必须是2(通过)或3(拒绝) +3. **批量处理每个提现申请**: + - 检查提现申请是否存在 + - 检查提现申请状态,允许"待审核"和"已通过"状态的提现申请被审核(已通过的提现申请可以重新审核为拒绝) + - 更新提现申请状态和审核信息 + - **如果审核拒绝**: + - 自动将提现金额退回用户钱包(包括从"待审核"改为"已拒绝",或从"已通过"改为"已拒绝") + - 创建一条类型为"退款"的余额变动记录 + - 备注为"提现审核拒绝,退回余额" +4. 返回成功和失败的数量,以及失败的ID列表 + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | withdrawIDs is required and cannot be empty | 提现申请ID列表不能为空 | +| 400 | status must be 2 (approved) or 3 (rejected) | 审核状态必须是2或3 | +| 401 | 无权限 | 需要管理员权限 | + +**注意**: +- 批量审核时,部分成功部分失败是正常的 +- 失败的提现申请会在 `failedIDs` 中返回 +- 失败的常见原因: + - 提现申请不存在 + - 提现申请状态不是"待审核"或"已通过" + - 更新状态时出错 + +**请求示例**: + +```json +// 批量审核通过 +{ + "withdrawIDs": ["xxx-xxx-xxx-1", "xxx-xxx-xxx-2", "xxx-xxx-xxx-3"], + "status": 2, + "auditRemark": "批量审核通过,已打款" +} + +// 批量审核拒绝 +{ + "withdrawIDs": ["xxx-xxx-xxx-1", "xxx-xxx-xxx-2"], + "status": 3, + "auditRemark": "提现账号信息有误,已拒绝" +} + +// 单个审核(也支持) +{ + "withdrawIDs": ["xxx-xxx-xxx"], + "status": 2, + "auditRemark": "审核通过,已打款" +} +``` + +**响应示例**: + +```json +// 全部成功 +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "successCount": 3, + "failCount": 0, + "failedIDs": [] + } +} + +// 部分成功 +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "successCount": 2, + "failCount": 1, + "failedIDs": ["xxx-xxx-xxx-3"] // 这个ID可能不存在或状态不对 + } +} +``` + +--- + +## 通用说明 + +### 分页参数说明 + +所有列表接口都使用统一的分页参数格式: + +```json +{ + "pagination": { + "pageNumber": 1, // 页码,从1开始 + "showNumber": 10 // 每页显示数量 + } +} +``` + +### 时间戳说明 + +所有时间字段都是毫秒时间戳(Unix timestamp in milliseconds),例如: +- `1699000000000` 表示 `2023-11-03 12:00:00`(UTC时间) + +### 金额单位说明 + +所有金额字段的单位都是**分**(cent),例如: +- `10000` 表示 `100.00` 元 +- `100` 表示 `1.00` 元 + +### 权限说明 + +所有接口都需要管理员权限,需要在请求头中携带有效的管理员 token。 + +### 响应格式说明 + +所有接口都遵循统一的响应格式: + +```json +{ + "errCode": 0, // 错误码,0表示成功 + "errMsg": "", // 错误信息 + "errDlt": "", // 错误详情 + "data": {} // 响应数据 +} +``` + +--- + +## 接口调用示例 + +### 示例1:获取待审核的提现申请列表 + +```bash +curl -X POST http://your-domain/withdraw/list \ + -H "Content-Type: application/json" \ + -H "token: your-admin-token" \ + -d '{ + "status": 1, + "pagination": { + "pageNumber": 1, + "showNumber": 20 + } + }' +``` + +### 示例2:批量审核提现申请(通过) + +```bash +curl -X POST http://your-domain/withdraw/audit \ + -H "Content-Type: application/json" \ + -H "token: your-admin-token" \ + -d '{ + "withdrawIDs": ["withdraw-123", "withdraw-124", "withdraw-125"], + "status": 2, + "auditRemark": "批量审核通过,已打款" + }' +``` + +### 示例3:批量审核提现申请(拒绝) + +```bash +curl -X POST http://your-domain/withdraw/audit \ + -H "Content-Type: application/json" \ + -H "token: your-admin-token" \ + -d '{ + "withdrawIDs": ["withdraw-123", "withdraw-124"], + "status": 3, + "auditRemark": "提现账号信息有误,已拒绝" + }' +``` + +### 示例4:单个审核(也支持) + +```bash +curl -X POST http://your-domain/withdraw/audit \ + -H "Content-Type: application/json" \ + -H "token: your-admin-token" \ + -d '{ + "withdrawIDs": ["withdraw-123"], + "status": 2, + "auditRemark": "审核通过,已打款" + }' +``` + +--- + +## 状态流转图 + +``` +待审核 (1) + ├─ 审核通过 (2) → 已通过(余额已在用户申请时扣除,无需额外操作) + │ ├─ 重新审核拒绝 (3) → 已拒绝(余额自动退回用户钱包) + │ └─ 处理中 (4) → 已完成 (5) + └─ 审核拒绝 (3) → 已拒绝(余额自动退回用户钱包) +``` + +--- + +## 注意事项 + +1. **用户申请提现**:用户在前端申请提现时,余额会立即扣除,创建提现申请记录 +2. **后台审核**:管理员通过后台接口审核用户的提现申请,支持批量审核 +3. **批量审核**:可以一次审核多个提现申请,返回成功和失败的数量 +4. **审核通过**:余额已在用户申请时扣除,审核通过时无需额外操作 +5. **审核拒绝**:审核拒绝时会自动退回余额到用户钱包,并创建退款记录(包括从"已通过"改为"已拒绝"的情况) +6. **状态检查**:允许"待审核"和"已通过"状态的提现申请被审核,已通过的提现申请可以重新审核为拒绝 +7. **部分失败处理**:批量审核时,部分成功部分失败是正常的,失败的ID会在响应中返回 +8. **金额单位**:所有金额都以"分"为单位,前端显示时需要除以100 +9. **数据来源**:所有接口操作的都是 `withdraw_applications` 集合(用户申请的提现),不是 `withdraws` 集合 diff --git a/docs/API_WITHDRAW_APPLICATION.md b/docs/API_WITHDRAW_APPLICATION.md new file mode 100644 index 0000000..4cc9f95 --- /dev/null +++ b/docs/API_WITHDRAW_APPLICATION.md @@ -0,0 +1,439 @@ +# 提现申请接口文档 + +## 基础信息 + +- **基础路径**: `/wallet` +- **认证方式**: 所有接口都需要在请求头中携带 `token`(通过 `mw.CheckToken` 中间件验证) +- **请求方法**: 所有接口均为 `POST` +- **Content-Type**: `application/json` + +## 响应格式说明 + +所有接口的响应格式统一为: + +```json +{ + "errCode": 0, // 错误码,0 表示成功 + "errMsg": "", // 错误消息 + "errDlt": "", // 错误详情 + "data": {} // 响应数据 +} +``` + +## 公共数据结构 + +### RequestPagination(分页信息) + +```json +{ + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 +} +``` + +### WithdrawApplicationInfo(提现申请信息) + +```json +{ + "id": "string", // 申请ID + "userID": "string", // 用户ID + "amount": 10000, // 提现金额(单位:分) + "withdrawAccount": "string", // 提现账号 + "withdrawAccountType": 1, // 提现账号类型:1-支付宝,2-微信,3-银行卡 + "status": 1, // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + "auditorID": "string", // 审核人ID(管理员ID) + "auditTime": 1234567890123, // 审核时间(毫秒时间戳,未审核时为0) + "auditRemark": "string", // 审核备注 + "ip": "string", // 申请IP + "deviceID": "string", // 设备ID + "platform": "string", // 平台(iOS、Android、Web等) + "deviceModel": "string", // 设备型号 + "deviceBrand": "string", // 设备品牌 + "osVersion": "string", // 操作系统版本 + "appVersion": "string", // 应用版本 + "remark": "string", // 申请备注 + "createTime": 1234567890123, // 创建时间(毫秒时间戳) + "updateTime": 1234567890123 // 更新时间(毫秒时间戳) +} +``` + +### 提现申请状态说明 + +| 状态值 | 状态名称 | 说明 | +|--------|---------|------| +| 1 | 待审核 | 用户已提交申请,等待管理员审核 | +| 2 | 已通过 | 管理员审核通过 | +| 3 | 已拒绝 | 管理员审核拒绝 | +| 4 | 处理中 | 审核通过后,正在处理提现 | +| 5 | 已完成 | 提现已完成 | + +--- + +## 接口列表 + +### 1. 设置支付密码 + +**接口地址**: `/wallet/payment_password/set` + +**请求参数**: + +```json +{ + "newPassword": "string", // 新支付密码(必填) + "oldPassword": "string" // 旧支付密码(修改时必填,首次设置时不需要) +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**业务逻辑**: + +1. **首次设置支付密码**(钱包不存在或未设置支付密码): + - 不需要提供 `oldPassword` + - 如果提供了 `oldPassword`,会返回错误 + - 如果钱包不存在,会自动创建钱包并设置支付密码 + +2. **修改支付密码**(已设置支付密码): + - 必须提供 `oldPassword` + - 验证旧密码是否正确 + - 验证新密码不能与旧密码相同 + - 更新支付密码 + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | 新支付密码不能为空 | newPassword 为空 | +| 400 | 修改支付密码需要提供旧密码 | 已设置密码但未提供 oldPassword | +| 400 | 首次设置支付密码不需要提供旧密码 | 未设置密码但提供了 oldPassword | +| 400 | 旧支付密码错误 | oldPassword 验证失败 | +| 400 | 新密码不能与旧密码相同 | newPassword == oldPassword | + +**请求示例**: + +首次设置: +```json +{ + "newPassword": "123456" +} +``` + +修改密码: +```json +{ + "newPassword": "654321", + "oldPassword": "123456" +} +``` + +--- + +### 2. 设置提现账号 + +**接口地址**: `/wallet/withdraw_account/set` + +**请求参数**: + +```json +{ + "account": "string", // 提现账号(必填) + "accountType": 1 // 账号类型(必填):1-支付宝,2-微信,3-银行卡 +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": {} +} +``` + +**账号类型说明**: + +| 类型值 | 类型名称 | 说明 | +|--------|---------|------| +| 1 | 支付宝 | 支付宝账号 | +| 2 | 微信 | 微信账号 | +| 3 | 银行卡 | 银行卡号 | + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | 提现账号不能为空 | account 为空 | +| 400 | 账号类型无效,必须是1-支付宝,2-微信,3-银行卡 | accountType 不在有效范围内 | + +**业务逻辑**: + +1. 验证必填字段(账号、账号类型) +2. 验证账号类型是否有效(1-3) +3. 更新钱包中的提现账号和账号类型 + +--- + +### 3. 申请提现 + +**接口地址**: `/wallet/withdraw/apply` + +**请求参数**: + +```json +{ + "amount": 10000, // 提现金额(单位:分,必填,必须大于0) + "paymentPassword": "string", // 支付密码(必填) + "ip": "string", // 申请IP(可选) + "deviceID": "string", // 设备ID(可选) + "platform": "string", // 平台(可选,如:iOS、Android、Web) + "deviceModel": "string", // 设备型号(可选,如:iPhone 14 Pro) + "deviceBrand": "string", // 设备品牌(可选,如:Apple) + "osVersion": "string", // 操作系统版本(可选,如:iOS 17.0) + "appVersion": "string" // 应用版本(可选) +} +``` + +**注意**: +- 提现账号从用户钱包中自动获取,不需要在请求中提供 +- 如果钱包中未设置提现账号,会返回错误提示 +- 备注(remark)由后台管理员在审核时填写,用户申请时不需要提供 + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "applicationID": "uuid-string" // 申请ID + } +} +``` + +**错误码说明**: + +| 错误码 | 错误信息 | 说明 | +|--------|---------|------| +| 400 | 提现金额必须大于0 | amount <= 0 | +| 400 | 支付密码不能为空 | paymentPassword 为空 | +| 400 | 钱包不存在,无法申请提现 | 用户钱包不存在 | +| 400 | 请先设置支付密码 | 用户未设置支付密码 | +| 400 | 支付密码错误 | 支付密码验证失败 | +| 400 | 余额不足,无法申请提现 | 钱包余额 < 提现金额 | +| 400 | 请先在钱包中设置提现账号 | 钱包中未设置提现账号 | + +**业务逻辑**: + +1. 验证必填字段(金额、支付密码) +2. 获取用户钱包信息 +3. 验证支付密码 +4. 检查余额是否足够 +5. 检查钱包中是否设置了提现账号(从钱包中获取) +6. 创建提现申请记录(状态:待审核,提现账号从钱包中获取) + +--- + +### 4. 获取提现申请列表 + +**接口地址**: `/wallet/withdraw/list` + +**请求参数**: + +```json +{ + "pagination": { + "pageNumber": 1, // 页码(从1开始) + "showNumber": 10 // 每页显示数量 + } +} +``` + +**响应参数**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 100, // 总数 + "applications": [ // 申请列表 + { + "id": "string", + "userID": "string", + "amount": 10000, + "withdrawAccount": "string", + "status": 1, + "auditorID": "string", + "auditTime": 1234567890123, + "auditRemark": "string", + "ip": "string", + "deviceID": "string", + "platform": "string", + "deviceModel": "string", + "deviceBrand": "string", + "osVersion": "string", + "appVersion": "string", + "remark": "string", + "createTime": 1234567890123, + "updateTime": 1234567890123 + } + ] + } +} +``` + +**业务逻辑**: + +1. 从 token 中获取当前用户ID +2. 根据用户ID查询提现申请列表 +3. 按创建时间倒序排列 +4. 支持分页查询 + +--- + +## 请求示例 + +### 申请提现 + +```bash +curl -X POST http://your-domain/wallet/withdraw/apply \ + -H "Content-Type: application/json" \ + -H "token: your-token" \ + -d '{ + "amount": 10000, + "paymentPassword": "123456", + "ip": "192.168.1.1", + "deviceID": "device-uuid", + "platform": "iOS", + "deviceModel": "iPhone 14 Pro", + "deviceBrand": "Apple", + "osVersion": "iOS 17.0", + "appVersion": "1.0.0" + }' +``` + +**响应示例**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "applicationID": "550e8400-e29b-41d4-a716-446655440000" + } +} +``` + +### 获取提现申请列表 + +```bash +curl -X POST http://your-domain/wallet/withdraw/list \ + -H "Content-Type: application/json" \ + -H "token: your-token" \ + -d '{ + "pagination": { + "pageNumber": 1, + "showNumber": 10 + } + }' +``` + +**响应示例**: + +```json +{ + "errCode": 0, + "errMsg": "", + "errDlt": "", + "data": { + "total": 5, + "applications": [ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "userID": "user123", + "amount": 10000, + "withdrawAccount": "6222021234567890123", + "status": 1, + "auditorID": "", + "auditTime": 0, + "auditRemark": "", + "ip": "192.168.1.1", + "deviceID": "device-uuid", + "platform": "iOS", + "deviceModel": "iPhone 14 Pro", + "deviceBrand": "Apple", + "osVersion": "iOS 17.0", + "appVersion": "1.0.0", + "remark": "提现备注", + "createTime": 1704067200000, + "updateTime": 1704067200000 + } + ] + } +} +``` + +--- + +## RPC 接口说明 + +### gRPC 服务 + +**服务名**: `openim.chat.Chat` + +### 1. CreateWithdrawApplication + +**RPC 方法**: `CreateWithdrawApplication` + +**请求消息**: `CreateWithdrawApplicationReq` + +**响应消息**: `CreateWithdrawApplicationResp` + +### 2. SetPaymentPassword + +**RPC 方法**: `SetPaymentPassword` + +**请求消息**: `SetPaymentPasswordReq` + +**响应消息**: `SetPaymentPasswordResp` + +### 3. GetWithdrawApplications + +**RPC 方法**: `GetWithdrawApplications` + +**请求消息**: `GetWithdrawApplicationsReq` + +**响应消息**: `GetWithdrawApplicationsResp` + +--- + +## 注意事项 + +1. **支付密码验证**: 申请提现时必须提供正确的支付密码 +2. **余额检查**: 系统会检查钱包余额是否足够,余额不足时无法申请 +3. **提现账号**: 如果钱包中已设置提现账号,可以不传 `withdrawAccount`,系统会使用钱包中的账号 +4. **申请状态**: 新创建的申请状态为"待审核"(status=1),需要管理员审核 +5. **分页查询**: 列表接口支持分页,默认按创建时间倒序排列 +6. **权限控制**: 用户只能查看自己的提现申请列表 + +--- + +## 相关接口 + +- [钱包余额查询](./API_WALLET.md#获取钱包余额) +- [钱包信息查询](./API_WALLET.md#获取钱包详细信息) +- [设置支付密码](#设置支付密码) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS new file mode 100644 index 0000000..015466d --- /dev/null +++ b/docs/CODEOWNERS @@ -0,0 +1 @@ +* @Bloomingg @FGadvancer @skiffer-git @withchao diff --git a/docs/contrib/cicd-actions.md b/docs/contrib/cicd-actions.md new file mode 100644 index 0000000..99072f3 --- /dev/null +++ b/docs/contrib/cicd-actions.md @@ -0,0 +1,129 @@ +# Continuous Integration and Automation + +Every change on the OpenIM repository, either made through a pull request or direct push, triggers the continuous integration pipelines defined within the same repository. Needless to say, all the OpenIM contributions can be merged until all the checks pass (AKA having green builds). + +- [Continuous Integration and Automation](#continuous-integration-and-automation) + - [CI Platforms](#ci-platforms) + - [GitHub Actions](#github-actions) + - [Running locally](#running-locally) + +## CI Platforms + +Currently, there are two different platforms involved in running the CI processes: + +- GitHub actions +- Drone pipelines on CNCF infrastructure + +### GitHub Actions + +All the existing GitHub Actions are defined as YAML files under the `.github/workflows` directory. These can be grouped into: + +- **PR Checks**. These actions run all the required validations upon PR creation and update. Covering the DCO compliance check, `x86_64` test batteries (unit, integration, smoke), and code coverage. +- **Repository automation**. Currently, it only covers issues and epic grooming. + +Everything runs on GitHub's provided runners; thus, the tests are limited to run in `x86_64` architectures. + + +## Running locally + +A contributor should verify their changes locally to speed up the pull request process. Fortunately, all the CI steps can be on local environments, except for the publishing ones, through either of the following methods: + +**User Makefile:** +```bash +root@PS2023EVRHNCXG:~/workspaces/openim/Open-IM-Server# make help 😊 + +Usage: make ... + +Targets: + +all Run tidy, gen, add-copyright, format, lint, cover, build 🚀 +build Build binaries by default 🛠️ +multiarch Build binaries for multiple platforms. See option PLATFORMS. 🌍 +tidy tidy go.mod ✨ +vendor vendor go.mod 📦 +style code style -> fmt,vet,lint 💅 +fmt Run go fmt against code. ✨ +vet Run go vet against code. ✅ +lint Check syntax and styling of go sources. ✔️ +format Gofmt (reformat) package sources (exclude vendor dir if existed). 🔄 +test Run unit test. 🧪 +cover Run unit test and get test coverage. 📊 +updates Check for updates to go.mod dependencies 🆕 +imports task to automatically handle import packages in Go files using goimports tool 📥 +clean Remove all files that are created by building. 🗑️ +image Build docker images for host arch. 🐳 +image.multiarch Build docker images for multiple platforms. See option PLATFORMS. 🌍🐳 +push Build docker images for host arch and push images to registry. 📤🐳 +push.multiarch Build docker images for multiple platforms and push images to registry. 🌍📤🐳 +tools Install dependent tools. 🧰 +gen Generate all necessary files. 🧩 +swagger Generate swagger document. 📖 +serve-swagger Serve swagger spec and docs. 🚀📚 +verify-copyright Verify the license headers for all files. ✅ +add-copyright Add copyright ensure source code files have license headers. 📄 +release release the project 🎉 +help Show this help info. ℹ️ +help-all Show all help details info. ℹ️📚 + +Options: + +DEBUG Whether or not to generate debug symbols. Default is 0. ❓ + +BINS Binaries to build. Default is all binaries under cmd. 🛠️ +This option is available when using: make {build}(.multiarch) 🧰 +Example: make build BINS="openim-api openim_cms_api". + +PLATFORMS Platform to build for. Default is linux_arm64 and linux_amd64. 🌍 +This option is available when using: make {build}.multiarch 🌍 +Example: make multiarch PLATFORMS="linux_s390x linux_mips64 +linux_mips64le darwin_amd64 windows_amd64 linux_amd64 linux_arm64". + +V Set to 1 enable verbose build. Default is 0. 📝 +``` + + +How to Use Makefile to Help Contributors Build Projects Quickly 😊 + +The `make help` command is a handy tool that provides useful information on how to utilize the Makefile effectively. By running this command, contributors will gain insights into various targets and options available for building projects swiftly. + +Here's a breakdown of the targets and options provided by the Makefile: + +**Targets 😃** + +1. `all`: This target runs multiple tasks like `tidy`, `gen`, `add-copyright`, `format`, `lint`, `cover`, and `build`. It ensures comprehensive project building. +2. `build`: The primary target that compiles binaries by default. It is particularly useful for creating the necessary executable files. +3. `multiarch`: A target that builds binaries for multiple platforms. Contributors can specify the desired platforms using the `PLATFORMS` option. +4. `tidy`: This target cleans up the `go.mod` file, ensuring its consistency. +5. `vendor`: A target that updates the project dependencies based on the `go.mod` file. +6. `style`: Checks the code style using tools like `fmt`, `vet`, and `lint`. It ensures a consistent coding style throughout the project. +7. `fmt`: Formats the code using the `go fmt` command, ensuring proper indentation and formatting. +8. `vet`: Runs the `go vet` command to identify common errors in the code. +9. `lint`: Validates the syntax and styling of Go source files using a linter. +10. `format`: Reformats the package sources using `gofmt`. It excludes the vendor directory if it exists. +11. `test`: Executes unit tests to ensure the functionality and stability of the code. +12. `cover`: Performs unit tests and calculates the test coverage of the code. +13. `updates`: Checks for updates to the project's dependencies specified in the `go.mod` file. +14. `imports`: Automatically handles import packages in Go files using the `goimports` tool. +15. `clean`: Removes all files generated during the build process, effectively cleaning up the project directory. +16. `image`: Builds Docker images for the host architecture. +17. `image.multiarch`: Similar to the `image` target, but it builds Docker images for multiple platforms. Contributors can specify the desired platforms using the `PLATFORMS` option. +18. `push`: Builds Docker images for the host architecture and pushes them to a registry. +19. `push.multiarch`: Builds Docker images for multiple platforms and pushes them to a registry. Contributors can specify the desired platforms using the `PLATFORMS` option. +20. `tools`: Installs the necessary tools or dependencies required by the project. +21. `gen`: Generates all the required files automatically. +22. `swagger`: Generates the swagger document for the project. +23. `serve-swagger`: Serves the swagger specification and documentation. +24. `verify-copyright`: Verifies the license headers for all project files. +25. `add-copyright`: Adds copyright headers to the source code files. +26. `release`: Releases the project, presumably for distribution. +27. `help`: Displays information about available targets and options. +28. `help-all`: Shows detailed information about all available targets and options. + +**Options 😄** + +1. `DEBUG`: A boolean option that determines whether or not to generate debug symbols. The default value is 0 (false). +2. `BINS`: Specifies the binaries to build. By default, it builds all binaries under the `cmd` directory. Contributors can provide a list of specific binaries using this option. +3. `PLATFORMS`: Specifies the platforms to build for. The default platforms are `linux_arm64` and `linux_amd64`. Contributors can specify multiple platforms by providing a space-separated list of platform names. +4. `V`: A boolean option that enables verbose build output when set to 1 (true). The default value is 0 (false). + +With these targets and options in place, contributors can efficiently build projects using the Makefile. Happy coding! 🚀😊 diff --git a/docs/contrib/code_conventions.md b/docs/contrib/code_conventions.md new file mode 100644 index 0000000..1387da2 --- /dev/null +++ b/docs/contrib/code_conventions.md @@ -0,0 +1,38 @@ +# Code conventions + +- [Code conventions](#code-conventions) + - [POSIX shell](#posix-shell) + - [Go](#go) + - [Directory and file conventions](#directory-and-file-conventions) + - [Testing conventions](#testing-conventions) + +## POSIX shell + +- [Style guide](https://google.github.io/styleguide/shell.xml) + +## Go + +- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) +- [Effective Go](https://golang.org/doc/effective_go.html) +- Know and avoid [Go landmines](https://gist.github.com/lavalamp/4bd23295a9f32706a48f) +- Comment your code. + - [Go's commenting conventions](http://blog.golang.org/godoc-documenting-go-code) + - If reviewers ask questions about why the code is the way it is, that's a sign that comments might be helpful. +- Command-line flags should use dashes, not underscores +- Naming + - Please consider package name when selecting an interface name, and avoid redundancy. For example, `storage.Interface` is better than `storage.StorageInterface`. + - Do not use uppercase characters, underscores, or dashes in package names. + - Please consider parent directory name when choosing a package name. For example, `pkg/controllers/autoscaler/foo.go` should say `package autoscaler` not `package autoscalercontroller`. + - Unless there's a good reason, the `package foo` line should match the name of the directory in which the `.go` file exists. + - Importers can use a different name if they need to disambiguate. + +## Directory and file conventions + +- Avoid general utility packages. Packages called "util" are suspect. Instead, derive a name that describes your desired function. For example, the utility functions dealing with waiting for operations are in the `wait` package and include functionality like `Poll`. The full name is `wait.Poll`. +- All filenames should be lowercase. +- All source files and directories should use underscores, not dashes. + - Package directories should generally avoid using separators as much as possible. When package names are multiple words, they usually should be in nested subdirectories. + +## Testing conventions + +Please refer to [TESTING.md](../../tests/TESTING.md) document. diff --git a/docs/contrib/development.md b/docs/contrib/development.md new file mode 100644 index 0000000..64aa08c --- /dev/null +++ b/docs/contrib/development.md @@ -0,0 +1,80 @@ +# Development Guide + +Since OpenIM is written in Go, it is fair to assume that the Go tools are all one needs to contribute to this project. Unfortunately, there is a point where this no longer holds true when required to test or build local changes. This document elaborates on the required tooling for OpenIM development. + +- [Development Guide](#development-guide) + - [Non-Linux environment prerequisites](#non-linux-environment-prerequisites) + - [Windows Setup](#windows-setup) + - [macOS Setup](#macos-setup) + - [Installing Required Software](#installing-required-software) + - [Go](#go) + - [Docker](#docker) + - [Vagrant](#vagrant) + - [Cloning, Building and Testing OpenIM](#cloning-building-and-testing-openim) + - [Dependency management](#dependency-management) + +## Non-Linux environment prerequisites + +All the test and build scripts within this repository were created to be run on GNU Linux development environments. Due to this, it is suggested to use the virtual machine defined on this repository's [Vagrantfile](../../Vagrantfile) to use them. + +Either way, if one still wants to build and test OpenIM on non-Linux environments, specific setups are to be followed. + +### Windows Setup + +To build OpenIM on Windows is only possible for versions that support Windows Subsystem for Linux (WSL). If the development environment in question has Windows 10, Version 2004, Build 19041 or higher, [follow these instructions to install WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-win10); otherwise, use a Linux Virtual machine instead. + +### macOS Setup + +The shell scripts in charge of the build and test processes rely on GNU utils (i.e. `sed`), [which slightly differ on macOS](https://unix.stackexchange.com/a/79357), meaning that one must make some adjustments before using them. + +First, install the GNU utils: + +```sh +brew install coreutils findutils gawk gnu-sed gnu-tar grep make +``` + +Then update the shell init script (i.e. `.bashrc`) to prepend the GNU Utils to the `$PATH` variable + +```sh +GNUBINS="$(find /usr/local/opt -type d -follow -name gnubin -print)" + +for bindir in ${GNUBINS[@]}; do + PATH=$bindir:$PATH +done + +export PATH +``` + +## Installing Required Software + +### Go + +It is well known that OpenIM is written in [Go](http://golang.org). Please follow the [Go Getting Started guide](https://golang.org/doc/install) to install and set up the Go tools used to compile and run the test batteries. + +| OpenIM | requires Go | +|----------------|-------------| +| 2.24 - 3.00 | 1.15 + | +| 3.30 + | 1.18 + | + +### Docker + +OpenIM build and test processes development require Docker to run certain steps. [Follow the Docker website instructions to install Docker](https://docs.docker.com/get-docker/) in the development environment. + +### Vagrant + +As described in the [Testing documentation](../../tests/TESTING.md), all the smoke tests are run in virtual machines managed by Vagrant. To install Vagrant in the development environment, [follow the instructions from the Hashicorp website](https://www.vagrantup.com/downloads), alongside any of the following hypervisors: + +- [VirtualBox](https://www.virtualbox.org/) +- [libvirt](https://libvirt.org/) and the [vagrant-libvirt plugin](https://github.com/vagrant-libvirt/vagrant-libvirt#installation) + +## Cloning, Building and Testing OpenIM + +These topics already have been addressed on their respective documents: + +- [Git Workflow](./git-workflow.md) +- [Building](../../BUILDING.md) +- [Testing](../../tests/TESTING.md) + +## Dependency management + +OpenIM uses [go modules](https://github.com/golang/go/wiki/Modules) to manage dependencies. diff --git a/docs/contrib/git_workflow.md b/docs/contrib/git_workflow.md new file mode 100644 index 0000000..9919f20 --- /dev/null +++ b/docs/contrib/git_workflow.md @@ -0,0 +1,102 @@ +# Git workflows + +This document is an overview of OpenIM git workflow. It includes conventions, tips, and how to maintain good repository hygiene. + +- [Git workflows](#git-workflows) + - [Branching model](#branching-model) + - [Branch naming conventions](#branch-naming-conventions) + - [Backport policy](#backport-policy) + - [Git operations](#git-operations) + - [Setting up](#setting-up) + - [Branching out](#branching-out) + - [Keeping local branches in sync](#keeping-local-branches-in-sync) + - [Pushing changes](#pushing-changes) + +## Branching model + +OpenIM project uses the [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) as its branching model, where most of the changes come from repositories forks instead of branches within the same one. + +### Branch naming conventions + +Every forked repository works independently, meaning that any contributor can create branches with the name they see fit. However, it is worth noting that OpenIM mirrors [OpenIM version skew policy](https://github.com/openimsdk/Open-IM-Server/releases) by maintaining release branches for the most recent three minor releases. The only exception is that the main branch mirrors the latest OpenIM release (3.10) instead of using a `release-` prefixed one. + +```text +main -------------------------------------------. (OpenIM 3.10) +release-3.0.0 \---------------|---------------. (OpenIM 3.00) +release-2.4.0 \---------------. (OpenIM 2.40) +``` + + +### Backport policy + +All new work happens on the main branch, which means that for most cases, one should branch out from there and create the pull request against it. If the change involves adding a feature or patching OpenIM, the maintainers will backport it into the supported release branches. + +## Git operations + +There are everyday tasks related to git that every contributor needs to perform, and this section elaborates on them. + +### Setting up + +Creating a OpenIM fork, cloning it, and setting its upstream remote can be summarized on: + +1. Visit +2. Click the `Fork` button (top right) to establish a cloud-based fork +3. Clone fork to local storage +4. Add to your fork OpenIM remote as upstream + +Once cloned, in code it would look this way: + +```sh +## Clone fork to local storage +export user="your github profile name" +git clone https://github.com/$user/OpenIM.git +# or: git clone git@github.com:$user/OpenIM.git + +## Add OpenIM as upstream to your fork +cd OpenIM +git remote add upstream https://github.com/openimsdk/Open-IM-Server.git +# or: git remote add upstream git@github.com:OpenIMSDK/Open-IM-Server.git + +## Ensure to never push to upstream directly +git remote set-url --push upstream no_push + +## Confirm that your remotes make sense: +git remote -v +``` + +### Branching out + +Every time one wants to work on a new OpenIM feature, we do: + +1. Get local main branch up to date +2. Create a new branch from the main one (i.e.: myfeature branch ) + +In code it would look this way: + +```sh +## Get local main up to date +# Assuming the OpenIM clone is the current working directory +git fetch upstream +git checkout main +git rebase upstream/main + +## Create a new branch from main +git checkout -b myfeature +``` + +### Keeping local branches in sync + +Either when branching out from main or a release one, keep in mind it is worth checking if any change has been pushed upstream by doing: + +```sh +git fetch upstream +git rebase upstream/main +``` + +It is suggested to `fetch` then `rebase` instead of `pull` since the latter does a merge, which leaves merge commits. For this, one can consider changing the local repository configuration by doing `git config branch.autoSetupRebase always` to change the behavior of `git pull`, or another non-merge option such as `git pull --rebase`. + +### Pushing changes + +For commit messages and signatures please refer to the [CONTRIBUTING.md](../../CONTRIBUTING.md) document. + +Nobody should push directly to upstream, even if one has such contributor access; instead, prefer [Github's pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) mechanism to contribute back into OpenIM. For expectations and guidelines about pull requests, consult the [CONTRIBUTING.md](../../CONTRIBUTING.md) document. diff --git a/docs/conversions/README.md b/docs/conversions/README.md new file mode 100644 index 0000000..05fd7dc --- /dev/null +++ b/docs/conversions/README.md @@ -0,0 +1,9 @@ +## OpenIM Project Development Standards + +- [Code Standards](https://chat.openai.com/go_code.md) +- [Directory Standards](https://chat.openai.com/directory.md) +- [Commit Standards](https://chat.openai.com/commit.md) +- [Versioning Standards](https://chat.openai.com/version.md) +- [Interface Standards](https://chat.openai.com/api.md) +- [Log Standards](https://chat.openai.com/log.md) +- [Error Code Standards](https://chat.openai.com/error_code.md) \ No newline at end of file diff --git a/docs/conversions/api.md b/docs/conversions/api.md new file mode 100644 index 0000000..1dd3892 --- /dev/null +++ b/docs/conversions/api.md @@ -0,0 +1,5 @@ +## Interface Standards + +Our project, OpenIM, adheres to the [OpenAPI 3.0](https://spec.openapis.org/oas/latest.html) interface standards. + +> Chinese translation: [OpenAPI Specification Chinese Translation](https://fishead.gitbook.io/openapi-specification-zhcn-translation/3.0.0.zhcn) \ No newline at end of file diff --git a/docs/conversions/commit.md b/docs/conversions/commit.md new file mode 100644 index 0000000..661661f --- /dev/null +++ b/docs/conversions/commit.md @@ -0,0 +1,9 @@ +## Commit Standards + +Our project, OpenIM, follows the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) standards. + +> Chinese translation: [Conventional Commits: A Specification Making Commit Logs More Human and Machine-friendly](https://tool.lu/en_US/article/2ac/preview) + +In addition to adhering to these standards, we encourage all contributors to the OpenIM project to ensure that their commit messages are clear and descriptive. This helps in maintaining a clean and meaningful project history. Each commit message should succinctly describe the changes made and, where necessary, the reasoning behind those changes. + +To facilitate a streamlined process, we also recommend using appropriate commit type based on Conventional Commits guidelines such as `fix:` for bug fixes, `feat:` for new features, and so forth. Understanding and using these conventions helps in generating automatic release notes, making versioning easier, and improving overall readability of commit history. \ No newline at end of file diff --git a/docs/conversions/directory.md b/docs/conversions/directory.md new file mode 100644 index 0000000..4e30d38 --- /dev/null +++ b/docs/conversions/directory.md @@ -0,0 +1,3 @@ +## Catalog Service Interface Specification + ++ [https://github.com/kubecub/go-project-layout](https://github.com/kubecub/go-project-layout) \ No newline at end of file diff --git a/docs/conversions/error_code.md b/docs/conversions/error_code.md new file mode 100644 index 0000000..169567b --- /dev/null +++ b/docs/conversions/error_code.md @@ -0,0 +1,22 @@ +## Error Code Standards + +Error codes are one of the important means for users to locate and solve problems. When an application encounters an exception, users can quickly locate and resolve the problem based on the error code and the description and solution of the error code in the documentation. + +### Error Code Naming Standards + +- Follow CamelCase notation; +- Error codes are divided into two levels. For example, `InvalidParameter.BindError`, separated by a `.`. The first-level error code is platform-level, and the second-level error code is resource-level, which can be customized according to the scenario; +- The second-level error code can only use English letters or numbers ([a-zA-Z0-9]), and should use standard English word spelling, standard abbreviations, RFC term abbreviations, etc.; +- The error code should avoid multiple definitions of the same semantics, for example: `InvalidParameter.ErrorBind`, `InvalidParameter.BindError`. + +### First-Level Common Error Codes + +| Error Code | Error Description | Error Type | +| ---------------- | ------------------------------------------------------------ | ---------- | +| InternalError | Internal error | 1 | +| InvalidParameter | Parameter error (including errors in parameter type, format, value, etc.) | 0 | +| AuthFailure | Authentication / Authorization error | 0 | +| ResourceNotFound | Resource does not exist | 0 | +| FailedOperation | Operation failed | 2 | + +> Error Type: 0 represents the client, 1 represents the server, 2 represents both the client / server. \ No newline at end of file diff --git a/docs/conversions/go_code.md b/docs/conversions/go_code.md new file mode 100644 index 0000000..85d099f --- /dev/null +++ b/docs/conversions/go_code.md @@ -0,0 +1,901 @@ +## Go 代码开发规范 +在Go 项目开发中,一个好的编码规范可以极大的提高代码质量。为了帮你节省时间和精力,这里我整理了一份清晰、可直接套用的 Go 编码规范,供你参考。 + +这份规范,是我参考了 Go 官方提供的编码规范,以及 Go 社区沉淀的一些比较合理的规范之后,加入自己的理解总结出的,它比很多公司内部的规范更全面,你掌握了,以后在面试大厂的时候,或者在大厂里写代码的时候,都会让人高看你一眼,觉得你code很专业。 + +这份编码规范中包含代码风格、命名规范、注释规范、类型、控制结构、函数、GOPATH 设置规范、依赖管理和最佳实践九类规范。如果你觉得这些规范内容太多了,看完一遍也记不住,这完全没关系。你可以多看几遍,也可以在用到时把它翻出来,在实际应用中掌握。这篇特别放送的内容,更多是作为写代码时候的一个参考手册。 + +## 1. 代码风格 + +### 1.1 代码格式 + +- 代码都必须用 `gofmt` 进行格式化。 +- 运算符和操作数之间要留空格。 +- 建议一行代码不超过120个字符,超过部分,请采用合适的换行方式换行。但也有些例外场景,例如import行、工具自动生成的代码、带tag的struct字段。 +- 文件长度不能超过800行。 +- 函数长度不能超过80行。 +- import规范 + - 代码都必须用`goimports`进行格式化(建议将代码Go代码编辑器设置为:保存时运行 `goimports`)。 + - 不要使用相对路径引入包,例如 `import ../util/net` 。 + - 包名称与导入路径的最后一个目录名不匹配时,或者多个相同包名冲突时,则必须使用导入别名。 + +```go + // bad + "github.com/dgrijalva/jwt-go/v4" + + //good + jwt "github.com/dgrijalva/jwt-go/v4" +``` + - 导入的包建议进行分组,匿名包的引用使用一个新的分组,并对匿名包引用进行说明。 + +```go + import ( + // go 标准包 + "fmt" + + // 第三方包 + "github.com/jinzhu/gorm" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + // 匿名包单独分组,并对匿名包引用进行说明 + // import mysql driver + _ "github.com/jinzhu/gorm/dialects/mysql" + + // 内部包 + v1 "github.com/marmotedu/api/apiserver/v1" + metav1 "github.com/marmotedu/apimachinery/pkg/meta/v1" + "github.com/marmotedu/iam/pkg/cli/genericclioptions" + ) +``` + +### 1.2 声明、初始化和定义 + +当函数中需要使用到多个变量时,可以在函数开始处使用`var`声明。在函数外部声明必须使用 `var` ,不要采用 `:=` ,容易踩到变量的作用域的问题。 + +```go +var ( + Width int + Height int +) +``` + +- 在初始化结构引用时,请使用`&T{}`代替`new(T)`,以使其与结构体初始化一致。 + +```go +// bad +sptr := new(T) +sptr.Name = "bar" + +// good +sptr := &T{Name: "bar"} +``` + +- struct 声明和初始化格式采用多行,定义如下。 + +```go +type User struct{ + Username string + Email string +} + +user := User{ + Username: "belm", + Email: "nosbelm@qq.com", +} +``` + +- 相似的声明放在一组,同样适用于常量、变量和类型声明。 + +```go +// bad +import "a" +import "b" + +// good +import ( + "a" + "b" +) +``` + +- 尽可能指定容器容量,以便为容器预先分配内存,例如: + +```go +v := make(map[int]string, 4) +v := make([]string, 0, 4) +``` + +- 在顶层,使用标准var关键字。请勿指定类型,除非它与表达式的类型不同。 + +```go +// bad +var _s string = F() + +func F() string { return "A" } + +// good +var _s = F() +// 由于 F 已经明确了返回一个字符串类型,因此我们没有必要显式指定_s 的类型 +// 还是那种类型 + +func F() string { return "A" } +``` + +- 对于未导出的顶层常量和变量,使用`_`作为前缀。 + +```go +// bad +const ( + defaultHost = "127.0.0.1" + defaultPort = 8080 +) + +// good +const ( + _defaultHost = "127.0.0.1" + _defaultPort = 8080 +) +``` + +- 嵌入式类型(例如 mutex)应位于结构体内的字段列表的顶部,并且必须有一个空行将嵌入式字段与常规字段分隔开。 + +```go +// bad +type Client struct { + version int + http.Client +} + +// good +type Client struct { + http.Client + + version int +} +``` + +### 1.3 错误处理 + +- `error`作为函数的值返回,必须对`error`进行处理,或将返回值赋值给明确忽略。对于`defer xx.Close()`可以不用显式处理。 + +```go +func load() error { + // normal code +} + +// bad +load() + +// good + _ = load() +``` + +- `error`作为函数的值返回且有多个返回值的时候,`error`必须是最后一个参数。 + +```go +// bad +func load() (error, int) { + // normal code +} + +// good +func load() (int, error) { + // normal code +} +``` + +- 尽早进行错误处理,并尽早返回,减少嵌套。 + +```go +// bad +if err != nil { + // error code +} else { + // normal code +} + +// good +if err != nil { + // error handling + return err +} +// normal code +``` + +- 如果需要在 if 之外使用函数调用的结果,则应采用下面的方式。 + +```go +// bad +if v, err := foo(); err != nil { + // error handling +} + +// good +v, err := foo() +if err != nil { + // error handling +} +``` + +- 错误要单独判断,不与其他逻辑组合判断。 + +```go +// bad +v, err := foo() +if err != nil || v == nil { + // error handling + return err +} + +// good +v, err := foo() +if err != nil { + // error handling + return err +} + +if v == nil { + // error handling + return errors.New("invalid value v") +} +``` + +- 如果返回值需要初始化,则采用下面的方式。 + +```go +v, err := f() +if err != nil { + // error handling + return // or continue. +} +``` + +- 错误描述建议 + - 错误描述用小写字母开头,结尾不要加标点符号,例如: +```go + // bad + errors.New("Redis connection failed") + errors.New("redis connection failed.") + + // good + errors.New("redis connection failed") +``` + - 告诉用户他们可以做什么,而不是告诉他们不能做什么。 + - 当声明一个需求时,用must 而不是should。例如,`must be greater than 0、must match regex '[a-z]+'`。 + - 当声明一个格式不对时,用must not。例如,`must not contain`。 + - 当声明一个动作时用may not。例如,`may not be specified when otherField is empty、only name may be specified`。 + - 引用文字字符串值时,请在单引号中指示文字。例如,`ust not contain '..'`。 + - 当引用另一个字段名称时,请在反引号中指定该名称。例如,must be greater than `request`。 + - 指定不等时,请使用单词而不是符号。例如,`must be less than 256、must be greater than or equal to 0 (不要用 larger than、bigger than、more than、higher than)`。 + - 指定数字范围时,请尽可能使用包含范围。 + - 建议 Go 1.13 以上,error 生成方式为 `fmt.Errorf("module xxx: %w", err)`。 + +### 1.4 panic处理 + +- 在业务逻辑处理中禁止使用panic。 +- 在main包中,只有当程序完全不可运行时使用panic,例如无法打开文件、无法连接数据库导致程序无法正常运行。 +- 在main包中,使用 `log.Fatal` 来记录错误,这样就可以由log来结束程序,或者将panic抛出的异常记录到日志文件中,方便排查问题。 +- 可导出的接口一定不能有panic。 +- 包内建议采用error而不是panic来传递错误。 + +### 1.5 单元测试 + +- 单元测试文件名命名规范为 `example_test.go`。 +- 每个重要的可导出函数都要编写测试用例。 +- 因为单元测试文件内的函数都是不对外的,所以可导出的结构体、函数等可以不带注释。 +- 如果存在 `func (b *Bar) Foo` ,单测函数可以为 `func TestBar_Foo`。 + +### 1.6 类型断言失败处理 + +- type assertion 的单个返回值针对不正确的类型将产生 panic。请始终使用 “comma ok”的惯用法。 + +```go +// bad +t := n.(int) + +// good +t, ok := n.(int) +if !ok { + // error handling +} +``` + +## 2. 命名规范 + +命名规范是代码规范中非常重要的一部分,一个统一的、短小的、精确的命名规范可以大大提高代码的可读性,也可以借此规避一些不必要的Bug。 + +### 2.1 包命名 + +- 包名必须和目录名一致,尽量采取有意义、简短的包名,不要和标准库冲突。 +- 包名全部小写,没有大写或下划线,使用多级目录来划分层级。 +- 项目名可以通过中划线来连接多个单词。 +- 包名以及包所在的目录名,不要使用复数,例如,是`net/url`,而不是`net/urls`。 +- 不要用 common、util、shared 或者 lib 这类宽泛的、无意义的包名。 +- 包名要简单明了,例如 net、time、log。 + +### 2.2 函数命名 + +- 函数名采用驼峰式,首字母根据访问控制决定使用大写或小写,例如:`MixedCaps`或者`mixedCaps`。 +- 代码生成工具自动生成的代码(如`xxxx.pb.go`)和为了对相关测试用例进行分组,而采用的下划线(如`TestMyFunction_WhatIsBeingTested`)排除此规则。 + +### 2.3 文件命名 + +- 文件名要简短有意义。 +- 文件名应小写,并使用下划线分割单词。 + +### 2.4 结构体命名 + +- 采用驼峰命名方式,首字母根据访问控制决定使用大写或小写,例如`MixedCaps`或者`mixedCaps`。 +- 结构体名不应该是动词,应该是名词,比如 `Node`、`NodeSpec`。 +- 避免使用Data、Info这类无意义的结构体名。 +- 结构体的声明和初始化应采用多行,例如: + +```go +// User 多行声明 +type User struct { + Name string + Email string +} + +// 多行初始化 +u := User{ + UserName: "belm", + Email: "nosbelm@qq.com", +} +``` + +### 2.5 接口命名 + +- 接口命名的规则,基本和结构体命名规则保持一致: + - 单个函数的接口名以 “er"”作为后缀(例如Reader,Writer),有时候可能导致蹩脚的英文,但是没关系。 + - 两个函数的接口名以两个函数名命名,例如ReadWriter。 + - 三个以上函数的接口名,类似于结构体名。 + +例如: + +``` + // Seeking to an offset before the start of the file is an error. + // Seeking to any positive offset is legal, but the behavior of subsequent + // I/O operations on the underlying object is implementation-dependent. + type Seeker interface { + Seek(offset int64, whence int) (int64, error) + } + + // ReadWriter is the interface that groups the basic Read and Write methods. + type ReadWriter interface { + Reader + Writer + } +``` + +### 2.6 变量命名 + +- 变量名必须遵循驼峰式,首字母根据访问控制决定使用大写或小写。 +- 在相对简单(对象数量少、针对性强)的环境中,可以将一些名称由完整单词简写为单个字母,例如: + - user 可以简写为 u; + - userID 可以简写 uid。 +- 特有名词时,需要遵循以下规则: + - 如果变量为私有,且特有名词为首个单词,则使用小写,如 apiClient。 + - 其他情况都应当使用该名词原有的写法,如 APIClient、repoID、UserID。 + +下面列举了一些常见的特有名词。 + +``` +// A GonicMapper that contains a list of common initialisms taken from golang/lint +var LintGonicMapper = GonicMapper{ + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ID": true, + "IP": true, + "JSON": true, + "LHS": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SSH": true, + "TLS": true, + "TTL": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XSRF": true, + "XSS": true, +} +``` + +- 若变量类型为bool类型,则名称应以Has,Is,Can或Allow开头,例如: + +```go +var hasConflict bool +var isExist bool +var canManage bool +var allowGitHook bool +``` + +- 局部变量应当尽可能短小,比如使用buf指代buffer,使用i指代index。 +- 代码生成工具自动生成的代码可排除此规则(如`xxx.pb.go`里面的Id) + +### 2.7 常量命名 + +- 常量名必须遵循驼峰式,首字母根据访问控制决定使用大写或小写。 +- 如果是枚举类型的常量,需要先创建相应类型: + +```go +// Code defines an error code type. +type Code int + +// Internal errors. +const ( + // ErrUnknown - 0: An unknown error occurred. + ErrUnknown Code = iota + // ErrFatal - 1: An fatal error occurred. + ErrFatal +) +``` + +### 2.8 Error的命名 + +- Error类型应该写成FooError的形式。 + +```go +type ExitError struct { + // .... +} +``` + +- Error变量写成ErrFoo的形式。 + +```go +var ErrFormat = errors.New("unknown format") +``` + +## 3. 注释规范 + +- 每个可导出的名字都要有注释,该注释对导出的变量、函数、结构体、接口等进行简要介绍。 +- 全部使用单行注释,禁止使用多行注释。 +- 和代码的规范一样,单行注释不要过长,禁止超过 120 字符,超过的请使用换行展示,尽量保持格式优雅。 +- 注释必须是完整的句子,以需要注释的内容作为开头,句点作为结尾,`格式为 // 名称 描述.`。例如: + +```go +// bad +// logs the flags in the flagset. +func PrintFlags(flags *pflag.FlagSet) { + // normal code +} + +// good +// PrintFlags logs the flags in the flagset. +func PrintFlags(flags *pflag.FlagSet) { + // normal code +} +``` + +- 所有注释掉的代码在提交code review前都应该被删除,否则应该说明为什么不删除,并给出后续处理建议。 + +- 在多段注释之间可以使用空行分隔加以区分,如下所示: + +```go +// Package superman implements methods for saving the world. +// +// Experience has shown that a small number of procedures can prove +// helpful when attempting to save the world. +package superman +``` + +### 3.1 包注释 + +- 每个包都有且仅有一个包级别的注释。 +- 包注释统一用 // 进行注释,格式为 `// Package 包名 包描述`,例如: + +```go +// Package genericclioptions contains flags which can be added to you command, bound, completed, and produce +// useful helper functions. +package genericclioptions +``` + +### 3.2 变量/常量注释 + +- 每个可导出的变量/常量都必须有注释说明,`格式为// 变量名 变量描述`,例如: + +```go +// ErrSigningMethod defines invalid signing method error. +var ErrSigningMethod = errors.New("Invalid signing method") +``` +- 出现大块常量或变量定义时,可在前面注释一个总的说明,然后在每一行常量的前一行或末尾详细注释该常量的定义,例如: +```go +// Code must start with 1xxxxx. +const ( + // ErrSuccess - 200: OK. + ErrSuccess int = iota + 100001 + + // ErrUnknown - 500: Internal server error. + ErrUnknown + + // ErrBind - 400: Error occurred while binding the request body to the struct. + ErrBind + + // ErrValidation - 400: Validation failed. + ErrValidation +) +``` +### 3.3 结构体注释 + +- 每个需要导出的结构体或者接口都必须有注释说明,格式为 `// 结构体名 结构体描述.`。 +- 结构体内的可导出成员变量名,如果意义不明确,必须要给出注释,放在成员变量的前一行或同一行的末尾。例如: + +```go +// User represents a user restful resource. It is also used as gorm model. +type User struct { + // Standard object's metadata. + metav1.ObjectMeta `json:"metadata,omitempty"` + + Nickname string `json:"nickname" gorm:"column:nickname"` + Password string `json:"password" gorm:"column:password"` + Email string `json:"email" gorm:"column:email"` + Phone string `json:"phone" gorm:"column:phone"` + IsAdmin int `json:"isAdmin,omitempty" gorm:"column:isAdmin"` +} +``` + +### 3.4 方法注释 + +每个需要导出的函数或者方法都必须有注释,格式为// 函数名 函数描述.,例如: + +```go +// BeforeUpdate run before update database record. +func (p *Policy) BeforeUpdate() (err error) { + // normal code + return nil +} +``` + +### 3.5 类型注释 + +- 每个需要导出的类型定义和类型别名都必须有注释说明,格式为 `// 类型名 类型描述.`,例如: + +```go +// Code defines an error code type. +type Code int +``` + +## 4. 类型 + +### 4.1 字符串 + +- 空字符串判断。 + +```go +// bad +if s == "" { + // normal code +} + +// good +if len(s) == 0 { + // normal code +} +``` + +- `[]byte`/`string`相等比较。 + +```go +// bad +var s1 []byte +var s2 []byte +... +bytes.Equal(s1, s2) == 0 +bytes.Equal(s1, s2) != 0 + +// good +var s1 []byte +var s2 []byte +... +bytes.Compare(s1, s2) == 0 +bytes.Compare(s1, s2) != 0 +``` + +- 复杂字符串使用raw字符串避免字符转义。 + +```go +// bad +regexp.MustCompile("\\.") + +// good +regexp.MustCompile(`\.`) +``` + +### 4.2 切片 + +- 空slice判断。 + +```go +// bad +if len(slice) = 0 { + // normal code +} + +// good +if slice != nil && len(slice) == 0 { + // normal code +} +``` + +上面判断同样适用于map、channel。 + +- 声明slice。 + +```go +// bad +s := []string{} +s := make([]string, 0) + +// good +var s []string +``` + +- slice复制。 + +```go +// bad +var b1, b2 []byte +for i, v := range b1 { + b2[i] = v +} +for i := range b1 { + b2[i] = b1[i] +} + +// good +copy(b2, b1) +``` + +- slice新增。 + +```go +// bad +var a, b []int +for _, v := range a { + b = append(b, v) +} + +// good +var a, b []int +b = append(b, a...) +``` + +### 4.3 结构体 + +- struct初始化。 + +struct以多行格式初始化。 + +```go +type user struct { + Id int64 + Name string +} + +u1 := user{100, "Colin"} + +u2 := user{ + Id: 200, + Name: "Lex", +} +``` + +## 5. 控制结构 + +### 5.1 if + +- if 接受初始化语句,约定如下方式建立局部变量。 + +```go +if err := loadConfig(); err != nil { + // error handling + return err +} +``` + +- if 对于bool类型的变量,应直接进行真假判断。 + +```go +var isAllow bool +if isAllow { + // normal code +} +``` + +### 5.2 for + +- 采用短声明建立局部变量。 + +```go +sum := 0 +for i := 0; i < 10; i++ { + sum += 1 +} +``` + +- 不要在 for 循环里面使用 defer,defer只有在函数退出时才会执行。 + +```go +// bad +for file := range files { + fd, err := os.Open(file) + if err != nil { + return err + } + defer fd.Close() + // normal code +} + +// good +for file := range files { + func() { + fd, err := os.Open(file) + if err != nil { + return err + } + defer fd.Close() + // normal code + }() +} +``` + +### 5.3 range + +- 如果只需要第一项(key),就丢弃第二个。 + +```go +for key := range keys { +// normal code +} +``` + +- 如果只需要第二项,则把第一项置为下划线。 + +```go +sum := 0 +for _, value := range array { + sum += value +} +``` + +### 5.4 switch + +- 必须要有default。 + +```go +switch os := runtime.GOOS; os { + case "linux": + fmt.Println("Linux.") + case "darwin": + fmt.Println("OS X.") + default: + fmt.Printf("%s.\n", os) +} +``` + +### 5.5 goto +- 业务代码禁止使用 goto 。 +- 框架或其他底层源码尽量不用。 + +## 6. 函数 + +- 传入变量和返回变量以小写字母开头。 +- 函数参数个数不能超过5个。 +- 函数分组与顺序 +- 函数应按粗略的调用顺序排序。 +- 同一文件中的函数应按接收者分组。 +- 尽量采用值传递,而非指针传递。 +- 传入参数是 map、slice、chan、interface ,不要传递指针。 + +### 6.1 函数参数 + +- 如果函数返回相同类型的两个或三个参数,或者如果从上下文中不清楚结果的含义,使用命名返回,其他情况不建议使用命名返回,例如: + +```go +func coordinate() (x, y float64, err error) { + // normal code +} +``` +- 传入变量和返回变量都以小写字母开头。 +- 尽量用值传递,非指针传递。 +- 参数数量均不能超过5个。 +- 多返回值最多返回三个,超过三个请使用 struct。 + +### 6.2 defer + +- 当存在资源创建时,应紧跟defer释放资源(可以大胆使用defer,defer在Go1.14版本中,性能大幅提升,defer的性能损耗即使在性能敏感型的业务中,也可以忽略)。 +- 先判断是否错误,再defer释放资源,例如: + +```go +rep, err := http.Get(url) +if err != nil { + return err +} + +defer resp.Body.Close() +``` + +### 6.3 方法的接收器 + +- 推荐以类名第一个英文首字母的小写作为接收器的命名。 +- 接收器的命名在函数超过20行的时候不要用单字符。 +- 接收器的命名不能采用me、this、self这类易混淆名称。 + +### 6.4 嵌套 +- 嵌套深度不能超过4层。 + +### 6.5 变量命名 +- 变量声明尽量放在变量第一次使用的前面,遵循就近原则。 +- 如果魔法数字出现超过两次,则禁止使用,改用一个常量代替,例如: + +```go +// PI ... +const Prise = 3.14 + +func getAppleCost(n float64) float64 { + return Prise * n +} + +func getOrangeCost(n float64) float64 { + return Prise * n +} +``` + +## 7. GOPATH 设置规范 +- Go 1.11 之后,弱化了 GOPATH 规则,已有代码(很多库肯定是在1.11之前建立的)肯定符合这个规则,建议保留 GOPATH 规则,便于维护代码。 +- 建议只使用一个 GOPATH,不建议使用多个 GOPATH。如果使用多个GOPATH,编译生效的 bin 目录是在第一个 GOPATH 下。 + +## 8. 依赖管理 + +- Go 1.11 以上必须使用 Go Modules。 +- 使用Go Modules作为依赖管理的项目时,不建议提交vendor目录。 +- 使用Go Modules作为依赖管理的项目时,必须提交go.sum文件。 + +### 9. 最佳实践 + +- 尽量少用全局变量,而是通过参数传递,使每个函数都是“无状态”的。这样可以减少耦合,也方便分工和单元测试。 +- 在编译时验证接口的符合性,例如: + +```go +type LogHandler struct { + h http.Handler + log *zap.Logger +} +var _ http.Handler = LogHandler{} +``` +- 服务器处理请求时,应该创建一个context,保存该请求的相关信息(如requestID),并在函数调用链中传递。 + +### 9.1 性能 +- string 表示的是不可变的字符串变量,对 string 的修改是比较重的操作,基本上都需要重新申请内存。所以,如果没有特殊需要,需要修改时多使用 []byte。 +- 优先使用 strconv 而不是 fmt。 + +### 9.2 注意事项 + +- append 要小心自动分配内存,append 返回的可能是新分配的地址。 +- 如果要直接修改 map 的 value 值,则 value 只能是指针,否则要覆盖原来的值。 +- map 在并发中需要加锁。 +- 编译过程无法检查 interface{} 的转换,只能在运行时检查,小心引起 panic。 + +## 总结 + +这里向你介绍了九类常用的编码规范。但今天的最后,我要在这里提醒你一句:规范是人定的,你也可以根据需要,制定符合你项目的规范,但同时我也建议你采纳这些业界沉淀下来的规范,并通过工具来确保规范的执行。 diff --git a/docs/conversions/images.md b/docs/conversions/images.md new file mode 100644 index 0000000..ae85a5b --- /dev/null +++ b/docs/conversions/images.md @@ -0,0 +1,69 @@ +# OpenIM Image Management Strategy and Pulling Guide + +OpenIM is an efficient, stable, and scalable instant messaging framework that provides convenient deployment methods through Docker images. OpenIM manages multiple image sources, hosted respectively on GitHub (ghcr), Alibaba Cloud, and Docker Hub. This document is aimed at detailing the image management strategy of OpenIM and providing the steps for pulling these images. + +## Image Management Strategy + +OpenIM's versions correspond to GitHub's tag versions. Each time we release a new version and tag it on GitHub, an automated process is triggered that pushes the new Docker image version to the following three platforms: + +1. **GitHub (ghcr.io):** We use GitHub Container Registry (ghcr.io) to host OpenIM's Docker images. This allows us to better integrate with the GitHub source code repository, providing better version control and continuous integration/deployment (CI/CD) features. You can view all GitHub images [here](https://github.com/orgs/OpenIMSDK/packages). +2. **Alibaba Cloud (registry.cn-hangzhou.aliyuncs.com):** For users in Mainland China, we also host OpenIM's Docker images on Alibaba Cloud to provide faster pull speeds. You can view all Alibaba Cloud images on this [page](https://cr.console.aliyun.com/cn-hangzhou/instances/repositories) of Alibaba Cloud Image Service (note that you need to log in to your Alibaba Cloud account first). +3. **Docker Hub (docker.io):** Docker Hub is the most commonly used Docker image hosting platform, and we also host OpenIM's images there to facilitate developers worldwide. You can view all Docker Hub images on the [OpenIM's Docker Hub page](https://hub.docker.com/r/openim). + +## Methods and Steps for Pulling Images + +When pulling OpenIM's Docker images, you can choose the most suitable source based on your geographic location and network conditions. Here are the steps to pull OpenIM images from each source: + +1. First, make sure Docker is installed on your machine. If not, you can refer to the [Docker official documentation](https://docs.docker.com/get-docker/) for installation. + +2. Open the terminal and run the following commands to pull the images: + + For OpenIM Server: + + - Pull from GitHub: + + ``` + bashCopy code + docker pull ghcr.io/openimsdk/openim-server:latest + ``` + + - Pull from Alibaba Cloud: + + ``` + bashCopy code + docker pull registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest + ``` + + - Pull from Docker Hub: + + ``` + bashCopy code + docker pull docker.io/openim/openim-server:latest + ``` + + For OpenIM Chat: + + - Pull from GitHub: + + ``` + bashCopy code + docker pull ghcr.io/openimsdk/openim-chat:latest + ``` + + - Pull from Alibaba Cloud: + + ``` + bashCopy code + docker pull registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat:latest + ``` + + - Pull from Docker Hub: + + ``` + bashCopy code + docker pull docker.io/openim/openim-chat:latest + ``` + +3. Run the `docker images` command to confirm that the image has been successfully pulled. + +This concludes OpenIM's image management strategy and the steps for pulling images. If you have any questions, please feel free to ask. \ No newline at end of file diff --git a/docs/conversions/logging.md b/docs/conversions/logging.md new file mode 100644 index 0000000..22918df --- /dev/null +++ b/docs/conversions/logging.md @@ -0,0 +1,20 @@ +## Log Standards + +### Log Standards + +- The unified log package `github.com/openimsdk/Open-IM-Server/internal/pkg/log` should be used for all logging; +- Use structured logging formats: `log.Infow`, `log.Warnw`, `log.Errorw`, etc. For example: `log.Infow("Update post function called")`; +- All logs should start with an uppercase letter and should not end with a `.`. For example: `log.Infow("Update post function called")`; +- Use past tense. For example, use `Could not delete B` instead of `Cannot delete B`; +- Adhere to log level standards: + - Debug level logs use `log.Debugw`; + - Info level logs use `log.Infow`; + - Warning level logs use `log.Warnw`; + - Error level logs use `log.Errorw`; + - Panic level logs use `log.Panicw`; + - Fatal level logs use `log.Fatalw`. +- Log settings: + - Development and test environments: The log level is set to `debug`, the log format can be set to `console` / `json` as needed, and caller is enabled; + - Production environment: The log level is set to `info`, the log format is set to `json`, and caller is enabled. (**Note**: In the early stages of going online, to facilitate troubleshooting, the log level can be set to `debug`) +- When logging, avoid outputting sensitive information, such as passwords, keys, etc. +- If you are calling a logging function in a function/method with a `context.Context` parameter, it is recommended to use `log.L(ctx).Infow()` for logging. \ No newline at end of file diff --git a/docs/conversions/version.md b/docs/conversions/version.md new file mode 100644 index 0000000..a421dd5 --- /dev/null +++ b/docs/conversions/version.md @@ -0,0 +1,57 @@ +# OpenIM Branch Management and Versioning + +Our project, OpenIM, follows the [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/) standards. + +## OpenIM version + +OpenIM manages two primary branches: `main` and `release`. The project uses Semantic Versioning 2.0.0 to tag different versions of the software, each indicating a significant milestone in the software's development. + +In the OpenIM repository, the versioning adheres to the `MAJOR.MINOR.PATCH` format, where: + +- `MAJOR` version changes when there are incompatible changes to the API, +- `MINOR` version changes when features are added in a backward-compatible manner, and +- `PATCH` version changes when backward-compatible bugs are fixed. + +## Milestones and Branching + +When a significant milestone like v3.1.0 is achieved, a new branch `release-v3.1` is created. This branch contains all the code pertaining to this stable release. All bug fixes and features intended for the next version, v3.2.0, are merged into this branch. + +The release of `PATCH` versions (Z in `X.Y.Z`) are driven by bug fixes, and these can be rolled out depending on the bug's priority or over a scheduled time. On the other hand, `MINOR` versions (Y in `X.Y.Z`) are released based on the project's roadmap, milestone completion, or on a scheduled timeline. Importantly, the API of minor versions is always backward-compatible. + +## Dealing with Major Bugs + +In the event of a major bug discovery, the fix would selectively be merged into the previous version (e.g., v3.1 or the `release-v3.1` branch), as well as into the `main` branch. This is to ensure that users relying on the older version can still receive important bug fixes, while also keeping the main branch updated. + +It's worth noting that a robust testing regime should be in place to ensure the integrity of all branches at any given time. Automated tests and code review sessions are crucial components of maintaining a healthy codebase. + +To summarize, OpenIM's approach to branch management and versioning ensures a balance between introducing new features, fixing bugs, and maintaining backward compatibility. This strategy is vital for managing user expectations, supporting older versions, and paving the way for the project's continuous growth. + +## Git Workflow Example + +To put the above principles into practice, here's a Git workflow example that you might follow when working on a bug fix: + +``` +bashCopy code# Checkout the branch for the version that needs the bug fix +git checkout release-v3.1 + +# Create a new branch for the bug fix +git checkout -b bug/bug-name + +# ... Make changes, commit your work ... + +# Push the branch to your remote repository +git push origin bug/bug-name + +# After the pull request is merged into the release-v3.1 branch, +# checkout and update your main branch +git checkout main +git pull origin main + +# Merge or rebase the changes from release-v3.1 into main +git merge release-v3.1 + +# Push the updates to the main branch +git push origin main +``` + +Remember, communication with your team is key throughout this process, keeping everyone up-to-date with the changes being made. \ No newline at end of file diff --git a/docs/统计接口调用example.md b/docs/统计接口调用example.md new file mode 100644 index 0000000..d61ca9a --- /dev/null +++ b/docs/统计接口调用example.md @@ -0,0 +1,34 @@ +- chat 管理端 在线人数统计 +curl -sS -X POST "http://127.0.0.1:10009/statistic/online_user_count" \ +-H "Content-Type: application/json" \ +-H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJpbUFkbWluIiwiVXNlclR5cGUiOjIsIlBsYXRmb3JtSUQiOjAsImV4cCI6MTc3NTI5NTUzMSwibmJmIjoxNzY3NTE5NDcxLCJpYXQiOjE3Njc1MTk1MzF9.m-7AuhZS9Xd_5YMBdxNn7-QQ865PrC2SgKZjByDc3XE" \ +-H "operationID: op_chat_online_001" \ + -d "{}" + +- chat 管理端 在线人数走势统计 +curl -sS -X POST "http://127.0.0.1:10009/statistic/online_user_count_trend" \ +-H "Content-Type: application/json" \ +-H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJpbUFkbWluIiwiVXNlclR5cGUiOjIsIlBsYXRmb3JtSUQiOjAsImV4cCI6MTc3NTI5NTUzMSwibmJmIjoxNzY3NTE5NDcxLCJpYXQiOjE3Njc1MTk1MzF9.m-7AuhZS9Xd_5YMBdxNn7-QQ865PrC2SgKZjByDc3XE" \ +-H "operationID: op_chat_online_trend_001" \ + -d '{"startTime":1700000000000,"endTime":1700086400000,"intervalMinutes":15}' + +- chat 管理端 用户发送消息总数统计 +curl -sS -X POST "http://127.0.0.1:10009/statistic/user_send_msg_count" \ +-H "Content-Type: application/json" \ +-H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJpbUFkbWluIiwiVXNlclR5cGUiOjIsIlBsYXRmb3JtSUQiOjAsImV4cCI6MTc3NTI5NTUzMSwibmJmIjoxNzY3NTE5NDcxLCJpYXQiOjE3Njc1MTk1MzF9.m-7AuhZS9Xd_5YMBdxNn7-QQ865PrC2SgKZjByDc3XE" \ +-H "operationID: op_chat_msg_count_001" \ + -d "{}" + +- chat 管理端 用户发送消息总数走势统计 +curl -sS -X POST "http://127.0.0.1:10009/statistic/user_send_msg_count_trend" \ +-H "Content-Type: application/json" \ +-H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJpbUFkbWluIiwiVXNlclR5cGUiOjIsIlBsYXRmb3JtSUQiOjAsImV4cCI6MTc3NTI5NTUzMSwibmJmIjoxNzY3NTE5NDcxLCJpYXQiOjE3Njc1MTk1MzF9.m-7AuhZS9Xd_5YMBdxNn7-QQ865PrC2SgKZjByDc3XE" \ +-H "operationID: op_chat_msg_trend_001" \ + -d '{"userID":"u001","chatType":1,"startTime":1700000000000,"endTime":1700086400000,"intervalMinutes":30}' + +- chat 管理端 用户发送消息筛选与查询 +curl -sS -X POST "http://127.0.0.1:10009/statistic/user_send_msg_query" \ +-H "Content-Type: application/json" \ +-H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOiJpbUFkbWluIiwiVXNlclR5cGUiOjIsIlBsYXRmb3JtSUQiOjAsImV4cCI6MTc3NTI5NTUzMSwibmJmIjoxNzY3NTE5NDcxLCJpYXQiOjE3Njc1MTk1MzF9.m-7AuhZS9Xd_5YMBdxNn7-QQ865PrC2SgKZjByDc3XE" \ +-H "operationID: op_chat_msg_query_001" \ + -d '{"userID":"u001","startTime":1700000000000,"endTime":1700086400000,"content":"关键词","pageNumber":1,"showNumber":50}' diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..50bfdf9 --- /dev/null +++ b/go.mod @@ -0,0 +1,154 @@ +module git.imall.cloud/openim/chat + +go 1.22.7 + +toolchain go1.23.2 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/uuid v1.6.0 + github.com/jinzhu/copier v0.4.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.1 + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/gorm v1.25.8 +) + +require ( + github.com/alibabacloud-go/darabonba-openapi v0.2.1 + github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 + github.com/alibabacloud-go/tea v1.2.1 +) + +require ( + git.imall.cloud/openim/protocol v1.0.4 + github.com/livekit/protocol v1.10.1 + github.com/mitchellh/mapstructure v1.5.0 + github.com/openimsdk/gomake v0.0.15-alpha.11 + github.com/openimsdk/tools v0.0.50-alpha.65 + github.com/redis/go-redis/v9 v9.5.1 + github.com/sashabaranov/go-openai v1.38.1 + github.com/spf13/cobra v1.8.0 + github.com/spf13/viper v1.18.2 + github.com/xuri/excelize/v2 v2.8.0 + go.etcd.io/etcd/client/v3 v3.5.13 + go.mongodb.org/mongo-driver v1.14.0 + golang.org/x/sync v0.10.0 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df +) + +require ( + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect + github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect + github.com/alibabacloud-go/openapi-util v0.0.11 // indirect + github.com/alibabacloud-go/tea-utils v1.4.5 // indirect + github.com/alibabacloud-go/tea-xml v1.1.2 // indirect + github.com/aliyun/credentials-go v1.1.2 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/clbanning/mxj/v2 v2.5.6 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.18.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/strftime v1.0.6 // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/openimsdk/protocol v0.0.69-alpha.4 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/richardlehane/mscfb v1.0.4 // indirect + github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tjfoc/gmsm v1.3.2 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/twitchtv/twirp v8.1.3+incompatible // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect + github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.etcd.io/etcd/api/v3 v3.5.13 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/api v0.31.2 // indirect + k8s.io/apimachinery v0.31.2 // indirect + k8s.io/client-go v0.31.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) + +// replace git.imall.cloud/openim/protocol => ../protocol diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b272ba1 --- /dev/null +++ b/go.sum @@ -0,0 +1,525 @@ +git.imall.cloud/openim/protocol v1.0.4 h1:8az6AR2C27wL2fI3ZNej/K+4YC/symnJLLjRu5AxLFM= +git.imall.cloud/openim/protocol v1.0.4/go.mod h1:FQVq/s9Nw5IcvlY34OMGfT7+AAxlQ2cVEo73lATXIpg= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc= +github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY= +github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 h1:hfZA4cgIl6frNdsRmAyj8sn9J1bihQpYbzIVv2T/+Cs= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18/go.mod h1:di54xjBFHvKiQQo7st3TUmiMy0ywne5TOHup786Rhes= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.11 h1:iYnqOPR5hyEEnNZmebGyRMkkEJRWUEjDiiaOHZ5aNhA= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.1 h1:rFF1LnrAdhaiPmKwH5xwYOKlMh66CqRwPUTzIK74ask= +github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= +github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/clbanning/mxj/v2 v2.5.6 h1:Jm4VaCI/+Ug5Q57IzEoZbwx4iQFA6wkXv72juUSeK+g= +github.com/clbanning/mxj/v2 v2.5.6/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= +github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frostbyte73/core v0.0.10 h1:D4DQXdPb8ICayz0n75rs4UYTXrUSdxzUfeleuNJORsU= +github.com/frostbyte73/core v0.0.10/go.mod h1:XsOGqrqe/VEV7+8vJ+3a8qnCIXNbKsoEiu/czs7nrcU= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0= +github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= +github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= +github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= +github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= +github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c= +github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y= +github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkDaKb5iXdynYrzB84ErPPO4LbRASk58= +github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= +github.com/livekit/protocol v1.10.1 h1:upe6pKRqH8wpsMuR2OLtgizEm94iia3pDYm3O4/2PRY= +github.com/livekit/protocol v1.10.1/go.mod h1:eWPz45pnxwpCwB84qqhHxG0bCRgasa2itN6GAHCDddc= +github.com/livekit/psrpc v0.5.3-0.20240227154351-b7f99eaaf7b3 h1:bvjzDR+Rvdf3JgzQMtLiGVHBQ8KoOWM7x7sHj79jevQ= +github.com/livekit/psrpc v0.5.3-0.20240227154351-b7f99eaaf7b3/go.mod h1:CQUBSPfYYAaevg1TNCc6/aYsa8DJH4jSRFdCeSZk5u0= +github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs= +github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJvtio5ZjJTbdlQ= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= +github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= +github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= +github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/openimsdk/gomake v0.0.15-alpha.11 h1:PQudYDRESYeYlUYrrLLJhYIlUPO5x7FAx+o5El9U/Bw= +github.com/openimsdk/gomake v0.0.15-alpha.11/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/protocol v0.0.69-alpha.4 h1:QJkOFV5Hlu7CbkHG5smeVw+5fx5DVkpNJWqlAOJxuIY= +github.com/openimsdk/protocol v0.0.69-alpha.4/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/tools v0.0.50-alpha.65 h1:BRtxkyWxDWPHuHphSwEyHZj7kJSR98am/fHOH84naK8= +github.com/openimsdk/tools v0.0.50-alpha.65/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= +github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/ice/v2 v2.3.13 h1:xOxP+4V9nSDlUaGFRf/LvAuGHDXRcjIdsbbXPK/w7c8= +github.com/pion/ice/v2 v2.3.13/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc= +github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12 h1:bKWiX93XKgDZENEXCijvHRU/wRifm6JV5DGcH6twtSM= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.12 h1:2VX50pedElH+is6FI+OKyRTeN5oy4mrk2HjnGa3UCmY= +github.com/pion/sctp v1.8.12/go.mod h1:cMLT45jqw3+jiJCrtHVwfQLnfR0MGZ4rgOJwUOIqLkI= +github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw= +github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.3 h1:XcOE3/x41HOSKbl1BfyY1TF1dERx7lVvlMCbXU7kfvA= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/turn/v2 v2.1.3 h1:pYxTVWG2gpC97opdRc5IGsQ1lJ9O/IlNhkzj7MMrGAA= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.28 h1:ienStxZ6HcjtH2UlmnFpMM0loENiYjaX437uIUpQSKo= +github.com/pion/webrtc/v3 v3.2.28/go.mod h1:PNRCEuQlibrmuBhOTnol9j6KkIbUG11aHLEfNpUYey0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/puzpuzpuz/xsync v1.5.2 h1:yRAP4wqSOZG+/4pxJ08fPTwrfL0IzE/LKQ/cw509qGY= +github.com/puzpuzpuz/xsync v1.5.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= +github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= +github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= +github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sashabaranov/go-openai v1.38.1 h1:TtZabbFQZa1nEni/IhVtDF/WQjVqDgd+cWR5OeddzF8= +github.com/sashabaranov/go-openai v1.38.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU= +github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg= +github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U= +github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg= +github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o= +github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/etcd/api/v3 v3.5.13 h1:8WXU2/NBge6AUF1K1gOexB6e07NgsN1hXK0rSTtgSp4= +go.etcd.io/etcd/api/v3 v3.5.13/go.mod h1:gBqlqkcMMZMVTMm4NDZloEVJzxQOQIls8splbqBDa0c= +go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= +go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8= +go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js= +go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo= +gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go new file mode 100644 index 0000000..d429637 --- /dev/null +++ b/internal/api/admin/admin.go @@ -0,0 +1,1663 @@ +package admin + +import ( + "context" + "crypto/md5" + "encoding/hex" + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "git.imall.cloud/openim/chat/internal/api/util" + "git.imall.cloud/openim/chat/pkg/common/apistruct" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/common/xlsx" + "git.imall.cloud/openim/chat/pkg/common/xlsx/model" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "git.imall.cloud/openim/protocol/constant" + "git.imall.cloud/openim/protocol/sdkws" + "git.imall.cloud/openim/protocol/user" + wrapperspb "git.imall.cloud/openim/protocol/wrapperspb" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/encrypt" +) + +func New(chatClient chat.ChatClient, adminClient admin.AdminClient, imApiCaller imapi.CallerInterface, api *util.Api) *Api { + return &Api{ + Api: api, + chatClient: chatClient, + adminClient: adminClient, + imApiCaller: imApiCaller, + } +} + +type Api struct { + *util.Api + chatClient chat.ChatClient + adminClient admin.AdminClient + imApiCaller imapi.CallerInterface +} + +func (o *Api) AdminLogin(c *gin.Context) { + req, err := a2r.ParseRequest[admin.LoginReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + // if req.Version == "" { + // apiresp.GinError(c, errs.New("openim-admin-front version too old, please use new version").Wrap()) + // return + // } + loginResp, err := o.adminClient.Login(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + imAdminUserID := o.GetDefaultIMAdminUserID() + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + var resp apistruct.AdminLoginResp + if err := datautil.CopyStructFields(&resp, loginResp); err != nil { + apiresp.GinError(c, err) + return + } + resp.ImToken = imToken + resp.ImUserID = imAdminUserID + apiresp.GinSuccess(c, resp) +} + +func (o *Api) ResetUserPassword(c *gin.Context) { + req, err := a2r.ParseRequest[chat.ChangePasswordReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.chatClient.ChangePassword(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + err = o.imApiCaller.ForceOffLine(mctx.WithApiToken(c, imToken), req.UserID) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +func (o *Api) AdminUpdateInfo(c *gin.Context) { + req, err := a2r.ParseRequest[admin.AdminUpdateInfoReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.adminClient.AdminUpdateInfo(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + imAdminUserID := o.GetDefaultIMAdminUserID() + imToken, err := o.imApiCaller.GetAdminTokenCache(c, imAdminUserID) + if err != nil { + log.ZError(c, "AdminUpdateInfo ImAdminTokenWithDefaultAdmin", err, "imAdminUserID", imAdminUserID) + return + } + if err := o.imApiCaller.UpdateUserInfo(mctx.WithApiToken(c, imToken), imAdminUserID, resp.Nickname, resp.FaceURL, 1, ""); err != nil { + log.ZError(c, "AdminUpdateInfo UpdateUserInfo", err, "userID", resp.UserID, "nickName", resp.Nickname, "faceURL", resp.FaceURL) + } + apiresp.GinSuccess(c, nil) +} + +func (o *Api) AdminInfo(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetAdminInfo, o.adminClient) +} + +func (o *Api) ChangeAdminPassword(c *gin.Context) { + a2r.Call(c, admin.AdminClient.ChangeAdminPassword, o.adminClient) +} + +func (o *Api) ChangeOperationPassword(c *gin.Context) { + a2r.Call(c, admin.AdminClient.ChangeOperationPassword, o.adminClient) +} + +func (o *Api) SetGoogleAuthKey(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SetGoogleAuthKey, o.adminClient) +} + +func (o *Api) AddAdminAccount(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddAdminAccount, o.adminClient) +} + +func (o *Api) AddUserAccount(c *gin.Context) { + req, err := a2r.ParseRequest[chat.AddUserAccountReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + ctx := o.WithAdminUser(mctx.WithApiToken(c, imToken)) + + err = o.registerChatUser(ctx, ip, []*chat.RegisterUserInfo{req.User}) + if err != nil { + return + } + + apiresp.GinSuccess(c, nil) +} + +func (o *Api) DelAdminAccount(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelAdminAccount, o.adminClient) +} + +func (o *Api) SearchAdminAccount(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchAdminAccount, o.adminClient) +} + +func (o *Api) GetStatistics(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetStatistics, o.adminClient) +} + +func (o *Api) AddDefaultFriend(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddDefaultFriend, o.adminClient) +} + +func (o *Api) DelDefaultFriend(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelDefaultFriend, o.adminClient) +} + +func (o *Api) SearchDefaultFriend(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchDefaultFriend, o.adminClient) +} + +func (o *Api) FindDefaultFriend(c *gin.Context) { + a2r.Call(c, admin.AdminClient.FindDefaultFriend, o.adminClient) +} + +func (o *Api) AddDefaultGroup(c *gin.Context) { + req, err := a2r.ParseRequest[admin.AddDefaultGroupReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + groups, err := o.imApiCaller.FindGroupInfo(mctx.WithApiToken(c, imToken), req.GroupIDs) + if err != nil { + apiresp.GinError(c, err) + return + } + if len(req.GroupIDs) != len(groups) { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("group id not found")) + return + } + resp, err := o.adminClient.AddDefaultGroup(c, &admin.AddDefaultGroupReq{ + GroupIDs: req.GroupIDs, + }) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) DelDefaultGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelDefaultGroup, o.adminClient) +} + +func (o *Api) FindDefaultGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.FindDefaultGroup, o.adminClient) +} + +func (o *Api) SearchDefaultGroup(c *gin.Context) { + req, err := a2r.ParseRequest[admin.SearchDefaultGroupReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + searchResp, err := o.adminClient.SearchDefaultGroup(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + resp := apistruct.SearchDefaultGroupResp{ + Total: searchResp.Total, + Groups: make([]*sdkws.GroupInfo, 0, len(searchResp.GroupIDs)), + } + if len(searchResp.GroupIDs) > 0 { + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + groups, err := o.imApiCaller.FindGroupInfo(mctx.WithApiToken(c, imToken), searchResp.GroupIDs) + if err != nil { + apiresp.GinError(c, err) + return + } + groupMap := make(map[string]*sdkws.GroupInfo) + for _, group := range groups { + groupMap[group.GroupID] = group + } + for _, groupID := range searchResp.GroupIDs { + if group, ok := groupMap[groupID]; ok { + resp.Groups = append(resp.Groups, group) + } else { + resp.Groups = append(resp.Groups, &sdkws.GroupInfo{ + GroupID: groupID, + }) + } + } + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) AddInvitationCode(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddInvitationCode, o.adminClient) +} + +func (o *Api) GenInvitationCode(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GenInvitationCode, o.adminClient) +} + +func (o *Api) DelInvitationCode(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelInvitationCode, o.adminClient) +} + +func (o *Api) SearchInvitationCode(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchInvitationCode, o.adminClient) +} + +func (o *Api) AddUserIPLimitLogin(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddUserIPLimitLogin, o.adminClient) +} + +func (o *Api) SearchUserIPLimitLogin(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchUserIPLimitLogin, o.adminClient) +} + +func (o *Api) DelUserIPLimitLogin(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelUserIPLimitLogin, o.adminClient) +} + +func (o *Api) SearchIPForbidden(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchIPForbidden, o.adminClient) +} + +func (o *Api) AddIPForbidden(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddIPForbidden, o.adminClient) +} + +func (o *Api) DelIPForbidden(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelIPForbidden, o.adminClient) +} + +func (o *Api) ParseToken(c *gin.Context) { + a2r.Call(c, admin.AdminClient.ParseToken, o.adminClient) +} + +func (o *Api) BlockUser(c *gin.Context) { + req, err := a2r.ParseRequest[admin.BlockUserReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.adminClient.BlockUser(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + err = o.imApiCaller.ForceOffLine(mctx.WithApiToken(c, imToken), req.UserID) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) UnblockUser(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UnblockUser, o.adminClient) +} + +func (o *Api) SearchBlockUser(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchBlockUser, o.adminClient) +} + +func (o *Api) SetClientConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SetClientConfig, o.adminClient) +} + +func (o *Api) DelClientConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelClientConfig, o.adminClient) +} + +func (o *Api) GetClientConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetClientConfig, o.adminClient) +} + +func (o *Api) AddApplet(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddApplet, o.adminClient) +} + +func (o *Api) DelApplet(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DelApplet, o.adminClient) +} + +func (o *Api) UpdateApplet(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateApplet, o.adminClient) +} + +func (o *Api) SearchApplet(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchApplet, o.adminClient) +} + +func (o *Api) LoginUserCount(c *gin.Context) { + a2r.Call(c, chat.ChatClient.UserLoginCount, o.chatClient) +} + +// OnlineUserCount 在线人数统计 +func (o *Api) OnlineUserCount(c *gin.Context) { + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.imApiCaller.OnlineUserCount(mctx.WithApiToken(c, imToken)) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +// OnlineUserCountTrend 在线人数走势统计 +func (o *Api) OnlineUserCountTrend(c *gin.Context) { + req, err := a2r.ParseRequest[imapi.OnlineUserCountTrendReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.imApiCaller.OnlineUserCountTrend(mctx.WithApiToken(c, imToken), req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +// UserSendMsgCount 用户发送消息总数统计 +func (o *Api) UserSendMsgCount(c *gin.Context) { + req, err := a2r.ParseRequest[imapi.UserSendMsgCountReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.imApiCaller.UserSendMsgCount(mctx.WithApiToken(c, imToken), req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +// UserSendMsgCountTrend 用户发送消息走势统计 +func (o *Api) UserSendMsgCountTrend(c *gin.Context) { + req, err := a2r.ParseRequest[imapi.UserSendMsgCountTrendReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.imApiCaller.UserSendMsgCountTrend(mctx.WithApiToken(c, imToken), req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +// UserSendMsgQuery 用户发送消息查询 +func (o *Api) UserSendMsgQuery(c *gin.Context) { + req, err := a2r.ParseRequest[imapi.UserSendMsgQueryReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.imApiCaller.UserSendMsgQuery(mctx.WithApiToken(c, imToken), req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) NewUserCount(c *gin.Context) { + req, err := a2r.ParseRequest[user.UserRegisterCountReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + dateCount, total, err := o.imApiCaller.UserRegisterCount(mctx.WithApiToken(c, imToken), req.Start, req.End) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, &apistruct.NewUserCountResp{ + DateCount: dateCount, + Total: total, + }) +} + +func (o *Api) ImportUserByXlsx(c *gin.Context) { + formFile, err := c.FormFile("data") + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + file, err := formFile.Open() + if err != nil { + apiresp.GinError(c, err) + return + } + defer file.Close() + var users []model.User + if err := xlsx.ParseAll(file, &users); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("xlsx file parse error "+err.Error())) + return + } + us, err := o.xlsx2user(users) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + ctx := o.WithAdminUser(mctx.WithApiToken(c, imToken)) + apiresp.GinError(c, o.registerChatUser(ctx, ip, us)) +} + +func (o *Api) ImportUserByJson(c *gin.Context) { + req, err := a2r.ParseRequest[struct { + Users []*chat.RegisterUserInfo `json:"users"` + }](c) + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + ctx := o.WithAdminUser(mctx.WithApiToken(c, imToken)) + apiresp.GinError(c, o.registerChatUser(ctx, ip, req.Users)) +} + +func (o *Api) xlsx2user(users []model.User) ([]*chat.RegisterUserInfo, error) { + chatUsers := make([]*chat.RegisterUserInfo, len(users)) + for i, info := range users { + if info.Nickname == "" { + return nil, errs.ErrArgs.WrapMsg("nickname is empty") + } + if info.AreaCode == "" || info.PhoneNumber == "" { + return nil, errs.ErrArgs.WrapMsg("areaCode or phoneNumber is empty") + } + if info.Password == "" { + return nil, errs.ErrArgs.WrapMsg("password is empty") + } + if !strings.HasPrefix(info.AreaCode, "+") { + return nil, errs.ErrArgs.WrapMsg("areaCode format error") + } + if _, err := strconv.ParseUint(info.AreaCode[1:], 10, 16); err != nil { + return nil, errs.ErrArgs.WrapMsg("areaCode format error") + } + gender, _ := strconv.Atoi(info.Gender) + chatUsers[i] = &chat.RegisterUserInfo{ + UserID: info.UserID, + Nickname: info.Nickname, + FaceURL: info.FaceURL, + Birth: o.xlsxBirth(info.Birth).UnixMilli(), + Gender: int32(gender), + AreaCode: info.AreaCode, + PhoneNumber: info.PhoneNumber, + Email: info.Email, + Account: info.Account, + Password: encrypt.Md5(info.Password), + } + } + return chatUsers, nil +} + +func (o *Api) xlsxBirth(s string) time.Time { + if s == "" { + return time.Now() + } + var separator byte + for _, b := range []byte(s) { + if b < '0' || b > '9' { + separator = b + } + } + + arr := strings.Split(s, string([]byte{separator})) + if len(arr) != 3 { + return time.Now() + } + year, _ := strconv.Atoi(arr[0]) + month, _ := strconv.Atoi(arr[1]) + day, _ := strconv.Atoi(arr[2]) + t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local) + if t.Before(time.Date(1900, 0, 0, 0, 0, 0, 0, time.Local)) { + return time.Now() + } + return t +} + +func (o *Api) registerChatUser(ctx context.Context, ip string, users []*chat.RegisterUserInfo) error { + if len(users) == 0 { + return errs.ErrArgs.WrapMsg("users is empty") + } + for _, info := range users { + respRegisterUser, err := o.chatClient.RegisterUser(ctx, &chat.RegisterUserReq{Ip: ip, User: info, Platform: constant.AdminPlatformID}) + if err != nil { + return err + } + exMap := make(map[string]interface{}) + exMap["userType"] = info.UserType + exMap["userFlag"] = info.UserFlag + ex, err := json.Marshal(exMap) + if err != nil { + return err + } + + userInfo := &sdkws.UserInfo{ + UserID: respRegisterUser.UserID, + Nickname: info.Nickname, + FaceURL: info.FaceURL, + UserType: info.UserType, // 使用传入的用户类型,如果没有则默认为0 + UserFlag: info.UserFlag, // 使用传入的用户标签 + Ex: string(ex), + } + if err = o.imApiCaller.RegisterUser(ctx, []*sdkws.UserInfo{userInfo}); err != nil { + return err + } + + if resp, err := o.adminClient.FindDefaultFriend(ctx, &admin.FindDefaultFriendReq{}); err == nil { + _ = o.imApiCaller.ImportFriend(ctx, respRegisterUser.UserID, resp.UserIDs) + } + if resp, err := o.adminClient.FindDefaultGroup(ctx, &admin.FindDefaultGroupReq{}); err == nil { + _ = o.imApiCaller.InviteToGroup(ctx, respRegisterUser.UserID, resp.GroupIDs) + } + } + return nil +} + +func (o *Api) BatchImportTemplate(c *gin.Context) { + md5Sum := md5.Sum(config.ImportTemplate) + md5Val := hex.EncodeToString(md5Sum[:]) + if c.GetHeader("If-None-Match") == md5Val { + c.Status(http.StatusNotModified) + return + } + c.Header("Content-Disposition", "attachment; filename=template.xlsx") + c.Header("Content-Transfer-Encoding", "binary") + c.Header("Content-Description", "File Transfer") + c.Header("Content-Length", strconv.Itoa(len(config.ImportTemplate))) + c.Header("ETag", md5Val) + c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", config.ImportTemplate) +} + +func (o *Api) SetAllowRegister(c *gin.Context) { + a2r.Call(c, chat.ChatClient.SetAllowRegister, o.chatClient) +} + +func (o *Api) GetAllowRegister(c *gin.Context) { + a2r.Call(c, chat.ChatClient.GetAllowRegister, o.chatClient) +} + +func (o *Api) LatestApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.LatestApplicationVersion, o.adminClient) +} + +func (o *Api) PageApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.PageApplicationVersion, o.adminClient) +} + +func (o *Api) AddApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddApplicationVersion, o.adminClient) +} + +func (o *Api) UpdateApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateApplicationVersion, o.adminClient) +} + +func (o *Api) DeleteApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteApplicationVersion, o.adminClient) +} + +// ==================== 敏感词管理相关 API ==================== + +// 敏感词管理 +func (o *Api) AddSensitiveWord(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddSensitiveWord, o.adminClient) +} + +func (o *Api) UpdateSensitiveWord(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateSensitiveWord, o.adminClient) +} + +func (o *Api) DeleteSensitiveWord(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteSensitiveWord, o.adminClient) +} + +func (o *Api) GetSensitiveWord(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetSensitiveWord, o.adminClient) +} + +func (o *Api) SearchSensitiveWords(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SearchSensitiveWords, o.adminClient) +} + +func (o *Api) BatchAddSensitiveWords(c *gin.Context) { + a2r.Call(c, admin.AdminClient.BatchAddSensitiveWords, o.adminClient) +} + +func (o *Api) BatchUpdateSensitiveWords(c *gin.Context) { + a2r.Call(c, admin.AdminClient.BatchUpdateSensitiveWords, o.adminClient) +} + +func (o *Api) BatchDeleteSensitiveWords(c *gin.Context) { + a2r.Call(c, admin.AdminClient.BatchDeleteSensitiveWords, o.adminClient) +} + +// 敏感词分组管理 +func (o *Api) AddSensitiveWordGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.AddSensitiveWordGroup, o.adminClient) +} + +func (o *Api) UpdateSensitiveWordGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateSensitiveWordGroup, o.adminClient) +} + +func (o *Api) DeleteSensitiveWordGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteSensitiveWordGroup, o.adminClient) +} + +func (o *Api) GetSensitiveWordGroup(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetSensitiveWordGroup, o.adminClient) +} + +func (o *Api) GetAllSensitiveWordGroups(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetAllSensitiveWordGroups, o.adminClient) +} + +// 敏感词配置管理 +func (o *Api) GetSensitiveWordConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetSensitiveWordConfig, o.adminClient) +} + +func (o *Api) UpdateSensitiveWordConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateSensitiveWordConfig, o.adminClient) +} + +// 敏感词日志管理 +func (o *Api) GetSensitiveWordLogs(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetSensitiveWordLogs, o.adminClient) +} + +func (o *Api) DeleteSensitiveWordLogs(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteSensitiveWordLogs, o.adminClient) +} + +// 用户登录记录管理 +func (o *Api) GetUserLoginRecords(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetUserLoginRecords, o.adminClient) +} + +// 敏感词统计 +func (o *Api) GetSensitiveWordStats(c *gin.Context) { + req := &admin.GetSensitiveWordStatsReq{} + resp, err := o.adminClient.GetSensitiveWordStats(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) GetSensitiveWordLogStats(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetSensitiveWordLogStats, o.adminClient) +} + +// ==================== 定时任务管理相关 API ==================== + +// GetScheduledTasks 获取定时任务列表 +func (o *Api) GetScheduledTasks(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetScheduledTasks, o.adminClient) +} + +// DeleteScheduledTask 删除定时任务 +func (o *Api) DeleteScheduledTask(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteScheduledTask, o.adminClient) +} + +// ==================== 系统配置管理相关 API ==================== + +// CreateSystemConfig 创建系统配置 +func (o *Api) CreateSystemConfig(c *gin.Context) { + // 自定义处理,支持 value 字段为多种类型 + var req struct { + Key string `json:"key" binding:"required"` + Title string `json:"title"` + Value interface{} `json:"value"` // 支持多种类型:string, number, bool, object + ValueType int32 `json:"valueType"` + Description string `json:"description"` + Enabled bool `json:"enabled"` + ShowInApp interface{} `json:"showInApp"` // 是否在APP端展示 + } + + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request: "+err.Error())) + return + } + + // 如果未设置值类型,默认为字符串类型 + valueType := req.ValueType + if valueType == 0 { + valueType = 1 // ConfigValueTypeString + } + + // 将 value 转换为字符串 + valueStr := "" + if req.Value != nil { + // 根据 valueType 转换 + switch valueType { + case 1: // String + if str, ok := req.Value.(string); ok { + valueStr = str + } else { + valueStr = fmt.Sprintf("%v", req.Value) + } + case 2: // Number + switch v := req.Value.(type) { + case string: + valueStr = v + case float64: + valueStr = strconv.FormatFloat(v, 'f', -1, 64) + case float32: + valueStr = strconv.FormatFloat(float64(v), 'f', -1, 32) + case int: + valueStr = strconv.Itoa(v) + case int64: + valueStr = strconv.FormatInt(v, 10) + case int32: + valueStr = strconv.FormatInt(int64(v), 10) + default: + valueStr = fmt.Sprintf("%v", v) + } + case 3: // Bool + switch v := req.Value.(type) { + case string: + // 对于字符串,先尝试解析为布尔值,如果失败则报错 + if v == "" { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("boolean value cannot be empty, must be 'true' or 'false'")) + return + } + // 标准化布尔值字符串(支持 "1", "t", "T", "true", "TRUE", "True" 等) + if parsed, err := strconv.ParseBool(v); err == nil { + valueStr = strconv.FormatBool(parsed) + } else { + apiresp.GinError(c, errs.ErrArgs.WrapMsg(fmt.Sprintf("invalid boolean value '%s', must be 'true' or 'false'", v))) + return + } + case bool: + valueStr = strconv.FormatBool(v) + default: + // 对于其他类型,尝试转换为字符串后再解析 + strVal := fmt.Sprintf("%v", v) + if strVal == "" { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("boolean value cannot be empty, must be 'true' or 'false'")) + return + } + if parsed, err := strconv.ParseBool(strVal); err == nil { + valueStr = strconv.FormatBool(parsed) + } else { + apiresp.GinError(c, errs.ErrArgs.WrapMsg(fmt.Sprintf("invalid boolean value '%s', must be 'true' or 'false'", strVal))) + return + } + } + case 4: // JSON + switch v := req.Value.(type) { + case string: + valueStr = v + default: + // 序列化为 JSON + jsonBytes, err := json.Marshal(v) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid JSON value")) + return + } + valueStr = string(jsonBytes) + } + default: + valueStr = fmt.Sprintf("%v", req.Value) + } + } + + // 如果 value 未提供,根据 valueType 设置默认值 + if valueStr == "" { + switch valueType { + case 3: // Bool + // 布尔类型默认值为 false + valueStr = "false" + case 2: // Number + // 数字类型默认值为 0 + valueStr = "0" + case 4: // JSON + // JSON 类型默认值为空对象 + valueStr = "{}" + // String 类型允许空字符串,保持 valueStr = "" + } + } + + // 验证转换后的值 + if err := o.validateValueByType(valueStr, valueType); err != nil { + apiresp.GinError(c, err) + return + } + + // 处理 showInApp 字段(默认为 false) + showInApp := false + if req.ShowInApp != nil { + if sa, ok := req.ShowInApp.(bool); ok { + showInApp = sa + } + } + + // 构建 protobuf 请求 + pbReq := &admin.CreateSystemConfigReq{ + Key: req.Key, + Title: req.Title, + Value: valueStr, + ValueType: valueType, + Description: req.Description, + Enabled: req.Enabled, + ShowInApp: showInApp, + } + + // 调用 RPC + resp, err := o.adminClient.CreateSystemConfig(c, pbReq) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +// validateValueByType 验证值是否符合类型要求(API 层辅助函数) +func (o *Api) validateValueByType(value string, valueType int32) error { + switch valueType { + case 1: // String + return nil + case 2: // Number + if _, err := strconv.ParseFloat(value, 64); err != nil { + return errs.ErrArgs.WrapMsg("value must be a valid number") + } + return nil + case 3: // Bool + if value == "" { + return errs.ErrArgs.WrapMsg("boolean value cannot be empty, must be 'true' or 'false'") + } + if _, err := strconv.ParseBool(value); err != nil { + return errs.ErrArgs.WrapMsg(fmt.Sprintf("invalid boolean value '%s', must be 'true' or 'false' (also accepts: '1', '0', 't', 'f', 'T', 'F')", value)) + } + return nil + case 4: // JSON + var js interface{} + if err := json.Unmarshal([]byte(value), &js); err != nil { + return errs.ErrArgs.WrapMsg("value must be a valid JSON") + } + return nil + default: + return errs.ErrArgs.WrapMsg("invalid value type") + } +} + +// GetSystemConfig 获取系统配置详情 +func (o *Api) GetSystemConfig(c *gin.Context) { + // 使用自定义处理,转换返回的 value 类型 + var req admin.GetSystemConfigReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetSystemConfig(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换 value 为对应类型 + convertedValue := o.convertValueFromString(resp.Config.Value, resp.Config.ValueType) + + // 构建响应 + result := map[string]interface{}{ + "key": resp.Config.Key, + "title": resp.Config.Title, + "value": convertedValue, + "valueType": resp.Config.ValueType, + "description": resp.Config.Description, + "enabled": resp.Config.Enabled, + "showInApp": resp.Config.ShowInApp, + "createTime": resp.Config.CreateTime, + "updateTime": resp.Config.UpdateTime, + } + + apiresp.GinSuccess(c, map[string]interface{}{"config": result}) +} + +// convertValueFromString 将字符串值转换为对应类型(用于返回给前端) +func (o *Api) convertValueFromString(value string, valueType int32) interface{} { + switch valueType { + case 1: // String + return value + case 2: // Number + // 尝试解析为数字 + if num, err := strconv.ParseFloat(value, 64); err == nil { + // 如果是整数,返回整数;否则返回浮点数 + if num == float64(int64(num)) { + return int64(num) + } + return num + } + return value + case 3: // Bool + if b, err := strconv.ParseBool(value); err == nil { + return b + } + return value + case 4: // JSON + var js interface{} + if err := json.Unmarshal([]byte(value), &js); err == nil { + return js + } + return value + default: + return value + } +} + +// GetAllSystemConfigs 获取所有系统配置(分页) +func (o *Api) GetAllSystemConfigs(c *gin.Context) { + var req admin.GetAllSystemConfigsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetAllSystemConfigs(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表中的 value 为对应类型 + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, config := range resp.List { + convertedValue := o.convertValueFromString(config.Value, config.ValueType) + list = append(list, map[string]interface{}{ + "key": config.Key, + "title": config.Title, + "value": convertedValue, + "valueType": config.ValueType, + "description": config.Description, + "enabled": config.Enabled, + "showInApp": config.ShowInApp, + "createTime": config.CreateTime, + "updateTime": config.UpdateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "list": list, + }) +} + +// UpdateSystemConfig 更新系统配置 +func (o *Api) UpdateSystemConfig(c *gin.Context) { + // 自定义处理,支持 value 字段为多种类型 + var req struct { + Key string `json:"key" binding:"required"` + Title interface{} `json:"title"` + Value interface{} `json:"value"` // 支持多种类型 + ValueType interface{} `json:"valueType"` + Description interface{} `json:"description"` + Enabled interface{} `json:"enabled"` + ShowInApp interface{} `json:"showInApp"` // 是否在APP端展示 + } + + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + // 获取当前配置以确定 valueType + currentConfig, err := o.adminClient.GetSystemConfig(c, &admin.GetSystemConfigReq{Key: req.Key}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 确定要使用的 valueType + valueType := currentConfig.Config.ValueType + if req.ValueType != nil { + // 处理 JSON 中的数字类型(可能是 float64) + switch v := req.ValueType.(type) { + case float64: + valueType = int32(v) + case int: + valueType = int32(v) + case int32: + valueType = v + } + } + + // 构建 protobuf 请求 + pbReq := &admin.UpdateSystemConfigReq{ + Key: req.Key, + } + + // 处理可选字段 + if req.Title != nil { + if titleStr, ok := req.Title.(string); ok { + pbReq.Title = &wrapperspb.StringValue{Value: titleStr} + } + } + if req.Description != nil { + if descStr, ok := req.Description.(string); ok { + pbReq.Description = &wrapperspb.StringValue{Value: descStr} + } + } + if req.Enabled != nil { + if enabled, ok := req.Enabled.(bool); ok { + pbReq.Enabled = &wrapperspb.BoolValue{Value: enabled} + } + } + if req.ShowInApp != nil { + if showInApp, ok := req.ShowInApp.(bool); ok { + pbReq.ShowInApp = &wrapperspb.BoolValue{Value: showInApp} + } + } + if req.ValueType != nil { + if vt, ok := req.ValueType.(float64); ok { + pbReq.ValueType = &wrapperspb.Int32Value{Value: int32(vt)} + } + } + + // 如果提供了 value,转换为字符串 + if req.Value != nil { + valueStr := o.convertValueToString(req.Value, valueType) + // 验证转换后的值 + if err := o.validateValueByType(valueStr, valueType); err != nil { + apiresp.GinError(c, err) + return + } + pbReq.Value = &wrapperspb.StringValue{Value: valueStr} + } + + // 调用 RPC + resp, err := o.adminClient.UpdateSystemConfig(c, pbReq) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +// convertValueToString 将任意类型的值转换为字符串 +func (o *Api) convertValueToString(value interface{}, valueType int32) string { + if value == nil { + return "" + } + + switch valueType { + case 1: // String + if str, ok := value.(string); ok { + return str + } + return fmt.Sprintf("%v", value) + case 2: // Number + switch v := value.(type) { + case string: + return v + case float64: + return strconv.FormatFloat(v, 'f', -1, 64) + case float32: + return strconv.FormatFloat(float64(v), 'f', -1, 32) + case int: + return strconv.Itoa(v) + case int64: + return strconv.FormatInt(v, 10) + case int32: + return strconv.FormatInt(int64(v), 10) + default: + return fmt.Sprintf("%v", v) + } + case 3: // Bool + switch v := value.(type) { + case string: + return v + case bool: + return strconv.FormatBool(v) + default: + return fmt.Sprintf("%v", v) + } + case 4: // JSON + switch v := value.(type) { + case string: + return v + default: + jsonBytes, _ := json.Marshal(v) + return string(jsonBytes) + } + default: + return fmt.Sprintf("%v", value) + } +} + +// UpdateSystemConfigValue 更新系统配置值 +func (o *Api) UpdateSystemConfigValue(c *gin.Context) { + var req struct { + Key string `json:"key" binding:"required"` + Value interface{} `json:"value"` // 支持多种类型 + } + + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + // 获取当前配置以确定 valueType + currentConfig, err := o.adminClient.GetSystemConfig(c, &admin.GetSystemConfigReq{Key: req.Key}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换为字符串 + valueStr := o.convertValueToString(req.Value, currentConfig.Config.ValueType) + + // 验证转换后的值 + if err := o.validateValueByType(valueStr, currentConfig.Config.ValueType); err != nil { + apiresp.GinError(c, err) + return + } + + // 调用 RPC + resp, err := o.adminClient.UpdateSystemConfigValue(c, &admin.UpdateSystemConfigValueReq{ + Key: req.Key, + Value: valueStr, + }) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +// UpdateSystemConfigEnabled 更新系统配置启用状态 +func (o *Api) UpdateSystemConfigEnabled(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateSystemConfigEnabled, o.adminClient) +} + +// DeleteSystemConfig 删除系统配置 +func (o *Api) DeleteSystemConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.DeleteSystemConfig, o.adminClient) +} + +// GetEnabledSystemConfigs 获取所有已启用的配置 +func (o *Api) GetEnabledSystemConfigs(c *gin.Context) { + resp, err := o.adminClient.GetEnabledSystemConfigs(c, &admin.GetEnabledSystemConfigsReq{}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表中的 value 为对应类型 + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, config := range resp.List { + convertedValue := o.convertValueFromString(config.Value, config.ValueType) + list = append(list, map[string]interface{}{ + "key": config.Key, + "title": config.Title, + "value": convertedValue, + "valueType": config.ValueType, + "description": config.Description, + "enabled": config.Enabled, + "showInApp": config.ShowInApp, + "createTime": config.CreateTime, + "updateTime": config.UpdateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{"list": list}) +} + +// ==================== 钱包管理相关 API ==================== + +// GetUserWallet 获取用户钱包信息 +func (o *Api) GetUserWallet(c *gin.Context) { + var req admin.GetUserWalletReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetUserWallet(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 构建响应 + result := map[string]interface{}{ + "userID": resp.Wallet.UserID, + "balance": resp.Wallet.Balance, + "withdrawAccount": resp.Wallet.WithdrawAccount, + "withdrawReceiveAccount": resp.Wallet.WithdrawReceiveAccount, + "hasPaymentPassword": resp.Wallet.HasPaymentPassword, + "createTime": resp.Wallet.CreateTime, + "updateTime": resp.Wallet.UpdateTime, + } + + // 添加实名认证信息(如果存在) + if resp.Wallet.RealNameAuth != nil { + result["realNameAuth"] = map[string]interface{}{ + "idCard": resp.Wallet.RealNameAuth.IdCard, + "name": resp.Wallet.RealNameAuth.Name, + "idCardPhotoFront": resp.Wallet.RealNameAuth.IdCardPhotoFront, + "idCardPhotoBack": resp.Wallet.RealNameAuth.IdCardPhotoBack, + "auditStatus": resp.Wallet.RealNameAuth.AuditStatus, + } + } + + apiresp.GinSuccess(c, map[string]interface{}{"wallet": result}) +} + +// UpdateUserWalletBalance 更新用户余额(后台充值/扣款) +func (o *Api) UpdateUserWalletBalance(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateUserWalletBalance, o.adminClient) +} + +// BatchUpdateWalletBalance 批量更新用户余额(后台批量充值/扣款) +func (o *Api) BatchUpdateWalletBalance(c *gin.Context) { + a2r.Call(c, admin.AdminClient.BatchUpdateWalletBalance, o.adminClient) +} + +// GetWallets 获取钱包列表 +func (o *Api) GetWallets(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetWallets, o.adminClient) +} + +// GetUserWalletBalanceRecords 获取用户余额变动记录列表 +func (o *Api) GetUserWalletBalanceRecords(c *gin.Context) { + var req admin.GetUserWalletBalanceRecordsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetUserWalletBalanceRecords(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表格式(Ant Design Pro 标准格式) + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, record := range resp.List { + list = append(list, map[string]interface{}{ + "id": record.Id, + "userID": record.UserID, + "amount": record.Amount, + "type": record.Type, + "beforeBalance": record.BeforeBalance, + "afterBalance": record.AfterBalance, + "orderID": record.OrderID, + "transactionID": record.TransactionID, + "redPacketID": record.RedPacketID, + "remark": record.Remark, + "createTime": record.CreateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "list": list, + }) +} + +// UpdateUserPaymentPassword 修改用户支付密码(后台) +func (o *Api) UpdateUserPaymentPassword(c *gin.Context) { + a2r.Call(c, admin.AdminClient.UpdateUserPaymentPassword, o.adminClient) +} + +// SetUserWithdrawAccount 设置用户提款账号(后台) +func (o *Api) SetUserWithdrawAccount(c *gin.Context) { + a2r.Call(c, admin.AdminClient.SetUserWithdrawAccount, o.adminClient) +} + +// ==================== 提现管理相关 API(操作 withdraw_applications)==================== + +// GetWithdraw 获取提现申请详情 +func (o *Api) GetWithdraw(c *gin.Context) { + var req admin.GetWithdrawReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetWithdraw(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 构建响应 + result := map[string]interface{}{ + "id": resp.Withdraw.Id, + "userID": resp.Withdraw.UserID, + "amount": resp.Withdraw.Amount, + "withdrawAccount": resp.Withdraw.WithdrawAccount, + "status": resp.Withdraw.Status, + "auditorID": resp.Withdraw.AuditorID, + "auditTime": resp.Withdraw.AuditTime, + "auditRemark": resp.Withdraw.AuditRemark, + "ip": resp.Withdraw.Ip, + "deviceID": resp.Withdraw.DeviceID, + "platform": resp.Withdraw.Platform, + "deviceModel": resp.Withdraw.DeviceModel, + "deviceBrand": resp.Withdraw.DeviceBrand, + "osVersion": resp.Withdraw.OsVersion, + "appVersion": resp.Withdraw.AppVersion, + "createTime": resp.Withdraw.CreateTime, + "updateTime": resp.Withdraw.UpdateTime, + } + + apiresp.GinSuccess(c, map[string]interface{}{"withdraw": result}) +} + +// GetUserWithdraws 获取用户的提现申请列表 +func (o *Api) GetUserWithdraws(c *gin.Context) { + var req admin.GetUserWithdrawsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetUserWithdraws(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表格式 + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, withdraw := range resp.List { + item := map[string]interface{}{ + "id": withdraw.Id, + "userID": withdraw.UserID, + "amount": withdraw.Amount, + "withdrawAccount": withdraw.WithdrawAccount, + "status": withdraw.Status, + "auditorID": withdraw.AuditorID, + "auditTime": withdraw.AuditTime, + "auditRemark": withdraw.AuditRemark, + "ip": withdraw.Ip, + "deviceID": withdraw.DeviceID, + "platform": withdraw.Platform, + "deviceModel": withdraw.DeviceModel, + "deviceBrand": withdraw.DeviceBrand, + "osVersion": withdraw.OsVersion, + "appVersion": withdraw.AppVersion, + "createTime": withdraw.CreateTime, + "updateTime": withdraw.UpdateTime, + } + + // 添加用户实名认证信息(如果存在) + if withdraw.RealNameAuth != nil { + item["realNameAuth"] = map[string]interface{}{ + "idCard": withdraw.RealNameAuth.IdCard, + "name": withdraw.RealNameAuth.Name, + "idCardPhotoFront": withdraw.RealNameAuth.IdCardPhotoFront, + "idCardPhotoBack": withdraw.RealNameAuth.IdCardPhotoBack, + "auditStatus": withdraw.RealNameAuth.AuditStatus, + } + } + + list = append(list, item) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "list": list, + }) +} + +// GetWithdraws 获取提现申请列表(后台,支持按状态筛选) +func (o *Api) GetWithdraws(c *gin.Context) { + var req admin.GetWithdrawsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetWithdraws(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表格式 + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, withdraw := range resp.List { + item := map[string]interface{}{ + "id": withdraw.Id, + "userID": withdraw.UserID, + "amount": withdraw.Amount, + "withdrawAccount": withdraw.WithdrawAccount, + "status": withdraw.Status, + "auditorID": withdraw.AuditorID, + "auditTime": withdraw.AuditTime, + "auditRemark": withdraw.AuditRemark, + "ip": withdraw.Ip, + "deviceID": withdraw.DeviceID, + "platform": withdraw.Platform, + "deviceModel": withdraw.DeviceModel, + "deviceBrand": withdraw.DeviceBrand, + "osVersion": withdraw.OsVersion, + "appVersion": withdraw.AppVersion, + "createTime": withdraw.CreateTime, + "updateTime": withdraw.UpdateTime, + } + + // 添加用户实名认证信息(如果存在) + if withdraw.RealNameAuth != nil { + item["realNameAuth"] = map[string]interface{}{ + "idCard": withdraw.RealNameAuth.IdCard, + "name": withdraw.RealNameAuth.Name, + "idCardPhotoFront": withdraw.RealNameAuth.IdCardPhotoFront, + "idCardPhotoBack": withdraw.RealNameAuth.IdCardPhotoBack, + "auditStatus": withdraw.RealNameAuth.AuditStatus, + } + } + + list = append(list, item) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "list": list, + }) +} + +// AuditWithdraw 批量审核提现申请 +func (o *Api) AuditWithdraw(c *gin.Context) { + var req admin.AuditWithdrawReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.AuditWithdraw(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 构建响应 + result := map[string]interface{}{ + "successCount": resp.SuccessCount, + "failCount": resp.FailCount, + "failedIDs": resp.FailedIDs, + } + + apiresp.GinSuccess(c, result) +} + +// GetRealNameAuths 获取实名认证列表(支持按审核状态筛选) +func (o *Api) GetRealNameAuths(c *gin.Context) { + var req admin.GetRealNameAuthsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.GetRealNameAuths(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换列表格式 + list := make([]map[string]interface{}, 0, len(resp.List)) + for _, auth := range resp.List { + list = append(list, map[string]interface{}{ + "userID": auth.UserID, + "nickname": auth.Nickname, + "faceURL": auth.FaceURL, + "idCard": auth.IdCard, + "name": auth.Name, + "idCardPhotoFront": auth.IdCardPhotoFront, + "idCardPhotoBack": auth.IdCardPhotoBack, + "auditStatus": auth.AuditStatus, + "createTime": auth.CreateTime, + "updateTime": auth.UpdateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "list": list, + }) +} + +// AuditRealNameAuth 审核实名认证(通过/拒绝) +func (o *Api) AuditRealNameAuth(c *gin.Context) { + var req admin.AuditRealNameAuthReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.adminClient.AuditRealNameAuth(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} diff --git a/internal/api/admin/config_manager.go b/internal/api/admin/config_manager.go new file mode 100644 index 0000000..035c647 --- /dev/null +++ b/internal/api/admin/config_manager.go @@ -0,0 +1,337 @@ +package admin + +import ( + "encoding/json" + "reflect" + "strconv" + "time" + + "git.imall.cloud/openim/chat/pkg/common/apistruct" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + "git.imall.cloud/openim/chat/version" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + clientv3 "go.etcd.io/etcd/client/v3" +) + +const ( + // wait for Restart http call return + waitHttp = time.Millisecond * 200 +) + +type ConfigManager struct { + config *config.AllConfig + client *clientv3.Client + configPath string + runtimeEnv string +} + +func NewConfigManager(cfg *config.AllConfig, client *clientv3.Client, configPath string, runtimeEnv string) *ConfigManager { + return &ConfigManager{ + config: cfg, + client: client, + configPath: configPath, + runtimeEnv: runtimeEnv, + } +} + +func (cm *ConfigManager) GetConfig(c *gin.Context) { + var req apistruct.GetConfigReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + conf := cm.config.Name2Config(req.ConfigName) + if conf == nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail("config name not found").Wrap()) + return + } + b, err := json.Marshal(conf) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, string(b)) +} + +func (cm *ConfigManager) GetConfigList(c *gin.Context) { + var resp apistruct.GetConfigListResp + resp.ConfigNames = cm.config.GetConfigNames() + resp.Environment = runtimeenv.PrintRuntimeEnvironment() + resp.Version = version.Version + + apiresp.GinSuccess(c, resp) +} + +func (cm *ConfigManager) SetConfig(c *gin.Context) { + if cm.config.Discovery.Enable != kdisc.ETCDCONST { + apiresp.GinError(c, errs.New("only etcd support set config").Wrap()) + return + } + var req apistruct.SetConfigReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var err error + switch req.ConfigName { + case config.DiscoveryConfigFileName: + err = compareAndSave[config.Discovery](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.LogConfigFileName: + err = compareAndSave[config.Log](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.MongodbConfigFileName: + err = compareAndSave[config.Mongo](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatAPIAdminCfgFileName: + err = compareAndSave[config.API](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatAPIChatCfgFileName: + err = compareAndSave[config.API](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatRPCAdminCfgFileName: + err = compareAndSave[config.Admin](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatRPCChatCfgFileName: + err = compareAndSave[config.Chat](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ShareFileName: + err = compareAndSave[config.Share](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.RedisConfigFileName: + err = compareAndSave[config.Redis](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + default: + apiresp.GinError(c, errs.ErrArgs.Wrap()) + return + } + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) SetConfigs(c *gin.Context) { + if cm.config.Discovery.Enable != kdisc.ETCDCONST { + apiresp.GinError(c, errs.New("only etcd support set config").Wrap()) + return + } + var req apistruct.SetConfigsReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var ( + err error + ops []*clientv3.Op + ) + + for _, cf := range req.Configs { + var op *clientv3.Op + switch cf.ConfigName { + case config.DiscoveryConfigFileName: + op, err = compareAndOp[config.Discovery](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.LogConfigFileName: + op, err = compareAndOp[config.Log](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.MongodbConfigFileName: + op, err = compareAndOp[config.Mongo](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatAPIAdminCfgFileName: + op, err = compareAndOp[config.API](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatAPIChatCfgFileName: + op, err = compareAndOp[config.API](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatRPCAdminCfgFileName: + op, err = compareAndOp[config.Admin](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatRPCChatCfgFileName: + op, err = compareAndOp[config.Chat](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ShareFileName: + op, err = compareAndOp[config.Share](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.RedisConfigFileName: + op, err = compareAndOp[config.Redis](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + default: + apiresp.GinError(c, errs.ErrArgs.Wrap()) + return + } + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + if op != nil { + ops = append(ops, op) + } + } + if len(ops) > 0 { + tx := cm.client.Txn(c) + if _, err = tx.Then(datautil.Batch(func(op *clientv3.Op) clientv3.Op { return *op }, ops)...).Commit(); err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "save to etcd failed")) + return + } + + } + + apiresp.GinSuccess(c, nil) +} + +func compareAndOp[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, client *clientv3.Client) (*clientv3.Op, error) { + conf := new(T) + err := json.Unmarshal([]byte(req.Data), &conf) + if err != nil { + return nil, errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + eq := reflect.DeepEqual(old, conf) + if eq { + return nil, nil + } + data, err := json.Marshal(conf) + if err != nil { + return nil, errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + op := clientv3.OpPut(etcd.BuildKey(req.ConfigName), string(data)) + return &op, nil +} + +func compareAndSave[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, client *clientv3.Client) error { + conf := new(T) + err := json.Unmarshal([]byte(req.Data), &conf) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + eq := reflect.DeepEqual(old, conf) + if eq { + return nil + } + data, err := json.Marshal(conf) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + _, err = client.Put(c, etcd.BuildKey(req.ConfigName), string(data)) + if err != nil { + return errs.WrapMsg(err, "save to etcd failed") + } + return nil +} + +func (cm *ConfigManager) ResetConfig(c *gin.Context) { + go func() { + if err := cm.resetConfig(c, true); err != nil { + log.ZError(c, "reset config err", err) + } + }() + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) resetConfig(c *gin.Context, checkChange bool, ops ...clientv3.Op) error { + txn := cm.client.Txn(c) + type initConf struct { + old any + new any + } + configMap := map[string]*initConf{ + config.DiscoveryConfigFileName: {old: &cm.config.Discovery, new: new(config.Discovery)}, + config.LogConfigFileName: {old: &cm.config.Log, new: new(config.Log)}, + config.MongodbConfigFileName: {old: &cm.config.Mongo, new: new(config.Mongo)}, + config.ChatAPIAdminCfgFileName: {old: &cm.config.AdminAPI, new: new(config.API)}, + config.ChatAPIChatCfgFileName: {old: &cm.config.ChatAPI, new: new(config.API)}, + config.ChatRPCAdminCfgFileName: {old: &cm.config.Admin, new: new(config.Admin)}, + config.ChatRPCChatCfgFileName: {old: &cm.config.Chat, new: new(config.Chat)}, + config.RedisConfigFileName: {old: &cm.config.Redis, new: new(config.Redis)}, + config.ShareFileName: {old: &cm.config.Share, new: new(config.Share)}, + } + + changedKeys := make([]string, 0, len(configMap)) + for k, v := range configMap { + err := config.Load( + cm.configPath, + k, + config.EnvPrefixMap[k], + cm.runtimeEnv, + v.new, + ) + if err != nil { + log.ZError(c, "load config failed", err) + continue + } + equal := reflect.DeepEqual(v.old, v.new) + if !checkChange || !equal { + changedKeys = append(changedKeys, k) + } + } + + for _, k := range changedKeys { + data, err := json.Marshal(configMap[k].new) + if err != nil { + log.ZError(c, "marshal config failed", err) + continue + } + ops = append(ops, clientv3.OpPut(etcd.BuildKey(k), string(data))) + } + if len(ops) > 0 { + txn.Then(ops...) + _, err := txn.Commit() + if err != nil { + return errs.WrapMsg(err, "commit etcd txn failed") + } + } + return nil +} + +func (cm *ConfigManager) Restart(c *gin.Context) { + go cm.restart(c) + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) restart(c *gin.Context) { + time.Sleep(waitHttp) // wait for Restart http call return + t := time.Now().Unix() + _, err := cm.client.Put(c, etcd.BuildKey(etcd.RestartKey), strconv.Itoa(int(t))) + if err != nil { + log.ZError(c, "restart etcd put key failed", err) + } +} + +func (cm *ConfigManager) SetEnableConfigManager(c *gin.Context) { + var req apistruct.SetEnableConfigManagerReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var enableStr string + if req.Enable { + enableStr = etcd.Enable + } else { + enableStr = etcd.Disable + } + resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey)) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed")) + return + } + if !(resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable) && req.Enable { + go func() { + time.Sleep(waitHttp) // wait for Restart http call return + err := cm.resetConfig(c, false, clientv3.OpPut(etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr)) + if err != nil { + log.ZError(c, "writeAllConfig failed", err) + } + }() + } else { + _, err = cm.client.Put(c, etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "setEnableConfigManager failed")) + return + } + } + + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) GetEnableConfigManager(c *gin.Context) { + resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey)) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed")) + return + } + var enable bool + if resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable { + enable = true + } + apiresp.GinSuccess(c, &apistruct.GetEnableConfigManagerResp{Enable: enable}) +} diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go new file mode 100644 index 0000000..0bce1f6 --- /dev/null +++ b/internal/api/admin/start.go @@ -0,0 +1,314 @@ +package admin + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + chatmw "git.imall.cloud/openim/chat/internal/api/mw" + "git.imall.cloud/openim/chat/internal/api/util" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + adminclient "git.imall.cloud/openim/chat/pkg/protocol/admin" + chatclient "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + clientv3 "go.etcd.io/etcd/client/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + *config.AllConfig + + RuntimeEnv string + ConfigPath string +} + +func Start(ctx context.Context, index int, config *Config) error { + config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + + if len(config.Share.ChatAdmin) == 0 { + return errs.New("share chat admin not configured") + } + apiPort, err := datautil.GetElemByIndex(config.AdminAPI.Api.Ports, index) + if err != nil { + return err + } + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv, nil) + if err != nil { + return err + } + + chatConn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminConn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + chatClient := chatclient.NewChatClient(chatConn) + adminClient := adminclient.NewAdminClient(adminConn) + im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID) + base := util.Api{ + ImUserID: config.Share.OpenIM.AdminUserID, + ProxyHeader: config.Share.ProxyHeader, + ChatAdminUserID: config.Share.ChatAdmin[0], + } + adminApi := New(chatClient, adminClient, im, &base) + mwApi := chatmw.New(adminClient) + gin.SetMode(gin.ReleaseMode) + engine := gin.New() + engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), func(c *gin.Context) { + // 确保 operationID 被正确设置到 context 中 + operationID := c.GetHeader("operationid") + if operationID != "" { + c.Set("operationID", operationID) + } + c.Next() + }) + SetAdminRoute(engine, adminApi, mwApi, config, client) + + if config.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), config.GetConfigNames()) + cm.Watch(ctx) + } + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} + +func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW, cfg *Config, client discovery.SvcDiscoveryRegistry) { + + adminRouterGroup := router.Group("/account") + adminRouterGroup.POST("/login", admin.AdminLogin) // Login + adminRouterGroup.POST("/update", mw.CheckAdmin, admin.AdminUpdateInfo) // Modify information + adminRouterGroup.POST("/info", mw.CheckAdmin, admin.AdminInfo) // Get information + adminRouterGroup.POST("/change_password", mw.CheckAdmin, admin.ChangeAdminPassword) // Change admin account's password + adminRouterGroup.POST("/change_operation_password", mw.CheckAdmin, admin.ChangeOperationPassword) // Change operation password + adminRouterGroup.POST("/set_google_auth_key", mw.CheckAdmin, admin.SetGoogleAuthKey) // Set Google Authenticator key + adminRouterGroup.POST("/add_admin", mw.CheckAdmin, admin.AddAdminAccount) // Add admin account + adminRouterGroup.POST("/add_user", mw.CheckAdmin, admin.AddUserAccount) // Add user account + adminRouterGroup.POST("/del_admin", mw.CheckAdmin, admin.DelAdminAccount) // Delete admin + adminRouterGroup.POST("/search", mw.CheckAdmin, admin.SearchAdminAccount) // Get admin list + adminRouterGroup.POST("/statistics", mw.CheckAdmin, admin.GetStatistics) // Get system statistics + //account.POST("/add_notification_account") + + importGroup := router.Group("/user/import") + importGroup.POST("/json", mw.CheckAdmin, admin.ImportUserByJson) + importGroup.POST("/xlsx", mw.CheckAdmin, admin.ImportUserByXlsx) + importGroup.GET("/xlsx", admin.BatchImportTemplate) + + allowRegisterGroup := router.Group("/user/allow_register", mw.CheckAdmin) + allowRegisterGroup.POST("/get", admin.GetAllowRegister) + allowRegisterGroup.POST("/set", admin.SetAllowRegister) + + defaultRouter := router.Group("/default", mw.CheckAdmin) + defaultUserRouter := defaultRouter.Group("/user") + defaultUserRouter.POST("/add", admin.AddDefaultFriend) // Add default friend at registration + defaultUserRouter.POST("/del", admin.DelDefaultFriend) // Delete default friend at registration + defaultUserRouter.POST("/find", admin.FindDefaultFriend) // Default friend list + defaultUserRouter.POST("/search", admin.SearchDefaultFriend) // Search default friend list at registration + defaultGroupRouter := defaultRouter.Group("/group") + defaultGroupRouter.POST("/add", admin.AddDefaultGroup) // Add default group at registration + defaultGroupRouter.POST("/del", admin.DelDefaultGroup) // Delete default group at registration + defaultGroupRouter.POST("/find", admin.FindDefaultGroup) // Get default group list at registration + defaultGroupRouter.POST("/search", admin.SearchDefaultGroup) // Search default group list at registration + + invitationCodeRouter := router.Group("/invitation_code", mw.CheckAdmin) + invitationCodeRouter.POST("/add", admin.AddInvitationCode) // Add invitation code + invitationCodeRouter.POST("/gen", admin.GenInvitationCode) // Generate invitation code + invitationCodeRouter.POST("/del", admin.DelInvitationCode) // Delete invitation code + invitationCodeRouter.POST("/search", admin.SearchInvitationCode) // Search invitation code + + forbiddenRouter := router.Group("/forbidden", mw.CheckAdmin) + ipForbiddenRouter := forbiddenRouter.Group("/ip") + ipForbiddenRouter.POST("/add", admin.AddIPForbidden) // Add forbidden IP for registration/login + ipForbiddenRouter.POST("/del", admin.DelIPForbidden) // Delete forbidden IP for registration/login + ipForbiddenRouter.POST("/search", admin.SearchIPForbidden) // Search forbidden IPs for registration/login + userForbiddenRouter := forbiddenRouter.Group("/user") + userForbiddenRouter.POST("/add", admin.AddUserIPLimitLogin) // Add limit for user login on specific IP + userForbiddenRouter.POST("/del", admin.DelUserIPLimitLogin) // Delete user limit on specific IP for login + userForbiddenRouter.POST("/search", admin.SearchUserIPLimitLogin) // Search limit for user login on specific IP + + appletRouterGroup := router.Group("/applet", mw.CheckAdmin) + appletRouterGroup.POST("/add", admin.AddApplet) // Add applet + appletRouterGroup.POST("/del", admin.DelApplet) // Delete applet + appletRouterGroup.POST("/update", admin.UpdateApplet) // Modify applet + appletRouterGroup.POST("/search", admin.SearchApplet) // Search applet + + blockRouter := router.Group("/block", mw.CheckAdmin) + blockRouter.POST("/add", admin.BlockUser) // Block user + blockRouter.POST("/del", admin.UnblockUser) // Unblock user + blockRouter.POST("/search", admin.SearchBlockUser) // Search blocked users + + userRouter := router.Group("/user", mw.CheckAdmin) + userRouter.POST("/password/reset", admin.ResetUserPassword) // Reset user password + + initGroup := router.Group("/client_config", mw.CheckAdmin) + initGroup.POST("/get", admin.GetClientConfig) // Get client initialization configuration + initGroup.POST("/set", admin.SetClientConfig) // Set client initialization configuration + initGroup.POST("/del", admin.DelClientConfig) // Delete client initialization configuration + + statistic := router.Group("/statistic", mw.CheckAdmin) + statistic.POST("/new_user_count", admin.NewUserCount) + statistic.POST("/login_user_count", admin.LoginUserCount) + statistic.POST("/online_user_count", admin.OnlineUserCount) + statistic.POST("/online_user_count_trend", admin.OnlineUserCountTrend) + statistic.POST("/user_send_msg_count", admin.UserSendMsgCount) + statistic.POST("/user_send_msg_count_trend", admin.UserSendMsgCountTrend) + statistic.POST("/user_send_msg_query", admin.UserSendMsgQuery) + + applicationGroup := router.Group("application") + applicationGroup.POST("/add_version", mw.CheckAdmin, admin.AddApplicationVersion) + applicationGroup.POST("/update_version", mw.CheckAdmin, admin.UpdateApplicationVersion) + applicationGroup.POST("/delete_version", mw.CheckAdmin, admin.DeleteApplicationVersion) + applicationGroup.POST("/latest_version", admin.LatestApplicationVersion) + applicationGroup.POST("/page_versions", admin.PageApplicationVersion) + + var etcdClient *clientv3.Client + if cfg.Discovery.Enable == kdisc.ETCDCONST { + etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient() + } + cm := NewConfigManager(cfg.AllConfig, etcdClient, cfg.ConfigPath, cfg.RuntimeEnv) + { + configGroup := router.Group("/config", mw.CheckAdmin) + configGroup.POST("/get_config_list", cm.GetConfigList) + configGroup.POST("/get_config", cm.GetConfig) + configGroup.POST("/set_config", cm.SetConfig) + configGroup.POST("/set_configs", cm.SetConfigs) + configGroup.POST("/reset_config", cm.ResetConfig) + configGroup.POST("/get_enable_config_manager", cm.GetEnableConfigManager) + configGroup.POST("/set_enable_config_manager", cm.SetEnableConfigManager) + } + { + router.POST("/restart", mw.CheckAdmin, cm.Restart) + } + + // ==================== 敏感词管理路由 ==================== + sensitiveWordRouter := router.Group("/sensitive_word") // 暂时注释掉 mw.CheckAdmin 用于测试 + + // 敏感词管理 + sensitiveWordRouter.POST("/add", mw.CheckAdmin, admin.AddSensitiveWord) // 添加敏感词 + sensitiveWordRouter.POST("/update", mw.CheckAdmin, admin.UpdateSensitiveWord) // 更新敏感词 + sensitiveWordRouter.POST("/delete", mw.CheckAdmin, admin.DeleteSensitiveWord) // 删除敏感词 + sensitiveWordRouter.POST("/get", mw.CheckAdmin, admin.GetSensitiveWord) // 获取敏感词 + sensitiveWordRouter.POST("/search", mw.CheckAdmin, admin.SearchSensitiveWords) // 搜索敏感词 + sensitiveWordRouter.POST("/batch_add", mw.CheckAdmin, admin.BatchAddSensitiveWords) // 批量添加敏感词 + sensitiveWordRouter.POST("/batch_update", mw.CheckAdmin, admin.BatchUpdateSensitiveWords) // 批量更新敏感词 + sensitiveWordRouter.POST("/batch_delete", mw.CheckAdmin, admin.BatchDeleteSensitiveWords) // 批量删除敏感词 + + // 敏感词分组管理 + groupRouter := sensitiveWordRouter.Group("/group") + groupRouter.POST("/add", mw.CheckAdmin, admin.AddSensitiveWordGroup) // 添加敏感词分组 + groupRouter.POST("/update", mw.CheckAdmin, admin.UpdateSensitiveWordGroup) // 更新敏感词分组 + groupRouter.POST("/delete", mw.CheckAdmin, admin.DeleteSensitiveWordGroup) // 删除敏感词分组 + groupRouter.POST("/get", mw.CheckAdmin, admin.GetSensitiveWordGroup) // 获取敏感词分组 + groupRouter.POST("/list", mw.CheckAdmin, admin.GetAllSensitiveWordGroups) // 获取所有敏感词分组 + + // 敏感词配置管理 + configRouter := sensitiveWordRouter.Group("/config") + configRouter.GET("/", mw.CheckAdmin, admin.GetSensitiveWordConfig) // 获取敏感词配置 + configRouter.POST("/get", mw.CheckAdmin, admin.GetSensitiveWordConfig) // 获取敏感词配置 + configRouter.POST("/update", mw.CheckAdmin, admin.UpdateSensitiveWordConfig) // 更新敏感词配置 + + // 敏感词日志管理 + logRouter := sensitiveWordRouter.Group("/log") + logRouter.POST("/list", mw.CheckAdmin, admin.GetSensitiveWordLogs) // 获取敏感词日志 + + // 用户登录记录管理 + loginRecordRouter := router.Group("/user_login_record", mw.CheckAdmin) + loginRecordRouter.POST("/list", admin.GetUserLoginRecords) // 查询用户登录记录 + logRouter.POST("/delete", mw.CheckAdmin, admin.DeleteSensitiveWordLogs) // 删除敏感词日志 + + // 敏感词统计 + statsRouter := sensitiveWordRouter.Group("/stats") + statsRouter.GET("/", mw.CheckAdmin, admin.GetSensitiveWordStats) // 获取敏感词统计 + statsRouter.POST("/word_stats", mw.CheckAdmin, admin.GetSensitiveWordStats) // 获取敏感词统计 + statsRouter.POST("/log_stats", mw.CheckAdmin, admin.GetSensitiveWordLogStats) // 获取敏感词日志统计 + + // ==================== 定时任务管理路由 ==================== + scheduledTaskRouter := router.Group("/scheduled_task", mw.CheckAdmin) + scheduledTaskRouter.POST("/list", admin.GetScheduledTasks) // 获取定时任务列表 + scheduledTaskRouter.POST("/delete", admin.DeleteScheduledTask) // 删除定时任务 + + // ==================== 系统配置管理路由 ==================== + systemConfigRouter := router.Group("/system_config", mw.CheckAdmin) + systemConfigRouter.POST("/create", admin.CreateSystemConfig) // 创建系统配置 + systemConfigRouter.POST("/get", admin.GetSystemConfig) // 获取系统配置详情 + systemConfigRouter.POST("/list", admin.GetAllSystemConfigs) // 获取所有系统配置(分页) + systemConfigRouter.POST("/update", admin.UpdateSystemConfig) // 更新系统配置 + systemConfigRouter.POST("/update_value", admin.UpdateSystemConfigValue) // 更新系统配置值 + systemConfigRouter.POST("/update_enabled", admin.UpdateSystemConfigEnabled) // 更新系统配置启用状态 + systemConfigRouter.POST("/delete", admin.DeleteSystemConfig) // 删除系统配置 + systemConfigRouter.POST("/get_enabled", admin.GetEnabledSystemConfigs) // 获取所有已启用的配置 + + // ==================== 钱包管理路由 ==================== + walletRouter := router.Group("/wallet", mw.CheckAdmin) + walletRouter.POST("/get", admin.GetUserWallet) // 获取用户钱包信息 + walletRouter.POST("/get_wallets", admin.GetWallets) // 获取钱包列表 + walletRouter.POST("/update_balance", admin.UpdateUserWalletBalance) // 更新用户余额(后台充值/扣款) + walletRouter.POST("/batch_update_balance", admin.BatchUpdateWalletBalance) // 批量更新用户余额(后台批量充值/扣款) + walletRouter.POST("/balance_records", admin.GetUserWalletBalanceRecords) // 获取用户余额变动记录列表 + walletRouter.POST("/update_payment_password", admin.UpdateUserPaymentPassword) // 修改用户支付密码 + walletRouter.POST("/set_withdraw_account", admin.SetUserWithdrawAccount) // 设置用户提款账号 + + // ==================== 提现管理路由(操作 withdraw_applications)==================== + withdrawRouter := router.Group("/withdraw", mw.CheckAdmin) + withdrawRouter.POST("/get", admin.GetWithdraw) // 获取提现申请详情 + withdrawRouter.POST("/list", admin.GetWithdraws) // 获取提现申请列表(支持按状态筛选) + withdrawRouter.POST("/user_list", admin.GetUserWithdraws) // 获取用户的提现申请列表 + withdrawRouter.POST("/audit", admin.AuditWithdraw) // 审核提现申请 + + // ==================== 实名认证审核路由 ==================== + realNameAuthRouter := router.Group("/real_name_auth", mw.CheckAdmin) + realNameAuthRouter.POST("/list", admin.GetRealNameAuths) // 获取实名认证列表(支持按审核状态筛选) + realNameAuthRouter.POST("/audit", admin.AuditRealNameAuth) // 审核实名认证(通过/拒绝) +} diff --git a/internal/api/bot/bot.go b/internal/api/bot/bot.go new file mode 100644 index 0000000..6308bb1 --- /dev/null +++ b/internal/api/bot/bot.go @@ -0,0 +1,177 @@ +package bot + +import ( + "encoding/json" + "sort" + "strings" + + "git.imall.cloud/openim/chat/internal/api/util" + "git.imall.cloud/openim/chat/pkg/botstruct" + "git.imall.cloud/openim/chat/pkg/common/imwebhook" + "git.imall.cloud/openim/chat/pkg/protocol/bot" + "git.imall.cloud/openim/protocol/constant" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "golang.org/x/sync/errgroup" +) + +func New(botClient bot.BotClient, api *util.Api) *Api { + return &Api{ + Api: api, + botClient: botClient, + } +} + +type Api struct { + *util.Api + botClient bot.BotClient +} + +func (o *Api) CreateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.CreateAgent, o.botClient) +} + +func (o *Api) DeleteAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.DeleteAgent, o.botClient) +} + +func (o *Api) UpdateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.UpdateAgent, o.botClient) +} + +func (o *Api) PageFindAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.PageFindAgent, o.botClient) +} + +func (o *Api) AfterSendSingleMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendSingleMsgReq{} + ) + + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + if req.ContentType != constant.Text { + apiresp.GinSuccess(c, nil) + return + } + isAgent := botstruct.IsAgentUserID(req.RecvID) + if !isAgent { + apiresp.GinSuccess(c, nil) + return + } + + var elem botstruct.TextElem + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + return + } + convID := getConversationIDByMsg(req.SessionType, req.SendID, req.RecvID, "") + + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + res, err := o.botClient.SendBotMessage(c, &bot.SendBotMessageReq{ + AgentID: req.RecvID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Content, + Ex: req.Ex, + Key: key, + }) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, res) +} + +func (o *Api) AfterSendGroupMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendGroupMsgReq{} + ) + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + + if req.ContentType != constant.AtText { + apiresp.GinSuccess(c, nil) + } + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + + var ( + elem botstruct.AtElem + reqs []*bot.SendBotMessageReq + ) + + convID := getConversationIDByMsg(req.SessionType, req.SendID, "", req.GroupID) + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + } + for _, userID := range elem.AtUserList { + if botstruct.IsAgentUserID(userID) { + reqs = append(reqs, &bot.SendBotMessageReq{ + AgentID: userID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Text, + Ex: req.Ex, + Key: key, + }) + } + } + if len(reqs) == 0 { + apiresp.GinSuccess(c, nil) + } + + g := errgroup.Group{} + g.SetLimit(min(len(reqs), 5)) + for i := 0; i < len(reqs); i++ { + i := i + g.Go(func() error { + _, err := o.botClient.SendBotMessage(c, reqs[i]) + if err != nil { + return err + } + return nil + }) + } + + err = g.Wait() + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, nil) +} + +func getConversationIDByMsg(sessionType int32, sendID, recvID, groupID string) string { + switch sessionType { + case constant.SingleChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "si_" + strings.Join(l, "_") // single chat + case constant.WriteGroupChatType: + return "g_" + groupID // group chat + case constant.ReadGroupChatType: + return "sg_" + groupID // super group chat + case constant.NotificationChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "sn_" + strings.Join(l, "_") + } + return "" +} diff --git a/internal/api/bot/start.go b/internal/api/bot/start.go new file mode 100644 index 0000000..abb62f4 --- /dev/null +++ b/internal/api/bot/start.go @@ -0,0 +1,139 @@ +package bot + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + chatmw "git.imall.cloud/openim/chat/internal/api/mw" + "git.imall.cloud/openim/chat/internal/api/util" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + adminclient "git.imall.cloud/openim/chat/pkg/protocol/admin" + botclient "git.imall.cloud/openim/chat/pkg/protocol/bot" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + ApiConfig config.APIBot + Discovery config.Discovery + Share config.Share + Redis config.Redis + + RuntimeEnv string +} + +func Start(ctx context.Context, index int, cfg *Config) error { + cfg.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + apiPort, err := datautil.GetElemByIndex(cfg.ApiConfig.Api.Ports, index) + if err != nil { + return err + } + client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv, nil) + if err != nil { + return err + } + + botConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Bot, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminClient := adminclient.NewAdminClient(adminConn) + botClient := botclient.NewBotClient(botConn) + base := util.Api{ + ImUserID: cfg.Share.OpenIM.AdminUserID, + ProxyHeader: cfg.Share.ProxyHeader, + ChatAdminUserID: cfg.Share.ChatAdmin[0], + } + botApi := New(botClient, &base) + mwApi := chatmw.New(adminClient) + gin.SetMode(gin.ReleaseMode) + engine := gin.New() + engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), func(c *gin.Context) { + // 确保 operationID 被正确设置到 context 中 + operationID := c.GetHeader("operationid") + if operationID != "" { + c.Set("operationID", operationID) + } + c.Next() + }) + SetBotRoute(engine, botApi, mwApi) + + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + if cfg.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), + []string{ + config.ChatAPIBotCfgFileName, + config.DiscoveryConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, + ) + cm.Watch(ctx) + } + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} + +func SetBotRoute(router gin.IRouter, bot *Api, mw *chatmw.MW) { + account := router.Group("/agent") + account.POST("/create", mw.CheckAdmin, bot.CreateAgent) + account.POST("/delete", mw.CheckAdmin, bot.DeleteAgent) + account.POST("/update", mw.CheckAdmin, bot.UpdateAgent) + account.POST("/page", mw.CheckToken, bot.PageFindAgent) + + imwebhook := router.Group("/im_callback") + imwebhook.POST("/callbackAfterSendSingleMsgCommand", bot.AfterSendSingleMsg) + imwebhook.POST("/callbackAfterSendGroupMsgCommand", bot.AfterSendGroupMsg) +} diff --git a/internal/api/chat/chat.go b/internal/api/chat/chat.go new file mode 100644 index 0000000..f216271 --- /dev/null +++ b/internal/api/chat/chat.go @@ -0,0 +1,904 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "encoding/json" + "fmt" + "io" + "strings" + "time" + + apiuserutil "git.imall.cloud/openim/chat/internal/api/util" + + "strconv" + + "git.imall.cloud/openim/chat/pkg/common/apistruct" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + chatpb "git.imall.cloud/openim/chat/pkg/protocol/chat" + constantpb "git.imall.cloud/openim/protocol/constant" + "git.imall.cloud/openim/protocol/sdkws" + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" +) + +func New(chatClient chatpb.ChatClient, adminClient admin.AdminClient, imApiCaller imapi.CallerInterface, api *apiuserutil.Api) *Api { + return &Api{ + Api: api, + chatClient: chatClient, + adminClient: adminClient, + imApiCaller: imApiCaller, + } +} + +type Api struct { + *apiuserutil.Api + chatClient chatpb.ChatClient + adminClient admin.AdminClient + imApiCaller imapi.CallerInterface +} + +// operationIDKey 用于 context.WithValue 的自定义类型,避免使用字符串导致类型冲突 +type operationIDKey struct{} + +// ################## ACCOUNT ################## + +func (o *Api) SendVerifyCode(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.SendVerifyCodeReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + req.Ip = ip + resp, err := o.chatClient.SendVerifyCode(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) VerifyCode(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.VerifyCode, o.chatClient) +} + +func (o *Api) GetCaptchaImage(c *gin.Context) { + // 获取或生成operationID(图片请求可能没有operationID header) + operationID := c.GetHeader("operationID") + if operationID == "" { + // 如果没有operationID,生成一个UUID + operationID = uuid.New().String() + } + + // 将operationID设置到context中,确保RPC调用能获取到 + // 使用自定义类型作为 key,避免使用字符串导致类型冲突 + ctx := context.WithValue(c.Request.Context(), operationIDKey{}, operationID) + + // 调用RPC方法获取验证码(6位数字) + resp, err := o.chatClient.GetCaptchaImage(ctx, &chatpb.GetCaptchaImageReq{}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 在API层生成验证码图片 + imgBytes, err := apiuserutil.GenerateCaptchaImageFromCode(resp.Code) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 验证图片数据 + if len(imgBytes) == 0 { + apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("generated captcha image is empty")) + return + } + + // 检查GIF文件头 + if len(imgBytes) < 6 { + apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("generated captcha image data too short")) + return + } + + // 设置响应头,返回GIF图片 + c.Header("Content-Type", "image/gif") + c.Header("Content-Length", fmt.Sprintf("%d", len(imgBytes))) + c.Header("Cache-Control", "no-cache, no-store, must-revalidate") + c.Header("Pragma", "no-cache") + c.Header("Expires", "0") + // 将验证码ID放在响应头中,客户端可用于后续验证 + c.Header("X-Captcha-ID", resp.CaptchaID) + + // 返回图片数据 + c.Data(200, "image/gif", imgBytes) +} + +func (o *Api) RegisterUser(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.RegisterUserReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + req.Ip = ip + + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + apiCtx := mctx.WithApiToken(c, imToken) + rpcCtx := o.WithAdminUser(c) + + checkResp, err := o.chatClient.CheckUserExist(rpcCtx, &chatpb.CheckUserExistReq{User: req.User}) + if err != nil { + + apiresp.GinError(c, err) + return + } + if checkResp.IsRegistered { + isUserNotExist, err := o.imApiCaller.AccountCheckSingle(apiCtx, checkResp.Userid) + if err != nil { + apiresp.GinError(c, err) + return + } + // if User is not exist in SDK server. You need delete this user and register new user again. + if isUserNotExist { + _, err := o.chatClient.DelUserAccount(rpcCtx, &chatpb.DelUserAccountReq{UserIDs: []string{checkResp.Userid}}) + + if err != nil { + apiresp.GinError(c, err) + return + } + } + } + + // H5注册场景(提供了registerToken)默认自动登录 + if req.RegisterToken != "" && !req.AutoLogin { + req.AutoLogin = true + } + + respRegisterUser, err := o.chatClient.RegisterUser(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + userInfo := &sdkws.UserInfo{ + UserID: respRegisterUser.UserID, + Nickname: req.User.Nickname, + FaceURL: req.User.FaceURL, + CreateTime: time.Now().UnixMilli(), + UserType: 0, // 设置默认用户类型 + UserFlag: "", + } + err = o.imApiCaller.RegisterUser(apiCtx, []*sdkws.UserInfo{userInfo}) + if err != nil { + apiresp.GinError(c, err) + return + } + + if resp, err := o.adminClient.FindDefaultFriend(rpcCtx, &admin.FindDefaultFriendReq{}); err == nil { + _ = o.imApiCaller.ImportFriend(apiCtx, respRegisterUser.UserID, resp.UserIDs) + } + if resp, err := o.adminClient.FindDefaultGroup(rpcCtx, &admin.FindDefaultGroupReq{}); err == nil { + _ = o.imApiCaller.InviteToGroup(apiCtx, respRegisterUser.UserID, resp.GroupIDs) + } + var resp apistruct.UserRegisterResp + if req.AutoLogin { + resp.ImToken, err = o.imApiCaller.GetUserToken(apiCtx, respRegisterUser.UserID, req.Platform) + if err != nil { + apiresp.GinError(c, err) + return + } + } + resp.ChatToken = respRegisterUser.ChatToken + resp.UserID = respRegisterUser.UserID + apiresp.GinSuccess(c, &resp) +} + +func (o *Api) Login(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.LoginReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, err) + return + } + req.Ip = ip + + resp, err := o.chatClient.Login(c, req) + + if err != nil { + // 调试日志:打印错误的详细信息 + errStr := err.Error() + log.ZError(c, "Login error detected", err, + "errorString", errStr, + "errorType", fmt.Sprintf("%T", err), + "contains20015", strings.Contains(errStr, "20015"), + "containsAccountBlocked", strings.Contains(errStr, "AccountBlocked"), + "contains封禁", strings.Contains(errStr, "账户已被封禁")) + + // 检查是否是账户被封禁的错误,确保返回明确的错误提示 + // 需要检查错误字符串中是否包含封禁相关的关键词,即使错误被包装了 + if strings.Contains(errStr, "20015") || strings.Contains(errStr, "AccountBlocked") || strings.Contains(errStr, "账户已被封禁") { + log.ZInfo(c, "Detected AccountBlocked error, returning explicit error", "originalError", errStr) + apiresp.GinError(c, eerrs.ErrAccountBlocked.WrapMsg("账户已被封禁")) + return + } + + // 如果错误被包装成 ServerInternalError,尝试从错误链中提取原始错误 + // 检查错误消息中是否包含封禁相关的堆栈信息 + if strings.Contains(errStr, "ServerInternalError") && (strings.Contains(errStr, "20015") || strings.Contains(errStr, "AccountBlocked")) { + log.ZInfo(c, "Detected AccountBlocked error in wrapped ServerInternalError, returning explicit error", "originalError", errStr) + apiresp.GinError(c, eerrs.ErrAccountBlocked.WrapMsg("账户已被封禁")) + return + } + + log.ZError(c, "Login error not AccountBlocked, returning original error", err) + apiresp.GinError(c, err) + return + } + + adminToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + apiCtx := mctx.WithApiToken(c, adminToken) + imToken, err := o.imApiCaller.GetUserToken(apiCtx, resp.UserID, req.Platform) + if err != nil { + + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, &apistruct.LoginResp{ + ImToken: imToken, + UserID: resp.UserID, + ChatToken: resp.ChatToken, + }) +} + +func (o *Api) ResetPassword(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.ResetPassword, o.chatClient) +} + +func (o *Api) ChangePassword(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.ChangePasswordReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.chatClient.ChangePassword(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + err = o.imApiCaller.ForceOffLine(mctx.WithApiToken(c, imToken), req.UserID) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +// ################## USER ################## + +func (o *Api) UpdateUserInfo(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.UpdateUserInfoReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 检查req是否为nil + if req == nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("request is nil")) + return + } + + // 检查必要参数 + if req.UserID == "" { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("userID is required")) + return + } + + respUpdate, err := o.chatClient.UpdateUserInfo(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + var imToken string + imToken, err = o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 检查token是否为空 + if imToken == "" { + apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("failed to get admin token")) + return + } + + // 检查imApiCaller是否为nil + if o.imApiCaller == nil { + apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("imApiCaller is nil")) + return + } + + var ( + nickName string + faceURL string + userFlag string + ) + if req.Nickname != nil { + nickName = req.Nickname.Value + } else { + nickName = respUpdate.NickName + } + if req.FaceURL != nil { + faceURL = req.FaceURL.Value + } else { + faceURL = respUpdate.FaceUrl + } + // 处理UserFlag字段 + if req.UserFlag != nil { + userFlag = req.UserFlag.Value + } + + // 确保字符串参数不为nil(虽然这里应该是安全的,但添加额外保护) + if nickName == "" { + nickName = "" + } + if faceURL == "" { + faceURL = "" + } + + err = o.imApiCaller.UpdateUserInfo(mctx.WithApiToken(c, imToken), req.UserID, nickName, faceURL, req.UserType, userFlag) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 构造 ex 字段的 JSON 数据(包含 userFlag 和 userType) + type UserEx struct { + UserFlag string `json:"userFlag"` + UserType int32 `json:"userType"` + } + userEx := UserEx{ + UserFlag: userFlag, + UserType: req.UserType, + } + exBytes, err := json.Marshal(userEx) + if err != nil { + apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("failed to marshal user ex")) + return + } + + // 调用 UpdateUserInfoEx 更新 ex 字段 + err = o.imApiCaller.UpdateUserInfoEx(mctx.WithApiToken(c, imToken), req.UserID, string(exBytes)) + if err != nil { + + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, apistruct.UpdateUserInfoResp{}) +} + +func (o *Api) FindUserPublicInfo(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.FindUserPublicInfo, o.chatClient) +} + +func (o *Api) FindUserFullInfo(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.FindUserFullInfo, o.chatClient) +} + +func (o *Api) SearchUserFullInfo(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.SearchUserFullInfo, o.chatClient) +} + +func (o *Api) SearchUserPublicInfo(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.SearchUserPublicInfo, o.chatClient) +} + +func (o *Api) GetTokenForVideoMeeting(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetTokenForVideoMeeting, o.chatClient) +} + +// ################## APPLET ################## + +func (o *Api) FindApplet(c *gin.Context) { + a2r.Call(c, admin.AdminClient.FindApplet, o.adminClient) +} + +// ################## CONFIG ################## + +func (o *Api) GetClientConfig(c *gin.Context) { + a2r.Call(c, admin.AdminClient.GetClientConfig, o.adminClient) +} + +// ################## CALLBACK ################## + +func (o *Api) OpenIMCallback(c *gin.Context) { + body, err := io.ReadAll(c.Request.Body) + if err != nil { + apiresp.GinError(c, err) + return + } + req := &chatpb.OpenIMCallbackReq{ + Command: c.Query(constantpb.CallbackCommand), + Body: string(body), + } + if _, err := o.chatClient.OpenIMCallback(c, req); err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, nil) +} + +func (o *Api) SearchFriend(c *gin.Context) { + req, err := a2r.ParseRequest[struct { + UserID string `json:"userID"` + chatpb.SearchUserInfoReq + }](c) + if err != nil { + apiresp.GinError(c, err) + return + } + if req.UserID == "" { + req.UserID = mctx.GetOpUserID(c) + } + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + userIDs, err := o.imApiCaller.FriendUserIDs(mctx.WithApiToken(c, imToken), req.UserID) + if err != nil { + apiresp.GinError(c, err) + return + } + if len(userIDs) == 0 { + apiresp.GinSuccess(c, &chatpb.SearchUserInfoResp{}) + return + } + req.SearchUserInfoReq.UserIDs = userIDs + resp, err := o.chatClient.SearchUserInfo(c, &req.SearchUserInfoReq) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, resp) +} + +func (o *Api) AddFriend(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.AddFriendReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + // 获取当前用户ID(发起添加好友的用户) + ownerUserID := mctx.GetOpUserID(c) + + // 获取用户信息,检查 userType + userInfoResp, err := o.chatClient.FindUserFullInfo(c, &chatpb.FindUserFullInfoReq{UserIDs: []string{ownerUserID}}) + if err != nil { + apiresp.GinError(c, err) + return + } + if len(userInfoResp.Users) == 0 || userInfoResp.Users[0].UserType != 1 { + apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only userType=1 users can add friends directly")) + return + } + + // 调用 chat-deploy 的 ImportFriends + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 调用 ImportFriend,传入要添加的好友ID + err = o.imApiCaller.ImportFriend(mctx.WithApiToken(c, imToken), ownerUserID, []string{req.UserID}) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, nil) +} + +func (o *Api) LatestApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.LatestApplicationVersion, o.adminClient) +} + +func (o *Api) PageApplicationVersion(c *gin.Context) { + a2r.Call(c, admin.AdminClient.PageApplicationVersion, o.adminClient) +} + +// ==================== 敏感词检测相关 API ==================== + +// GetSensitiveWords 获取敏感词列表 +func (o *Api) GetSensitiveWords(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetSensitiveWords, o.chatClient) +} + +// CheckSensitiveWords 检测敏感词 +func (o *Api) CheckSensitiveWords(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.CheckSensitiveWords, o.chatClient) +} + +// ==================== 收藏相关 API ==================== + +// CreateFavorite 创建收藏 +func (o *Api) CreateFavorite(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.CreateFavorite, o.chatClient) +} + +// GetFavorite 获取收藏详情 +func (o *Api) GetFavorite(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetFavorite, o.chatClient) +} + +// GetFavorites 获取收藏列表 +func (o *Api) GetFavorites(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetFavorites, o.chatClient) +} + +// SearchFavorites 搜索收藏 +func (o *Api) SearchFavorites(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.SearchFavorites, o.chatClient) +} + +// UpdateFavorite 更新收藏 +func (o *Api) UpdateFavorite(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.UpdateFavorite, o.chatClient) +} + +// DeleteFavorite 删除收藏 +func (o *Api) DeleteFavorite(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.DeleteFavorite, o.chatClient) +} + +// GetFavoritesByTags 根据标签获取收藏 +func (o *Api) GetFavoritesByTags(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetFavoritesByTags, o.chatClient) +} + +// GetFavoriteCount 获取收藏数量 +func (o *Api) GetFavoriteCount(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetFavoriteCount, o.chatClient) +} + +// ==================== 定时任务相关 API ==================== + +// CreateScheduledTask 创建定时任务 +func (o *Api) CreateScheduledTask(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.CreateScheduledTask, o.chatClient) +} + +// GetScheduledTask 获取定时任务详情 +func (o *Api) GetScheduledTask(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetScheduledTask, o.chatClient) +} + +// GetScheduledTasks 获取定时任务列表 +func (o *Api) GetScheduledTasks(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.GetScheduledTasks, o.chatClient) +} + +// UpdateScheduledTask 更新定时任务 +func (o *Api) UpdateScheduledTask(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.UpdateScheduledTask, o.chatClient) +} + +// DeleteScheduledTask 删除定时任务 +func (o *Api) DeleteScheduledTask(c *gin.Context) { + a2r.Call(c, chatpb.ChatClient.DeleteScheduledTask, o.chatClient) +} + +// ==================== 系统配置相关 API ==================== + +// GetAppSystemConfigs 获取APP端配置(返回所有 show_in_app=true 且 enabled=true 的配置) +func (o *Api) GetAppSystemConfigs(c *gin.Context) { + resp, err := o.chatClient.GetAppSystemConfigs(c, &chatpb.GetAppSystemConfigsReq{}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换为对象格式,key 作为对象的键,value 作为值 + configMap := make(map[string]interface{}) + for _, config := range resp.Configs { + convertedValue := o.convertValueFromString(config.Value, config.ValueType) + configMap[config.Key] = convertedValue + } + + apiresp.GinSuccess(c, configMap) +} + +// convertValueFromString 将字符串值转换为对应类型(用于返回给前端) +func (o *Api) convertValueFromString(value string, valueType int32) interface{} { + switch valueType { + case 1: // String + return value + case 2: // Number + // 尝试解析为数字 + if num, err := strconv.ParseFloat(value, 64); err == nil { + // 如果是整数,返回整数;否则返回浮点数 + if num == float64(int64(num)) { + return int64(num) + } + return num + } + return value + case 3: // Bool + if b, err := strconv.ParseBool(value); err == nil { + return b + } + return value + case 4: // JSON + var js interface{} + if err := json.Unmarshal([]byte(value), &js); err == nil { + return js + } + return value + default: + return value + } +} + +// ==================== 钱包相关 API ==================== + +// GetWalletBalance 获取钱包余额 +func (o *Api) GetWalletBalance(c *gin.Context) { + resp, err := o.chatClient.GetWalletBalance(c, &chatpb.GetWalletBalanceReq{}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 将余额从分转换为元(前端显示用) + apiresp.GinSuccess(c, map[string]interface{}{ + "balance": resp.Balance, // 余额(单位:分) + }) +} + +// GetWalletInfo 获取钱包详细信息 +func (o *Api) GetWalletInfo(c *gin.Context) { + resp, err := o.chatClient.GetWalletInfo(c, &chatpb.GetWalletInfoReq{}) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 构建响应 + result := map[string]interface{}{ + "balance": resp.Balance, // 余额(单位:分) + "withdrawAccount": resp.WithdrawAccount, + "withdrawAccountType": resp.WithdrawAccountType, + "withdrawReceiveAccount": resp.WithdrawReceiveAccount, + "hasPaymentPassword": resp.HasPaymentPassword, + } + + // 添加实名认证信息(如果存在) + if resp.RealNameAuth != nil { + result["realNameAuth"] = map[string]interface{}{ + "idCard": resp.RealNameAuth.IdCard, + "idCardPhotoFront": resp.RealNameAuth.IdCardPhotoFront, + "idCardPhotoBack": resp.RealNameAuth.IdCardPhotoBack, + "name": resp.RealNameAuth.Name, + "auditStatus": resp.RealNameAuth.AuditStatus, + } + } + + apiresp.GinSuccess(c, result) +} + +// GetWalletBalanceRecords 获取余额明细 +func (o *Api) GetWalletBalanceRecords(c *gin.Context) { + var req chatpb.GetWalletBalanceRecordsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.chatClient.GetWalletBalanceRecords(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换为响应格式 + records := make([]map[string]interface{}, 0, len(resp.Records)) + for _, record := range resp.Records { + records = append(records, map[string]interface{}{ + "id": record.Id, + "userID": record.UserID, + "amount": record.Amount, + "type": record.Type, + "beforeBalance": record.BeforeBalance, + "afterBalance": record.AfterBalance, + "orderID": record.OrderID, + "transactionID": record.TransactionID, + "redPacketID": record.RedPacketID, + "remark": record.Remark, + "createTime": record.CreateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "records": records, + }) +} + +// SetPaymentPassword 设置支付密码 +func (o *Api) SetPaymentPassword(c *gin.Context) { + var req chatpb.SetPaymentPasswordReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.chatClient.SetPaymentPassword(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +// SetWithdrawAccount 设置提现账号 +func (o *Api) SetWithdrawAccount(c *gin.Context) { + var req chatpb.SetWithdrawAccountReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.chatClient.SetWithdrawAccount(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) +} + +// CreateWithdrawApplication 申请提现 +func (o *Api) CreateWithdrawApplication(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.CreateWithdrawApplicationReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 从请求中获取客户端IP + ip, err := o.GetClientIP(c) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("无法获取客户端IP")) + return + } + req.Ip = ip + + resp, err := o.chatClient.CreateWithdrawApplication(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "applicationID": resp.ApplicationID, + }) +} + +// GetWithdrawApplications 获取提现申请列表 +func (o *Api) GetWithdrawApplications(c *gin.Context) { + var req chatpb.GetWithdrawApplicationsReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid request")) + return + } + + resp, err := o.chatClient.GetWithdrawApplications(c, &req) + if err != nil { + apiresp.GinError(c, err) + return + } + + // 转换为响应格式 + applications := make([]map[string]interface{}, 0, len(resp.Applications)) + for _, app := range resp.Applications { + applications = append(applications, map[string]interface{}{ + "id": app.Id, + "userID": app.UserID, + "amount": app.Amount, + "withdrawAccount": app.WithdrawAccount, + "withdrawAccountType": app.WithdrawAccountType, + "status": app.Status, + "auditorID": app.AuditorID, + "auditTime": app.AuditTime, + "auditRemark": app.AuditRemark, + "ip": app.Ip, + "deviceID": app.DeviceID, + "platform": app.Platform, + "deviceModel": app.DeviceModel, + "deviceBrand": app.DeviceBrand, + "osVersion": app.OsVersion, + "appVersion": app.AppVersion, + "remark": app.Remark, + "createTime": app.CreateTime, + "updateTime": app.UpdateTime, + }) + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "total": resp.Total, + "applications": applications, + }) +} + +// RealNameAuth 实名认证 +func (o *Api) RealNameAuth(c *gin.Context) { + req, err := a2r.ParseRequest[chatpb.RealNameAuthReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + + resp, err := o.chatClient.RealNameAuth(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, map[string]interface{}{ + "success": resp.Success, + "message": resp.Message, + "idCardPhotoFront": resp.IdCardPhotoFront, + "idCardPhotoBack": resp.IdCardPhotoBack, + }) +} diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go new file mode 100644 index 0000000..1bb6a11 --- /dev/null +++ b/internal/api/chat/start.go @@ -0,0 +1,197 @@ +package chat + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + chatmw "git.imall.cloud/openim/chat/internal/api/mw" + "git.imall.cloud/openim/chat/internal/api/util" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + adminclient "git.imall.cloud/openim/chat/pkg/protocol/admin" + chatclient "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + ApiConfig config.API + Discovery config.Discovery + Share config.Share + Redis config.Redis + + RuntimeEnv string +} + +func Start(ctx context.Context, index int, cfg *Config) error { + cfg.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + + if len(cfg.Share.ChatAdmin) == 0 { + return errs.New("share chat admin not configured") + } + apiPort, err := datautil.GetElemByIndex(cfg.ApiConfig.Api.Ports, index) + if err != nil { + return err + } + client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv, nil) + if err != nil { + return err + } + + chatConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + chatClient := chatclient.NewChatClient(chatConn) + adminClient := adminclient.NewAdminClient(adminConn) + im := imapi.New(cfg.Share.OpenIM.ApiURL, cfg.Share.OpenIM.Secret, cfg.Share.OpenIM.AdminUserID) + base := util.Api{ + ImUserID: cfg.Share.OpenIM.AdminUserID, + ProxyHeader: cfg.Share.ProxyHeader, + ChatAdminUserID: cfg.Share.ChatAdmin[0], + } + adminApi := New(chatClient, adminClient, im, &base) + mwApi := chatmw.New(adminClient) + gin.SetMode(gin.ReleaseMode) + engine := gin.New() + engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) + SetChatRoute(engine, adminApi, mwApi) + + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + if cfg.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), + []string{ + config.ChatAPIChatCfgFileName, + config.DiscoveryConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, + ) + cm.Watch(ctx) + } + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} + +func SetChatRoute(router gin.IRouter, chat *Api, mw *chatmw.MW) { + account := router.Group("/account") + account.GET("/captcha", chat.GetCaptchaImage) // Get captcha image + account.POST("/code/send", chat.SendVerifyCode) // Send verification code + account.POST("/code/verify", chat.VerifyCode) // Verify the verification code + account.POST("/register", mw.CheckAdminOrNil, chat.RegisterUser) // Register + account.POST("/login", chat.Login) // Login + account.POST("/password/reset", chat.ResetPassword) // Forgot password + account.POST("/password/change", mw.CheckToken, chat.ChangePassword) // Change password + + user := router.Group("/user", mw.CheckToken) + user.POST("/update", chat.UpdateUserInfo) // Edit personal information + user.POST("/find/public", chat.FindUserPublicInfo) // Get user's public information + user.POST("/find/full", chat.FindUserFullInfo) // Get all information of the user + user.POST("/search/full", chat.SearchUserFullInfo) // Search user's public information + user.POST("/search/public", chat.SearchUserPublicInfo) // Search all information of the user + user.POST("/rtc/get_token", chat.GetTokenForVideoMeeting) // Get token for video meeting for the user + + router.POST("/friend/search", mw.CheckToken, chat.SearchFriend) + router.POST("/friend/add", mw.CheckToken, chat.AddFriend) + + router.Group("/applet").POST("/find", mw.CheckToken, chat.FindApplet) // Applet list + + router.Group("/client_config").POST("/get", chat.GetClientConfig) // Get client initialization configuration + + applicationGroup := router.Group("application") + applicationGroup.POST("/latest_version", chat.LatestApplicationVersion) + applicationGroup.POST("/page_versions", chat.PageApplicationVersion) + + router.Group("/callback").POST("/open_im", chat.OpenIMCallback) // Callback + + // 系统配置相关接口(客户端) + systemConfig := router.Group("/system_config") + systemConfig.POST("/get_app_configs", chat.GetAppSystemConfigs) // 获取APP端配置(show_in_app=true 且 enabled=true) + + // 钱包相关接口(客户端) + wallet := router.Group("/wallet", mw.CheckToken) + wallet.POST("/balance", chat.GetWalletBalance) // 获取钱包余额 + wallet.POST("/info", chat.GetWalletInfo) // 获取钱包详细信息 + wallet.POST("/balance_records", chat.GetWalletBalanceRecords) // 获取余额明细 + wallet.POST("/payment_password/set", chat.SetPaymentPassword) // 设置支付密码(首次设置或修改) + wallet.POST("/withdraw_account/set", chat.SetWithdrawAccount) // 设置提现账号 + wallet.POST("/withdraw/apply", chat.CreateWithdrawApplication) // 申请提现 + wallet.POST("/withdraw/list", chat.GetWithdrawApplications) // 获取提现申请列表 + wallet.POST("/real_name_auth", chat.RealNameAuth) // 实名认证 + + // 敏感词相关接口(客户端) + sensitive := router.Group("/sensitive_word", mw.CheckToken) + sensitive.POST("/get", chat.GetSensitiveWords) // 获取敏感词列表 + sensitive.POST("/check", chat.CheckSensitiveWords) // 检测敏感词 + + // 收藏相关接口 + favorite := router.Group("/favorite", mw.CheckToken) + favorite.POST("/create", chat.CreateFavorite) // 创建收藏 + favorite.POST("/get", chat.GetFavorite) // 获取收藏详情 + favorite.POST("/list", chat.GetFavorites) // 获取收藏列表 + favorite.POST("/search", chat.SearchFavorites) // 搜索收藏 + favorite.POST("/update", chat.UpdateFavorite) // 更新收藏 + favorite.POST("/delete", chat.DeleteFavorite) // 删除收藏 + favorite.POST("/tags", chat.GetFavoritesByTags) // 根据标签获取收藏 + favorite.POST("/count", chat.GetFavoriteCount) // 获取收藏数量 + + // 定时任务相关接口 + scheduledTask := router.Group("/scheduled_task", mw.CheckToken) + scheduledTask.POST("/create", chat.CreateScheduledTask) // 创建定时任务 + scheduledTask.POST("/get", chat.GetScheduledTask) // 获取定时任务详情 + scheduledTask.POST("/list", chat.GetScheduledTasks) // 获取定时任务列表 + scheduledTask.POST("/update", chat.UpdateScheduledTask) // 更新定时任务 + scheduledTask.POST("/delete", chat.DeleteScheduledTask) // 删除定时任务 +} diff --git a/internal/api/mw/mw.go b/internal/api/mw/mw.go new file mode 100644 index 0000000..677b2a3 --- /dev/null +++ b/internal/api/mw/mw.go @@ -0,0 +1,145 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mw + +import ( + "strconv" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" +) + +func New(client admin.AdminClient) *MW { + return &MW{client: client} +} + +type MW struct { + client admin.AdminClient +} + +func (o *MW) parseToken(c *gin.Context) (string, int32, string, error) { + token := c.GetHeader("token") + if token == "" { + return "", 0, "", errs.ErrArgs.WrapMsg("token is empty") + } + resp, err := o.client.ParseToken(c, &admin.ParseTokenReq{Token: token}) + if err != nil { + return "", 0, "", err + } + return resp.UserID, resp.UserType, token, nil +} + +func (o *MW) parseTokenType(c *gin.Context, userType int32) (string, string, error) { + userID, t, token, err := o.parseToken(c) + if err != nil { + return "", "", err + } + if t != userType { + return "", "", errs.ErrArgs.WrapMsg("token type error") + } + return userID, token, nil +} + +func (o *MW) isValidToken(c *gin.Context, userID string, token string) error { + resp, err := o.client.GetUserToken(c, &admin.GetUserTokenReq{UserID: userID}) + if err != nil { + return err + } + if len(resp.TokensMap) == 0 { + return errs.ErrTokenExpired.Wrap() + } + if v, ok := resp.TokensMap[token]; ok { + switch v { + case constantpb.NormalToken: + case constantpb.KickedToken: + return errs.ErrTokenExpired.Wrap() + default: + return errs.ErrTokenUnknown.Wrap() + } + } else { + return errs.ErrTokenExpired.Wrap() + } + return nil +} + +func (o *MW) setToken(c *gin.Context, userID string, userType int32) { + SetToken(c, userID, userType) +} + +func (o *MW) CheckToken(c *gin.Context) { + userID, userType, token, err := o.parseToken(c) + if err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + if err := o.isValidToken(c, userID, token); err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + o.setToken(c, userID, userType) +} + +func (o *MW) CheckAdmin(c *gin.Context) { + userID, token, err := o.parseTokenType(c, constant.AdminUser) + if err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + if err := o.isValidToken(c, userID, token); err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + o.setToken(c, userID, constant.AdminUser) +} + +func (o *MW) CheckUser(c *gin.Context) { + userID, token, err := o.parseTokenType(c, constant.NormalUser) + if err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + if err := o.isValidToken(c, userID, token); err != nil { + c.Abort() + apiresp.GinError(c, err) + return + } + o.setToken(c, userID, constant.NormalUser) +} + +func (o *MW) CheckAdminOrNil(c *gin.Context) { + defer c.Next() + userID, userType, _, err := o.parseToken(c) + if err != nil { + return + } + if userType == constant.AdminUser { + o.setToken(c, userID, constant.AdminUser) + } +} + +func SetToken(c *gin.Context, userID string, userType int32) { + c.Set(constant.RpcOpUserID, userID) + c.Set(constant.RpcOpUserType, []string{strconv.Itoa(int(userType))}) + c.Set(constant.RpcCustomHeader, []string{constant.RpcOpUserType}) +} diff --git a/internal/api/util/api.go b/internal/api/util/api.go new file mode 100644 index 0000000..121a612 --- /dev/null +++ b/internal/api/util/api.go @@ -0,0 +1,292 @@ +package util + +import ( + "context" + "fmt" + "net" + "strings" + + "git.imall.cloud/openim/chat/pkg/common/mctx" + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" +) + +type Api struct { + ImUserID string + ProxyHeader string + ChatAdminUserID string +} + +func (o *Api) WithAdminUser(ctx context.Context) context.Context { + return mctx.WithAdminUser(ctx, o.ChatAdminUserID) +} + +// isPrivateIP 检查IP是否是内网IP +func isPrivateIP(ip net.IP) bool { + if ip == nil { + return false + } + // 检查是否是内网IP范围 + // 10.0.0.0/8 + // 172.16.0.0/12 + // 192.168.0.0/16 + // 127.0.0.0/8 (localhost) + if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() { + return true + } + ip4 := ip.To4() + if ip4 == nil { + return false + } + // 10.0.0.0/8 + if ip4[0] == 10 { + return true + } + // 172.16.0.0/12 + if ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31 { + return true + } + // 192.168.0.0/16 + if ip4[0] == 192 && ip4[1] == 168 { + return true + } + return false +} + +// parseForwardedHeader 解析标准的 Forwarded 头(RFC 7239) +// 格式:Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43 +func parseForwardedHeader(forwarded string) string { + // 查找 for= 后面的IP地址 + parts := strings.Split(forwarded, ";") + for _, part := range parts { + part = strings.TrimSpace(part) + if strings.HasPrefix(strings.ToLower(part), "for=") { + ip := strings.TrimPrefix(part, "for=") + ip = strings.TrimPrefix(ip, "For=") + ip = strings.TrimPrefix(ip, "FOR=") + // 移除可能的引号和端口号 + ip = strings.Trim(ip, `"`) + if idx := strings.Index(ip, ":"); idx != -1 { + ip = ip[:idx] + } + if parsedIP := net.ParseIP(ip); parsedIP != nil { + return ip + } + } + } + return "" +} + +// GetClientIP 获取客户端真实IP地址 +// 支持多层反向代理和CDN场景 +// 优先级: +// 1. CDN特定头(CF-Connecting-IP, True-Client-IP等)- 最可靠 +// 2. 标准 Forwarded 头(RFC 7239)- 现代标准 +// 3. X-Real-IP - 通常由第一层代理设置,比X-Forwarded-For更可靠 +// 4. X-Forwarded-For - 取最左边的IP(客户端真实IP),格式:client_ip, proxy1_ip, proxy2_ip, ... +// 5. 其他常见头(X-Client-IP, True-Client-IP等) +// 6. 自定义ProxyHeader +// 7. RemoteAddr - 最后回退 +func (o *Api) GetClientIP(c *gin.Context) (string, error) { + // 记录所有相关的HTTP头用于调试 + headers := map[string]string{ + "Forwarded": c.Request.Header.Get("Forwarded"), // RFC 7239 标准头 + "X-Forwarded-For": c.Request.Header.Get("X-Forwarded-For"), + "X-Real-IP": c.Request.Header.Get("X-Real-IP"), + "CF-Connecting-IP": c.Request.Header.Get("CF-Connecting-IP"), // Cloudflare - 真实客户端IP + "CF-Ray": c.Request.Header.Get("CF-Ray"), // Cloudflare - 请求ID,用于验证来自CF + "True-Client-IP": c.Request.Header.Get("True-Client-IP"), // Cloudflare Enterprise, Akamai + "X-Client-IP": c.Request.Header.Get("X-Client-IP"), // 一些代理 + "X-Forwarded": c.Request.Header.Get("X-Forwarded"), // 一些代理 + "Forwarded-For": c.Request.Header.Get("Forwarded-For"), // 非标准,但有些代理使用 + "X-Cluster-Client-IP": c.Request.Header.Get("X-Cluster-Client-IP"), // Kubernetes + "RemoteAddr": c.Request.RemoteAddr, + } + if o.ProxyHeader != "" { + headers["Custom-"+o.ProxyHeader] = c.Request.Header.Get(o.ProxyHeader) + } + + // 打印所有能获取到的IP相关信息用于调试 + customProxyHeader := "" + if o.ProxyHeader != "" { + customProxyHeader = headers["Custom-"+o.ProxyHeader] + } + log.ZInfo(c, "GetClientIP 调试信息 - 所有HTTP头", + "Forwarded", headers["Forwarded"], + "X-Forwarded-For", headers["X-Forwarded-For"], + "X-Real-IP", headers["X-Real-IP"], + "CF-Connecting-IP", headers["CF-Connecting-IP"], + "CF-Ray", headers["CF-Ray"], + "True-Client-IP", headers["True-Client-IP"], + "X-Client-IP", headers["X-Client-IP"], + "X-Forwarded", headers["X-Forwarded"], + "Forwarded-For", headers["Forwarded-For"], + "X-Cluster-Client-IP", headers["X-Cluster-Client-IP"], + "RemoteAddr", headers["RemoteAddr"], + "Custom-ProxyHeader", customProxyHeader) + + // 1. 优先检查 Cloudflare 的 CF-Connecting-IP(最可靠,Cloudflare 直接设置真实客户端IP) + // 检查是否来自 Cloudflare(通过 CF-Ray 头判断) + cfRay := c.Request.Header.Get("CF-Ray") + cfConnectingIP := c.Request.Header.Get("CF-Connecting-IP") + if cfConnectingIP != "" { + // 特别记录 Cloudflare 相关信息 + log.ZInfo(c, "GetClientIP detected Cloudflare request", + "CF-Connecting-IP", cfConnectingIP, + "CF-Ray", cfRay) + + ip := strings.TrimSpace(cfConnectingIP) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + // Cloudflare 的 CF-Connecting-IP 总是包含真实客户端IP,无论公网还是内网 + // 如果同时有 CF-Ray,说明确实来自 Cloudflare,更加可靠 + if cfRay != "" { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "CF-Connecting-IP", + "cfRay", cfRay, + "isPrivateIP", isPrivateIP(parsedIP)) + } else { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "CF-Connecting-IP", + "isPrivateIP", isPrivateIP(parsedIP)) + } + return ip, nil + } + } + + // 2. 检查其他CDN特定的头 + cdnHeaders := []string{ + "True-Client-IP", // Cloudflare Enterprise, Akamai + "X-Client-IP", // 一些CDN和代理 + "X-Cluster-Client-IP", // Kubernetes Ingress + } + for _, headerName := range cdnHeaders { + ipStr := c.Request.Header.Get(headerName) + if ipStr != "" { + ip := strings.TrimSpace(ipStr) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + // CDN头通常包含真实客户端IP,优先返回公网IP + if !isPrivateIP(parsedIP) { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", headerName, + "isPrivateIP", false) + return ip, nil + } + // 即使是内网IP,CDN头也相对可靠 + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", headerName, + "isPrivateIP", true) + return ip, nil + } + } + } + + // 3. 检查标准 Forwarded 头(RFC 7239)- 现代标准,最可靠 + forwarded := c.Request.Header.Get("Forwarded") + if forwarded != "" { + ip := parseForwardedHeader(forwarded) + if ip != "" { + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "Forwarded", + "isPrivateIP", isPrivateIP(parsedIP)) + return ip, nil + } + } + } + + // 4. 检查 X-Real-IP 头(通常由第一层代理设置,比X-Forwarded-For更可靠) + xRealIP := c.Request.Header.Get("X-Real-IP") + if xRealIP != "" { + ip := strings.TrimSpace(xRealIP) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "X-Real-IP", + "isPrivateIP", isPrivateIP(parsedIP)) + return ip, nil + } + } + + // 5. 检查 X-Forwarded-For 头(格式:client_ip, proxy1_ip, proxy2_ip, ...) + // 重要:在多层代理中,最左边的IP是客户端真实IP,应该优先取第一个IP + xForwardedFor := c.Request.Header.Get("X-Forwarded-For") + if xForwardedFor != "" { + ips := strings.Split(xForwardedFor, ",") + // 取最左边的IP(第一个IP),这是客户端真实IP + // 格式:client_ip, proxy1_ip, proxy2_ip, ... + if len(ips) > 0 { + ip := strings.TrimSpace(ips[0]) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "X-Forwarded-For", + "totalIPs", len(ips), + "isPrivateIP", isPrivateIP(parsedIP), + "note", "取最左边的IP(客户端真实IP)") + return ip, nil + } + } + } + + // 6. 检查其他常见头 + otherHeaders := []string{"X-Client-IP", "X-Forwarded", "Forwarded-For"} + for _, headerName := range otherHeaders { + ipStr := c.Request.Header.Get(headerName) + if ipStr != "" { + ip := strings.TrimSpace(ipStr) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", headerName, + "isPrivateIP", isPrivateIP(parsedIP)) + return ip, nil + } + } + } + + // 7. 如果配置了自定义的 ProxyHeader,检查它 + if o.ProxyHeader != "" { + customHeaderIP := c.Request.Header.Get(o.ProxyHeader) + if customHeaderIP != "" { + ip := strings.TrimSpace(customHeaderIP) + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "Custom-"+o.ProxyHeader, + "isPrivateIP", isPrivateIP(parsedIP)) + return ip, nil + } + } + } + + // 8. 最后使用 RemoteAddr(在集群环境中可能是代理服务器的IP) + remoteAddr := c.Request.RemoteAddr + ip, _, err := net.SplitHostPort(remoteAddr) + if err != nil { + log.ZError(c, "GetClientIP failed to parse RemoteAddr", err, "RemoteAddr", remoteAddr) + return "", errs.ErrInternalServer.WrapMsg(fmt.Sprintf("failed to parse RemoteAddr: %v", err)) + } + parsedIP := net.ParseIP(ip) + log.ZInfo(c, "GetClientIP 最终选择IP", + "ip", ip, + "source", "RemoteAddr", + "isPrivateIP", parsedIP != nil && isPrivateIP(parsedIP)) + return ip, nil +} + +func (o *Api) GetDefaultIMAdminUserID() string { + return o.ImUserID +} diff --git a/internal/api/util/captcha.go b/internal/api/util/captcha.go new file mode 100644 index 0000000..ddb36c0 --- /dev/null +++ b/internal/api/util/captcha.go @@ -0,0 +1,783 @@ +package util + +import ( + "bytes" + "fmt" + "image" + "image/color" + "image/draw" + "image/gif" + "math" + "math/rand" + "time" + + "github.com/openimsdk/tools/errs" +) + +// GenerateCaptchaImageFromCode 根据给定的验证码生成动态GIF图片 +// 返回GIF图片的字节数组 +func GenerateCaptchaImageFromCode(code string) (imgBytes []byte, err error) { + // 图片尺寸 - 宽度280px,高度50px + width := 280 + height := 50 + + // GIF动画参数 + frameCount := 12 // 12帧动画,更流畅 + delay := 8 // 每帧延迟8(单位:1/100秒) + + // 创建统一的调色板(所有帧共享) + sharedPalette := createSharedPalette() + + // 创建GIF + g := &gif.GIF{ + Image: []*image.Paletted{}, + Delay: []int{}, + } + + // 使用固定种子保证数字位置基本一致 + baseSeed := time.Now().UnixNano() + + // 预生成每帧的基础数据(干扰线、圆圈等的位置) + noiseData := generateNoiseData(baseSeed, frameCount, width, height) + + // 生成每一帧 + for i := 0; i < frameCount; i++ { + frame := image.NewRGBA(image.Rect(0, 0, width, height)) + + // 设置背景色(浅灰色,稍微模糊) + bgColor := color.RGBA{235, 235, 235, 255} + draw.Draw(frame, frame.Bounds(), &image.Uniform{bgColor}, image.Point{}, draw.Src) + + // 使用随机数生成器(每帧略有不同) + rng := rand.New(rand.NewSource(baseSeed + int64(i*1000))) + + // 绘制丰富的背景 - 添加渐变背景 + drawGradientBackground(frame, rng, width, height) + + // 绘制移动的背景圆圈(类似bubbles效果) + drawAnimatedCircles(frame, noiseData, i, width, height) + + // 绘制额外的背景形状(矩形、椭圆等) + drawAdditionalShapes(frame, rng, width, height) + + // 添加动态干扰线(位置会变化) + drawAnimatedNoiseLines(frame, noiseData, i, width, height) + + // 决定是否显示数字(每隔几帧就隐藏数字,造成闪烁效果) + // 例如:0,1,2显示数字,3,4隐藏,5,6显示,7,8隐藏,9,10显示,11隐藏 + showNumbers := (i % 3) != 2 // 每3帧中有2帧显示数字,1帧隐藏 + + if showNumbers { + // 绘制验证码文字(位置会抖动) + drawNumbersWithWiggle(frame, code, rng, width, height, i, frameCount) + } + + // 添加动态干扰点(位置会变化) + drawAnimatedNoiseDots(frame, noiseData, i, width, height) + + // 添加模糊噪点 - 增加噪点密度 + addBlurNoise(frame, rng) + + // 添加额外的随机干扰线 + drawRandomNoiseLines(frame, rng, width, height) + + // 转换为调色板图像(GIF需要) + // 使用统一的调色板 + paletted := convertToPalettedWithPalette(frame, sharedPalette) + + if paletted == nil { + return nil, errs.New(fmt.Sprintf("failed to convert frame %d to paletted", i+1)) + } + + g.Image = append(g.Image, paletted) + g.Delay = append(g.Delay, delay) + } + + // 编码为GIF + var buf bytes.Buffer + err = gif.EncodeAll(&buf, g) + if err != nil { + return nil, errs.WrapMsg(err, "encode gif failed") + } + + // 验证数据不为空 + if buf.Len() == 0 { + return nil, errs.New("generated gif data is empty") + } + + return buf.Bytes(), nil +} + +// NoiseData 存储每帧的干扰数据 +type NoiseData struct { + lines [][]LineData + circles [][]CircleData + dots [][]DotData +} + +type LineData struct { + x1, y1, x2, y2 int + color color.RGBA + thickness int +} + +type CircleData struct { + x, y, radius int + color color.RGBA +} + +type DotData struct { + x, y int + color color.RGBA + size int +} + +// generateNoiseData 预生成所有帧的干扰数据 +func generateNoiseData(baseSeed int64, frameCount, width, height int) *NoiseData { + rng := rand.New(rand.NewSource(baseSeed)) + + data := &NoiseData{ + lines: make([][]LineData, frameCount), + circles: make([][]CircleData, frameCount), + dots: make([][]DotData, frameCount), + } + + // 生成干扰线数据(每帧位置略有变化)- 增加干扰线数量 + lineCount := 20 // 从10增加到20 + for frame := 0; frame < frameCount; frame++ { + lines := make([]LineData, lineCount) + for i := 0; i < lineCount; i++ { + // 基础位置 + baseX1 := rng.Intn(width) + baseY1 := rng.Intn(height) + baseX2 := rng.Intn(width) + baseY2 := rng.Intn(height) + + // 每帧添加偏移,形成移动效果 + offsetX := int(float64(frame) * 2.5 * float64(rng.Float64()-0.5)) + offsetY := int(float64(frame) * 2.5 * float64(rng.Float64()-0.5)) + + lines[i] = LineData{ + x1: clampCoord(baseX1+offsetX, width), + y1: clampCoord(baseY1+offsetY, height), + x2: clampCoord(baseX2+offsetX, width), + y2: clampCoord(baseY2+offsetY, height), + color: color.RGBA{ + uint8(150 + rng.Intn(80)), // 更宽的颜色范围 + uint8(150 + rng.Intn(80)), + uint8(150 + rng.Intn(80)), + 200 + uint8(rng.Intn(55)), // 半透明 + }, + thickness: 1 + rng.Intn(3), // 增加线条粗细变化 + } + } + data.lines[frame] = lines + } + + // 生成背景圆圈数据(移动的bubbles)- 增加圆圈数量和大小变化 + circleCount := 15 // 从8增加到15 + for frame := 0; frame < frameCount; frame++ { + circles := make([]CircleData, circleCount) + for i := 0; i < circleCount; i++ { + // 基础位置 + baseX := rng.Intn(width*2) - width/2 + baseY := rng.Intn(height*2) - height/2 + + // 每帧移动 + moveX := int(float64(frame) * 1.5 * float64(rng.Float64()-0.5)) + moveY := int(float64(frame) * 1.5 * float64(rng.Float64()-0.5)) + + circles[i] = CircleData{ + x: clampCoord(baseX+moveX, width), + y: clampCoord(baseY+moveY, height), + radius: 8 + rng.Intn(35), // 更大的半径范围(8-43) + color: color.RGBA{ + uint8(180 + rng.Intn(50)), // 更宽的颜色范围 + uint8(180 + rng.Intn(50)), + uint8(180 + rng.Intn(50)), + 150 + uint8(rng.Intn(105)), // 更宽的透明度范围 + }, + } + } + data.circles[frame] = circles + } + + // 生成干扰点数据(闪烁效果)- 增加点数量 + dotCount := 200 // 从100增加到200 + for frame := 0; frame < frameCount; frame++ { + dots := make([]DotData, dotCount) + for i := 0; i < dotCount; i++ { + x := rng.Intn(width) + y := rng.Intn(height) + + // 某些点会在某些帧消失(闪烁效果) + visible := frame%3 != i%3 || rng.Float64() > 0.3 + + dots[i] = DotData{ + x: x, + y: y, + color: color.RGBA{ + uint8(120 + rng.Intn(110)), // 更宽的颜色范围 + uint8(120 + rng.Intn(110)), + uint8(120 + rng.Intn(110)), + func() uint8 { + if visible { + return 200 + uint8(rng.Intn(55)) + } + return uint8(80 + rng.Intn(120)) + }(), + }, + size: 1 + rng.Intn(3), // 更大的点尺寸(1-3) + } + } + data.dots[frame] = dots + } + + return data +} + +func clampCoord(v, max int) int { + if v < 0 { + return 0 + } + if v >= max { + return max - 1 + } + return v +} + +// createSharedPalette 创建统一的调色板(所有帧共享) +func createSharedPalette() color.Palette { + palette := make(color.Palette, 256) + + // 添加灰色渐变(0-239) + for i := 0; i < 240; i++ { + val := uint8(i * 255 / 240) + palette[i] = color.RGBA{val, val, val, 255} + } + + // 添加常用颜色(240-255) + colorMap := map[int]color.RGBA{ + 240: {30, 30, 30, 255}, + 241: {60, 60, 60, 255}, + 242: {50, 50, 50, 255}, + 243: {40, 40, 80, 255}, + 244: {80, 40, 40, 255}, + 245: {50, 80, 50, 255}, + 246: {100, 30, 30, 255}, + 247: {30, 100, 30, 255}, + 248: {30, 30, 100, 255}, + 249: {140, 140, 140, 255}, + 250: {160, 160, 160, 255}, + 251: {180, 180, 180, 255}, + 252: {200, 200, 200, 255}, + 253: {220, 220, 220, 255}, + 254: {235, 235, 235, 255}, + 255: {255, 255, 255, 255}, + } + + for idx, col := range colorMap { + if idx < 256 { + palette[idx] = col + } + } + + return palette +} + +// convertToPalettedWithPalette 使用指定调色板将RGBA图像转换为Paletted图像 +func convertToPalettedWithPalette(img *image.RGBA, palette color.Palette) *image.Paletted { + bounds := img.Bounds() + + // 创建Paletted图像 + paletted := image.NewPaletted(bounds, palette) + + // 转换:找到最接近的调色板颜色 + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + for x := bounds.Min.X; x < bounds.Max.X; x++ { + c := img.At(x, y) + // 找到调色板中最接近的颜色 + idx := findClosestColor(c, palette) + paletted.SetColorIndex(x, y, uint8(idx)) + } + } + + return paletted +} + +// findClosestColor 在调色板中找到最接近的颜色索引 +func findClosestColor(c color.Color, palette color.Palette) int { + r, g, b, _ := c.RGBA() + minDist := uint32(^uint32(0)) + bestIdx := 0 + + for i := 0; i < len(palette); i++ { + cr, cg, cb, _ := palette[i].RGBA() + // 计算欧氏距离 + dr := (r >> 8) - (cr >> 8) + dg := (g >> 8) - (cg >> 8) + db := (b >> 8) - (cb >> 8) + dist := dr*dr + dg*dg + db*db + + if dist < minDist { + minDist = dist + bestIdx = i + } + } + + return bestIdx +} + +// drawGradientBackground 绘制渐变背景 +func drawGradientBackground(img *image.RGBA, rng *rand.Rand, width, height int) { + // 随机选择渐变方向 + vertical := rng.Intn(2) == 0 + + if vertical { + // 垂直渐变 + startR := uint8(220 + rng.Intn(35)) + startG := uint8(220 + rng.Intn(35)) + startB := uint8(220 + rng.Intn(35)) + endR := uint8(200 + rng.Intn(55)) + endG := uint8(200 + rng.Intn(55)) + endB := uint8(200 + rng.Intn(55)) + + for y := 0; y < height; y++ { + ratio := float64(y) / float64(height) + r := uint8(float64(startR)*(1-ratio) + float64(endR)*ratio) + g := uint8(float64(startG)*(1-ratio) + float64(endG)*ratio) + b := uint8(float64(startB)*(1-ratio) + float64(endB)*ratio) + + for x := 0; x < width; x++ { + img.Set(x, y, color.RGBA{r, g, b, 255}) + } + } + } else { + // 水平渐变 + startR := uint8(220 + rng.Intn(35)) + startG := uint8(220 + rng.Intn(35)) + startB := uint8(220 + rng.Intn(35)) + endR := uint8(200 + rng.Intn(55)) + endG := uint8(200 + rng.Intn(55)) + endB := uint8(200 + rng.Intn(55)) + + for x := 0; x < width; x++ { + ratio := float64(x) / float64(width) + r := uint8(float64(startR)*(1-ratio) + float64(endR)*ratio) + g := uint8(float64(startG)*(1-ratio) + float64(endG)*ratio) + b := uint8(float64(startB)*(1-ratio) + float64(endB)*ratio) + + for y := 0; y < height; y++ { + img.Set(x, y, color.RGBA{r, g, b, 255}) + } + } + } +} + +// drawAdditionalShapes 绘制额外的背景形状 +func drawAdditionalShapes(img *image.RGBA, rng *rand.Rand, width, height int) { + shapeCount := 5 + rng.Intn(8) // 5-12个形状 + + for i := 0; i < shapeCount; i++ { + shapeType := rng.Intn(3) + x := rng.Intn(width) + y := rng.Intn(height) + + // 随机颜色(浅色,半透明) + col := color.RGBA{ + uint8(190 + rng.Intn(45)), + uint8(190 + rng.Intn(45)), + uint8(190 + rng.Intn(45)), + uint8(100 + rng.Intn(100)), + } + + switch shapeType { + case 0: // 矩形 + w := 15 + rng.Intn(40) + h := 15 + rng.Intn(40) + drawRect(img, x, y, w, h, col) + case 1: // 椭圆 + rx := 10 + rng.Intn(25) + ry := 10 + rng.Intn(25) + drawEllipse(img, x, y, rx, ry, col) + case 2: // 小圆圈 + radius := 5 + rng.Intn(15) + drawCircle(img, x, y, radius, col) + } + } +} + +// drawRect 绘制矩形 +func drawRect(img *image.RGBA, x, y, w, h int, c color.Color) { + for dy := 0; dy < h && y+dy < img.Bounds().Dy(); dy++ { + if y+dy < 0 { + continue + } + for dx := 0; dx < w && x+dx < img.Bounds().Dx(); dx++ { + if x+dx < 0 { + continue + } + r, g, b, _ := img.At(x+dx, y+dy).RGBA() + cr, cg, cb, ca := c.RGBA() + + alpha := uint32(ca >> 8) + invAlpha := 255 - alpha + + newR := uint8(((uint32(r>>8) * invAlpha) + (uint32(cr>>8) * alpha)) / 255) + newG := uint8(((uint32(g>>8) * invAlpha) + (uint32(cg>>8) * alpha)) / 255) + newB := uint8(((uint32(b>>8) * invAlpha) + (uint32(cb>>8) * alpha)) / 255) + + img.Set(x+dx, y+dy, color.RGBA{newR, newG, newB, 255}) + } + } +} + +// drawEllipse 绘制椭圆 +func drawEllipse(img *image.RGBA, cx, cy, rx, ry int, c color.Color) { + for y := -ry; y <= ry; y++ { + for x := -rx; x <= rx; x++ { + // 椭圆方程: (x/rx)^2 + (y/ry)^2 <= 1 + if float64(x*x)/(float64(rx*rx))+float64(y*y)/(float64(ry*ry)) <= 1.0 { + px := cx + x + py := cy + y + if px >= 0 && px < img.Bounds().Dx() && py >= 0 && py < img.Bounds().Dy() { + r, g, b, _ := img.At(px, py).RGBA() + cr, cg, cb, ca := c.RGBA() + + alpha := uint32(ca >> 8) + invAlpha := 255 - alpha + + newR := uint8(((uint32(r>>8) * invAlpha) + (uint32(cr>>8) * alpha)) / 255) + newG := uint8(((uint32(g>>8) * invAlpha) + (uint32(cg>>8) * alpha)) / 255) + newB := uint8(((uint32(b>>8) * invAlpha) + (uint32(cb>>8) * alpha)) / 255) + + img.Set(px, py, color.RGBA{newR, newG, newB, 255}) + } + } + } + } +} + +// drawRandomNoiseLines 绘制额外的随机干扰线 +func drawRandomNoiseLines(img *image.RGBA, rng *rand.Rand, width, height int) { + lineCount := 8 + rng.Intn(12) // 8-19条随机线 + + for i := 0; i < lineCount; i++ { + x1 := rng.Intn(width) + y1 := rng.Intn(height) + x2 := rng.Intn(width) + y2 := rng.Intn(height) + + col := color.RGBA{ + uint8(160 + rng.Intn(70)), + uint8(160 + rng.Intn(70)), + uint8(160 + rng.Intn(70)), + uint8(150 + rng.Intn(105)), + } + + thickness := 1 + rng.Intn(2) + drawThickLine(img, x1, y1, x2, y2, col, thickness) + } +} + +// addBlurNoise 添加模糊噪点效果 - 增加噪点密度 +func addBlurNoise(img *image.RGBA, rng *rand.Rand) { + // 增加随机噪点,使图片看起来更模糊(从1/50增加到1/30) + for i := 0; i < img.Bounds().Dx()*img.Bounds().Dy()/30; i++ { + x := rng.Intn(img.Bounds().Dx()) + y := rng.Intn(img.Bounds().Dy()) + + // 获取当前像素 + r, g, b, _ := img.At(x, y).RGBA() + rVal := uint8(r >> 8) + gVal := uint8(g >> 8) + bVal := uint8(b >> 8) + + // 添加轻微随机变化 + noise := int8(rng.Intn(21) - 10) // -10 到 10 + newR := clamp(int(rVal) + int(noise)) + newG := clamp(int(gVal) + int(noise)) + newB := clamp(int(bVal) + int(noise)) + + img.Set(x, y, color.RGBA{uint8(newR), uint8(newG), uint8(newB), 255}) + } +} + +func clamp(v int) int { + if v < 0 { + return 0 + } + if v > 255 { + return 255 + } + return v +} + +// drawNumbersWithWiggle 绘制数字,带抖动效果(类似wiggle)- 增加随机分布 +func drawNumbersWithWiggle(img *image.RGBA, code string, rng *rand.Rand, width, height int, frameIndex, totalFrames int) { + // 根据宽度和高度调整字符大小(适配新的280x50尺寸) + charWidth := width / 18 // 约15(280宽度时为15.5) + charHeight := height * 4 / 5 // 约40(50高度时为40) + charSpacing := width / 25 // 字符间距,稍微减小以适应更小的空间 + + // 基础起始位置 - 更随机化 + baseStartX := width/12 + rng.Intn(width/20) // 随机起始X位置 + baseStartY := height/8 + rng.Intn(height/6) // 随机起始Y位置,允许上下移动(适配50px高度) + + // 数字颜色(深色但稍微模糊,降低对比度) + colors := []color.RGBA{ + {30, 30, 30, 255}, // 深灰(不是纯黑,更模糊) + {60, 60, 60, 255}, // 中灰 + {40, 40, 80, 255}, // 深蓝(模糊) + {80, 40, 40, 255}, // 深红(模糊) + {50, 80, 50, 255}, // 深绿(模糊) + {50, 50, 50, 255}, // 灰色 + } + + // 计算抖动偏移(使用正弦波创建平滑的抖动效果) + wiggleX := float64(frameIndex) / float64(totalFrames) * 2 * 3.14159 + wiggleY := float64(frameIndex) / float64(totalFrames) * 2 * 3.14159 * 1.3 + + for i, char := range code { + // 随机选择颜色(偏深色但不要太黑,更模糊) + charColor := colors[rng.Intn(len(colors))] + + // 基础位置 - 每个字符位置增加随机偏移 + charRandomOffsetX := rng.Intn(width/25) - width/50 // ±5像素的随机偏移 + charRandomOffsetY := rng.Intn(height/8) - height/16 // ±3像素的随机偏移 + + baseX := baseStartX + i*(charWidth+charSpacing) + charRandomOffsetX + baseY := baseStartY + charRandomOffsetY + + // 添加抖动效果(每个字符的抖动幅度和相位不同)- 增加抖动幅度 + charWiggleX := math.Sin(wiggleX+float64(i)*0.8) * 4.0 // 从2.0增加到4.0 + charWiggleY := math.Sin(wiggleY+float64(i)*1.1) * 4.0 // 从2.0增加到4.0 + + // 额外的随机偏移 - 增加随机范围 + xOffset := int(charWiggleX) + rng.Intn(7) - 3 // 从±1增加到±3 + yOffset := int(charWiggleY) + rng.Intn(7) - 3 // 从±1增加到±3 + + x := baseX + xOffset + y := baseY + yOffset + + // 确保不超出边界 + if x < 0 { + x = 0 + } + if x+charWidth > width { + x = width - charWidth + } + if y < 0 { + y = 0 + } + if y+charHeight > height { + y = height - charHeight + } + + // 绘制数字(使用简化版本:绘制矩形块模拟数字) + drawSimpleNumber(img, byte(char), x, y, charWidth, charHeight, charColor) + } +} + +// drawSimpleNumber 绘制单个数字(简化版本,根据尺寸缩放) +func drawSimpleNumber(img *image.RGBA, digit byte, x, y, width, height int, c color.Color) { + digitValue := int(digit - '0') + + // 缩放比例(相对于原始16x24大小) + scaleX := float64(width) / 16.0 + scaleY := float64(height) / 24.0 + + // 根据数字绘制不同的小矩形块来模拟数字形状(原始坐标) + basePatterns := [][]struct{ x, y, w, h int }{ + // 0 + {{2, 2, 14, 2}, {2, 2, 2, 20}, {14, 2, 2, 20}, {2, 20, 14, 2}}, + // 1 + {{8, 2, 2, 20}}, + // 2 + {{2, 2, 12, 2}, {12, 2, 2, 10}, {2, 10, 12, 2}, {2, 10, 2, 10}, {2, 20, 12, 2}}, + // 3 + {{2, 2, 12, 2}, {12, 2, 2, 20}, {2, 10, 10, 2}, {2, 20, 12, 2}}, + // 4 + {{2, 2, 2, 10}, {2, 10, 10, 2}, {12, 2, 2, 20}}, + // 5 + {{2, 2, 12, 2}, {2, 2, 2, 10}, {2, 10, 12, 2}, {12, 10, 2, 10}, {2, 20, 12, 2}}, + // 6 + {{2, 2, 12, 2}, {2, 2, 2, 20}, {12, 10, 2, 10}, {2, 10, 10, 2}, {2, 20, 12, 2}}, + // 7 + {{2, 2, 12, 2}, {12, 2, 2, 20}}, + // 8 + {{2, 2, 12, 2}, {2, 2, 2, 10}, {12, 2, 2, 10}, {2, 10, 12, 2}, {2, 10, 2, 10}, {12, 10, 2, 10}, {2, 20, 12, 2}}, + // 9 + {{2, 2, 12, 2}, {2, 2, 2, 10}, {12, 2, 2, 20}, {2, 10, 10, 2}}, + } + + if digitValue >= 0 && digitValue <= 9 { + pattern := basePatterns[digitValue] + for _, p := range pattern { + // 缩放坐标 + px := int(float64(p.x) * scaleX) + py := int(float64(p.y) * scaleY) + pw := int(float64(p.w) * scaleX) + ph := int(float64(p.h) * scaleY) + + // 确保最小尺寸 + if pw < 1 { + pw = 1 + } + if ph < 1 { + ph = 1 + } + + rect := image.Rect(x+px, y+py, x+px+pw, y+py+ph) + draw.Draw(img, rect, &image.Uniform{c}, image.Point{}, draw.Over) + } + } +} + +// drawAnimatedCircles 绘制移动的背景圆圈 +func drawAnimatedCircles(img *image.RGBA, data *NoiseData, frameIndex int, width, height int) { + if frameIndex >= len(data.circles) { + return + } + + for _, circle := range data.circles[frameIndex] { + drawCircle(img, circle.x, circle.y, circle.radius, circle.color) + } +} + +// drawCircle 绘制圆圈 +func drawCircle(img *image.RGBA, cx, cy, radius int, c color.Color) { + for y := -radius; y <= radius; y++ { + for x := -radius; x <= radius; x++ { + if x*x+y*y <= radius*radius { + px := cx + x + py := cy + y + if px >= 0 && px < img.Bounds().Dx() && py >= 0 && py < img.Bounds().Dy() { + // 获取当前像素并混合颜色 + r, g, b, _ := img.At(px, py).RGBA() + cr, cg, cb, ca := c.RGBA() + + // Alpha混合 + alpha := uint32(ca >> 8) + invAlpha := 255 - alpha + + newR := uint8(((uint32(r>>8) * invAlpha) + (uint32(cr>>8) * alpha)) / 255) + newG := uint8(((uint32(g>>8) * invAlpha) + (uint32(cg>>8) * alpha)) / 255) + newB := uint8(((uint32(b>>8) * invAlpha) + (uint32(cb>>8) * alpha)) / 255) + + img.Set(px, py, color.RGBA{newR, newG, newB, 255}) + } + } + } + } +} + +// drawAnimatedNoiseLines 绘制动态干扰线 +func drawAnimatedNoiseLines(img *image.RGBA, data *NoiseData, frameIndex int, width, height int) { + if frameIndex >= len(data.lines) { + return + } + + for _, line := range data.lines[frameIndex] { + drawThickLine(img, line.x1, line.y1, line.x2, line.y2, line.color, line.thickness) + } +} + +// drawAnimatedNoiseDots 绘制动态干扰点 +func drawAnimatedNoiseDots(img *image.RGBA, data *NoiseData, frameIndex int, width, height int) { + if frameIndex >= len(data.dots) { + return + } + + for _, dot := range data.dots[frameIndex] { + if dot.color.A < 50 { + continue // 跳过几乎透明的点 + } + + // 绘制点(可能是1x1或2x2) + for dx := 0; dx < dot.size && dot.x+dx < width; dx++ { + for dy := 0; dy < dot.size && dot.y+dy < height; dy++ { + img.Set(dot.x+dx, dot.y+dy, dot.color) + } + } + } +} + +// drawThickLine 绘制粗线 +func drawThickLine(img *image.RGBA, x1, y1, x2, y2 int, c color.Color, thickness int) { + for i := 0; i < thickness; i++ { + offsetX := i - thickness/2 + offsetY := i - thickness/2 + drawLine(img, x1+offsetX, y1+offsetY, x2+offsetX, y2+offsetY, c) + } +} + +// drawLine 绘制直线(Bresenham算法简化版) +func drawLine(img *image.RGBA, x1, y1, x2, y2 int, c color.Color) { + dx := abs(x2 - x1) + dy := abs(y2 - y1) + sx := 1 + if x1 > x2 { + sx = -1 + } + sy := 1 + if y1 > y2 { + sy = -1 + } + err := dx - dy + + x, y := x1, y1 + for { + if x >= 0 && x < img.Bounds().Dx() && y >= 0 && y < img.Bounds().Dy() { + img.Set(x, y, c) + } + if x == x2 && y == y2 { + break + } + e2 := 2 * err + if e2 > -dy { + err -= dy + x += sx + } + if e2 < dx { + err += dx + y += sy + } + } +} + +// addNoiseDots 添加干扰点(更多更密集) +func addNoiseDots(img *image.RGBA, rng *rand.Rand, count int) { + for i := 0; i < count; i++ { + x := rng.Intn(img.Bounds().Dx()) + y := rng.Intn(img.Bounds().Dy()) + + // 随机颜色(浅色,增加模糊效果) + brightness := 140 + rng.Intn(90) // 140-230之间 + dotColor := color.RGBA{ + uint8(brightness + rng.Intn(30) - 15), + uint8(brightness + rng.Intn(30) - 15), + uint8(brightness + rng.Intn(30) - 15), + 255, + } + + // 有时绘制小区域而不是单个点(更密集的干扰) + if rng.Intn(3) == 0 { + // 绘制2x2的小块 + for dx := 0; dx < 2 && x+dx < img.Bounds().Dx(); dx++ { + for dy := 0; dy < 2 && y+dy < img.Bounds().Dy(); dy++ { + img.Set(x+dx, y+dy, dotColor) + } + } + } else { + img.Set(x, y, dotColor) + } + } +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} diff --git a/internal/rpc/admin/admin.go b/internal/rpc/admin/admin.go new file mode 100644 index 0000000..d07f822 --- /dev/null +++ b/internal/rpc/admin/admin.go @@ -0,0 +1,1143 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "crypto/hmac" + cryptorand "crypto/rand" + "crypto/sha1" + "encoding/base32" + "encoding/binary" + "fmt" + "math/rand" + "net/url" + "strconv" + "strings" + "time" + + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/utils/datautil" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/google/uuid" +) + +func (o *adminServer) GetAdminInfo(ctx context.Context, req *admin.GetAdminInfoReq) (*admin.GetAdminInfoResp, error) { + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + a, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return nil, err + } + + // 生成完整的二维码URL,优先使用账号,如果没有则使用昵称 + accountName := a.Account + if accountName == "" { + accountName = a.Nickname + } + googleAuthKey := o.generateGoogleAuthQRCodeURL(a.GoogleAuthKey, accountName) + + return &admin.GetAdminInfoResp{ + Account: a.Account, + Password: a.Password, + OperationPassword: a.OperationPassword, + FaceURL: a.FaceURL, + Nickname: a.Nickname, + UserID: a.UserID, + Level: a.Level, + GoogleAuthKey: googleAuthKey, + CreateTime: a.CreateTime.UnixMilli(), + }, nil +} + +func (o *adminServer) ChangeAdminPassword(ctx context.Context, req *admin.ChangeAdminPasswordReq) (*admin.ChangeAdminPasswordResp, error) { + user, err := o.Database.GetAdminUserID(ctx, req.UserID) + if err != nil { + return nil, err + } + + if user.Password != req.CurrentPassword { + return nil, errs.ErrInternalServer.WrapMsg("password error") + } + + if err := o.Database.ChangePassword(ctx, req.UserID, req.NewPassword); err != nil { + return nil, err + } + + // 修改密码成功后,清除 Redis 中的 token,使所有登录会话失效 + if err := o.Database.DeleteToken(ctx, req.UserID); err != nil { + // 清除 token 失败不影响密码修改,只记录日志 + log.ZWarn(ctx, "Failed to delete token after password change", err, "userID", req.UserID) + } + + return &admin.ChangeAdminPasswordResp{}, nil +} + +func (o *adminServer) ChangeOperationPassword(ctx context.Context, req *admin.ChangeOperationPasswordReq) (*admin.ChangeOperationPasswordResp, error) { + // 获取当前登录的管理员ID + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 获取管理员信息 + adminUser, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return nil, err + } + + // 检查是否为超级管理员(level:100) + if adminUser.Level != constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg("only super admin (level:100) can set operation password") + } + + // 验证新密码不能为空 + if req.NewPassword == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "new password cannot be empty") + } + + // 根据数据库中是否已有操作密码来判断是首次设置还是修改 + hasOperationPassword := adminUser.OperationPassword != "" + + if hasOperationPassword { + // 已设置过操作密码:必须校验旧密码且新旧不能相同 + if req.CurrentPassword == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "current password is required when changing operation password") + } + if adminUser.OperationPassword != req.CurrentPassword { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "current operation password is incorrect") + } + if req.NewPassword == req.CurrentPassword { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "new password cannot be the same as current password") + } + } + // 首次设置时,即使提供了 currentPassword 也不报错,直接忽略 + + // 更新操作密码 + if err := o.Database.ChangeOperationPassword(ctx, userID, req.NewPassword); err != nil { + return nil, err + } + + return &admin.ChangeOperationPasswordResp{}, nil +} + +func (o *adminServer) AddAdminAccount(ctx context.Context, req *admin.AddAdminAccountReq) (*admin.AddAdminAccountResp, error) { + if err := o.CheckSuperAdmin(ctx); err != nil { + return nil, err + } + + _, err := o.Database.GetAdmin(ctx, req.Account) + if err == nil { + return nil, errs.ErrDuplicateKey.WrapMsg("the account is registered") + } + + adm := &admindb.Admin{ + Account: req.Account, + Password: req.Password, + FaceURL: req.FaceURL, + Nickname: req.Nickname, + UserID: o.genUserID(), + Level: 80, + CreateTime: time.Now(), + } + if err = o.Database.AddAdminAccount(ctx, []*admindb.Admin{adm}); err != nil { + return nil, err + } + return &admin.AddAdminAccountResp{}, nil +} + +func (o *adminServer) DelAdminAccount(ctx context.Context, req *admin.DelAdminAccountReq) (*admin.DelAdminAccountResp, error) { + if err := o.CheckSuperAdmin(ctx); err != nil { + return nil, err + } + + if datautil.Duplicate(req.UserIDs) { + return nil, errs.ErrArgs.WrapMsg("user ids is duplicate") + } + + for _, userID := range req.UserIDs { + superAdmin, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return nil, err + } + if superAdmin.Level == constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg(fmt.Sprintf("%s is superAdminID", userID)) + } + } + + if err := o.Database.DelAdminAccount(ctx, req.UserIDs); err != nil { + return nil, err + } + return &admin.DelAdminAccountResp{}, nil +} + +func (o *adminServer) SearchAdminAccount(ctx context.Context, req *admin.SearchAdminAccountReq) (*admin.SearchAdminAccountResp, error) { + if err := o.CheckSuperAdmin(ctx); err != nil { + return nil, err + } + + total, adminAccounts, err := o.Database.SearchAdminAccount(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + accounts := make([]*admin.GetAdminInfoResp, 0, len(adminAccounts)) + for _, v := range adminAccounts { + // 生成完整的二维码URL,优先使用账号,如果没有则使用昵称 + accountName := v.Account + if accountName == "" { + accountName = v.Nickname + } + googleAuthKey := o.generateGoogleAuthQRCodeURL(v.GoogleAuthKey, accountName) + + temp := &admin.GetAdminInfoResp{ + Account: v.Account, + OperationPassword: v.OperationPassword, + FaceURL: v.FaceURL, + Nickname: v.Nickname, + UserID: v.UserID, + Level: v.Level, + GoogleAuthKey: googleAuthKey, + CreateTime: v.CreateTime.Unix(), + } + accounts = append(accounts, temp) + } + return &admin.SearchAdminAccountResp{Total: uint32(total), AdminAccounts: accounts}, nil +} + +func (o *adminServer) AdminUpdateInfo(ctx context.Context, req *admin.AdminUpdateInfoReq) (*admin.AdminUpdateInfoResp, error) { + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 如果请求中包含操作密码,禁止通过此接口设置 + // 操作密码只能通过 ChangeOperationPassword 接口修改 + if req.OperationPassword != nil { + return nil, errs.ErrArgs.WrapMsg("operation password can only be changed through ChangeOperationPassword interface") + } + + update, err := ToDBAdminUpdate(req) + if err != nil { + return nil, err + } + info, err := o.Database.GetAdminUserID(ctx, mcontext.GetOpUserID(ctx)) + if err != nil { + return nil, err + } + if err := o.Database.UpdateAdmin(ctx, userID, update); err != nil { + return nil, err + } + resp := &admin.AdminUpdateInfoResp{UserID: info.UserID} + if req.Nickname == nil { + resp.Nickname = info.Nickname + } else { + resp.Nickname = req.Nickname.Value + } + if req.FaceURL == nil { + resp.FaceURL = info.FaceURL + } else { + resp.FaceURL = req.FaceURL.Value + } + return resp, nil +} + +func (o *adminServer) Login(ctx context.Context, req *admin.LoginReq) (*admin.LoginResp, error) { + a, err := o.Database.GetAdmin(ctx, req.Account) + if err != nil { + if dbutil.IsDBNotFound(err) { + return nil, eerrs.ErrAccountNotFound.Wrap() + } + return nil, err + } + if a.Password != req.Password { + return nil, eerrs.ErrPassword.Wrap() + } + + // 如果设置了 Google Authenticator key,则必须验证 Google 验证码 + if a.GoogleAuthKey != "" { + if req.GoogleAuthCode == "" { + return nil, eerrs.ErrGoogleAuthCodeRequired.WrapMsg("Google Authenticator 验证码不能为空") + } + + // 验证 Google 验证码 + if !o.verifyTOTP(a.GoogleAuthKey, req.GoogleAuthCode) { + return nil, eerrs.ErrGoogleAuthCodeNotMatch.WrapMsg("Google Authenticator 验证码错误") + } + } + + adminToken, err := o.CreateToken(ctx, &admin.CreateTokenReq{UserID: a.UserID, UserType: constant.AdminUser}) + if err != nil { + return nil, err + } + return &admin.LoginResp{ + AdminUserID: a.UserID, + AdminAccount: a.Account, + AdminToken: adminToken.Token, + Nickname: a.Nickname, + FaceURL: a.FaceURL, + Level: a.Level, + }, nil +} + +func (o *adminServer) ChangePassword(ctx context.Context, req *admin.ChangePasswordReq) (*admin.ChangePasswordResp, error) { + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + a, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return nil, err + } + + // 准备更新字段 + update := make(map[string]any) + + // 修改登录密码 + if req.Password != "" { + passwordUpdate, err := ToDBAdminUpdatePassword(req.Password) + if err != nil { + return nil, err + } + for k, v := range passwordUpdate { + update[k] = v + } + } + + // 修改操作密码(如果提供了新操作密码) + if req.NewOperationPassword != "" { + // 检查是否为超级管理员(level:100) + if a.Level != constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg("only super admin (level:100) can set operation password") + } + + // 如果已设置操作密码,需要验证旧密码 + if a.OperationPassword != "" { + if req.CurrentOperationPassword == "" { + return nil, errs.ErrArgs.WrapMsg("current operation password is required when changing operation password") + } + if a.OperationPassword != req.CurrentOperationPassword { + return nil, errs.ErrNoPermission.WrapMsg("current operation password is incorrect") + } + if req.NewOperationPassword == req.CurrentOperationPassword { + return nil, errs.ErrArgs.WrapMsg("new operation password cannot be the same as current password") + } + } else { + // 首次设置操作密码,不需要提供旧密码 + if req.CurrentOperationPassword != "" { + return nil, errs.ErrArgs.WrapMsg("current operation password should not be provided when setting operation password for the first time") + } + } + + // 更新操作密码 + update["operation_password"] = req.NewOperationPassword + } + + // 执行更新 + passwordChanged := false + if len(update) > 0 { + // 检查是否修改了登录密码 + if req.Password != "" { + passwordChanged = true + } + if err := o.Database.UpdateAdmin(ctx, a.UserID, update); err != nil { + return nil, err + } + } + + // 如果修改了登录密码,清除 Redis 中的 token,使所有登录会话失效 + if passwordChanged { + if err := o.Database.DeleteToken(ctx, a.UserID); err != nil { + // 清除 token 失败不影响密码修改,只记录日志 + log.ZWarn(ctx, "Failed to delete token after password change", err, "userID", a.UserID) + } + } + + return &admin.ChangePasswordResp{}, nil +} + +func (o *adminServer) SetGoogleAuthKey(ctx context.Context, req *admin.SetGoogleAuthKeyReq) (*admin.SetGoogleAuthKeyResp, error) { + // 获取当前登录的管理员信息 + currentUserID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + currentAdmin, err := o.Database.GetAdminUserID(ctx, currentUserID) + if err != nil { + return nil, err + } + + // 确定要操作的目标管理员:默认当前登录者;如果传入 userID 且为超级管理员,则操作指定管理员 + targetUserID := currentUserID + targetAdmin := currentAdmin + if req.UserID != "" && req.UserID != currentUserID { + // 仅超级管理员可以为其他管理员操作 + if currentAdmin.Level != constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg("only super admin (level:100) can operate other admins' google auth key") + } + targetUserID = req.UserID + targetAdmin, err = o.Database.GetAdminUserID(ctx, targetUserID) + if err != nil { + return nil, err + } + } + + // 验证操作类型 + if req.OperationType < 1 || req.OperationType > 3 { + return nil, errs.ErrArgs.WrapMsg("operationType must be 1, 2, or 3") + } + + var newKey string + var qrCodeURL string + operationType := req.OperationType + + switch req.OperationType { + case 1: // 新设置:如果为空则设置,如果已存在则返回错误 + if targetAdmin.GoogleAuthKey != "" { + return nil, errs.ErrArgs.WrapMsg("Google Auth key already exists, use operationType=2 to regenerate or operationType=3 to clear") + } + // 生成新的密钥 + generatedKey, err := o.generateGoogleAuthKey() + if err != nil { + return nil, errs.ErrInternalServer.WrapMsg("failed to generate Google Auth key: " + err.Error()) + } + newKey = generatedKey + + case 2: // 强制覆盖旧的:即使存在也生成新的 + // 生成新的密钥 + generatedKey, err := o.generateGoogleAuthKey() + if err != nil { + return nil, errs.ErrInternalServer.WrapMsg("failed to generate Google Auth key: " + err.Error()) + } + newKey = generatedKey + + case 3: // 清空:删除现有的密钥 + newKey = "" + qrCodeURL = "" + // 更新数据库,清空密钥(使用 $unset 删除字段) + if err := o.Database.ClearGoogleAuthKey(ctx, targetUserID); err != nil { + return nil, err + } + return &admin.SetGoogleAuthKeyResp{ + GoogleAuthKey: "", + QrCodeURL: "", + OperationType: 3, + }, nil + } + + // 更新数据库(操作类型1和2) + if req.OperationType == 1 || req.OperationType == 2 { + update := map[string]any{ + "google_auth_key": newKey, + } + if err := o.Database.UpdateAdmin(ctx, targetUserID, update); err != nil { + return nil, err + } + + // 生成二维码URL + accountName := targetAdmin.Account + if accountName == "" { + accountName = targetAdmin.Nickname + } + qrCodeURL = o.generateGoogleAuthQRCodeURL(newKey, accountName) + } + + return &admin.SetGoogleAuthKeyResp{ + GoogleAuthKey: newKey, + QrCodeURL: qrCodeURL, + OperationType: operationType, + }, nil +} + +// generateGoogleAuthKey 生成Google身份验证码密钥(Base32编码,16字节) +func (o *adminServer) generateGoogleAuthKey() (string, error) { + // 生成16字节的随机数据(Google Authenticator标准) + keyBytes := make([]byte, 16) + if _, err := cryptorand.Read(keyBytes); err != nil { + return "", err + } + // 使用Base32编码(无填充),这是Google Authenticator使用的格式 + return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(keyBytes), nil +} + +// verifyTOTP 验证 TOTP (Time-based One-Time Password) 验证码 +// 基于 RFC 6238 标准,使用 HMAC-SHA1 算法 +func (o *adminServer) verifyTOTP(secret string, code string) bool { + // 验证码必须是 6 位数字 + if len(code) != 6 { + return false + } + + // 验证码必须全部是数字 + expectedCode, err := strconv.Atoi(code) + if err != nil { + return false + } + + // 如果 secret 是 otpauth URL 格式,从中提取密钥 + // 格式: otpauth://totp/...?secret=XXX&... + if strings.HasPrefix(secret, "otpauth://") { + // 解析 URL 提取 secret 参数 + parsedURL, err := url.Parse(secret) + if err != nil { + return false + } + secretParam := parsedURL.Query().Get("secret") + if secretParam == "" { + return false + } + secret = secretParam + } + + // 解码 Base32 编码的密钥 + key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(strings.ToUpper(secret)) + if err != nil { + return false + } + + // 获取当前时间戳(秒),除以 30 得到时间步数 + timestamp := time.Now().Unix() + timeStep := timestamp / 30 + + // 验证当前时间步和前后各一个时间步(允许时间偏差,共 3 个时间窗口,90 秒) + for i := -1; i <= 1; i++ { + step := timeStep + int64(i) + + // 将时间步转换为 8 字节的大端序字节数组 + counter := make([]byte, 8) + binary.BigEndian.PutUint64(counter, uint64(step)) + + // 使用 HMAC-SHA1 计算哈希 + h := hmac.New(sha1.New, key) + h.Write(counter) + hash := h.Sum(nil) + + // 动态截取(RFC 6238) + offset := hash[19] & 0x0f + binaryCode := binary.BigEndian.Uint32(hash[offset:offset+4]) & 0x7fffffff + + // 取最后 6 位数字 + calculatedCode := int(binaryCode % 1000000) + + // 如果匹配,返回 true + if calculatedCode == expectedCode { + return true + } + } + + return false +} + +// generateGoogleAuthQRCodeURL 生成Google Authenticator二维码URL +func (o *adminServer) generateGoogleAuthQRCodeURL(secret string, accountName string) string { + if secret == "" { + return "" + } + + // 使用账号或昵称作为账户标识,优先使用账号 + account := accountName + if account == "" { + account = "Admin" + } + + // 服务提供商名称 + issuer := "OpenIM Admin" + + // 构建 otpauth URL + // Google Authenticator 标准格式: otpauth://totp/{label}?secret={secret}&issuer={issuer}&algorithm=SHA1&digits=6&period=30 + // label 格式: {issuer}:{account},路径中的空格不需要编码 + // 参数值(secret 和 issuer)需要 URL 编码 + + // 构建 label,格式为 issuer:account + // 注意:路径部分(label)中的空格不需要编码,直接使用空格 + label := fmt.Sprintf("%s:%s", issuer, account) + + // 构建完整的 URL + // 参数值使用 QueryEscape 编码,但空格在参数值中会被编码为 %20 + otpauthURL := fmt.Sprintf("otpauth://totp/%s?secret=%s&issuer=%s&algorithm=SHA1&digits=6&period=30", + label, + url.QueryEscape(secret), + url.QueryEscape(issuer), + ) + + return otpauthURL +} + +func (o *adminServer) GetStatistics(ctx context.Context, req *admin.GetStatisticsReq) (*admin.GetStatisticsResp, error) { + // 普通管理员也可以查看统计数据 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 用户总数 + totalUsers, err := o.ChatDatabase.NewUserCountTotal(ctx, nil) + if err != nil { + return nil, err + } + + // 今天注册的用户数 + todayRegisteredUsers, err := o.ChatDatabase.CountTodayRegisteredUsers(ctx) + if err != nil { + return nil, err + } + + // 今天活跃用户数(今天登录的不同用户数) + todayActiveUsers, err := o.ChatDatabase.CountTodayActiveUsers(ctx) + if err != nil { + return nil, err + } + + // 从数据库查询群组和好友统计数据 + totalGroups, err := o.Database.CountTotalGroups(ctx) + if err != nil { + // 如果查询失败,返回 0,不阻塞其他统计数据的返回 + totalGroups = 0 + } + + todayNewGroups, err := o.Database.CountTodayNewGroups(ctx) + if err != nil { + todayNewGroups = 0 + } + + totalFriends, err := o.Database.CountTotalFriends(ctx) + if err != nil { + totalFriends = 0 + } + + // 消息和在线用户统计数据 + // 注意:这些数据可能存储在 OpenIM 的核心服务中,如果数据库中没有,需要通过 OpenIM API 获取 + // 目前先返回 0,后续可以根据实际情况实现 + var todayMessages, totalMessages, onlineUsers int64 + + // TODO: 实现消息统计和在线用户统计 + // 如果数据库中有消息表,可以在这里查询 + // 如果 OpenIM 有统计接口,可以通过 ImApiCaller 调用 + _ = o.ImApiCaller // 暂时保留,后续可以添加具体的统计接口调用 + + return &admin.GetStatisticsResp{ + TotalUsers: totalUsers, + TodayRegisteredUsers: todayRegisteredUsers, + TodayActiveUsers: todayActiveUsers, + TodayMessages: todayMessages, + TotalMessages: totalMessages, + TotalGroups: totalGroups, + TotalFriends: totalFriends, + OnlineUsers: onlineUsers, + TodayNewGroups: todayNewGroups, + }, nil +} + +func (o *adminServer) genUserID() string { + const l = 10 + data := make([]byte, l) + rand.Read(data) + chars := []byte("0123456789") + for i := 0; i < len(data); i++ { + if i == 0 { + data[i] = chars[1:][data[i]%9] + } else { + data[i] = chars[data[i]%10] + } + } + return string(data) +} + +func (o *adminServer) CheckSuperAdmin(ctx context.Context) error { + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return err + } + + adminUser, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return err + } + + if adminUser.Level != constant.AdvancedUserLevel { + return errs.ErrNoPermission.Wrap() + } + return nil +} + +// ==================== 敏感词管理相关 RPC ==================== + +// 敏感词管理 +func (o *adminServer) AddSensitiveWord(ctx context.Context, req *admin.AddSensitiveWordReq) (*admin.AddSensitiveWordResp, error) { + // 调用Chat RPC + chatReq := &chat.AddSensitiveWordReq{ + Word: req.Word, + Level: req.Level, + Type: req.Type, + Action: req.Action, + Status: req.Status, + Remark: req.Remark, + } + _, err := o.Chat.AddSensitiveWord(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.AddSensitiveWordResp{}, nil +} + +func (o *adminServer) UpdateSensitiveWord(ctx context.Context, req *admin.UpdateSensitiveWordReq) (*admin.UpdateSensitiveWordResp, error) { + // 调用Chat RPC + chatReq := &chat.UpdateSensitiveWordReq{ + Id: req.Id, + Word: req.Word, + Level: req.Level, + Type: req.Type, + Action: req.Action, + Status: req.Status, + Remark: req.Remark, + } + _, err := o.Chat.UpdateSensitiveWord(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.UpdateSensitiveWordResp{}, nil +} + +func (o *adminServer) DeleteSensitiveWord(ctx context.Context, req *admin.DeleteSensitiveWordReq) (*admin.DeleteSensitiveWordResp, error) { + // 调用Chat RPC + chatReq := &chat.DeleteSensitiveWordReq{ + Ids: req.Ids, + } + _, err := o.Chat.DeleteSensitiveWord(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.DeleteSensitiveWordResp{}, nil +} + +func (o *adminServer) GetSensitiveWord(ctx context.Context, req *admin.GetSensitiveWordReq) (*admin.GetSensitiveWordResp, error) { + // 调用Chat RPC + chatReq := &chat.GetSensitiveWordReq{ + Id: req.Id, + } + chatResp, err := o.Chat.GetSensitiveWord(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + return &admin.GetSensitiveWordResp{ + Word: convertToAdminSensitiveWordInfo(chatResp.Word), + }, nil +} + +func (o *adminServer) SearchSensitiveWords(ctx context.Context, req *admin.SearchSensitiveWordsReq) (*admin.SearchSensitiveWordsResp, error) { + // 调用Chat RPC + chatReq := &chat.SearchSensitiveWordsReq{ + Keyword: req.Keyword, + Action: req.Action, + Status: req.Status, + Pagination: req.Pagination, + } + chatResp, err := o.Chat.SearchSensitiveWords(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + var words []*admin.SensitiveWordInfo + for _, word := range chatResp.Words { + words = append(words, convertToAdminSensitiveWordInfo(word)) + } + + return &admin.SearchSensitiveWordsResp{ + Total: int64(chatResp.Total), + Words: words, + }, nil +} + +func (o *adminServer) BatchAddSensitiveWords(ctx context.Context, req *admin.BatchAddSensitiveWordsReq) (*admin.BatchAddSensitiveWordsResp, error) { + // 调用Chat RPC + chatReq := &chat.BatchAddSensitiveWordsReq{ + Words: convertToChatSensitiveWordDetailInfos(req.Words), + } + _, err := o.Chat.BatchAddSensitiveWords(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.BatchAddSensitiveWordsResp{}, nil +} + +func (o *adminServer) BatchUpdateSensitiveWords(ctx context.Context, req *admin.BatchUpdateSensitiveWordsReq) (*admin.BatchUpdateSensitiveWordsResp, error) { + // 调用Chat RPC + chatReq := &chat.BatchUpdateSensitiveWordsReq{ + Updates: convertToChatSensitiveWordDetailInfoMap(req.Updates), + } + _, err := o.Chat.BatchUpdateSensitiveWords(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.BatchUpdateSensitiveWordsResp{}, nil +} + +func (o *adminServer) BatchDeleteSensitiveWords(ctx context.Context, req *admin.BatchDeleteSensitiveWordsReq) (*admin.BatchDeleteSensitiveWordsResp, error) { + // 调用Chat RPC + chatReq := &chat.BatchDeleteSensitiveWordsReq{ + Ids: req.Ids, + } + _, err := o.Chat.BatchDeleteSensitiveWords(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.BatchDeleteSensitiveWordsResp{}, nil +} + +// 敏感词分组管理 +func (o *adminServer) AddSensitiveWordGroup(ctx context.Context, req *admin.AddSensitiveWordGroupReq) (*admin.AddSensitiveWordGroupResp, error) { + // 调用Chat RPC + chatReq := &chat.AddSensitiveWordGroupReq{ + Name: req.Name, + Remark: req.Remark, + } + _, err := o.Chat.AddSensitiveWordGroup(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.AddSensitiveWordGroupResp{}, nil +} + +func (o *adminServer) UpdateSensitiveWordGroup(ctx context.Context, req *admin.UpdateSensitiveWordGroupReq) (*admin.UpdateSensitiveWordGroupResp, error) { + // 调用Chat RPC + chatReq := &chat.UpdateSensitiveWordGroupReq{ + Id: req.Id, + Name: req.Name, + Remark: req.Remark, + } + _, err := o.Chat.UpdateSensitiveWordGroup(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.UpdateSensitiveWordGroupResp{}, nil +} + +func (o *adminServer) DeleteSensitiveWordGroup(ctx context.Context, req *admin.DeleteSensitiveWordGroupReq) (*admin.DeleteSensitiveWordGroupResp, error) { + // 调用Chat RPC + chatReq := &chat.DeleteSensitiveWordGroupReq{ + Ids: req.Ids, + } + _, err := o.Chat.DeleteSensitiveWordGroup(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.DeleteSensitiveWordGroupResp{}, nil +} + +func (o *adminServer) GetSensitiveWordGroup(ctx context.Context, req *admin.GetSensitiveWordGroupReq) (*admin.GetSensitiveWordGroupResp, error) { + // 调用Chat RPC + chatReq := &chat.GetSensitiveWordGroupReq{ + Id: req.Id, + } + chatResp, err := o.Chat.GetSensitiveWordGroup(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + return &admin.GetSensitiveWordGroupResp{ + Group: convertToAdminSensitiveWordGroupInfo(chatResp.Group), + }, nil +} + +func (o *adminServer) GetAllSensitiveWordGroups(ctx context.Context, req *admin.GetAllSensitiveWordGroupsReq) (*admin.GetAllSensitiveWordGroupsResp, error) { + // 调用Chat RPC + chatReq := &chat.GetAllSensitiveWordGroupsReq{} + chatResp, err := o.Chat.GetAllSensitiveWordGroups(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + var groups []*admin.SensitiveWordGroupInfo + for _, group := range chatResp.Groups { + groups = append(groups, convertToAdminSensitiveWordGroupInfo(group)) + } + + return &admin.GetAllSensitiveWordGroupsResp{ + Groups: groups, + }, nil +} + +// 敏感词配置管理 +func (o *adminServer) GetSensitiveWordConfig(ctx context.Context, req *admin.GetSensitiveWordConfigReq) (*admin.GetSensitiveWordConfigResp, error) { + fmt.Println("GetSensitiveWordConfig", "_________11", req) + // 调用Chat RPC获取敏感词配置 + chatResp, err := o.Chat.GetSensitiveWordConfig(ctx, &chat.GetSensitiveWordConfigReq{}) + if err != nil { + fmt.Println("GetSensitiveWordConfig", "_________22", err) + return nil, err + } + fmt.Println("GetSensitiveWordConfig", "_________33", chatResp) + // 转换响应 + return &admin.GetSensitiveWordConfigResp{ + Config: &admin.SensitiveWordConfigInfo{ + Id: chatResp.Config.Id, + EnableFilter: chatResp.Config.EnableFilter, + FilterMode: chatResp.Config.FilterMode, + ReplaceChar: chatResp.Config.ReplaceChar, + WhitelistUsers: chatResp.Config.WhitelistUsers, + WhitelistGroups: chatResp.Config.WhitelistGroups, + LogEnabled: chatResp.Config.LogEnabled, + AutoApprove: chatResp.Config.AutoApprove, + UpdateTime: chatResp.Config.UpdateTime, + }, + }, nil +} + +func (o *adminServer) UpdateSensitiveWordConfig(ctx context.Context, req *admin.UpdateSensitiveWordConfigReq) (*admin.UpdateSensitiveWordConfigResp, error) { + // 调用Chat RPC更新敏感词配置 + chatReq := &chat.UpdateSensitiveWordConfigReq{ + Config: &chat.SensitiveWordConfigInfo{ + Id: req.Config.Id, + EnableFilter: req.Config.EnableFilter, + FilterMode: req.Config.FilterMode, + ReplaceChar: req.Config.ReplaceChar, + WhitelistUsers: req.Config.WhitelistUsers, + WhitelistGroups: req.Config.WhitelistGroups, + LogEnabled: req.Config.LogEnabled, + AutoApprove: req.Config.AutoApprove, + UpdateTime: req.Config.UpdateTime, + }, + } + + _, err := o.Chat.UpdateSensitiveWordConfig(ctx, chatReq) + if err != nil { + return nil, err + } + + return &admin.UpdateSensitiveWordConfigResp{}, nil +} + +// 敏感词日志管理 +func (o *adminServer) GetSensitiveWordLogs(ctx context.Context, req *admin.GetSensitiveWordLogsReq) (*admin.GetSensitiveWordLogsResp, error) { + // 调用Chat RPC + chatReq := &chat.GetSensitiveWordLogsReq{ + UserId: req.UserId, + GroupId: req.GroupId, + Pagination: req.Pagination, + } + chatResp, err := o.Chat.GetSensitiveWordLogs(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + var logs []*admin.SensitiveWordLogInfo + for _, log := range chatResp.Logs { + logs = append(logs, convertToAdminSensitiveWordLogInfo(log)) + } + + return &admin.GetSensitiveWordLogsResp{ + Total: int64(chatResp.Total), + Logs: logs, + }, nil +} + +// GetUserLoginRecords 查询用户登录记录 +func (o *adminServer) GetUserLoginRecords(ctx context.Context, req *admin.GetUserLoginRecordsReq) (*admin.GetUserLoginRecordsResp, error) { + // 调用Chat RPC + chatReq := &chat.GetUserLoginRecordsReq{ + UserId: req.UserId, + Ip: req.Ip, + Pagination: req.Pagination, + } + chatResp, err := o.Chat.GetUserLoginRecords(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + var records []*admin.UserLoginRecordInfo + for _, record := range chatResp.Records { + records = append(records, &admin.UserLoginRecordInfo{ + UserId: record.UserId, + LoginTime: record.LoginTime, + Ip: record.Ip, + DeviceId: record.DeviceId, + Platform: record.Platform, + FaceUrl: record.FaceUrl, + Nickname: record.Nickname, + }) + } + + return &admin.GetUserLoginRecordsResp{ + Total: int64(chatResp.Total), + Records: records, + }, nil +} + +func (o *adminServer) DeleteSensitiveWordLogs(ctx context.Context, req *admin.DeleteSensitiveWordLogsReq) (*admin.DeleteSensitiveWordLogsResp, error) { + // 调用Chat RPC + chatReq := &chat.DeleteSensitiveWordLogsReq{ + Ids: req.Ids, + } + _, err := o.Chat.DeleteSensitiveWordLogs(ctx, chatReq) + if err != nil { + return nil, err + } + return &admin.DeleteSensitiveWordLogsResp{}, nil +} + +// 敏感词统计 +func (o *adminServer) GetSensitiveWordStats(ctx context.Context, req *admin.GetSensitiveWordStatsReq) (*admin.GetSensitiveWordStatsResp, error) { + // 调用Chat RPC获取敏感词统计 + chatResp, err := o.Chat.GetSensitiveWordStats(ctx, &chat.GetSensitiveWordStatsReq{}) + if err != nil { + return nil, err + } + + // 转换响应 + return &admin.GetSensitiveWordStatsResp{ + Stats: &admin.SensitiveWordStatsInfo{ + Total: chatResp.Stats.Total, + Enabled: chatResp.Stats.Enabled, + Disabled: chatResp.Stats.Disabled, + Replace: chatResp.Stats.Replace, + Block: chatResp.Stats.Block, + }, + }, nil +} + +func (o *adminServer) GetSensitiveWordLogStats(ctx context.Context, req *admin.GetSensitiveWordLogStatsReq) (*admin.GetSensitiveWordLogStatsResp, error) { + // 调用Chat RPC + chatReq := &chat.GetSensitiveWordLogStatsReq{ + StartTime: req.StartTime, + EndTime: req.EndTime, + } + chatResp, err := o.Chat.GetSensitiveWordLogStats(ctx, chatReq) + if err != nil { + return nil, err + } + + // 转换响应 + return &admin.GetSensitiveWordLogStatsResp{ + Stats: &admin.SensitiveWordLogStatsInfo{ + Total: chatResp.Stats.Total, + Replace: chatResp.Stats.Replace, + Block: chatResp.Stats.Block, + }, + }, nil +} + +// ==================== 辅助函数 ==================== + +// generateID 生成唯一ID +func generateID() string { + return uuid.New().String() +} + +// getAdminUserID 获取当前管理员用户ID +func getAdminUserID(ctx context.Context) string { + userID, _ := mctx.CheckAdmin(ctx) + return userID +} + +// convertToAdminSensitiveWordInfo 转换为Admin敏感词信息 +func convertToAdminSensitiveWordInfo(word *chat.SensitiveWordDetailInfo) *admin.SensitiveWordInfo { + return &admin.SensitiveWordInfo{ + Id: word.Id, + Word: word.Word, + Level: word.Level, + Type: word.Type, + Action: word.Action, + Status: word.Status, + Creator: word.Creator, + Updater: word.Updater, + CreateTime: word.CreateTime, + UpdateTime: word.UpdateTime, + Remark: word.Remark, + } +} + +// convertToChatSensitiveWordDetailInfos 转换为Chat敏感词详细信息列表 +func convertToChatSensitiveWordDetailInfos(words []*admin.SensitiveWordInfo) []*chat.SensitiveWordDetailInfo { + var result []*chat.SensitiveWordDetailInfo + for _, word := range words { + result = append(result, &chat.SensitiveWordDetailInfo{ + Id: word.Id, + Word: word.Word, + Level: word.Level, + Type: word.Type, + Action: word.Action, + Status: word.Status, + Creator: word.Creator, + Updater: word.Updater, + CreateTime: word.CreateTime, + UpdateTime: word.UpdateTime, + Remark: word.Remark, + }) + } + return result +} + +// convertToChatSensitiveWordDetailInfoMap 转换为Chat敏感词详细信息映射 +func convertToChatSensitiveWordDetailInfoMap(updates map[string]*admin.SensitiveWordInfo) map[string]*chat.SensitiveWordDetailInfo { + result := make(map[string]*chat.SensitiveWordDetailInfo) + for id, word := range updates { + result[id] = &chat.SensitiveWordDetailInfo{ + Id: word.Id, + Word: word.Word, + Level: word.Level, + Type: word.Type, + Action: word.Action, + Status: word.Status, + Creator: word.Creator, + Updater: word.Updater, + CreateTime: word.CreateTime, + UpdateTime: word.UpdateTime, + Remark: word.Remark, + } + } + return result +} + +// convertToAdminSensitiveWordGroupInfo 转换为Admin敏感词分组信息 +func convertToAdminSensitiveWordGroupInfo(group *chat.SensitiveWordGroupInfo) *admin.SensitiveWordGroupInfo { + return &admin.SensitiveWordGroupInfo{ + Id: group.Id, + Name: group.Name, + Remark: group.Remark, + CreateTime: group.CreateTime, + UpdateTime: group.UpdateTime, + } +} + +// convertToAdminSensitiveWordLogInfo 转换为Admin敏感词日志信息 +func convertToAdminSensitiveWordLogInfo(log *chat.SensitiveWordLogInfo) *admin.SensitiveWordLogInfo { + return &admin.SensitiveWordLogInfo{ + Id: log.Id, + UserId: log.UserId, + GroupId: log.GroupId, + Content: log.Content, + MatchedWords: log.MatchedWords, + Action: log.Action, + ProcessedText: log.ProcessedText, + CreateTime: log.CreateTime, + } +} diff --git a/internal/rpc/admin/applet.go b/internal/rpc/admin/applet.go new file mode 100644 index 0000000..b341166 --- /dev/null +++ b/internal/rpc/admin/applet.go @@ -0,0 +1,159 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "strings" + "time" + + "github.com/openimsdk/tools/utils/datautil" + + "github.com/google/uuid" + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/common/constant" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/common" +) + +func (o *adminServer) AddApplet(ctx context.Context, req *admin.AddAppletReq) (*admin.AddAppletResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if req.Name == "" { + return nil, errs.ErrArgs.WrapMsg("name empty") + } + if req.AppID == "" { + return nil, errs.ErrArgs.WrapMsg("appid empty") + } + if !(req.Status == constant.StatusOnShelf || req.Status == constant.StatusUnShelf) { + return nil, errs.ErrArgs.WrapMsg("invalid status") + } + m := admindb.Applet{ + ID: req.Id, + Name: req.Name, + AppID: req.AppID, + Icon: req.Icon, + URL: req.Url, + MD5: req.Md5, + Size: req.Size, + Version: req.Version, + Priority: req.Priority, + Status: uint8(req.Status), + CreateTime: time.Now(), + } + if m.ID == "" { + m.ID = uuid.New().String() + } + if err := o.Database.CreateApplet(ctx, []*admindb.Applet{&m}); err != nil { + return nil, err + } + return &admin.AddAppletResp{}, nil +} + +func (o *adminServer) DelApplet(ctx context.Context, req *admin.DelAppletReq) (*admin.DelAppletResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.AppletIds) == 0 { + return nil, errs.ErrArgs.WrapMsg("AppletIds empty") + } + applets, err := o.Database.FindApplet(ctx, req.AppletIds) + if err != nil { + return nil, err + } + if ids := datautil.Single(req.AppletIds, datautil.Slice(applets, func(e *admindb.Applet) string { return e.ID })); len(ids) > 0 { + return nil, errs.ErrArgs.WrapMsg("ids not found: " + strings.Join(ids, ", ")) + } + if err := o.Database.DelApplet(ctx, req.AppletIds); err != nil { + return nil, err + } + return &admin.DelAppletResp{}, nil +} + +func (o *adminServer) UpdateApplet(ctx context.Context, req *admin.UpdateAppletReq) (*admin.UpdateAppletResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + _, err := o.Database.GetApplet(ctx, req.Id) + if err != nil { + return nil, err + } + update, err := ToDBAppletUpdate(req) + if err != nil { + return nil, err + } + if err := o.Database.UpdateApplet(ctx, req.Id, update); err != nil { + return nil, err + } + return &admin.UpdateAppletResp{}, nil +} + +func (o *adminServer) FindApplet(ctx context.Context, req *admin.FindAppletReq) (*admin.FindAppletResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + applets, err := o.Database.FindOnShelf(ctx) + if err != nil { + return nil, err + } + resp := &admin.FindAppletResp{Applets: make([]*common.AppletInfo, 0, len(applets))} + for _, applet := range applets { + resp.Applets = append(resp.Applets, &common.AppletInfo{ + Id: applet.ID, + Name: applet.Name, + AppID: applet.AppID, + Icon: applet.Icon, + Url: applet.URL, + Md5: applet.MD5, + Size: applet.Size, + Version: applet.Version, + Priority: applet.Priority, + Status: uint32(applet.Status), + CreateTime: applet.CreateTime.UnixMilli(), + }) + } + return resp, nil +} + +func (o *adminServer) SearchApplet(ctx context.Context, req *admin.SearchAppletReq) (*admin.SearchAppletResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, applets, err := o.Database.SearchApplet(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + resp := &admin.SearchAppletResp{Total: uint32(total), Applets: make([]*common.AppletInfo, 0, len(applets))} + for _, applet := range applets { + resp.Applets = append(resp.Applets, &common.AppletInfo{ + Id: applet.ID, + Name: applet.Name, + AppID: applet.AppID, + Icon: applet.Icon, + Url: applet.URL, + Md5: applet.MD5, + Size: applet.Size, + Version: applet.Version, + Priority: applet.Priority, + Status: uint32(applet.Status), + CreateTime: applet.CreateTime.UnixMilli(), + }) + } + return resp, nil +} diff --git a/internal/rpc/admin/application.go b/internal/rpc/admin/application.go new file mode 100644 index 0000000..de354dd --- /dev/null +++ b/internal/rpc/admin/application.go @@ -0,0 +1,289 @@ +package admin + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + "github.com/redis/go-redis/v9" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +func IsNotFound(err error) bool { + switch errs.Unwrap(err) { + case redis.Nil, mongo.ErrNoDocuments: + return true + default: + return false + } +} + +func (o *adminServer) db2pbApplication(val *admindb.Application) *admin.ApplicationVersion { + return &admin.ApplicationVersion{ + Id: val.ID.Hex(), + Platform: val.Platform, + Version: val.Version, + Url: val.Url, + Text: val.Text, + Force: val.Force, + Latest: val.Latest, + Hot: val.Hot, + CreateTime: val.CreateTime.UnixMilli(), + } +} + +// LatestVersionAPIResponse 外部 API 响应结构 +type LatestVersionAPIResponse struct { + Success bool `json:"success"` + ErrorCode string `json:"errorCode"` + ErrorMessage string `json:"errorMessage"` + ShowType int `json:"showType"` + Data struct { + APKPath string `json:"apk_path"` + APKSize int64 `json:"apk_size"` + AppLogo string `json:"app_logo"` + AppName string `json:"app_name"` + CreatedAt string `json:"created_at"` + Success bool `json:"success"` + Version string `json:"version"` + } `json:"data"` +} + +func (o *adminServer) LatestApplicationVersion(ctx context.Context, req *admin.LatestApplicationVersionReq) (*admin.LatestApplicationVersionResp, error) { + // 从系统配置读取 build_app_id + buildAppIDConfig, err := o.ChatDatabase.GetSystemConfig(ctx, "build_app_id") + if err != nil { + log.ZWarn(ctx, "Failed to get build_app_id from system config, falling back to database", err) + // 如果获取配置失败,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + buildAppID := buildAppIDConfig.Value + if buildAppID == "" { + log.ZWarn(ctx, "build_app_id is empty in system config, falling back to database", nil) + // 如果配置值为空,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + // 调用外部 API + apiURL := "https://down.imall.cloud/api/download/latest" + requestBody := map[string]string{ + "app_id": buildAppID, + } + jsonData, err := json.Marshal(requestBody) + if err != nil { + log.ZError(ctx, "Failed to marshal request body", err, "buildAppID", buildAppID) + return nil, errs.ErrInternalServer.WrapMsg("failed to prepare request") + } + + httpReq, err := http.NewRequestWithContext(ctx, "POST", apiURL, bytes.NewBuffer(jsonData)) + if err != nil { + log.ZError(ctx, "Failed to create HTTP request", err, "url", apiURL) + return nil, errs.ErrInternalServer.WrapMsg("failed to create request") + } + httpReq.Header.Set("Content-Type", "application/json") + + client := &http.Client{ + Timeout: 10 * time.Second, + } + resp, err := client.Do(httpReq) + if err != nil { + log.ZError(ctx, "Failed to call external API", err, "url", apiURL) + // API 调用失败,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.ZError(ctx, "Failed to read response body", err) + // 读取响应失败,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + if resp.StatusCode != http.StatusOK { + log.ZWarn(ctx, "External API returned non-200 status", nil, "statusCode", resp.StatusCode, "body", string(body)) + // API 返回非 200,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + var apiResp LatestVersionAPIResponse + if err := json.Unmarshal(body, &apiResp); err != nil { + log.ZError(ctx, "Failed to unmarshal API response", err, "body", string(body)) + // 解析响应失败,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + if !apiResp.Success { + log.ZWarn(ctx, "External API returned success=false", nil, "errorCode", apiResp.ErrorCode, "errorMessage", apiResp.ErrorMessage) + // API 返回失败,回退到从数据库读取 + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } + } + + // 解析创建时间 + var createTime time.Time + if apiResp.Data.CreatedAt != "" { + createTime, err = time.Parse(time.RFC3339, apiResp.Data.CreatedAt) + if err != nil { + log.ZWarn(ctx, "Failed to parse created_at", err, "createdAt", apiResp.Data.CreatedAt) + createTime = time.Now() + } + } else { + createTime = time.Now() + } + + // 转换为 ApplicationVersion 格式 + version := &admin.ApplicationVersion{ + Id: "", // 外部 API 没有 ID + Platform: req.Platform, + Version: apiResp.Data.Version, + Url: apiResp.Data.APKPath, + Text: fmt.Sprintf("应用名称: %s", apiResp.Data.AppName), + Force: false, // 外部 API 没有提供此字段 + Latest: true, // 从 latest 接口获取的肯定是最新版本 + Hot: false, // 外部 API 没有提供此字段 + CreateTime: createTime.UnixMilli(), + } + + return &admin.LatestApplicationVersionResp{Version: version}, nil +} + +func (o *adminServer) AddApplicationVersion(ctx context.Context, req *admin.AddApplicationVersionReq) (*admin.AddApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + val := &admindb.Application{ + ID: primitive.NewObjectID(), + Platform: req.Platform, + Version: req.Version, + Url: req.Url, + Text: req.Text, + Force: req.Force, + Latest: req.Latest, + Hot: req.Hot, + CreateTime: time.Now(), + } + if err := o.Database.AddVersion(ctx, val); err != nil { + return nil, err + } + return &admin.AddApplicationVersionResp{}, nil +} + +func (o *adminServer) UpdateApplicationVersion(ctx context.Context, req *admin.UpdateApplicationVersionReq) (*admin.UpdateApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + oid, err := primitive.ObjectIDFromHex(req.Id) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) + } + update := make(map[string]any) + putUpdate(update, "platform", req.Platform) + putUpdate(update, "version", req.Version) + putUpdate(update, "url", req.Url) + putUpdate(update, "text", req.Text) + putUpdate(update, "force", req.Force) + putUpdate(update, "latest", req.Latest) + putUpdate(update, "hot", req.Hot) + if err := o.Database.UpdateVersion(ctx, oid, update); err != nil { + return nil, err + } + return &admin.UpdateApplicationVersionResp{}, nil +} + +func (o *adminServer) DeleteApplicationVersion(ctx context.Context, req *admin.DeleteApplicationVersionReq) (*admin.DeleteApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + ids := make([]primitive.ObjectID, 0, len(req.Id)) + for _, id := range req.Id { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) + } + ids = append(ids, oid) + } + if err := o.Database.DeleteVersion(ctx, ids); err != nil { + return nil, err + } + return &admin.DeleteApplicationVersionResp{}, nil +} + +func (o *adminServer) PageApplicationVersion(ctx context.Context, req *admin.PageApplicationVersionReq) (*admin.PageApplicationVersionResp, error) { + total, res, err := o.Database.PageVersion(ctx, req.Platform, req.Pagination) + if err != nil { + return nil, err + } + return &admin.PageApplicationVersionResp{ + Total: total, + Versions: datautil.Slice(res, o.db2pbApplication), + }, nil +} + +func putUpdate[T any](update map[string]any, name string, val interface{ GetValuePtr() *T }) { + ptrVal := val.GetValuePtr() + if ptrVal == nil { + return + } + update[name] = *ptrVal +} diff --git a/internal/rpc/admin/check.go b/internal/rpc/admin/check.go new file mode 100644 index 0000000..2a1acc9 --- /dev/null +++ b/internal/rpc/admin/check.go @@ -0,0 +1,70 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func (o *adminServer) CheckRegisterForbidden(ctx context.Context, req *admin.CheckRegisterForbiddenReq) (*admin.CheckRegisterForbiddenResp, error) { + forbiddens, err := o.Database.FindIPForbidden(ctx, []string{req.Ip}) + if err != nil { + return nil, err + } + for _, forbidden := range forbiddens { + if forbidden.LimitRegister { + return nil, eerrs.ErrForbidden.Wrap() + } + } + return &admin.CheckRegisterForbiddenResp{}, nil +} + +func (o *adminServer) CheckLoginForbidden(ctx context.Context, req *admin.CheckLoginForbiddenReq) (*admin.CheckLoginForbiddenResp, error) { + forbiddens, err := o.Database.FindIPForbidden(ctx, []string{req.Ip}) + if err != nil { + return nil, err + } + for _, forbidden := range forbiddens { + if forbidden.LimitLogin { + return nil, eerrs.ErrForbidden.WrapMsg("ip forbidden") + } + } + if _, err := o.Database.GetLimitUserLoginIP(ctx, req.UserID, req.Ip); err != nil { + if !dbutil.IsDBNotFound(err) { + return nil, err + } + count, err := o.Database.CountLimitUserLoginIP(ctx, req.UserID) + if err != nil { + return nil, err + } + if count > 0 { + return nil, eerrs.ErrForbidden.WrapMsg("user ip forbidden") + } + } + if forbiddenAccount, err := o.Database.GetBlockInfo(ctx, req.UserID); err == nil { + reason := "账户已被封禁" + if forbiddenAccount.Reason != "" { + reason = "账户已被封禁:" + forbiddenAccount.Reason + } + return nil, eerrs.ErrAccountBlocked.WrapMsg(reason) + } else if !dbutil.IsDBNotFound(err) { + return nil, err + } + return &admin.CheckLoginForbiddenResp{}, nil +} diff --git a/internal/rpc/admin/client_config.go b/internal/rpc/admin/client_config.go new file mode 100644 index 0000000..8fa4516 --- /dev/null +++ b/internal/rpc/admin/client_config.go @@ -0,0 +1,55 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func (o *adminServer) GetClientConfig(ctx context.Context, req *admin.GetClientConfigReq) (*admin.GetClientConfigResp, error) { + conf, err := o.Database.GetConfig(ctx) + if err != nil { + return nil, err + } + return &admin.GetClientConfigResp{Config: conf}, nil +} + +func (o *adminServer) SetClientConfig(ctx context.Context, req *admin.SetClientConfigReq) (*admin.SetClientConfigResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.Config) == 0 { + return nil, errs.ErrArgs.WrapMsg("update config empty") + } + if err := o.Database.SetConfig(ctx, req.Config); err != nil { + return nil, err + } + return &admin.SetClientConfigResp{}, nil +} + +func (o *adminServer) DelClientConfig(ctx context.Context, req *admin.DelClientConfigReq) (*admin.DelClientConfigResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if err := o.Database.DelConfig(ctx, req.Keys); err != nil { + return nil, err + } + return &admin.DelClientConfigResp{}, nil +} diff --git a/internal/rpc/admin/invitation.go b/internal/rpc/admin/invitation.go new file mode 100644 index 0000000..fbd012a --- /dev/null +++ b/internal/rpc/admin/invitation.go @@ -0,0 +1,217 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "math/rand" + "strings" + "time" + + "github.com/openimsdk/tools/utils/datautil" + + "github.com/openimsdk/tools/errs" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func (o *adminServer) AddInvitationCode(ctx context.Context, req *admin.AddInvitationCodeReq) (*admin.AddInvitationCodeResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.Codes) == 0 { + return nil, errs.ErrArgs.WrapMsg("codes is empty") + } + if datautil.Duplicate(req.Codes) { + return nil, errs.ErrArgs.WrapMsg("codes is duplicate") + } + irs, err := o.Database.FindInvitationRegister(ctx, req.Codes) + if err != nil { + return nil, err + } + if len(irs) > 0 { + ids := datautil.Slice(irs, func(info *admindb.InvitationRegister) string { return info.InvitationCode }) + return nil, errs.ErrArgs.WrapMsg("code existed", "ids", ids) + } + now := time.Now() + codes := make([]*admindb.InvitationRegister, 0, len(req.Codes)) + for _, code := range req.Codes { + codes = append(codes, &admindb.InvitationRegister{ + InvitationCode: code, + UsedByUserID: "", + CreateTime: now, + }) + } + if err := o.Database.CreatInvitationRegister(ctx, codes); err != nil { + return nil, err + } + return &admin.AddInvitationCodeResp{}, nil +} + +func (o *adminServer) GenInvitationCode(ctx context.Context, req *admin.GenInvitationCodeReq) (*admin.GenInvitationCodeResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if req.Num <= 0 || req.Len <= 0 { + return nil, errs.ErrArgs.WrapMsg("num or len <= 0") + } + if len(req.Chars) == 0 { + req.Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + } + now := time.Now() + invitationRegisters := make([]*admindb.InvitationRegister, 0, req.Num) + codes := make([]string, 0, req.Num) + for i := int32(0); i < req.Num; i++ { + buf := make([]byte, req.Len) + rand.Read(buf) + for i, b := range buf { + buf[i] = req.Chars[b%byte(len(req.Chars))] + } + codes = append(codes, string(buf)) + invitationRegisters = append(invitationRegisters, &admindb.InvitationRegister{ + InvitationCode: string(buf), + UsedByUserID: "", + CreateTime: now, + }) + } + if datautil.Duplicate(codes) { + return nil, errs.ErrArgs.WrapMsg("gen duplicate codes") + } + irs, err := o.Database.FindInvitationRegister(ctx, codes) + if err != nil { + return nil, err + } + if len(irs) > 0 { + ids := datautil.Single(codes, datautil.Slice(irs, func(ir *admindb.InvitationRegister) string { return ir.InvitationCode })) + return nil, errs.ErrArgs.WrapMsg(strings.Join(ids, ", ")) + } + if err := o.Database.CreatInvitationRegister(ctx, invitationRegisters); err != nil { + return nil, err + } + return &admin.GenInvitationCodeResp{}, nil +} + +func (o *adminServer) FindInvitationCode(ctx context.Context, req *admin.FindInvitationCodeReq) (*admin.FindInvitationCodeResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + if len(req.Codes) == 0 { + return nil, errs.ErrArgs.WrapMsg("codes is empty") + } + invitationRegisters, err := o.Database.FindInvitationRegister(ctx, req.Codes) + if err != nil { + return nil, err + } + userIDs := make([]string, 0, len(invitationRegisters)) + for _, register := range invitationRegisters { + if register.UsedByUserID != "" { + userIDs = append(userIDs, register.UsedByUserID) + } + } + userMap, err := o.Chat.MapUserPublicInfo(ctx, userIDs) + if err != nil { + return nil, err + } + resp := &admin.FindInvitationCodeResp{Codes: make([]*admin.InvitationRegister, 0, len(invitationRegisters))} + for _, register := range invitationRegisters { + resp.Codes = append(resp.Codes, &admin.InvitationRegister{ + InvitationCode: register.InvitationCode, + CreateTime: register.CreateTime.UnixMilli(), + UsedUserID: register.UsedByUserID, + UsedUser: userMap[register.UsedByUserID], + }) + } + return resp, nil +} + +func (o *adminServer) UseInvitationCode(ctx context.Context, req *admin.UseInvitationCodeReq) (*admin.UseInvitationCodeResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + codes, err := o.Database.FindInvitationRegister(ctx, []string{req.Code}) + if err != nil { + return nil, err + } + if len(codes) == 0 { + return nil, eerrs.ErrInvitationNotFound.Wrap() + } + if codes[0].UsedByUserID != "" { + return nil, eerrs.ErrInvitationCodeUsed.Wrap() + } + if err := o.Database.UpdateInvitationRegister(ctx, req.Code, ToDBInvitationRegisterUpdate(req.UserID)); err != nil { + return nil, err + } + return &admin.UseInvitationCodeResp{}, nil +} + +func (o *adminServer) DelInvitationCode(ctx context.Context, req *admin.DelInvitationCodeReq) (*admin.DelInvitationCodeResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.Codes) == 0 { + return nil, errs.ErrArgs.WrapMsg("codes is empty") + } + if datautil.Duplicate(req.Codes) { + return nil, errs.ErrArgs.WrapMsg("codes is duplicate") + } + irs, err := o.Database.FindInvitationRegister(ctx, req.Codes) + if err != nil { + return nil, err + } + if len(irs) != len(req.Codes) { + ids := datautil.Single(req.Codes, datautil.Slice(irs, func(ir *admindb.InvitationRegister) string { return ir.InvitationCode })) + return nil, errs.ErrArgs.WrapMsg("code not found " + strings.Join(ids, ", ")) + } + if err := o.Database.DelInvitationRegister(ctx, req.Codes); err != nil { + return nil, err + } + return &admin.DelInvitationCodeResp{}, nil +} + +func (o *adminServer) SearchInvitationCode(ctx context.Context, req *admin.SearchInvitationCodeReq) (*admin.SearchInvitationCodeResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, list, err := o.Database.SearchInvitationRegister(ctx, req.Keyword, req.Status, req.UserIDs, req.Codes, req.Pagination) + if err != nil { + return nil, err + } + userIDs := make([]string, 0, len(list)) + for _, register := range list { + if register.UsedByUserID != "" { + userIDs = append(userIDs, register.UsedByUserID) + } + } + userMap, err := o.Chat.MapUserPublicInfo(ctx, userIDs) + if err != nil { + return nil, err + } + invitationRegisters := make([]*admin.InvitationRegister, 0, len(list)) + for _, register := range list { + invitationRegisters = append(invitationRegisters, &admin.InvitationRegister{ + InvitationCode: register.InvitationCode, + CreateTime: register.CreateTime.UnixMilli(), + UsedUserID: register.UsedByUserID, + UsedUser: userMap[register.UsedByUserID], + }) + } + return &admin.SearchInvitationCodeResp{ + Total: uint32(total), + List: invitationRegisters, + }, nil +} diff --git a/internal/rpc/admin/ip_forbidden.go b/internal/rpc/admin/ip_forbidden.go new file mode 100644 index 0000000..e033256 --- /dev/null +++ b/internal/rpc/admin/ip_forbidden.go @@ -0,0 +1,77 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func (o *adminServer) SearchIPForbidden(ctx context.Context, req *admin.SearchIPForbiddenReq) (*admin.SearchIPForbiddenResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, forbiddens, err := o.Database.SearchIPForbidden(ctx, req.Keyword, req.Status, req.Pagination) + if err != nil { + return nil, err + } + resp := &admin.SearchIPForbiddenResp{ + Forbiddens: make([]*admin.IPForbidden, 0, len(forbiddens)), + Total: uint32(total), + } + for _, forbidden := range forbiddens { + resp.Forbiddens = append(resp.Forbiddens, &admin.IPForbidden{ + Ip: forbidden.IP, + LimitLogin: forbidden.LimitLogin, + LimitRegister: forbidden.LimitRegister, + CreateTime: forbidden.CreateTime.UnixMilli(), + }) + } + return resp, nil +} + +func (o *adminServer) AddIPForbidden(ctx context.Context, req *admin.AddIPForbiddenReq) (*admin.AddIPForbiddenResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + now := time.Now() + tables := make([]*admindb.IPForbidden, 0, len(req.Forbiddens)) + for _, forbidden := range req.Forbiddens { + tables = append(tables, &admindb.IPForbidden{ + IP: forbidden.Ip, + LimitLogin: forbidden.LimitLogin, + LimitRegister: forbidden.LimitRegister, + CreateTime: now, + }) + } + if err := o.Database.AddIPForbidden(ctx, tables); err != nil { + return nil, err + } + return &admin.AddIPForbiddenResp{}, nil +} + +func (o *adminServer) DelIPForbidden(ctx context.Context, req *admin.DelIPForbiddenReq) (*admin.DelIPForbiddenResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if err := o.Database.DelIPForbidden(ctx, req.Ips); err != nil { + return nil, err + } + return &admin.DelIPForbiddenResp{}, nil +} diff --git a/internal/rpc/admin/register_add_friend.go b/internal/rpc/admin/register_add_friend.go new file mode 100644 index 0000000..7254565 --- /dev/null +++ b/internal/rpc/admin/register_add_friend.go @@ -0,0 +1,134 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/utils/datautil" + + "github.com/openimsdk/tools/errs" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/common" +) + +func (o *adminServer) AddDefaultFriend(ctx context.Context, req *admin.AddDefaultFriendReq) (*admin.AddDefaultFriendResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("user ids is empty") + } + if datautil.Duplicate(req.UserIDs) { + return nil, errs.ErrArgs.WrapMsg("user ids is duplicate") + } + users, err := o.Chat.FindUserPublicInfo(ctx, req.UserIDs) + if err != nil { + return nil, err + } + if ids := datautil.Single(req.UserIDs, datautil.Slice(users, func(user *common.UserPublicInfo) string { return user.UserID })); len(ids) > 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("user id not found", "userID", ids) + } + exists, err := o.Database.FindDefaultFriend(ctx, req.UserIDs) + if err != nil { + return nil, err + } + if len(exists) > 0 { + return nil, errs.ErrDuplicateKey.WrapMsg("user id existed", "userID", exists) + } + now := time.Now() + ms := make([]*admindb.RegisterAddFriend, 0, len(req.UserIDs)) + for _, userID := range req.UserIDs { + ms = append(ms, &admindb.RegisterAddFriend{ + UserID: userID, + CreateTime: now, + }) + } + if err := o.Database.AddDefaultFriend(ctx, ms); err != nil { + return nil, err + } + return &admin.AddDefaultFriendResp{}, nil +} + +func (o *adminServer) DelDefaultFriend(ctx context.Context, req *admin.DelDefaultFriendReq) (*admin.DelDefaultFriendResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("user ids is empty") + } + if datautil.Duplicate(req.UserIDs) { + return nil, errs.ErrArgs.WrapMsg("user ids is duplicate") + } + exists, err := o.Database.FindDefaultFriend(ctx, req.UserIDs) + if err != nil { + return nil, err + } + if ids := datautil.Single(req.UserIDs, exists); len(ids) > 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("user id not found", "userID", ids) + } + now := time.Now() + ms := make([]*admindb.RegisterAddFriend, 0, len(req.UserIDs)) + for _, userID := range req.UserIDs { + ms = append(ms, &admindb.RegisterAddFriend{ + UserID: userID, + CreateTime: now, + }) + } + if err := o.Database.DelDefaultFriend(ctx, req.UserIDs); err != nil { + return nil, err + } + return &admin.DelDefaultFriendResp{}, nil +} + +func (o *adminServer) FindDefaultFriend(ctx context.Context, req *admin.FindDefaultFriendReq) (*admin.FindDefaultFriendResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + userIDs, err := o.Database.FindDefaultFriend(ctx, nil) + if err != nil { + return nil, err + } + return &admin.FindDefaultFriendResp{UserIDs: userIDs}, nil +} + +func (o *adminServer) SearchDefaultFriend(ctx context.Context, req *admin.SearchDefaultFriendReq) (*admin.SearchDefaultFriendResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, infos, err := o.Database.SearchDefaultFriend(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + userIDs := datautil.Slice(infos, func(info *admindb.RegisterAddFriend) string { return info.UserID }) + userMap, err := o.Chat.MapUserPublicInfo(ctx, userIDs) + if err != nil { + return nil, err + } + attributes := make([]*admin.DefaultFriendAttribute, 0, len(infos)) + for _, info := range infos { + attribute := &admin.DefaultFriendAttribute{ + UserID: info.UserID, + CreateTime: info.CreateTime.UnixMilli(), + User: userMap[info.UserID], + } + attributes = append(attributes, attribute) + } + return &admin.SearchDefaultFriendResp{Total: uint32(total), Users: attributes}, nil +} diff --git a/internal/rpc/admin/register_add_group.go b/internal/rpc/admin/register_add_group.go new file mode 100644 index 0000000..bb0559e --- /dev/null +++ b/internal/rpc/admin/register_add_group.go @@ -0,0 +1,112 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/utils/datautil" + + "github.com/openimsdk/tools/errs" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func (o *adminServer) AddDefaultGroup(ctx context.Context, req *admin.AddDefaultGroupReq) (*admin.AddDefaultGroupResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.GroupIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("group ids is empty") + } + if datautil.Duplicate(req.GroupIDs) { + return nil, errs.ErrArgs.WrapMsg("group ids is duplicate") + } + exists, err := o.Database.FindDefaultGroup(ctx, req.GroupIDs) + if err != nil { + return nil, err + } + if len(exists) > 0 { + return nil, errs.ErrDuplicateKey.WrapMsg("group id existed", "groupID", exists) + } + now := time.Now() + ms := make([]*admindb.RegisterAddGroup, 0, len(req.GroupIDs)) + for _, groupID := range req.GroupIDs { + ms = append(ms, &admindb.RegisterAddGroup{ + GroupID: groupID, + CreateTime: now, + }) + } + if err := o.Database.AddDefaultGroup(ctx, ms); err != nil { + return nil, err + } + return &admin.AddDefaultGroupResp{}, nil +} + +func (o *adminServer) DelDefaultGroup(ctx context.Context, req *admin.DelDefaultGroupReq) (*admin.DelDefaultGroupResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.GroupIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("group ids is empty") + } + if datautil.Duplicate(req.GroupIDs) { + return nil, errs.ErrArgs.WrapMsg("group ids is duplicate") + } + exists, err := o.Database.FindDefaultGroup(ctx, req.GroupIDs) + if err != nil { + return nil, err + } + if ids := datautil.Single(req.GroupIDs, exists); len(ids) > 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("group id not found", "groupID", ids) + } + now := time.Now() + ms := make([]*admindb.RegisterAddGroup, 0, len(req.GroupIDs)) + for _, groupID := range req.GroupIDs { + ms = append(ms, &admindb.RegisterAddGroup{ + GroupID: groupID, + CreateTime: now, + }) + } + if err := o.Database.DelDefaultGroup(ctx, req.GroupIDs); err != nil { + return nil, err + } + return &admin.DelDefaultGroupResp{}, nil +} + +func (o *adminServer) FindDefaultGroup(ctx context.Context, req *admin.FindDefaultGroupReq) (*admin.FindDefaultGroupResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + groupIDs, err := o.Database.FindDefaultGroup(ctx, nil) + if err != nil { + return nil, err + } + return &admin.FindDefaultGroupResp{GroupIDs: groupIDs}, nil +} + +func (o *adminServer) SearchDefaultGroup(ctx context.Context, req *admin.SearchDefaultGroupReq) (*admin.SearchDefaultGroupResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, infos, err := o.Database.SearchDefaultGroup(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + return &admin.SearchDefaultGroupResp{Total: uint32(total), GroupIDs: datautil.Slice(infos, func(info *admindb.RegisterAddGroup) string { return info.GroupID })}, nil +} diff --git a/internal/rpc/admin/scheduled_task.go b/internal/rpc/admin/scheduled_task.go new file mode 100644 index 0000000..a1dd8c4 --- /dev/null +++ b/internal/rpc/admin/scheduled_task.go @@ -0,0 +1,102 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/errs" +) + +// ==================== 定时任务管理相关 RPC ==================== + +// GetScheduledTasks 获取定时任务列表(管理员接口,可查看所有任务) +func (o *adminServer) GetScheduledTasks(ctx context.Context, req *admin.GetScheduledTasksReq) (*admin.GetScheduledTasksResp, error) { + // 验证管理员权限 + _, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 获取所有定时任务列表 + total, tasks, err := o.ChatDatabase.GetAllScheduledTasks(ctx, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + taskInfos := make([]*admin.ScheduledTaskInfo, 0, len(tasks)) + for _, task := range tasks { + taskInfos = append(taskInfos, convertScheduledTaskToAdminProto(task)) + } + + return &admin.GetScheduledTasksResp{ + Total: total, + Tasks: taskInfos, + }, nil +} + +// DeleteScheduledTask 删除定时任务(管理员接口,可删除任何任务) +func (o *adminServer) DeleteScheduledTask(ctx context.Context, req *admin.DeleteScheduledTaskReq) (*admin.DeleteScheduledTaskResp, error) { + // 验证管理员权限 + _, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 验证请求参数 + if len(req.TaskIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("taskIDs is required") + } + + // 删除任务 + if err := o.ChatDatabase.DeleteScheduledTask(ctx, req.TaskIDs); err != nil { + return nil, err + } + + return &admin.DeleteScheduledTaskResp{}, nil +} + +// convertScheduledTaskToAdminProto 将数据库模型转换为 admin protobuf 消息 +func convertScheduledTaskToAdminProto(task *chatdb.ScheduledTask) *admin.ScheduledTaskInfo { + messages := make([]*admin.ScheduledTaskMessage, 0, len(task.Messages)) + for _, msg := range task.Messages { + messages = append(messages, &admin.ScheduledTaskMessage{ + Type: msg.Type, + Content: msg.Content, + Thumbnail: msg.Thumbnail, + Duration: msg.Duration, + FileSize: msg.FileSize, + Width: msg.Width, + Height: msg.Height, + }) + } + + return &admin.ScheduledTaskInfo{ + Id: task.ID, + UserID: task.UserID, + Name: task.Name, + CronExpression: task.CronExpression, + Messages: messages, + RecvIDs: task.RecvIDs, + GroupIDs: task.GroupIDs, + Status: task.Status, + CreateTime: task.CreateTime.UnixMilli(), + UpdateTime: task.UpdateTime.UnixMilli(), + } +} diff --git a/internal/rpc/admin/start.go b/internal/rpc/admin/start.go new file mode 100644 index 0000000..328e12c --- /dev/null +++ b/internal/rpc/admin/start.go @@ -0,0 +1,110 @@ +package admin + +import ( + "context" + "crypto/md5" + "encoding/hex" + "math/rand" + "time" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/db/database" + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/tokenverify" + adminpb "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + chatClient "git.imall.cloud/openim/chat/pkg/rpclient/chat" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/utils/runtimeenv" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + RpcConfig config.Admin + RedisConfig config.Redis + MongodbConfig config.Mongo + Discovery config.Discovery + Share config.Share + + RuntimeEnv string +} + +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + + if len(config.Share.ChatAdmin) == 0 { + return errs.New("share chat admin not configured") + } + rand.Seed(time.Now().UnixNano()) + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + if err != nil { + return err + } + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) + if err != nil { + return err + } + var srv adminServer + srv.Database, err = database.NewAdminDatabase(mgocli, rdb) + if err != nil { + return err + } + srv.ChatDatabase, err = database.NewChatDatabase(mgocli, rdb) + if err != nil { + return err + } + conn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + srv.Chat = chatClient.NewChatClient(chat.NewChatClient(conn)) + srv.Token = &tokenverify.Token{ + Expires: time.Duration(config.RpcConfig.TokenPolicy.Expire) * time.Hour * 24, + Secret: config.RpcConfig.Secret, + } + srv.ImApiCaller = imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID) + if err := srv.initAdmin(ctx, config.Share.ChatAdmin, config.Share.OpenIM.AdminUserID); err != nil { + return err + } + adminpb.RegisterAdminServer(server, &srv) + return nil +} + +type adminServer struct { + adminpb.UnimplementedAdminServer + Database database.AdminDatabaseInterface + ChatDatabase database.ChatDatabaseInterface + Chat *chatClient.ChatClient + Token *tokenverify.Token + ImApiCaller imapi.CallerInterface +} + +func (o *adminServer) initAdmin(ctx context.Context, admins []string, imUserID string) error { + for _, account := range admins { + if _, err := o.Database.GetAdmin(ctx, account); err == nil { + continue + } else if !dbutil.IsDBNotFound(err) { + return err + } + sum := md5.Sum([]byte(account)) + a := admin.Admin{ + Account: account, + UserID: imUserID, + Password: hex.EncodeToString(sum[:]), + Level: constant.DefaultAdminLevel, + CreateTime: time.Now(), + } + if err := o.Database.AddAdminAccount(ctx, []*admin.Admin{&a}); err != nil { + return err + } + } + return nil +} diff --git a/internal/rpc/admin/system_config.go b/internal/rpc/admin/system_config.go new file mode 100644 index 0000000..142f721 --- /dev/null +++ b/internal/rpc/admin/system_config.go @@ -0,0 +1,439 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "time" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + adminpb "git.imall.cloud/openim/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/errs" +) + +// ==================== 系统配置管理相关 RPC ==================== + +// convertValueToString 将任意类型的值转换为字符串(根据 ValueType) +// 支持接收:字符串、数字、布尔值、JSON对象 +func convertValueToString(value interface{}, valueType int32) (string, error) { + if value == nil { + return "", errs.ErrArgs.WrapMsg("value cannot be nil") + } + + switch valueType { + case chatdb.ConfigValueTypeString: + // 字符串类型:直接转换为字符串 + switch v := value.(type) { + case string: + return v, nil + default: + // 其他类型转为字符串 + return fmt.Sprintf("%v", v), nil + } + + case chatdb.ConfigValueTypeNumber: + // 数字类型:转换为数字字符串 + switch v := value.(type) { + case string: + // 验证是否为有效数字 + if _, err := strconv.ParseFloat(v, 64); err != nil { + return "", errs.ErrArgs.WrapMsg("value must be a valid number") + } + return v, nil + case float64: + return strconv.FormatFloat(v, 'f', -1, 64), nil + case float32: + return strconv.FormatFloat(float64(v), 'f', -1, 32), nil + case int: + return strconv.Itoa(v), nil + case int64: + return strconv.FormatInt(v, 10), nil + case int32: + return strconv.FormatInt(int64(v), 10), nil + default: + // 尝试转换为数字 + if num, ok := v.(float64); ok { + return strconv.FormatFloat(num, 'f', -1, 64), nil + } + return "", errs.ErrArgs.WrapMsg("value must be a number") + } + + case chatdb.ConfigValueTypeBool: + // 布尔类型:转换为 "true" 或 "false" + switch v := value.(type) { + case string: + // 验证是否为有效的布尔字符串 + if _, err := strconv.ParseBool(v); err != nil { + return "", errs.ErrArgs.WrapMsg("value must be 'true' or 'false'") + } + return v, nil + case bool: + return strconv.FormatBool(v), nil + default: + return "", errs.ErrArgs.WrapMsg("value must be a boolean") + } + + case chatdb.ConfigValueTypeJSON: + // JSON类型:转换为 JSON 字符串 + switch v := value.(type) { + case string: + // 验证是否为有效的 JSON + var js interface{} + if err := json.Unmarshal([]byte(v), &js); err != nil { + return "", errs.ErrArgs.WrapMsg("value must be a valid JSON string") + } + return v, nil + default: + // 将对象序列化为 JSON 字符串 + jsonBytes, err := json.Marshal(v) + if err != nil { + return "", errs.ErrArgs.WrapMsg("value must be a valid JSON object") + } + return string(jsonBytes), nil + } + + default: + return "", errs.ErrArgs.WrapMsg("invalid value type") + } +} + +// convertValueFromString 将字符串值转换为对应类型(用于返回给前端) +func convertValueFromString(value string, valueType int32) (interface{}, error) { + switch valueType { + case chatdb.ConfigValueTypeString: + return value, nil + case chatdb.ConfigValueTypeNumber: + // 尝试解析为数字 + if num, err := strconv.ParseFloat(value, 64); err == nil { + // 如果是整数,返回整数;否则返回浮点数 + if num == float64(int64(num)) { + return int64(num), nil + } + return num, nil + } + return nil, errs.ErrArgs.WrapMsg("invalid number format") + case chatdb.ConfigValueTypeBool: + return strconv.ParseBool(value) + case chatdb.ConfigValueTypeJSON: + var js interface{} + if err := json.Unmarshal([]byte(value), &js); err != nil { + return nil, err + } + return js, nil + default: + return value, nil + } +} + +// validateValueByType 根据 ValueType 验证 Value 的格式 +func validateValueByType(value string, valueType int32) error { + switch valueType { + case chatdb.ConfigValueTypeString: + // 字符串类型:任何字符串都可以,无需验证 + return nil + case chatdb.ConfigValueTypeNumber: + // 数字类型:必须是有效的数字字符串 + if value == "" { + return errs.ErrArgs.WrapMsg("value cannot be empty for number type") + } + _, err := strconv.ParseFloat(value, 64) + if err != nil { + return errs.ErrArgs.WrapMsg("value must be a valid number string") + } + return nil + case chatdb.ConfigValueTypeBool: + // 布尔类型:必须是 "true" 或 "false" + if value == "" { + return errs.ErrArgs.WrapMsg("value cannot be empty for bool type") + } + _, err := strconv.ParseBool(value) + if err != nil { + return errs.ErrArgs.WrapMsg("value must be 'true' or 'false' for bool type") + } + return nil + case chatdb.ConfigValueTypeJSON: + // JSON类型:必须是有效的 JSON 字符串 + if value == "" { + return errs.ErrArgs.WrapMsg("value cannot be empty for JSON type") + } + var js interface{} + if err := json.Unmarshal([]byte(value), &js); err != nil { + return errs.ErrArgs.WrapMsg("value must be a valid JSON string") + } + return nil + default: + return errs.ErrArgs.WrapMsg("invalid value type") + } +} + +// CreateSystemConfig 创建系统配置 +func (o *adminServer) CreateSystemConfig(ctx context.Context, req *adminpb.CreateSystemConfigReq) (*adminpb.CreateSystemConfigResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.Key == "" { + return nil, errs.ErrArgs.WrapMsg("config key is required") + } + + // 检查配置键是否已存在 + _, err := o.ChatDatabase.GetSystemConfig(ctx, req.Key) + if err == nil { + return nil, errs.ErrDuplicateKey.WrapMsg("config key already exists") + } + + // 创建配置对象 + config := &chatdb.SystemConfig{ + Key: req.Key, + Title: req.Title, + Value: req.Value, + ValueType: req.ValueType, + Description: req.Description, + Enabled: req.Enabled, + ShowInApp: req.ShowInApp, + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + + // 如果未设置值类型,默认为字符串类型 + if config.ValueType == 0 { + config.ValueType = chatdb.ConfigValueTypeString + } + + // 根据 ValueType 验证 Value 的格式 + if err := validateValueByType(config.Value, config.ValueType); err != nil { + return nil, err + } + + // 保存到数据库 + if err := o.ChatDatabase.CreateSystemConfig(ctx, config); err != nil { + return nil, err + } + + return &adminpb.CreateSystemConfigResp{}, nil +} + +// GetSystemConfig 获取系统配置详情 +func (o *adminServer) GetSystemConfig(ctx context.Context, req *adminpb.GetSystemConfigReq) (*adminpb.GetSystemConfigResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 获取配置 + config, err := o.ChatDatabase.GetSystemConfig(ctx, req.Key) + if err != nil { + return nil, err + } + + return &adminpb.GetSystemConfigResp{ + Config: convertSystemConfigToProto(config), + }, nil +} + +// GetAllSystemConfigs 获取所有系统配置(分页) +func (o *adminServer) GetAllSystemConfigs(ctx context.Context, req *adminpb.GetAllSystemConfigsReq) (*adminpb.GetAllSystemConfigsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 获取配置列表 + total, configs, err := o.ChatDatabase.GetAllSystemConfigs(ctx, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + configInfos := make([]*adminpb.SystemConfigInfo, 0, len(configs)) + for _, config := range configs { + configInfos = append(configInfos, convertSystemConfigToProto(config)) + } + + return &adminpb.GetAllSystemConfigsResp{ + Total: uint32(total), + List: configInfos, + }, nil +} + +// UpdateSystemConfig 更新系统配置 +func (o *adminServer) UpdateSystemConfig(ctx context.Context, req *adminpb.UpdateSystemConfigReq) (*adminpb.UpdateSystemConfigResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证配置是否存在 + _, err := o.ChatDatabase.GetSystemConfig(ctx, req.Key) + if err != nil { + return nil, err + } + + // 获取当前配置,用于验证 + currentConfig, err := o.ChatDatabase.GetSystemConfig(ctx, req.Key) + if err != nil { + return nil, err + } + + // 确定要使用的 ValueType(如果更新了 ValueType,使用新的;否则使用当前的) + newValueType := currentConfig.ValueType + if req.ValueType != nil { + newValueType = req.ValueType.Value + } + + // 确定要使用的 Value(如果更新了 Value,使用新的;否则使用当前的) + newValue := currentConfig.Value + if req.Value != nil { + newValue = req.Value.Value + // 如果更新了 Value,需要根据 ValueType 验证 + if err := validateValueByType(newValue, newValueType); err != nil { + return nil, err + } + } else if req.ValueType != nil { + // 如果只更新了 ValueType,需要验证当前 Value 是否符合新的 ValueType + if err := validateValueByType(currentConfig.Value, newValueType); err != nil { + return nil, err + } + } + + // 构建更新数据 + updateData := make(map[string]any) + if req.Title != nil { + updateData["title"] = req.Title.Value + } + if req.Value != nil { + updateData["value"] = req.Value.Value + } + if req.ValueType != nil { + updateData["value_type"] = req.ValueType.Value + } + if req.Description != nil { + updateData["description"] = req.Description.Value + } + if req.Enabled != nil { + updateData["enabled"] = req.Enabled.Value + } + if req.ShowInApp != nil { + updateData["show_in_app"] = req.ShowInApp.Value + } + + // 更新配置 + if err := o.ChatDatabase.UpdateSystemConfig(ctx, req.Key, updateData); err != nil { + return nil, err + } + + return &adminpb.UpdateSystemConfigResp{}, nil +} + +// UpdateSystemConfigValue 更新系统配置值 +func (o *adminServer) UpdateSystemConfigValue(ctx context.Context, req *adminpb.UpdateSystemConfigValueReq) (*adminpb.UpdateSystemConfigValueResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 获取当前配置,用于获取 ValueType 进行验证 + config, err := o.ChatDatabase.GetSystemConfig(ctx, req.Key) + if err != nil { + return nil, err + } + + // 根据当前 ValueType 验证新 Value 的格式 + if err := validateValueByType(req.Value, config.ValueType); err != nil { + return nil, err + } + + // 更新配置值 + if err := o.ChatDatabase.UpdateSystemConfigValue(ctx, req.Key, req.Value); err != nil { + return nil, err + } + + return &adminpb.UpdateSystemConfigValueResp{}, nil +} + +// UpdateSystemConfigEnabled 更新系统配置启用状态 +func (o *adminServer) UpdateSystemConfigEnabled(ctx context.Context, req *adminpb.UpdateSystemConfigEnabledReq) (*adminpb.UpdateSystemConfigEnabledResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 更新启用状态 + if err := o.ChatDatabase.UpdateSystemConfigEnabled(ctx, req.Key, req.Enabled); err != nil { + return nil, err + } + + return &adminpb.UpdateSystemConfigEnabledResp{}, nil +} + +// DeleteSystemConfig 删除系统配置 +func (o *adminServer) DeleteSystemConfig(ctx context.Context, req *adminpb.DeleteSystemConfigReq) (*adminpb.DeleteSystemConfigResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 删除配置 + if err := o.ChatDatabase.DeleteSystemConfig(ctx, req.Keys); err != nil { + return nil, err + } + + return &adminpb.DeleteSystemConfigResp{}, nil +} + +// GetEnabledSystemConfigs 获取所有已启用的配置 +func (o *adminServer) GetEnabledSystemConfigs(ctx context.Context, req *adminpb.GetEnabledSystemConfigsReq) (*adminpb.GetEnabledSystemConfigsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 获取已启用的配置 + configs, err := o.ChatDatabase.GetEnabledSystemConfigs(ctx) + if err != nil { + return nil, err + } + + // 转换为响应格式 + configInfos := make([]*adminpb.SystemConfigInfo, 0, len(configs)) + for _, config := range configs { + configInfos = append(configInfos, convertSystemConfigToProto(config)) + } + + return &adminpb.GetEnabledSystemConfigsResp{ + List: configInfos, + }, nil +} + +// convertSystemConfigToProto 将数据库模型转换为 protobuf 消息 +func convertSystemConfigToProto(config *chatdb.SystemConfig) *adminpb.SystemConfigInfo { + return &adminpb.SystemConfigInfo{ + Key: config.Key, + Title: config.Title, + Value: config.Value, + ValueType: config.ValueType, + Description: config.Description, + Enabled: config.Enabled, + ShowInApp: config.ShowInApp, + CreateTime: config.CreateTime.UnixMilli(), + UpdateTime: config.UpdateTime.UnixMilli(), + } +} diff --git a/internal/rpc/admin/token.go b/internal/rpc/admin/token.go new file mode 100644 index 0000000..8be17a6 --- /dev/null +++ b/internal/rpc/admin/token.go @@ -0,0 +1,79 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/redis/go-redis/v9" + + "git.imall.cloud/openim/chat/pkg/eerrs" + adminpb "git.imall.cloud/openim/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/log" +) + +func (o *adminServer) CreateToken(ctx context.Context, req *adminpb.CreateTokenReq) (*adminpb.CreateTokenResp, error) { + token, expire, err := o.Token.CreateToken(req.UserID, req.UserType) + + if err != nil { + return nil, err + } + err = o.Database.CacheToken(ctx, req.UserID, token, expire) + if err != nil { + return nil, err + } + return &adminpb.CreateTokenResp{ + Token: token, + }, nil +} + +func (o *adminServer) ParseToken(ctx context.Context, req *adminpb.ParseTokenReq) (*adminpb.ParseTokenResp, error) { + userID, userType, err := o.Token.GetToken(req.Token) + if err != nil { + return nil, err + } + m, err := o.Database.GetTokens(ctx, userID) + if err != nil && err != redis.Nil { + return nil, err + } + if len(m) == 0 { + return nil, eerrs.ErrTokenNotExist.Wrap() + } + if _, ok := m[req.Token]; !ok { + return nil, eerrs.ErrTokenNotExist.Wrap() + } + + return &adminpb.ParseTokenResp{ + UserID: userID, + UserType: userType, + }, nil +} + +func (o *adminServer) GetUserToken(ctx context.Context, req *adminpb.GetUserTokenReq) (*adminpb.GetUserTokenResp, error) { + tokensMap, err := o.Database.GetTokens(ctx, req.UserID) + if err != nil { + return nil, err + } + return &adminpb.GetUserTokenResp{TokensMap: tokensMap}, nil +} + +func (o *adminServer) InvalidateToken(ctx context.Context, req *adminpb.InvalidateTokenReq) (*adminpb.InvalidateTokenResp, error) { + err := o.Database.DeleteToken(ctx, req.UserID) + if err != nil && err != redis.Nil { + return nil, err + } + log.ZDebug(ctx, "delete token from redis", "userID", req.UserID) + return &adminpb.InvalidateTokenResp{}, nil +} diff --git a/internal/rpc/admin/update.go b/internal/rpc/admin/update.go new file mode 100644 index 0000000..ec1df94 --- /dev/null +++ b/internal/rpc/admin/update.go @@ -0,0 +1,140 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "crypto/md5" + "encoding/hex" + "time" + + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +type Admin struct { + Account string `gorm:"column:account;primary_key;type:char(64)"` + Password string `gorm:"column:password;type:char(64)"` + FaceURL string `gorm:"column:face_url;type:char(64)"` + Nickname string `gorm:"column:nickname;type:char(64)"` + UserID string `gorm:"column:user_id;type:char(64)"` // openIM userID + Level int32 `gorm:"column:level;default:1" ` + CreateTime time.Time `gorm:"column:create_time"` +} + +func ToDBAdminUpdate(req *admin.AdminUpdateInfoReq) (map[string]any, error) { + update := make(map[string]any) + if req.Account != nil { + if req.Account.Value == "" { + return nil, errs.ErrArgs.WrapMsg("account is empty") + } + update["account"] = req.Account.Value + } + if req.Password != nil { + if req.Password.Value == "" { + return nil, errs.ErrArgs.WrapMsg("password is empty") + } + update["password"] = req.Password.Value + } + if req.FaceURL != nil { + update["face_url"] = req.FaceURL.Value + } + if req.Nickname != nil { + if req.Nickname.Value == "" { + return nil, errs.ErrArgs.WrapMsg("nickname is empty") + } + update["nickname"] = req.Nickname.Value + } + //if req.UserID != nil { + // update["user_id"] = req.UserID.Value + //} + if req.Level != nil { + update["level"] = req.Level.Value + } + if req.GoogleAuthKey != nil { + update["google_auth_key"] = req.GoogleAuthKey.Value + } + if req.OperationPassword != nil { + update["operation_password"] = req.OperationPassword.Value + } + if len(update) == 0 { + return nil, errs.ErrArgs.WrapMsg("no update info") + } + return update, nil +} + +func ToDBAdminUpdatePassword(password string) (map[string]any, error) { + if password == "" { + return nil, errs.ErrArgs.WrapMsg("password is empty") + } + return map[string]any{"password": password}, nil +} + +func ToDBAppletUpdate(req *admin.UpdateAppletReq) (map[string]any, error) { + update := make(map[string]any) + if req.Name != nil { + if req.Name.Value == "" { + return nil, errs.ErrArgs.WrapMsg("name is empty") + } + update["name"] = req.Name.Value + } + if req.AppID != nil { + if req.AppID.Value == "" { + return nil, errs.ErrArgs.WrapMsg("appID is empty") + } + update["app_id"] = req.AppID.Value + } + if req.Icon != nil { + update["icon"] = req.Icon.Value + } + if req.Url != nil { + if req.Url.Value == "" { + return nil, errs.ErrArgs.WrapMsg("url is empty") + } + update["url"] = req.Url.Value + } + if req.Md5 != nil { + if hash, _ := hex.DecodeString(req.Md5.Value); len(hash) != md5.Size { + return nil, errs.ErrArgs.WrapMsg("md5 is invalid") + } + update["md5"] = req.Md5.Value + } + if req.Size != nil { + if req.Size.Value <= 0 { + return nil, errs.ErrArgs.WrapMsg("size is invalid") + } + update["size"] = req.Size.Value + } + if req.Version != nil { + if req.Version.Value == "" { + return nil, errs.ErrArgs.WrapMsg("version is empty") + } + update["version"] = req.Version.Value + } + if req.Priority != nil { + update["priority"] = req.Priority.Value + } + if req.Status != nil { + update["status"] = req.Status.Value + } + if len(update) == 0 { + return nil, errs.ErrArgs.WrapMsg("no update info") + } + return update, nil +} + +func ToDBInvitationRegisterUpdate(userID string) map[string]any { + return map[string]any{"user_id": userID} +} diff --git a/internal/rpc/admin/user.go b/internal/rpc/admin/user.go new file mode 100644 index 0000000..050dbda --- /dev/null +++ b/internal/rpc/admin/user.go @@ -0,0 +1,147 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "strings" + "time" + + "git.imall.cloud/openim/protocol/wrapperspb" + "github.com/openimsdk/tools/utils/datautil" + + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mcontext" +) + +func (o *adminServer) CancellationUser(ctx context.Context, req *admin.CancellationUserReq) (*admin.CancellationUserResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + empty := wrapperspb.String("") + update := &chat.UpdateUserInfoReq{UserID: req.UserID, Account: empty, AreaCode: empty, PhoneNumber: empty, Email: empty} + if err := o.Chat.UpdateUser(ctx, update); err != nil { + return nil, err + } + return &admin.CancellationUserResp{}, nil +} + +func (o *adminServer) BlockUser(ctx context.Context, req *admin.BlockUserReq) (*admin.BlockUserResp, error) { + _, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + _, err = o.Database.GetBlockInfo(ctx, req.UserID) + if err == nil { + return nil, errs.ErrArgs.WrapMsg("user already blocked") + } else if !dbutil.IsDBNotFound(err) { + return nil, err + } + + t := &admindb.ForbiddenAccount{ + UserID: req.UserID, + Reason: req.Reason, + OperatorUserID: mcontext.GetOpUserID(ctx), + CreateTime: time.Now(), + } + if err := o.Database.BlockUser(ctx, []*admindb.ForbiddenAccount{t}); err != nil { + return nil, err + } + return &admin.BlockUserResp{}, nil +} + +func (o *adminServer) UnblockUser(ctx context.Context, req *admin.UnblockUserReq) (*admin.UnblockUserResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("empty user id") + } + if datautil.Duplicate(req.UserIDs) { + return nil, errs.ErrArgs.WrapMsg("duplicate user id") + } + bs, err := o.Database.FindBlockInfo(ctx, req.UserIDs) + if err != nil { + return nil, err + } + if len(req.UserIDs) != len(bs) { + ids := datautil.Single(req.UserIDs, datautil.Slice(bs, func(info *admindb.ForbiddenAccount) string { return info.UserID })) + return nil, errs.ErrArgs.WrapMsg("user not blocked " + strings.Join(ids, ", ")) + } + if err := o.Database.DelBlockUser(ctx, req.UserIDs); err != nil { + return nil, err + } + return &admin.UnblockUserResp{}, nil +} + +func (o *adminServer) SearchBlockUser(ctx context.Context, req *admin.SearchBlockUserReq) (*admin.SearchBlockUserResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, infos, err := o.Database.SearchBlockUser(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + userIDs := datautil.Slice(infos, func(info *admindb.ForbiddenAccount) string { return info.UserID }) + userMap, err := o.Chat.MapUserFullInfo(ctx, userIDs) + if err != nil { + return nil, err + } + users := make([]*admin.BlockUserInfo, 0, len(infos)) + for _, info := range infos { + user := &admin.BlockUserInfo{ + UserID: info.UserID, + Reason: info.Reason, + OpUserID: info.OperatorUserID, + CreateTime: info.CreateTime.UnixMilli(), + } + if userFull := userMap[info.UserID]; userFull != nil { + user.Account = userFull.Account + user.PhoneNumber = userFull.PhoneNumber + user.AreaCode = userFull.AreaCode + user.Email = userFull.Email + user.Nickname = userFull.Nickname + user.FaceURL = userFull.FaceURL + user.Gender = userFull.Gender + } + users = append(users, user) + } + return &admin.SearchBlockUserResp{Total: uint32(total), Users: users}, nil +} + +func (o *adminServer) FindUserBlockInfo(ctx context.Context, req *admin.FindUserBlockInfoReq) (*admin.FindUserBlockInfoResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + list, err := o.Database.FindBlockUser(ctx, req.UserIDs) + if err != nil { + return nil, err + } + blocks := make([]*admin.BlockInfo, 0, len(list)) + for _, info := range list { + blocks = append(blocks, &admin.BlockInfo{ + UserID: info.UserID, + Reason: info.Reason, + OpUserID: info.OperatorUserID, + CreateTime: info.CreateTime.UnixMilli(), + }) + } + return &admin.FindUserBlockInfoResp{Blocks: blocks}, nil +} diff --git a/internal/rpc/admin/user_ip_limit_login.go b/internal/rpc/admin/user_ip_limit_login.go new file mode 100644 index 0000000..39834e4 --- /dev/null +++ b/internal/rpc/admin/user_ip_limit_login.go @@ -0,0 +1,97 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/utils/datautil" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/errs" +) + +func (o *adminServer) SearchUserIPLimitLogin(ctx context.Context, req *admin.SearchUserIPLimitLoginReq) (*admin.SearchUserIPLimitLoginResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + total, list, err := o.Database.SearchUserLimitLogin(ctx, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + userIDs := datautil.Slice(list, func(info *admindb.LimitUserLoginIP) string { return info.UserID }) + userMap, err := o.Chat.MapUserPublicInfo(ctx, datautil.Distinct(userIDs)) + if err != nil { + return nil, err + } + limits := make([]*admin.LimitUserLoginIP, 0, len(list)) + for _, info := range list { + limits = append(limits, &admin.LimitUserLoginIP{ + UserID: info.UserID, + Ip: info.IP, + CreateTime: info.CreateTime.UnixMilli(), + User: userMap[info.UserID], + }) + } + return &admin.SearchUserIPLimitLoginResp{Total: uint32(total), Limits: limits}, nil +} + +func (o *adminServer) AddUserIPLimitLogin(ctx context.Context, req *admin.AddUserIPLimitLoginReq) (*admin.AddUserIPLimitLoginResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.Limits) == 0 { + return nil, errs.ErrArgs.WrapMsg("limits is empty") + } + now := time.Now() + ts := make([]*admindb.LimitUserLoginIP, 0, len(req.Limits)) + for _, limit := range req.Limits { + ts = append(ts, &admindb.LimitUserLoginIP{ + UserID: limit.UserID, + IP: limit.Ip, + CreateTime: now, + }) + } + if err := o.Database.AddUserLimitLogin(ctx, ts); err != nil { + return nil, err + } + return &admin.AddUserIPLimitLoginResp{}, nil +} + +func (o *adminServer) DelUserIPLimitLogin(ctx context.Context, req *admin.DelUserIPLimitLoginReq) (*admin.DelUserIPLimitLoginResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + if len(req.Limits) == 0 { + return nil, errs.ErrArgs.WrapMsg("limits is empty") + } + ts := make([]*admindb.LimitUserLoginIP, 0, len(req.Limits)) + for _, limit := range req.Limits { + if limit.UserID == "" || limit.Ip == "" { + return nil, errs.ErrArgs.WrapMsg("user_id or ip is empty") + } + ts = append(ts, &admindb.LimitUserLoginIP{ + UserID: limit.UserID, + IP: limit.Ip, + }) + } + if err := o.Database.DelUserLimitLogin(ctx, ts); err != nil { + return nil, err + } + return &admin.DelUserIPLimitLoginResp{}, nil +} diff --git a/internal/rpc/admin/wallet.go b/internal/rpc/admin/wallet.go new file mode 100644 index 0000000..73fd8fb --- /dev/null +++ b/internal/rpc/admin/wallet.go @@ -0,0 +1,982 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "errors" + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + adminpb "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/protocol/sdkws" + "github.com/google/uuid" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "go.mongodb.org/mongo-driver/mongo" +) + +// ==================== 钱包管理相关 RPC ==================== + +// GetUserWallet 获取用户钱包信息 +func (o *adminServer) GetUserWallet(ctx context.Context, req *adminpb.GetUserWalletReq) (*adminpb.GetUserWalletResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + + // 获取钱包信息 + wallet, err := o.ChatDatabase.GetWallet(ctx, req.UserID) + if err != nil { + // 如果钱包不存在,返回默认值 + if errors.Is(err, mongo.ErrNoDocuments) { + return &adminpb.GetUserWalletResp{ + Wallet: &adminpb.WalletInfo{ + UserID: req.UserID, + Balance: 0, + WithdrawAccount: "", + RealNameAuth: nil, + WithdrawReceiveAccount: "", + HasPaymentPassword: false, + CreateTime: 0, + UpdateTime: 0, + }, + }, nil + } + return nil, err + } + + // 转换实名认证信息 + var realNameAuth *adminpb.RealNameAuthInfo + if wallet.RealNameAuth.IDCard != "" { + realNameAuth = &adminpb.RealNameAuthInfo{ + IdCard: wallet.RealNameAuth.IDCard, + Name: wallet.RealNameAuth.Name, + IdCardPhotoFront: wallet.RealNameAuth.IDCardPhotoFront, + IdCardPhotoBack: wallet.RealNameAuth.IDCardPhotoBack, + AuditStatus: wallet.RealNameAuth.AuditStatus, // 审核状态:0-未审核,1-审核通过,2-审核拒绝 + } + } + + return &adminpb.GetUserWalletResp{ + Wallet: &adminpb.WalletInfo{ + UserID: wallet.UserID, + Balance: wallet.Balance, + WithdrawAccount: wallet.WithdrawAccount, + RealNameAuth: realNameAuth, + WithdrawReceiveAccount: wallet.WithdrawReceiveAccount, + HasPaymentPassword: wallet.PaymentPassword != "", + CreateTime: wallet.CreateTime.UnixMilli(), + UpdateTime: wallet.UpdateTime.UnixMilli(), + }, + }, nil +} + +// UpdateUserWalletBalance 更新用户余额(后台充值/扣款) +// 使用原子操作防止并发问题 +func (o *adminServer) UpdateUserWalletBalance(ctx context.Context, req *adminpb.UpdateUserWalletBalanceReq) (*adminpb.UpdateUserWalletBalanceResp, error) { + // 检查管理员权限 + userID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 获取管理员信息 + adminUser, err := o.Database.GetAdminUserID(ctx, userID) + if err != nil { + return nil, err + } + + // 检查是否为超级管理员(level:100) + if adminUser.Level != constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg("only super admin (level:100) can update wallet balance") + } + + // 检查是否设置了操作密码 + if adminUser.OperationPassword == "" { + return nil, errs.ErrNoPermission.WrapMsg("operation password must be set before updating wallet balance") + } + + // 验证操作密码 + if req.OperationPassword == "" { + return nil, eerrs.ErrPassword.WrapMsg("operation password is required") + } + if adminUser.OperationPassword != req.OperationPassword { + return nil, eerrs.ErrPassword.WrapMsg("operation password is incorrect") + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + if req.Amount == 0 { + return nil, errs.ErrArgs.WrapMsg("amount cannot be zero") + } + + // 使用原子操作更新余额(防止并发问题) + // IncrementBalance 方法已经处理了钱包不存在的情况(通过 upsert) + // 如果是扣款且余额不足,会返回明确的错误信息 + beforeBalance, afterBalance, err := o.ChatDatabase.IncrementWalletBalance(ctx, req.UserID, req.Amount) + if err != nil { + // 所有错误都直接返回,IncrementBalance 已经处理了各种情况: + // 1. 余额不足(扣款时):返回明确的错误信息 + // 2. 钱包不存在且充值:upsert 会自动创建 + // 3. 钱包不存在且扣款:返回余额不足错误 + return nil, err + } + + // 创建余额变动记录 + record := &chatdb.WalletBalanceRecord{ + ID: uuid.New().String(), + UserID: req.UserID, + Amount: req.Amount, + Type: req.Type, + BeforeBalance: beforeBalance, + AfterBalance: afterBalance, + Remark: req.Remark, + CreateTime: time.Now(), + } + if err := o.ChatDatabase.CreateWalletBalanceRecord(ctx, record); err != nil { + // 余额变动记录创建失败,记录错误日志 + // 注意:余额已经更新,但记录创建失败,这是一个严重的数据不一致问题 + // 不返回错误,因为余额已经更新,返回错误会让调用方误以为余额未更新 + log.ZError(ctx, "Failed to create wallet balance record", err, + "userID", req.UserID, + "amount", req.Amount, + "beforeBalance", beforeBalance, + "afterBalance", afterBalance, + "type", req.Type, + "remark", req.Remark) + } + + return &adminpb.UpdateUserWalletBalanceResp{ + Balance: afterBalance, + }, nil +} + +// GetUserWalletBalanceRecords 获取用户余额变动记录列表 +func (o *adminServer) GetUserWalletBalanceRecords(ctx context.Context, req *adminpb.GetUserWalletBalanceRecordsReq) (*adminpb.GetUserWalletBalanceRecordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + + // 获取余额变动记录列表 + total, records, err := o.ChatDatabase.GetWalletBalanceRecords(ctx, req.UserID, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + recordInfos := make([]*adminpb.WalletBalanceRecordInfo, 0, len(records)) + for _, record := range records { + recordInfos = append(recordInfos, &adminpb.WalletBalanceRecordInfo{ + Id: record.ID, + UserID: record.UserID, + Amount: record.Amount, + Type: record.Type, + BeforeBalance: record.BeforeBalance, + AfterBalance: record.AfterBalance, + OrderID: record.OrderID, + TransactionID: record.TransactionID, + RedPacketID: record.RedPacketID, + Remark: record.Remark, + CreateTime: record.CreateTime.UnixMilli(), + }) + } + + return &adminpb.GetUserWalletBalanceRecordsResp{ + Total: uint32(total), + List: recordInfos, + }, nil +} + +// UpdateUserPaymentPassword 修改用户支付密码(后台) +func (o *adminServer) UpdateUserPaymentPassword(ctx context.Context, req *adminpb.UpdateUserPaymentPasswordReq) (*adminpb.UpdateUserPaymentPasswordResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + if req.PaymentPassword == "" { + return nil, errs.ErrArgs.WrapMsg("paymentPassword is required") + } + + // 更新支付密码 + if err := o.ChatDatabase.UpdateWalletPaymentPassword(ctx, req.UserID, req.PaymentPassword); err != nil { + return nil, err + } + + return &adminpb.UpdateUserPaymentPasswordResp{}, nil +} + +// SetUserWithdrawAccount 设置用户提款账号(后台) +func (o *adminServer) SetUserWithdrawAccount(ctx context.Context, req *adminpb.SetUserWithdrawAccountReq) (*adminpb.SetUserWithdrawAccountResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + if req.WithdrawAccount == "" { + return nil, errs.ErrArgs.WrapMsg("withdrawAccount is required") + } + + // 更新提款账号 + if err := o.ChatDatabase.UpdateWalletWithdrawAccount(ctx, req.UserID, req.WithdrawAccount); err != nil { + return nil, err + } + + return &adminpb.SetUserWithdrawAccountResp{}, nil +} + +// ==================== 提现管理相关 RPC(操作 withdraw_applications)==================== + +// GetWithdraw 获取提现申请详情 +func (o *adminServer) GetWithdraw(ctx context.Context, req *adminpb.GetWithdrawReq) (*adminpb.GetWithdrawResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.WithdrawID == "" { + return nil, errs.ErrArgs.WrapMsg("applicationID is required") + } + + // 获取提现申请 + application, err := o.ChatDatabase.GetWithdrawApplication(ctx, req.WithdrawID) + if err != nil { + return nil, err + } + + // 转换为响应格式 + withdrawInfo := &adminpb.WithdrawInfo{ + Id: application.ID, + UserID: application.UserID, + Amount: application.Amount, + WithdrawAccount: application.WithdrawAccount, + Status: application.Status, + AuditorID: application.AuditorID, + AuditTime: application.AuditTime.UnixMilli(), + AuditRemark: application.AuditRemark, + Ip: application.IP, + DeviceID: application.DeviceID, + Platform: application.Platform, + DeviceModel: application.DeviceModel, + DeviceBrand: application.DeviceBrand, + OsVersion: application.OSVersion, + AppVersion: application.AppVersion, + CreateTime: application.CreateTime.UnixMilli(), + UpdateTime: application.UpdateTime.UnixMilli(), + } + + return &adminpb.GetWithdrawResp{ + Withdraw: withdrawInfo, + }, nil +} + +// GetUserWithdraws 获取用户的提现申请列表 +func (o *adminServer) GetUserWithdraws(ctx context.Context, req *adminpb.GetUserWithdrawsReq) (*adminpb.GetUserWithdrawsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + + // 获取用户的提现申请列表 + total, applications, err := o.ChatDatabase.GetWithdrawApplicationsByUserID(ctx, req.UserID, req.Pagination) + if err != nil { + return nil, err + } + + // 查询用户钱包信息(用于获取实名信息) + var wallet *chatdb.Wallet + wallet, err = o.ChatDatabase.GetWallet(ctx, req.UserID) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + log.ZWarn(ctx, "Failed to get wallet for user withdraws", err, "userID", req.UserID) + } + + // 转换为响应格式 + withdrawInfos := make([]*adminpb.WithdrawInfo, 0, len(applications)) + for _, application := range applications { + withdrawInfo := &adminpb.WithdrawInfo{ + Id: application.ID, + UserID: application.UserID, + Amount: application.Amount, + WithdrawAccount: application.WithdrawAccount, + Status: application.Status, + AuditorID: application.AuditorID, + AuditTime: application.AuditTime.UnixMilli(), + AuditRemark: application.AuditRemark, + Ip: application.IP, + DeviceID: application.DeviceID, + Platform: application.Platform, + DeviceModel: application.DeviceModel, + DeviceBrand: application.DeviceBrand, + OsVersion: application.OSVersion, + AppVersion: application.AppVersion, + CreateTime: application.CreateTime.UnixMilli(), + UpdateTime: application.UpdateTime.UnixMilli(), + } + + // 填充用户实名认证信息 + if wallet != nil && wallet.RealNameAuth.IDCard != "" { + withdrawInfo.RealNameAuth = &adminpb.RealNameAuthInfo{ + IdCard: wallet.RealNameAuth.IDCard, + Name: wallet.RealNameAuth.Name, + IdCardPhotoFront: wallet.RealNameAuth.IDCardPhotoFront, + IdCardPhotoBack: wallet.RealNameAuth.IDCardPhotoBack, + AuditStatus: wallet.RealNameAuth.AuditStatus, // 审核状态:0-未审核,1-审核通过,2-审核拒绝 + } + } + + withdrawInfos = append(withdrawInfos, withdrawInfo) + } + + return &adminpb.GetUserWithdrawsResp{ + Total: uint32(total), + List: withdrawInfos, + }, nil +} + +// GetWithdraws 获取提现申请列表(后台,支持按状态筛选) +func (o *adminServer) GetWithdraws(ctx context.Context, req *adminpb.GetWithdrawsReq) (*adminpb.GetWithdrawsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + var total int64 + var applications []*chatdb.WithdrawApplication + var err error + + // 如果指定了状态,按状态筛选;否则获取全部 + if req.Status > 0 { + total, applications, err = o.ChatDatabase.GetWithdrawApplicationsByStatus(ctx, req.Status, req.Pagination) + } else { + total, applications, err = o.ChatDatabase.GetWithdrawApplicationsPage(ctx, req.Pagination) + } + + if err != nil { + return nil, err + } + + // 收集所有用户ID,批量查询钱包信息(用于获取实名信息) + userIDs := make([]string, 0, len(applications)) + userIDSet := make(map[string]bool) + for _, application := range applications { + if !userIDSet[application.UserID] { + userIDs = append(userIDs, application.UserID) + userIDSet[application.UserID] = true + } + } + + // 批量查询钱包信息 + walletMap := make(map[string]*chatdb.Wallet) + if len(userIDs) > 0 { + wallets, err := o.ChatDatabase.GetWalletsByUserIDs(ctx, userIDs) + if err != nil { + log.ZWarn(ctx, "Failed to get wallets for withdraw list", err, "userIDs", userIDs) + } else { + for _, wallet := range wallets { + walletMap[wallet.UserID] = wallet + } + } + } + + // 转换为响应格式 + withdrawInfos := make([]*adminpb.WithdrawInfo, 0, len(applications)) + for _, application := range applications { + withdrawInfo := &adminpb.WithdrawInfo{ + Id: application.ID, + UserID: application.UserID, + Amount: application.Amount, + WithdrawAccount: application.WithdrawAccount, + Status: application.Status, + AuditorID: application.AuditorID, + AuditTime: application.AuditTime.UnixMilli(), + AuditRemark: application.AuditRemark, + Ip: application.IP, + DeviceID: application.DeviceID, + Platform: application.Platform, + DeviceModel: application.DeviceModel, + DeviceBrand: application.DeviceBrand, + OsVersion: application.OSVersion, + AppVersion: application.AppVersion, + CreateTime: application.CreateTime.UnixMilli(), + UpdateTime: application.UpdateTime.UnixMilli(), + } + + // 填充用户实名认证信息 + if wallet, ok := walletMap[application.UserID]; ok && wallet.RealNameAuth.IDCard != "" { + withdrawInfo.RealNameAuth = &adminpb.RealNameAuthInfo{ + IdCard: wallet.RealNameAuth.IDCard, + Name: wallet.RealNameAuth.Name, + IdCardPhotoFront: wallet.RealNameAuth.IDCardPhotoFront, + IdCardPhotoBack: wallet.RealNameAuth.IDCardPhotoBack, + AuditStatus: wallet.RealNameAuth.AuditStatus, // 审核状态:0-未审核,1-审核通过,2-审核拒绝 + } + } + + withdrawInfos = append(withdrawInfos, withdrawInfo) + } + + return &adminpb.GetWithdrawsResp{ + Total: uint32(total), + List: withdrawInfos, + }, nil +} + +// AuditWithdraw 批量审核提现申请 +func (o *adminServer) AuditWithdraw(ctx context.Context, req *adminpb.AuditWithdrawReq) (*adminpb.AuditWithdrawResp, error) { + // 检查管理员权限 + auditorID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if len(req.WithdrawIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("withdrawIDs is required and cannot be empty") + } + if req.Status != chatdb.WithdrawApplicationStatusApproved && req.Status != chatdb.WithdrawApplicationStatusRejected { + return nil, errs.ErrArgs.WrapMsg("status must be 2 (approved) or 3 (rejected)") + } + + var successCount uint32 + var failCount uint32 + var failedIDs []string + + // 批量处理每个提现申请 + for _, withdrawID := range req.WithdrawIDs { + // 获取提现申请 + application, err := o.ChatDatabase.GetWithdrawApplication(ctx, withdrawID) + if err != nil { + failCount++ + failedIDs = append(failedIDs, withdrawID) + log.ZWarn(ctx, "Get withdraw application failed", err, "withdrawID", withdrawID) + continue + } + + // 检查提现申请状态:允许"待审核"和"已通过"状态的提现申请可以被审核 + // 已通过的提现申请可以重新审核为拒绝 + if application.Status != chatdb.WithdrawApplicationStatusPending && application.Status != chatdb.WithdrawApplicationStatusApproved { + failCount++ + failedIDs = append(failedIDs, withdrawID) + log.ZWarn(ctx, "Withdraw application status is not pending or approved", nil, "withdrawID", withdrawID, "status", application.Status) + continue + } + + // 更新提现申请状态 + if err := o.ChatDatabase.UpdateWithdrawApplicationStatus(ctx, withdrawID, req.Status, auditorID, req.AuditRemark); err != nil { + failCount++ + failedIDs = append(failedIDs, withdrawID) + log.ZWarn(ctx, "Update withdraw application status failed", err, "withdrawID", withdrawID) + continue + } + + // 如果审核通过,不需要额外操作(因为用户申请时已经扣除了余额) + // 如果审核拒绝(包括从"待审核"改为"已拒绝",或从"已通过"改为"已拒绝"),需要将余额退回给用户 + if req.Status == chatdb.WithdrawApplicationStatusRejected { + // 退回余额 + beforeBalance, afterBalance, err := o.ChatDatabase.IncrementWalletBalance(ctx, application.UserID, application.Amount) + if err != nil { + // 记录错误但不影响审核状态更新 + log.ZError(ctx, "Refund balance failed", err, "withdrawID", withdrawID, "userID", application.UserID, "amount", application.Amount) + } else { + // 创建余额变动记录(退款) + record := &chatdb.WalletBalanceRecord{ + ID: uuid.New().String(), + UserID: application.UserID, + Amount: application.Amount, + Type: 4, // 4-退款 + BeforeBalance: beforeBalance, + AfterBalance: afterBalance, + Remark: "提现审核拒绝,退回余额", + CreateTime: time.Now(), + } + if err := o.ChatDatabase.CreateWalletBalanceRecord(ctx, record); err != nil { + log.ZWarn(ctx, "Create wallet balance record failed", err, "withdrawID", withdrawID) + } + } + } + + successCount++ + } + + return &adminpb.AuditWithdrawResp{ + SuccessCount: successCount, + FailCount: failCount, + FailedIDs: failedIDs, + }, nil +} + +// BatchUpdateWalletBalance 批量更新用户余额 +func (o *adminServer) BatchUpdateWalletBalance(ctx context.Context, req *adminpb.BatchUpdateWalletBalanceReq) (*adminpb.BatchUpdateWalletBalanceResp, error) { + // 检查管理员权限 + adminID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 获取管理员信息 + adminUser, err := o.Database.GetAdminUserID(ctx, adminID) + if err != nil { + return nil, err + } + + // 检查是否为超级管理员(level:100) + if adminUser.Level != constant.AdvancedUserLevel { + return nil, errs.ErrNoPermission.WrapMsg("only super admin (level:100) can batch update wallet balance") + } + + // 检查是否设置了操作密码 + if adminUser.OperationPassword == "" { + return nil, errs.ErrNoPermission.WrapMsg("operation password must be set before batch updating wallet balance") + } + + // 验证操作密码 + if req.OperationPassword == "" { + return nil, eerrs.ErrPassword.WrapMsg("operation password is required") + } + if adminUser.OperationPassword != req.OperationPassword { + return nil, eerrs.ErrPassword.WrapMsg("operation password is incorrect") + } + + // 验证必填字段 + if len(req.Users) == 0 { + return nil, errs.ErrArgs.WrapMsg("users list cannot be empty") + } + + // 验证默认操作类型 + defaultOperation := req.Operation + if defaultOperation == "" { + defaultOperation = "add" // 默认为增加 + } + if defaultOperation != "set" && defaultOperation != "add" && defaultOperation != "subtract" { + return nil, errs.ErrArgs.WrapMsg("default operation must be one of: set, add, subtract") + } + + var results []*adminpb.BatchUpdateResultItem + var successCount uint32 + var failedCount uint32 + + // 批量处理每个用户 + for _, userItem := range req.Users { + result := &adminpb.BatchUpdateResultItem{ + UserID: userItem.UserID, + PhoneNumber: userItem.PhoneNumber, + Account: userItem.Account, + Remark: userItem.Remark, + } + + // 1. 根据提供的标识符查找用户 + var targetUserID string + if userItem.UserID != "" { + // 直接使用 userID + targetUserID = userItem.UserID + } else if userItem.PhoneNumber != "" { + // 通过手机号查找用户(假设区号为空或默认) + attr, err := o.ChatDatabase.TakeAttributeByPhone(ctx, "", userItem.PhoneNumber) + if err != nil { + result.Success = false + result.Message = "user not found by phone number" + results = append(results, result) + failedCount++ + continue + } + targetUserID = attr.UserID + result.UserID = targetUserID + } else if userItem.Account != "" { + // 通过账号查找用户 + attr, err := o.ChatDatabase.TakeAttributeByAccount(ctx, userItem.Account) + if err != nil { + result.Success = false + result.Message = "user not found by account" + results = append(results, result) + failedCount++ + continue + } + targetUserID = attr.UserID + result.UserID = targetUserID + } else { + result.Success = false + result.Message = "at least one of userID, phoneNumber, or account must be provided" + results = append(results, result) + failedCount++ + continue + } + + // 2. 确定使用的金额和操作类型 + amount := userItem.Amount + if amount == 0 { + amount = req.Amount + } + operation := userItem.Operation + if operation == "" { + operation = defaultOperation + } + if operation != "set" && operation != "add" && operation != "subtract" { + result.Success = false + result.Message = "operation must be one of: set, add, subtract" + results = append(results, result) + failedCount++ + continue + } + + // 3. 获取当前余额 + wallet, err := o.ChatDatabase.GetWallet(ctx, targetUserID) + var oldBalance int64 + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + oldBalance = 0 + } else { + result.Success = false + result.Message = "failed to get wallet: " + err.Error() + results = append(results, result) + failedCount++ + continue + } + } else { + oldBalance = wallet.Balance + } + result.OldBalance = oldBalance + + // 4. 根据操作类型计算新余额和变动金额 + var newBalance int64 + var incrementAmount int64 + var balanceChangeType int32 = 99 // 99-其他(后台批量操作) + + switch operation { + case "set": + newBalance = amount + incrementAmount = amount - oldBalance + case "add": + incrementAmount = amount + newBalance = oldBalance + amount + case "subtract": + incrementAmount = -amount + newBalance = oldBalance - amount + } + + // 5. 检查余额是否会变为负数 + if newBalance < 0 { + result.Success = false + result.Message = "insufficient balance: cannot be negative" + result.NewBalance = oldBalance + results = append(results, result) + failedCount++ + continue + } + + // 6. 更新余额 + beforeBalance, afterBalance, err := o.ChatDatabase.IncrementWalletBalance(ctx, targetUserID, incrementAmount) + if err != nil { + result.Success = false + result.Message = "failed to update balance: " + err.Error() + result.NewBalance = oldBalance + results = append(results, result) + failedCount++ + continue + } + + result.OldBalance = beforeBalance + result.NewBalance = afterBalance + + // 7. 创建余额变动记录 + record := &chatdb.WalletBalanceRecord{ + ID: uuid.New().String(), + UserID: targetUserID, + Amount: incrementAmount, + Type: balanceChangeType, + BeforeBalance: beforeBalance, + AfterBalance: afterBalance, + Remark: userItem.Remark, + CreateTime: time.Now(), + } + if err := o.ChatDatabase.CreateWalletBalanceRecord(ctx, record); err != nil { + log.ZWarn(ctx, "Create wallet balance record failed", err, "userID", targetUserID) + } + + result.Success = true + result.Message = "success" + results = append(results, result) + successCount++ + } + + return &adminpb.BatchUpdateWalletBalanceResp{ + Total: uint32(len(req.Users)), + Success: successCount, + Failed: failedCount, + Results: results, + }, nil +} + +// GetWallets 获取钱包列表 +func (o *adminServer) GetWallets(ctx context.Context, req *adminpb.GetWalletsReq) (*adminpb.GetWalletsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + var total int64 + var wallets []*chatdb.Wallet + var err error + + // 如果提供了查询条件,先查找用户 + if req.UserID != "" || req.PhoneNumber != "" || req.Account != "" { + var userIDs []string + + if req.UserID != "" { + // 直接使用 userID + userIDs = []string{req.UserID} + } else if req.PhoneNumber != "" { + // 通过手机号模糊查询用户 + _, attributes, err := o.ChatDatabase.SearchUser(ctx, req.PhoneNumber, nil, nil, &sdkws.RequestPagination{PageNumber: 1, ShowNumber: 1000}) + if err != nil { + return nil, err + } + for _, attr := range attributes { + userIDs = append(userIDs, attr.UserID) + } + } else if req.Account != "" { + // 通过账号模糊查询用户 + _, attributes, err := o.ChatDatabase.SearchUser(ctx, req.Account, nil, nil, &sdkws.RequestPagination{PageNumber: 1, ShowNumber: 1000}) + if err != nil { + return nil, err + } + for _, attr := range attributes { + userIDs = append(userIDs, attr.UserID) + } + } + + // 根据 userIDs 查询钱包 + if len(userIDs) > 0 { + wallets, err = o.ChatDatabase.GetWalletsByUserIDs(ctx, userIDs) + if err != nil { + return nil, err + } + total = int64(len(wallets)) + } else { + total = 0 + wallets = []*chatdb.Wallet{} + } + } else { + // 没有查询条件,获取所有钱包(分页) + total, wallets, err = o.ChatDatabase.GetWalletsPage(ctx, req.Pagination) + if err != nil { + return nil, err + } + } + + // 提取所有 userIDs + userIDs := make([]string, 0, len(wallets)) + for _, wallet := range wallets { + userIDs = append(userIDs, wallet.UserID) + } + + // 批量获取用户属性(昵称、头像等) + userAttrMap := make(map[string]*chatdb.Attribute) + if len(userIDs) > 0 { + attributes, err := o.ChatDatabase.FindAttribute(ctx, userIDs) + if err != nil { + log.ZWarn(ctx, "Find user attributes failed", err, "userIDs", userIDs) + } else { + for _, attr := range attributes { + userAttrMap[attr.UserID] = attr + } + } + } + + // 转换为响应格式 + walletInfos := make([]*adminpb.WalletListItemInfo, 0, len(wallets)) + for _, wallet := range wallets { + info := &adminpb.WalletListItemInfo{ + UserID: wallet.UserID, + Balance: wallet.Balance, + CreateTime: wallet.CreateTime.UnixMilli(), + UpdateTime: wallet.UpdateTime.UnixMilli(), + } + + // 填充用户昵称和头像 + if attr, ok := userAttrMap[wallet.UserID]; ok { + info.Nickname = attr.Nickname + info.FaceURL = attr.FaceURL + } + + walletInfos = append(walletInfos, info) + } + + return &adminpb.GetWalletsResp{ + Total: uint32(total), + Wallets: walletInfos, + }, nil +} + +// GetRealNameAuths 获取实名认证列表(支持按审核状态筛选) +func (o *adminServer) GetRealNameAuths(ctx context.Context, req *adminpb.GetRealNameAuthsReq) (*adminpb.GetRealNameAuthsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + var total int64 + var wallets []*chatdb.Wallet + var err error + + // 查询逻辑:过滤身份证号不为空的(已完成实名认证) + // auditStatus: 0-待审核,1-审核通过,2-审核拒绝,<0 表示不过滤状态(全部) + // userID: 用户ID搜索(可选,为空时不过滤) + total, wallets, err = o.ChatDatabase.GetWalletsPageByRealNameAuthAuditStatus(ctx, req.AuditStatus, req.UserID, req.Pagination) + + if err != nil { + return nil, err + } + + // 提取所有 userIDs + userIDs := make([]string, 0, len(wallets)) + for _, wallet := range wallets { + userIDs = append(userIDs, wallet.UserID) + } + + // 批量获取用户属性(昵称、头像等) + userAttrMap := make(map[string]*chatdb.Attribute) + if len(userIDs) > 0 { + attributes, err := o.ChatDatabase.FindAttribute(ctx, userIDs) + if err != nil { + log.ZWarn(ctx, "Find user attributes failed", err, "userIDs", userIDs) + } else { + for _, attr := range attributes { + userAttrMap[attr.UserID] = attr + } + } + } + + // 转换为响应格式 + authInfos := make([]*adminpb.RealNameAuthListItemInfo, 0, len(wallets)) + for _, wallet := range wallets { + // 注意:数据库查询已经过滤了身份证号不为空的记录,这里不需要再次检查 + // 如果在这里再次过滤,会导致返回数量不一致 + + // 处理创建时间:如果为零值(负数时间戳),使用更新时间或当前时间 + createTime := wallet.CreateTime + if createTime.IsZero() || createTime.UnixMilli() < 0 { + if !wallet.UpdateTime.IsZero() { + createTime = wallet.UpdateTime + } else { + createTime = time.Now() + } + } + + // 处理更新时间:如果为零值(负数时间戳),使用当前时间 + updateTime := wallet.UpdateTime + if updateTime.IsZero() || updateTime.UnixMilli() < 0 { + updateTime = time.Now() + } + + info := &adminpb.RealNameAuthListItemInfo{ + UserID: wallet.UserID, + IdCard: wallet.RealNameAuth.IDCard, + Name: wallet.RealNameAuth.Name, + IdCardPhotoFront: wallet.RealNameAuth.IDCardPhotoFront, + IdCardPhotoBack: wallet.RealNameAuth.IDCardPhotoBack, + AuditStatus: wallet.RealNameAuth.AuditStatus, + CreateTime: createTime.UnixMilli(), + UpdateTime: updateTime.UnixMilli(), + } + + // 填充用户昵称和头像 + if attr, ok := userAttrMap[wallet.UserID]; ok { + info.Nickname = attr.Nickname + info.FaceURL = attr.FaceURL + } + + authInfos = append(authInfos, info) + } + + // 注意:不在应用层排序,因为数据库查询时已经按 create_time 倒序排序并分页 + // 如果在应用层重新排序,会导致分页结果不准确 + + return &adminpb.GetRealNameAuthsResp{ + Total: uint32(total), + List: authInfos, + }, nil +} + +// AuditRealNameAuth 审核实名认证(通过/拒绝) +func (o *adminServer) AuditRealNameAuth(ctx context.Context, req *adminpb.AuditRealNameAuthReq) (*adminpb.AuditRealNameAuthResp, error) { + // 检查管理员权限 + auditorID, err := mctx.CheckAdmin(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("userID is required") + } + if req.AuditStatus != 1 && req.AuditStatus != 2 { + return nil, errs.ErrArgs.WrapMsg("auditStatus must be 1 (approved) or 2 (rejected)") + } + + // 获取钱包信息 + wallet, err := o.ChatDatabase.GetWallet(ctx, req.UserID) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errs.ErrArgs.WrapMsg("wallet not found") + } + return nil, err + } + + // 检查是否已完成实名认证 + if wallet.RealNameAuth.IDCard == "" || wallet.RealNameAuth.Name == "" { + return nil, errs.ErrArgs.WrapMsg("user has not completed real name authentication") + } + + // 更新审核状态 + wallet.RealNameAuth.AuditStatus = req.AuditStatus + if err := o.ChatDatabase.UpdateWalletRealNameAuth(ctx, req.UserID, wallet.RealNameAuth); err != nil { + return nil, errs.WrapMsg(err, "failed to update real name auth audit status") + } + + log.ZInfo(ctx, "Real name auth audited", "userID", req.UserID, "auditorID", auditorID, "auditStatus", req.AuditStatus, "auditRemark", req.AuditRemark) + + return &adminpb.AuditRealNameAuthResp{}, nil +} diff --git a/internal/rpc/bot/agent.go b/internal/rpc/bot/agent.go new file mode 100644 index 0000000..596add9 --- /dev/null +++ b/internal/rpc/bot/agent.go @@ -0,0 +1,153 @@ +package bot + +import ( + "context" + "crypto/rand" + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/convert" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/bot" + pbconstant "git.imall.cloud/openim/protocol/constant" + "git.imall.cloud/openim/protocol/sdkws" + "git.imall.cloud/openim/protocol/user" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" +) + +func (b *botSvr) CreateAgent(ctx context.Context, req *bot.CreateAgentReq) (*bot.CreateAgentResp, error) { + if req.Agent == nil { + return nil, errs.ErrArgs.WrapMsg("req.Agent is nil") + } + + now := time.Now() + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + if req.Agent.UserID != "" { + req.Agent.UserID = constant.AgentUserIDPrefix + req.Agent.UserID + users, err := b.imCaller.GetUsersInfo(ctx, []string{req.Agent.UserID}) + if err != nil { + return nil, err + } + if len(users) > 0 { + return nil, errs.ErrDuplicateKey.WrapMsg("agent userID already exists") + } + } else { + randUserIDs := make([]string, 5) + for i := range randUserIDs { + randUserIDs[i] = constant.AgentUserIDPrefix + genID(10) + } + users, err := b.imCaller.GetUsersInfo(ctx, randUserIDs) + if err != nil { + return nil, err + } + if len(users) == len(randUserIDs) { + return nil, errs.ErrDuplicateKey.WrapMsg("gen agent userID already exists, please try again") + } + userIDs := datautil.Batch(func(u *sdkws.UserInfo) string { return u.UserID }, users) + for _, uid := range randUserIDs { + if datautil.Contain(uid, userIDs...) { + continue + } + req.Agent.UserID = uid + break + } + } + + if err := b.imCaller.AddNotificationAccount(ctx, &user.AddNotificationAccountReq{ + UserID: req.Agent.UserID, + NickName: req.Agent.Nickname, + FaceURL: req.Agent.FaceURL, + AppMangerLevel: pbconstant.AppRobotAdmin, + }); err != nil { + return nil, err + } + dbagent := convert.PB2DBAgent(req.Agent) + dbagent.CreateTime = now + err = b.database.CreateAgent(ctx, dbagent) + if err != nil { + return nil, err + } + return &bot.CreateAgentResp{}, nil +} + +func (b *botSvr) UpdateAgent(ctx context.Context, req *bot.UpdateAgentReq) (*bot.UpdateAgentResp, error) { + if _, err := b.database.TakeAgent(ctx, req.UserID); err != nil { + return nil, errs.ErrArgs.Wrap() + } + + if req.FaceURL != nil || req.Nickname != nil { + imReq := &user.UpdateNotificationAccountInfoReq{ + UserID: req.UserID, + } + if req.Nickname != nil { + imReq.NickName = *req.Nickname + } + if req.FaceURL != nil { + imReq.FaceURL = *req.FaceURL + } + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + err = b.imCaller.UpdateNotificationAccount(ctx, imReq) + if err != nil { + return nil, err + } + } + + update := ToDBAgentUpdate(req) + err := b.database.UpdateAgent(ctx, req.UserID, update) + if err != nil { + return nil, err + } + + return &bot.UpdateAgentResp{}, nil +} + +func (b *botSvr) PageFindAgent(ctx context.Context, req *bot.PageFindAgentReq) (*bot.PageFindAgentResp, error) { + total, agents, err := b.database.PageAgents(ctx, req.UserIDs, req.Pagination) + if err != nil { + return nil, err + } + //_, userType, err := mctx.Check(ctx) + //if err != nil { + // return nil, err + //} + //if userType != constant.AdminUser { + for i := range agents { + agents[i].Key = "" + } + //} + return &bot.PageFindAgentResp{ + Total: total, + Agents: convert.BatchDB2PBAgent(agents), + }, nil +} + +func (b *botSvr) DeleteAgent(ctx context.Context, req *bot.DeleteAgentReq) (*bot.DeleteAgentResp, error) { + err := b.database.DeleteAgents(ctx, req.UserIDs) + if err != nil { + return nil, err + } + return &bot.DeleteAgentResp{}, nil +} + +func genID(l int) string { + data := make([]byte, l) + _, _ = rand.Read(data) + chars := []byte("0123456789") + for i := 0; i < len(data); i++ { + if i == 0 { + data[i] = chars[1:][data[i]%9] + } else { + data[i] = chars[data[i]%10] + } + } + return string(data) +} diff --git a/internal/rpc/bot/send.go b/internal/rpc/bot/send.go new file mode 100644 index 0000000..0df98d0 --- /dev/null +++ b/internal/rpc/bot/send.go @@ -0,0 +1,92 @@ +package bot + +import ( + "context" + "encoding/json" + "time" + + "git.imall.cloud/openim/chat/pkg/botstruct" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/bot" + "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/sashabaranov/go-openai" +) + +func (b *botSvr) SendBotMessage(ctx context.Context, req *bot.SendBotMessageReq) (*bot.SendBotMessageResp, error) { + agent, err := b.database.TakeAgent(ctx, req.AgentID) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("agent not found") + } + //convRespID, err := b.database.TakeConversationRespID(ctx, req.ConversationID, req.AgentID) + //if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + // return nil, err + //} + //var respID string + //if convRespID != nil { + // respID = convRespID.PreviousResponseID + //} + + aiCfg := openai.DefaultConfig(agent.Key) + aiCfg.BaseURL = agent.Url + aiCfg.HTTPClient = b.httpClient + client := openai.NewClientWithConfig(aiCfg) + aiReq := openai.ChatCompletionRequest{ + Model: agent.Model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleSystem, + Content: agent.Prompts, + }, + { + Role: openai.ChatMessageRoleUser, + Content: req.Content, + }, + }, + } + aiCtx, cancel := context.WithTimeout(ctx, time.Duration(b.timeout)*time.Second) + defer cancel() + completion, err := client.CreateChatCompletion(aiCtx, aiReq) + if err != nil { + return nil, errs.Wrap(err) + } + + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + + content := "no response" + if len(completion.Choices) > 0 { + content = completion.Choices[0].Message.Content + } + err = b.imCaller.SendSimpleMsg(ctx, &imapi.SendSingleMsgReq{ + SendID: agent.UserID, + Content: content, + }, req.Key) + if err != nil { + return nil, err + } + + //err = b.database.UpdateConversationRespID(ctx, req.ConversationID, agent.UserID, ToDBConversationRespIDUpdate(completion.ID)) + //if err != nil { + // return nil, err + //} + return &bot.SendBotMessageResp{}, nil +} + +func getContent(contentType int32, content string) (string, error) { + switch contentType { + case constant.Text: + var elem botstruct.TextElem + err := json.Unmarshal([]byte(content), &elem) + if err != nil { + return "", errs.ErrArgs.WrapMsg(err.Error()) + } + return elem.Content, nil + default: + return "", errs.New("un support contentType").Wrap() + } +} diff --git a/internal/rpc/bot/start.go b/internal/rpc/bot/start.go new file mode 100644 index 0000000..092b59d --- /dev/null +++ b/internal/rpc/bot/start.go @@ -0,0 +1,53 @@ +package bot + +import ( + "context" + "net/http" + "time" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/db/database" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "git.imall.cloud/openim/chat/pkg/protocol/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/discovery" + "google.golang.org/grpc" +) + +type Config struct { + RpcConfig config.Bot + RedisConfig config.Redis + MongodbConfig config.Mongo + Discovery config.Discovery + Share config.Share +} + +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) + if err != nil { + return err + } + var srv botSvr + + srv.database, err = database.NewBotDatabase(mgocli) + if err != nil { + return err + } + srv.timeout = config.RpcConfig.Timeout + srv.httpClient = &http.Client{ + Timeout: time.Duration(config.RpcConfig.Timeout) * time.Second, + } + im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID) + srv.imCaller = im + bot.RegisterBotServer(server, &srv) + return nil +} + +type botSvr struct { + bot.UnimplementedBotServer + database database.BotDatabase + httpClient *http.Client + timeout int + imCaller imapi.CallerInterface + //Admin *chatClient.AdminClient +} diff --git a/internal/rpc/bot/update.go b/internal/rpc/bot/update.go new file mode 100644 index 0000000..379f846 --- /dev/null +++ b/internal/rpc/bot/update.go @@ -0,0 +1,37 @@ +package bot + +import "git.imall.cloud/openim/chat/pkg/protocol/bot" + +func ToDBAgentUpdate(req *bot.UpdateAgentReq) map[string]any { + update := make(map[string]any) + if req.Key != nil { + update["key"] = req.Key + } + if req.Prompts != nil { + update["prompts"] = req.Prompts + } + if req.Model != nil { + update["model"] = req.Model + } + if req.FaceURL != nil { + update["face_url"] = req.FaceURL + } + if req.Nickname != nil { + update["nick_name"] = req.Nickname + } + if req.Identity != nil { + update["identity"] = req.Identity + } + if req.Url != nil { + update["url"] = req.Url + } + + return update +} + +func ToDBConversationRespIDUpdate(respID string) map[string]any { + update := map[string]any{ + "previous_response_id": respID, + } + return update +} diff --git a/internal/rpc/chat/callback.go b/internal/rpc/chat/callback.go new file mode 100644 index 0000000..8bc83ae --- /dev/null +++ b/internal/rpc/chat/callback.go @@ -0,0 +1,61 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "encoding/json" + "fmt" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/errs" +) + +type CallbackBeforeAddFriendReq struct { + CallbackCommand `json:"callbackCommand"` + FromUserID string `json:"fromUserID" ` + ToUserID string `json:"toUserID"` + ReqMsg string `json:"reqMsg"` + OperationID string `json:"operationID"` +} + +type CallbackCommand string + +func (c CallbackCommand) GetCallbackCommand() string { + return string(c) +} + +func (o *chatSvr) OpenIMCallback(ctx context.Context, req *chat.OpenIMCallbackReq) (*chat.OpenIMCallbackResp, error) { + switch req.Command { + case constantpb.CallbackBeforeAddFriendCommand: + var data CallbackBeforeAddFriendReq + if err := json.Unmarshal([]byte(req.Body), &data); err != nil { + return nil, errs.Wrap(err) + } + user, err := o.Database.TakeAttributeByUserID(ctx, data.ToUserID) + if err != nil { + return nil, err + } + if user.AllowAddFriend != constant.OrdinaryUserAddFriendEnable { + return nil, eerrs.ErrRefuseFriend.WrapMsg(fmt.Sprintf("state %d", user.AllowAddFriend)) + } + return &chat.OpenIMCallbackResp{}, nil + default: + return nil, errs.ErrArgs.WrapMsg(fmt.Sprintf("invalid command %s", req.Command)) + } +} diff --git a/internal/rpc/chat/favorite.go b/internal/rpc/chat/favorite.go new file mode 100644 index 0000000..42cf866 --- /dev/null +++ b/internal/rpc/chat/favorite.go @@ -0,0 +1,292 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/errs" +) + +// ==================== 收藏相关 RPC ==================== + +// CreateFavorite 创建收藏 +func (o *chatSvr) CreateFavorite(ctx context.Context, req *chat.CreateFavoriteReq) (*chat.CreateFavoriteResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证收藏类型 + if req.Type < 1 || req.Type > 7 { + return nil, errs.ErrArgs.WrapMsg("invalid favorite type") + } + + // 创建收藏对象 + favorite := &chatdb.Favorite{ + UserID: userID, + Type: req.Type, + Title: req.Title, + Content: req.Content, + Description: req.Description, + Thumbnail: req.Thumbnail, + LinkURL: req.LinkURL, + FileSize: req.FileSize, + Duration: req.Duration, + Location: req.Location, + Tags: req.Tags, + Remark: req.Remark, + Status: 1, // 正常状态 + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + + // 保存到数据库 + if err := o.Database.CreateFavorite(ctx, favorite); err != nil { + return nil, err + } + + return &chat.CreateFavoriteResp{ + FavoriteID: favorite.ID, + }, nil +} + +// GetFavorite 获取收藏详情 +func (o *chatSvr) GetFavorite(ctx context.Context, req *chat.GetFavoriteReq) (*chat.GetFavoriteResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取收藏 + favorite, err := o.Database.GetFavorite(ctx, req.FavoriteID) + if err != nil { + return nil, err + } + + // 验证是否为当前用户的收藏 + if favorite.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your favorite") + } + + return &chat.GetFavoriteResp{ + Favorite: convertFavoriteToProto(favorite), + }, nil +} + +// GetFavorites 获取收藏列表 +func (o *chatSvr) GetFavorites(ctx context.Context, req *chat.GetFavoritesReq) (*chat.GetFavoritesResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + var total int64 + var favorites []*chatdb.Favorite + + if req.Type > 0 { + // 按类型查询 + total, favorites, err = o.Database.GetFavoritesByUserIDAndType(ctx, userID, req.Type, req.Pagination) + } else { + // 查询所有 + total, favorites, err = o.Database.GetFavoritesByUserID(ctx, userID, req.Pagination) + } + + if err != nil { + return nil, err + } + + // 转换为响应格式 + favoriteInfos := make([]*chat.FavoriteInfo, 0, len(favorites)) + for _, fav := range favorites { + favoriteInfos = append(favoriteInfos, convertFavoriteToProto(fav)) + } + + return &chat.GetFavoritesResp{ + Total: uint32(total), + Favorites: favoriteInfos, + }, nil +} + +// SearchFavorites 搜索收藏 +func (o *chatSvr) SearchFavorites(ctx context.Context, req *chat.SearchFavoritesReq) (*chat.SearchFavoritesResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 搜索收藏 + total, favorites, err := o.Database.SearchFavoritesByKeyword(ctx, userID, req.Keyword, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + favoriteInfos := make([]*chat.FavoriteInfo, 0, len(favorites)) + for _, fav := range favorites { + favoriteInfos = append(favoriteInfos, convertFavoriteToProto(fav)) + } + + return &chat.SearchFavoritesResp{ + Total: uint32(total), + Favorites: favoriteInfos, + }, nil +} + +// UpdateFavorite 更新收藏 +func (o *chatSvr) UpdateFavorite(ctx context.Context, req *chat.UpdateFavoriteReq) (*chat.UpdateFavoriteResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取收藏,验证所有权 + favorite, err := o.Database.GetFavorite(ctx, req.FavoriteID) + if err != nil { + return nil, err + } + + if favorite.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your favorite") + } + + // 构建更新数据 + updateData := make(map[string]any) + if req.Title != "" { + updateData["title"] = req.Title + } + if req.Description != "" { + updateData["description"] = req.Description + } + if req.Remark != "" { + updateData["remark"] = req.Remark + } + if len(req.Tags) > 0 { + updateData["tags"] = req.Tags + } + + // 更新收藏 + if err := o.Database.UpdateFavorite(ctx, req.FavoriteID, updateData); err != nil { + return nil, err + } + + return &chat.UpdateFavoriteResp{}, nil +} + +// DeleteFavorite 删除收藏 +func (o *chatSvr) DeleteFavorite(ctx context.Context, req *chat.DeleteFavoriteReq) (*chat.DeleteFavoriteResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证所有权(批量验证) + for _, favoriteID := range req.FavoriteIDs { + favorite, err := o.Database.GetFavorite(ctx, favoriteID) + if err != nil { + return nil, err + } + if favorite.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your favorite") + } + } + + // 删除收藏 + if err := o.Database.DeleteFavorite(ctx, req.FavoriteIDs); err != nil { + return nil, err + } + + return &chat.DeleteFavoriteResp{}, nil +} + +// GetFavoritesByTags 根据标签获取收藏 +func (o *chatSvr) GetFavoritesByTags(ctx context.Context, req *chat.GetFavoritesByTagsReq) (*chat.GetFavoritesByTagsResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + if len(req.Tags) == 0 { + return nil, errs.ErrArgs.WrapMsg("tags is empty") + } + + // 根据标签查询 + total, favorites, err := o.Database.GetFavoritesByTags(ctx, userID, req.Tags, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + favoriteInfos := make([]*chat.FavoriteInfo, 0, len(favorites)) + for _, fav := range favorites { + favoriteInfos = append(favoriteInfos, convertFavoriteToProto(fav)) + } + + return &chat.GetFavoritesByTagsResp{ + Total: uint32(total), + Favorites: favoriteInfos, + }, nil +} + +// GetFavoriteCount 获取收藏数量 +func (o *chatSvr) GetFavoriteCount(ctx context.Context, req *chat.GetFavoriteCountReq) (*chat.GetFavoriteCountResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取收藏数量 + count, err := o.Database.CountFavoritesByUserID(ctx, userID) + if err != nil { + return nil, err + } + + return &chat.GetFavoriteCountResp{ + Count: count, + }, nil +} + +// convertFavoriteToProto 将数据库模型转换为 protobuf 消息 +func convertFavoriteToProto(fav *chatdb.Favorite) *chat.FavoriteInfo { + return &chat.FavoriteInfo{ + Id: fav.ID, + UserID: fav.UserID, + Type: fav.Type, + Title: fav.Title, + Content: fav.Content, + Description: fav.Description, + Thumbnail: fav.Thumbnail, + LinkURL: fav.LinkURL, + FileSize: fav.FileSize, + Duration: fav.Duration, + Location: fav.Location, + Tags: fav.Tags, + Remark: fav.Remark, + CreateTime: fav.CreateTime.UnixMilli(), + UpdateTime: fav.UpdateTime.UnixMilli(), + } +} diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go new file mode 100644 index 0000000..765f618 --- /dev/null +++ b/internal/rpc/chat/login.go @@ -0,0 +1,1495 @@ +package chat + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + "strconv" + "strings" + "sync" + "time" + + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/utils/datautil" + + "github.com/google/uuid" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mcontext" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/util" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "git.imall.cloud/openim/chat/pkg/sms" +) + +type verifyType int + +const ( + phone verifyType = iota + mail +) + +func (o *chatSvr) verifyCodeJoin(areaCode, phoneNumber string) string { + return areaCode + " " + phoneNumber +} + +func (o *chatSvr) SendVerifyCode(ctx context.Context, req *chat.SendVerifyCodeReq) (*chat.SendVerifyCodeResp, error) { + switch int(req.UsedFor) { + case constant.VerificationCodeForRegister, constant.VerificationCodeForH5Register: + if err := o.Admin.CheckRegister(ctx, req.Ip); err != nil { + return nil, err + } + if req.Email == "" { + if req.AreaCode == "" || req.PhoneNumber == "" { + return nil, errs.ErrArgs.WrapMsg("area code or phone number is empty") + } + if !strings.HasPrefix(req.AreaCode, "+") { + req.AreaCode = "+" + req.AreaCode + } + if _, err := strconv.ParseUint(req.AreaCode[1:], 10, 64); err != nil { + return nil, errs.ErrArgs.WrapMsg("area code must be number") + } + if _, err := strconv.ParseUint(req.PhoneNumber, 10, 64); err != nil { + return nil, errs.ErrArgs.WrapMsg("phone number must be number") + } + } else { + if err := chat.EmailCheck(req.Email); err != nil { + return nil, errs.ErrArgs.WrapMsg("email must be right") + } + } + conf, err := o.Admin.GetConfig(ctx) + if err != nil { + return nil, err + } + if val := conf[constant.NeedInvitationCodeRegisterConfigKey]; datautil.Contain(strings.ToLower(val), "1", "true", "yes") { + if req.InvitationCode == "" { + return nil, errs.ErrArgs.WrapMsg("invitation code is empty") + } + if err := o.Admin.CheckInvitationCode(ctx, req.InvitationCode); err != nil { + return nil, err + } + } + case constant.VerificationCodeForLogin, constant.VerificationCodeForResetPassword: + if req.Email == "" { + _, err := o.Database.TakeAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) + if dbutil.IsDBNotFound(err) { + return nil, eerrs.ErrAccountNotFound.WrapMsg("phone unregistered") + } else if err != nil { + return nil, err + } + } else { + _, err := o.Database.TakeAttributeByEmail(ctx, req.Email) + if dbutil.IsDBNotFound(err) { + return nil, eerrs.ErrAccountNotFound.WrapMsg("email unregistered") + } else if err != nil { + return nil, err + } + } + + default: + return nil, errs.ErrArgs.WrapMsg("used unknown") + } + + // 先尝试从数据库 SystemConfig 集合读取 SMS 配置 + var dbSMSClient sms.SMS + var dbSMSClientErr error + if req.AreaCode != "" { + // 先读取数据库配置(从 system_configs 集合) + dbSMSClient, dbSMSClientErr = o.getSMSClientFromDB(ctx) + if dbSMSClientErr != nil { + log.ZWarn(ctx, "Failed to get SMS client from SystemConfig collection", dbSMSClientErr) + } else if dbSMSClient != nil { + log.ZInfo(ctx, "Using SMS client from database config", "clientName", dbSMSClient.Name()) + } + } + + // 确定最终使用的 SMS 客户端:优先使用数据库配置,如果没有则使用 yml 配置 + var finalSMSClient sms.SMS + if dbSMSClient != nil { + finalSMSClient = dbSMSClient + } else { + finalSMSClient = o.SMS + if dbSMSClientErr != nil { + log.ZWarn(ctx, "Failed to get SMS client from DB, using yml config", dbSMSClientErr) + } + } + + // 检查最终是否有可用的 SMS 或 Mail 客户端 + if finalSMSClient == nil && o.Mail == nil { + log.ZInfo(ctx, "SMS and Mail clients are both nil, using superCode", + "areaCode", req.AreaCode, + "phoneNumber", req.PhoneNumber, + "email", req.Email, + "usedFor", req.UsedFor, + "superCode", o.Code.SuperCode, + "dbSMSAvailable", dbSMSClient != nil, + "ymlSMSAvailable", o.SMS != nil) + return &chat.SendVerifyCodeResp{}, nil // super code + } + + if req.Email != "" { + switch o.conf.Mail.Use { + case constant.VerifySuperCode: + log.ZInfo(ctx, "Using superCode for email verification, skip email sending", + "email", req.Email, + "usedFor", req.UsedFor, + "superCode", o.Code.SuperCode) + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.VerifyMail: + default: + return nil, errs.ErrInternalServer.WrapMsg("email verification code is not enabled") + } + } + + if req.AreaCode != "" { + // 如果数据库有配置,直接使用;否则检查 yml 配置 + if dbSMSClient == nil { + // 使用 yml 配置,检查配置类型 + switch o.conf.Phone.Use { + case constant.VerifySuperCode: + log.ZInfo(ctx, "Using superCode for phone verification, skip SMS sending", + "areaCode", req.AreaCode, + "phoneNumber", req.PhoneNumber, + "usedFor", req.UsedFor, + "superCode", o.Code.SuperCode) + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.VerifyALi, constant.VerifyBao: + default: + return nil, errs.ErrInternalServer.WrapMsg("phone verification code is not enabled") + } + } + } + + isEmail := req.Email != "" + var account string + var timeWindowKey string // 用于在发送成功后设置时间窗口标志(手机号注册场景) + + // 先创建 account,并检查时间窗口 + if isEmail { + account = req.Email + } else { + account = o.verifyCodeJoin(req.AreaCode, req.PhoneNumber) + + // 对于手机号注册场景,先检查时间窗口(60秒内只能发送一次) + // 同一个号码在短时间内只能发送一次,不管请求几次 + if int(req.UsedFor) == constant.VerificationCodeForRegister || int(req.UsedFor) == constant.VerificationCodeForH5Register { + timeWindowKey = "verify_code_sent_window:" + account + timeWindow := 60 * time.Second // 60秒时间窗口 + + if o.rdb != nil { + // 检查是否在时间窗口内已经发送过 + exists, err := o.rdb.Exists(ctx, timeWindowKey).Result() + if err == nil && exists > 0 { + log.ZWarn(ctx, "Verify code already sent within time window for this account", nil, + "account", account, "timeWindow", timeWindow) + return nil, eerrs.ErrVerifyCodeSendFrequently.Wrap() + } + + // 获取分布式锁,防止并发请求 + lockKey := "send_verify_code_lock:" + account + lockValue := uuid.New().String() + lockTTL := 10 * time.Second + + acquired, err := o.rdb.SetNX(ctx, lockKey, lockValue, lockTTL).Result() + if err != nil { + log.ZWarn(ctx, "Failed to acquire distributed lock for send verify code", err, "account", account) + } else if !acquired { + log.ZWarn(ctx, "Another request is sending verify code for this account", nil, "account", account) + return nil, eerrs.ErrVerifyCodeSendFrequently.Wrap() + } else { + // 成功获取锁,确保在函数返回时释放锁 + defer func() { + script := ` + if redis.call("get", KEYS[1]) == ARGV[1] then + return redis.call("del", KEYS[1]) + else + return 0 + end + ` + if err := o.rdb.Eval(ctx, script, []string{lockKey}, lockValue).Err(); err != nil { + log.ZWarn(ctx, "Failed to release distributed lock for send verify code", err, "account", account) + } + }() + + // 再次检查时间窗口(双重检查,防止在获取锁的过程中其他请求已经发送) + exists, err = o.rdb.Exists(ctx, timeWindowKey).Result() + if err == nil && exists > 0 { + log.ZWarn(ctx, "Verify code already sent within time window (double check)", nil, + "account", account, "timeWindow", timeWindow) + return nil, eerrs.ErrVerifyCodeSendFrequently.Wrap() + } + } + } + } + } + + // 在获取锁之后才生成验证码,确保同一账号只有一个请求能生成验证码 + var ( + code = o.genVerifyCode() + sendCode func() error + ) + + if isEmail { + sendCode = func() error { + log.ZInfo(ctx, "Send email verify code request", "email", req.Email, "code", code, "usedFor", req.UsedFor) + err := o.Mail.SendMail(ctx, req.Email, code) + if err != nil { + log.ZError(ctx, "Send email verify code failed", err, "email", req.Email, "code", code) + } else { + log.ZInfo(ctx, "Send email verify code success", "email", req.Email, "code", code) + } + return err + } + } else { + // 使用之前从数据库读取的 SMS 客户端,如果没有则使用 yml 配置 + smsClient := finalSMSClient + smsClientType := "yml" + configSource := "yml" + + if dbSMSClient != nil { + // 使用数据库配置 + smsClientType = "database" + configSource = "database" + } else { + // 使用 yml 配置 + smsClient = o.SMS + } + + if smsClient == nil { + return nil, errs.ErrInternalServer.WrapMsg("SMS client is not available") + } + + // 记录使用的 SMS 客户端类型和配置来源 + clientName := smsClient.Name() + log.ZInfo(ctx, "Send SMS verify code request", + "areaCode", req.AreaCode, + "phoneNumber", req.PhoneNumber, + "code", code, + "usedFor", req.UsedFor, + "configSource", configSource, + "smsClientType", smsClientType, + "smsClientName", clientName) + + sendCode = func() error { + err := smsClient.SendCode(ctx, req.AreaCode, req.PhoneNumber, code) + if err != nil { + log.ZError(ctx, "Send SMS verify code failed", err, + "areaCode", req.AreaCode, + "phoneNumber", req.PhoneNumber, + "code", code, + "configSource", configSource, + "smsClientType", smsClientType, + "smsClientName", clientName) + } else { + log.ZInfo(ctx, "Send SMS verify code success", + "areaCode", req.AreaCode, + "phoneNumber", req.PhoneNumber, + "code", code, + "configSource", configSource, + "smsClientType", smsClientType, + "smsClientName", clientName) + } + return err + } + } + + now := time.Now() + count, err := o.Database.CountVerifyCodeRange(ctx, account, now.Add(-o.Code.UintTime), now) + if err != nil { + return nil, err + } + if o.Code.MaxCount < int(count) { + return nil, eerrs.ErrVerifyCodeSendFrequently.Wrap() + } + platformName := constantpb.PlatformIDToName(int(req.Platform)) + if platformName == "" { + platformName = fmt.Sprintf("platform:%d", req.Platform) + } + + // 使用 Redis 标志确保短信只发送一次,即使事务重试也不会重复 + sentFlagKey := "verify_code_sent:" + account + ":" + code + var smsSent bool + if o.rdb != nil { + // 检查是否已经发送过 + exists, _ := o.rdb.Exists(ctx, sentFlagKey).Result() + if exists > 0 { + log.ZInfo(ctx, "Verify code already sent, skipping send", "account", account, "code", code) + smsSent = true + } + } + + // 创建 sendCode 包装函数,确保只发送一次 + var sendCodeOnce func() error + if smsSent { + // 已经发送过,直接返回成功 + sendCodeOnce = func() error { return nil } + } else { + // 使用 sync.Once 确保即使事务重试也只发送一次 + // 注意:sync.Once 必须在外部作用域,不能在闭包内创建 + var sendOnce sync.Once + var sendErr error + sendCodeOnce = func() error { + sendOnce.Do(func() { + sendErr = sendCode() + // 发送成功后,设置 Redis 标志和时间窗口标志 + if sendErr == nil && o.rdb != nil { + _ = o.rdb.Set(ctx, sentFlagKey, "1", 5*time.Minute).Err() + // 设置时间窗口标志(60秒内不允许再次发送) + if timeWindowKey != "" { + _ = o.rdb.Set(ctx, timeWindowKey, "1", 60*time.Second).Err() + } + } + }) + return sendErr + } + } + + vc := &chatdb.VerifyCode{ + Account: account, + Code: code, + Platform: platformName, + Duration: uint(o.Code.ValidTime / time.Second), + Count: 0, + Used: false, + CreateTime: now, + } + if err := o.Database.AddVerifyCode(ctx, vc, sendCodeOnce); err != nil { + log.ZError(ctx, "Failed to add verify code to database or send code", err, + "account", account) + return nil, err + } + + // H5注册时,缓存手机号到Redis + if int(req.UsedFor) == constant.VerificationCodeForH5Register && req.PhoneNumber != "" { + // 构建完整手机号(包含区号) + fullPhone := o.verifyCodeJoin(req.AreaCode, req.PhoneNumber) + // 生成一个唯一ID用于关联验证码和手机号 + phoneKey := "h5_register_phone:" + account + // 缓存手机号,过期时间与验证码相同(5分钟) + if err := o.storePhoneToRedis(ctx, phoneKey, fullPhone); err != nil { + log.ZError(ctx, "store phone to redis failed", err, "phoneKey", phoneKey) + // 不阻断流程,只记录日志 + } + } + + return &chat.SendVerifyCodeResp{}, nil +} + +func (o *chatSvr) verifyCode(ctx context.Context, account string, verifyCode string, type_ verifyType) (string, error) { + if verifyCode == "" { + return "", errs.ErrArgs.WrapMsg("verify code is empty") + } + + // 先检查数据库中的 sms_type 配置 + // 如果 sms_type 为 true,说明使用的是数据库配置发送的真实验证码,应该直接验证数据库中的验证码 + usePlainText, err := o.checkSMSTypeFromDB(ctx) + if err != nil { + log.ZWarn(ctx, "Failed to check sms_type from DB in verifyCode, will check yml config", err) + usePlainText = false + } + + // 如果 sms_type 为 true,跳过 yml 配置检查,直接去数据库验证验证码 + if !usePlainText { + // sms_type 为 false 或不存在,检查 yml 配置 + switch type_ { + case phone: + switch o.conf.Phone.Use { + case constant.VerifySuperCode: + log.ZInfo(ctx, "Using superCode for phone verification", + "superCode", o.Code.SuperCode, + "inputCode", verifyCode) + if o.Code.SuperCode != verifyCode { + log.ZError(ctx, "SuperCode verification failed", nil, + "superCode", o.Code.SuperCode, + "inputCode", verifyCode, + "match", false) + return "", eerrs.ErrVerifyCodeNotMatch.Wrap() + } + log.ZInfo(ctx, "SuperCode verification success") + return "", nil + case constant.VerifyALi, constant.VerifyBao: + default: + return "", errs.ErrInternalServer.WrapMsg("phone verification code is not enabled", "use", o.conf.Phone.Use) + } + case mail: + switch o.conf.Mail.Use { + case constant.VerifySuperCode: + log.ZInfo(ctx, "Using superCode for email verification", + "superCode", o.Code.SuperCode, + "inputCode", verifyCode) + if o.Code.SuperCode != verifyCode { + log.ZError(ctx, "SuperCode verification failed", nil, + "superCode", o.Code.SuperCode, + "inputCode", verifyCode, + "match", false) + return "", eerrs.ErrVerifyCodeNotMatch.Wrap() + } + log.ZInfo(ctx, "SuperCode verification success") + return "", nil + case constant.VerifyMail: + default: + return "", errs.ErrInternalServer.WrapMsg("email verification code is not enabled") + } + } + } + + last, err := o.Database.TakeLastVerifyCode(ctx, account) + if err != nil { + if dbutil.IsDBNotFound(err) { + log.ZError(ctx, "Verify code not found in database", err, + "account", account) + return "", eerrs.ErrVerifyCodeExpired.Wrap() + } + log.ZError(ctx, "Failed to get verify code from database", err, + "account", account) + return "", err + } + + if last.CreateTime.Unix()+int64(last.Duration) < time.Now().Unix() { + log.ZError(ctx, "Verify code expired", nil, + "account", account, + "createTime", last.CreateTime.Unix(), + "duration", last.Duration, + "currentTime", time.Now().Unix(), + "expiredTime", last.CreateTime.Unix()+int64(last.Duration)) + return last.ID, eerrs.ErrVerifyCodeExpired.Wrap() + } + if last.Used { + log.ZError(ctx, "Verify code already used", nil, + "account", account, + "codeID", last.ID) + return last.ID, eerrs.ErrVerifyCodeUsed.Wrap() + } + if n := o.Code.ValidCount; n > 0 { + if last.Count >= n { + log.ZError(ctx, "Verify code max count exceeded", nil, + "account", account, + "count", last.Count, + "maxCount", n) + return last.ID, eerrs.ErrVerifyCodeMaxCount.Wrap() + } + if last.Code != verifyCode { + log.ZWarn(ctx, "Verify code mismatch, incrementing count", nil, + "account", account, + "storedCode", last.Code, + "inputCode", verifyCode, + "currentCount", last.Count) + if err := o.Database.UpdateVerifyCodeIncrCount(ctx, last.ID); err != nil { + return last.ID, err + } + } + } + + // 比较验证码 + if last.Code != verifyCode { + log.ZError(ctx, "Verify code not match", nil, + "account", account, + "storedCode", last.Code, + "inputCode", verifyCode) + return last.ID, eerrs.ErrVerifyCodeNotMatch.Wrap() + } + return last.ID, nil +} + +// verifyCodeByAccount 使用account作为key验证验证码(用于account注册场景) +func (o *chatSvr) verifyCodeByAccount(ctx context.Context, account string, verifyCode string) (string, error) { + if verifyCode == "" { + return "", errs.ErrArgs.WrapMsg("verify code is empty") + } + + // 检查超级验证码 + if o.Code.SuperCode != "" && o.Code.SuperCode == verifyCode { + log.ZInfo(ctx, "SuperCode verification success for account", + "account", account, + "superCode", o.Code.SuperCode) + return "", nil + } + + last, err := o.Database.TakeLastVerifyCode(ctx, account) + if err != nil { + if dbutil.IsDBNotFound(err) { + log.ZError(ctx, "Verify code not found in database for account", err, + "account", account) + return "", eerrs.ErrVerifyCodeExpired.Wrap() + } + log.ZError(ctx, "Failed to get verify code from database for account", err, + "account", account) + return "", err + } + + if last.CreateTime.Unix()+int64(last.Duration) < time.Now().Unix() { + log.ZError(ctx, "Verify code expired for account", nil, + "account", account, + "createTime", last.CreateTime.Unix(), + "duration", last.Duration, + "currentTime", time.Now().Unix()) + return last.ID, eerrs.ErrVerifyCodeExpired.Wrap() + } + if last.Used { + log.ZError(ctx, "Verify code already used for account", nil, + "account", account, + "codeID", last.ID) + return last.ID, eerrs.ErrVerifyCodeUsed.Wrap() + } + if n := o.Code.ValidCount; n > 0 { + if last.Count >= n { + log.ZError(ctx, "Verify code max count exceeded for account", nil, + "account", account, + "count", last.Count, + "maxCount", n) + return last.ID, eerrs.ErrVerifyCodeMaxCount.Wrap() + } + if last.Code != verifyCode { + log.ZWarn(ctx, "Verify code mismatch for account, incrementing count", nil, + "account", account, + "storedCode", last.Code, + "inputCode", verifyCode, + "currentCount", last.Count) + if err := o.Database.UpdateVerifyCodeIncrCount(ctx, last.ID); err != nil { + return last.ID, err + } + } + } + + // 比较验证码 + if last.Code != verifyCode { + log.ZError(ctx, "Verify code not match for account", nil, + "account", account, + "storedCode", last.Code, + "inputCode", verifyCode) + return last.ID, eerrs.ErrVerifyCodeNotMatch.Wrap() + } + return last.ID, nil +} + +func (o *chatSvr) VerifyCode(ctx context.Context, req *chat.VerifyCodeReq) (*chat.VerifyCodeResp, error) { + var verifyCode string + + // 如果提供了captchaID,则是图片验证码验证 + if req.CaptchaID != "" { + // 从Redis获取图片验证码 + storedCode, err := o.getCaptchaFromRedis(ctx, req.CaptchaID) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("验证码已过期或不存在,请重新获取") + } + + // 比较验证码 + if storedCode != req.VerifyCode { + return nil, eerrs.ErrVerifyCodeNotMatch.Wrap() + } + + // 验证成功,删除Redis中的验证码(一次性使用) + if err := o.delCaptchaFromRedis(ctx, req.CaptchaID); err != nil { + log.ZWarn(ctx, "delete captcha from redis failed", err, "captchaID", req.CaptchaID) + } + + // 如果是H5注册场景(提供了手机号),生成registerToken + if req.PhoneNumber != "" { + // 从Redis获取之前缓存的手机号 + account := o.verifyCodeJoin(req.AreaCode, req.PhoneNumber) + phoneKey := "h5_register_phone:" + account + cachedPhone, err := o.getPhoneFromRedis(ctx, phoneKey) + if err != nil { + // 如果Redis中没有,使用请求中的手机号 + cachedPhone = account + } + + // 生成registerToken + registerToken := uuid.New().String() + + // 加密手机号并存储到Redis(token -> 加密手机号),有效期120秒 + encryptedPhone, err := util.EncryptPhone(cachedPhone) + if err != nil { + log.ZError(ctx, "encrypt phone failed", err, "phone", cachedPhone) + // 如果加密失败,直接存储明文(不推荐,但保证流程继续) + if err := o.storeRegisterTokenToRedis(ctx, registerToken, cachedPhone); err != nil { + log.ZError(ctx, "store register token failed", err, "token", registerToken) + } + } else { + // 存储加密后的手机号 + if err := o.storeRegisterTokenToRedis(ctx, registerToken, encryptedPhone); err != nil { + log.ZError(ctx, "store register token failed", err, "token", registerToken) + } + } + + // 返回registerToken + return &chat.VerifyCodeResp{ + RegisterToken: registerToken, + }, nil + } + + // 图片验证码验证成功(非H5注册场景) + return &chat.VerifyCodeResp{}, nil + } + + // 否则是短信/邮件验证码验证 + // 根据数据库中的 sms_type 配置决定验证码格式 + // 检查数据库中的 sms_type 配置 + usePlainText, err := o.checkSMSTypeFromDB(ctx) + if err != nil { + log.ZWarn(ctx, "Failed to check sms_type from DB, will try decrypt", err) + // 如果查询失败,默认尝试解密(保持原有逻辑) + usePlainText = false + } + + if usePlainText { + // sms_type 为 true,使用明文验证码 + verifyCode = req.VerifyCode + } else { + // sms_type 为 false 或不存在,需要解密验证码(base64解码) + decryptedCode, err := util.DecryptVerifyCode(req.VerifyCode) + if err != nil { + log.ZError(ctx, "Failed to decrypt verify code", err) + return nil, errs.ErrArgs.WrapMsg("验证码解密失败", "error", err.Error()) + } + + // 解析验证码和时间戳(格式:验证码-时间戳) + code, timestamp, err := util.ParseVerifyCodeWithTimestamp(decryptedCode) + if err != nil { + log.ZError(ctx, "Failed to parse verify code with timestamp", err) + return nil, errs.ErrArgs.WrapMsg("解析验证码失败", "error", err.Error()) + } + + // 验证时间戳(必须在1分钟内) + if !util.ValidateTimestamp(timestamp, 30) { + return nil, errs.ErrArgs.WrapMsg("验证码已过期,请重新获取") + } + + // 使用解析出的验证码 + verifyCode = code + } + + var account string + if req.Account != "" { + // 使用account进行验证(注册场景) + account = req.Account + + // 检查账号是否已存在(注册场景不允许使用已存在的账号) + _, err := o.Database.TakeAttributeByAccount(ctx, account) + if err == nil { + // 账号已存在,返回错误告知 + return nil, eerrs.ErrAccountAlreadyRegister.WrapMsg("该账号已被注册,请使用其他账号") + } else if !dbutil.IsDBNotFound(err) { + // 数据库查询出错 + return nil, err + } + + // 对于account,我们需要查找验证码,但verifyCode函数只支持phone和mail + // 这里我们直接使用account作为key查找验证码 + if _, err := o.verifyCodeByAccount(ctx, account, verifyCode); err != nil { + return nil, err + } + + // 验证成功,生成registerToken用于注册 + registerToken := uuid.New().String() + + // 加密account并存储到Redis(token -> 加密account),有效期120秒 + encryptedAccount, err := util.EncryptPhone(account) // 复用EncryptPhone函数,它实际是AES加密 + if err != nil { + log.ZError(ctx, "encrypt account failed", err, "account", account) + // 如果加密失败,直接存储明文(不推荐,但保证流程继续) + if err := o.storeRegisterTokenToRedis(ctx, registerToken, account); err != nil { + log.ZError(ctx, "store register token failed", err, "token", registerToken) + } + } else { + // 存储加密后的account + if err := o.storeRegisterTokenToRedis(ctx, registerToken, encryptedAccount); err != nil { + log.ZError(ctx, "store register token failed", err, "token", registerToken) + } + } + + // 返回registerToken + return &chat.VerifyCodeResp{ + RegisterToken: registerToken, + }, nil + } else if req.PhoneNumber != "" { + account = o.verifyCodeJoin(req.AreaCode, req.PhoneNumber) + if _, err := o.verifyCode(ctx, account, verifyCode, phone); err != nil { + return nil, err + } + } else { + account = req.Email + if _, err := o.verifyCode(ctx, account, verifyCode, mail); err != nil { + return nil, err + } + } + + return &chat.VerifyCodeResp{}, nil +} + +func (o *chatSvr) genUserID() string { + const l = 10 + data := make([]byte, l) + rand.Read(data) + chars := []byte("0123456789") + for i := 0; i < len(data); i++ { + if i == 0 { + data[i] = chars[1:][data[i]%9] + } else { + data[i] = chars[data[i]%10] + } + } + return string(data) +} + +func (o *chatSvr) genVerifyCode() string { + data := make([]byte, o.Code.Len) + rand.Read(data) + chars := []byte("0123456789") + for i := 0; i < len(data); i++ { + data[i] = chars[data[i]%10] + } + return string(data) +} + +func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) (*chat.RegisterUserResp, error) { + isAdmin, err := o.Admin.CheckNilOrAdmin(ctx) + ctx = o.WithAdminUser(ctx) + if err != nil { + return nil, err + } + if err = o.checkRegisterInfo(ctx, req.User, isAdmin); err != nil { + return nil, err + } + var usedInvitationCode bool + if !isAdmin { + if !o.AllowRegister { + return nil, errs.ErrNoPermission.WrapMsg("register user is disabled") + } + if req.User.UserID != "" { + return nil, errs.ErrNoPermission.WrapMsg("only admin can set user id") + } + if err := o.Admin.CheckRegister(ctx, req.Ip); err != nil { + return nil, err + } + conf, err := o.Admin.GetConfig(ctx) + if err != nil { + return nil, err + } + if val := conf[constant.NeedInvitationCodeRegisterConfigKey]; datautil.Contain(strings.ToLower(val), "1", "true", "yes") { + usedInvitationCode = true + if req.InvitationCode == "" { + return nil, errs.ErrArgs.WrapMsg("invitation code is empty") + } + if err := o.Admin.CheckInvitationCode(ctx, req.InvitationCode); err != nil { + return nil, err + } + } + + // 如果提供了registerToken(H5注册场景或account注册场景),验证token + if req.RegisterToken != "" { + // 从Redis获取token关联的数据(可能是手机号或account) + tokenData, err := o.getRegisterTokenFromRedis(ctx, req.RegisterToken) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("registerToken已失效,请重新验证") + } + + // 尝试解密(可能是加密存储的) + var tokenDataDecrypted string + decryptedData, err := util.DecryptPhone(tokenData) + if err != nil { + // 如果解密失败,可能是明文存储的(兼容旧数据) + tokenDataDecrypted = tokenData + } else { + tokenDataDecrypted = decryptedData + } + + // 判断是account注册还是手机号注册 + if req.User.Account != "" { + // account注册场景 + if tokenDataDecrypted != req.User.Account { + return nil, errs.ErrArgs.WrapMsg("账号不匹配,请重新验证") + } + } else if req.User.PhoneNumber != "" { + // 手机号注册场景 + // 构建请求中的完整手机号 + account := o.verifyCodeJoin(req.User.AreaCode, req.User.PhoneNumber) + if tokenDataDecrypted != account { + return nil, errs.ErrArgs.WrapMsg("手机号不匹配,请重新验证") + } + } else { + return nil, errs.ErrArgs.WrapMsg("registerToken需要配合账号或手机号使用") + } + + // 验证成功,删除token(一次性使用) + if err := o.delRegisterTokenFromRedis(ctx, req.RegisterToken); err != nil { + log.ZWarn(ctx, "delete register token failed", err, "token", req.RegisterToken) + } + + // 已通过token验证,不需要验证短信验证码 + } else { + // 普通注册场景,验证短信/邮件验证码 + // 根据数据库中的 sms_type 配置决定验证码格式 + // 检查数据库中的 sms_type 配置 + usePlainText, err := o.checkSMSTypeFromDB(ctx) + if err != nil { + log.ZWarn(ctx, "Failed to check sms_type from DB for register, will try decrypt", err) + // 如果查询失败,默认尝试解密(保持原有逻辑) + usePlainText = false + } + + var verifyCode string + if usePlainText { + // sms_type 为 true,使用明文验证码 + verifyCode = req.VerifyCode + } else { + // sms_type 为 false 或不存在,需要解密验证码(base64解码) + decryptedCode, err := util.DecryptVerifyCode(req.VerifyCode) + if err != nil { + log.ZError(ctx, "Failed to decrypt verify code for register", err) + return nil, errs.ErrArgs.WrapMsg("验证码解密失败", "error", err.Error()) + } + + // 解析验证码和时间戳(格式:验证码-时间戳) + code, timestamp, err := util.ParseVerifyCodeWithTimestamp(decryptedCode) + if err != nil { + log.ZError(ctx, "Failed to parse verify code with timestamp for register", err) + return nil, errs.ErrArgs.WrapMsg("解析验证码失败", "error", err.Error()) + } + + // 验证时间戳(必须在1分钟内) + if !util.ValidateTimestamp(timestamp, 30) { + return nil, errs.ErrArgs.WrapMsg("验证码已过期,请重新获取") + } + + // 使用解析出的验证码 + verifyCode = code + } + + if req.User.Email == "" { + if _, err := o.verifyCode(ctx, o.verifyCodeJoin(req.User.AreaCode, req.User.PhoneNumber), verifyCode, phone); err != nil { + return nil, err + } + } else { + if _, err := o.verifyCode(ctx, req.User.Email, verifyCode, mail); err != nil { + return nil, err + } + } + } + } + if req.User.UserID == "" { + for i := 0; i < 20; i++ { + userID := o.genUserID() + _, err := o.Database.GetUser(ctx, userID) + if err == nil { + continue + } else if dbutil.IsDBNotFound(err) { + req.User.UserID = userID + break + } else { + return nil, err + } + } + if req.User.UserID == "" { + return nil, errs.ErrInternalServer.WrapMsg("gen user id failed") + } + } else { + _, err := o.Database.GetUser(ctx, req.User.UserID) + if err == nil { + return nil, errs.ErrArgs.WrapMsg("appoint user id already register") + } else if !dbutil.IsDBNotFound(err) { + return nil, err + } + } + var ( + credentials []*chatdb.Credential + registerType int32 + ) + + if req.User.PhoneNumber != "" { + registerType = constant.PhoneRegister + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) + } + + if req.User.Account != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + registerType = constant.AccountRegister + } + + if req.User.Email != "" { + registerType = constant.EmailRegister + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) + } + register := &chatdb.Register{ + UserID: req.User.UserID, + DeviceID: req.DeviceID, + IP: req.Ip, + Platform: constantpb.PlatformID2Name[int(req.Platform)], + AccountType: "", + Mode: constant.UserMode, + CreateTime: time.Now(), + } + account := &chatdb.Account{ + UserID: req.User.UserID, + Password: req.User.Password, + OperatorUserID: mcontext.GetOpUserID(ctx), + ChangeTime: register.CreateTime, + CreateTime: register.CreateTime, + } + + attribute := &chatdb.Attribute{ + UserID: req.User.UserID, + Account: req.User.Account, + PhoneNumber: req.User.PhoneNumber, + AreaCode: req.User.AreaCode, + Email: req.User.Email, + Nickname: req.User.Nickname, + FaceURL: req.User.FaceURL, + Gender: req.User.Gender, + UserType: req.User.UserType, // 使用传入的用户类型,如果没有则默认为0 + UserFlag: req.User.UserFlag, // 使用传入的用户标签,如果没有则默认为空 + BirthTime: time.UnixMilli(req.User.Birth), + ChangeTime: register.CreateTime, + CreateTime: register.CreateTime, + AllowVibration: constant.DefaultAllowVibration, + AllowBeep: constant.DefaultAllowBeep, + AllowAddFriend: constant.DefaultAllowAddFriend, + RegisterType: registerType, + } + if err := o.Database.RegisterUser(ctx, register, account, attribute, credentials); err != nil { + return nil, err + } + if usedInvitationCode { + if err := o.Admin.UseInvitationCode(ctx, req.User.UserID, req.InvitationCode); err != nil { + log.ZError(ctx, "UseInvitationCode", err, "userID", req.User.UserID, "invitationCode", req.InvitationCode) + } + } + + // 检查系统配置是否开启钱包功能 + walletConfig, err := o.Database.GetSystemConfig(ctx, "wallet.enabled") + if err == nil && walletConfig.Value == "true" { + // 为新注册用户创建默认钱包 + wallet := &chatdb.Wallet{ + UserID: req.User.UserID, + Balance: 0, + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + if err := o.Database.CreateWallet(ctx, wallet); err != nil { + log.ZError(ctx, "CreateWallet failed on register", err, "userID", req.User.UserID) + // 不影响注册流程,只记录错误 + } else { + log.ZInfo(ctx, "Auto created wallet for user on register", "userID", req.User.UserID) + } + } + + // 查询注册奖励配置,如果启用则给用户钱包赠送金额 + o.handleRegisterReward(ctx, req.User.UserID) + + var resp chat.RegisterUserResp + if req.AutoLogin { + chatToken, err := o.Admin.CreateToken(ctx, req.User.UserID, constant.NormalUser) + if err == nil { + resp.ChatToken = chatToken.Token + } else { + log.ZError(ctx, "Admin CreateToken Failed", err, "userID", req.User.UserID, "platform", req.Platform) + } + + // 注册成功后自动登录时,创建登录记录 + record := &chatdb.UserLoginRecord{ + UserID: req.User.UserID, + LoginTime: time.Now(), + IP: req.Ip, + DeviceID: req.DeviceID, + Platform: constantpb.PlatformID2Name[int(req.Platform)], + } + if err := o.Database.LoginRecord(ctx, record, nil); err != nil { + log.ZError(ctx, "LoginRecord failed on register auto login", err, "userID", req.User.UserID) + // 不影响注册流程,只记录错误 + } else { + log.ZInfo(ctx, "Created login record on register auto login", "userID", req.User.UserID, "ip", req.Ip) + } + } + resp.UserID = req.User.UserID + return &resp, nil +} + +func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginResp, error) { + resp := &chat.LoginResp{} + if req.Password == "" && req.VerifyCode == "" { + return nil, errs.ErrArgs.WrapMsg("password or code must be set") + } + var ( + err error + credential *chatdb.Credential + acc string + ) + + switch { + case req.Account != "": + acc = req.Account + case req.PhoneNumber != "": + if req.AreaCode == "" { + return nil, errs.ErrArgs.WrapMsg("area code must") + } + if !strings.HasPrefix(req.AreaCode, "+") { + req.AreaCode = "+" + req.AreaCode + } + if _, err := strconv.ParseUint(req.AreaCode[1:], 10, 64); err != nil { + return nil, errs.ErrArgs.WrapMsg("area code must be number") + } + acc = BuildCredentialPhone(req.AreaCode, req.PhoneNumber) + case req.Email != "": + acc = req.Email + default: + return nil, errs.ErrArgs.WrapMsg("account or phone number or email must be set") + } + + credential, err = o.Database.TakeCredentialByAccount(ctx, acc) + if err != nil { + if dbutil.IsDBNotFound(err) { + + return nil, eerrs.ErrAccountNotFound.WrapMsg("user unregistered") + } + + return nil, err + } + + if err := o.Admin.CheckLogin(ctx, credential.UserID, req.Ip); err != nil { + // 检查是否是账户被封禁的错误,确保错误码正确传递 + // 即使错误被包装,错误字符串中也会包含原始错误信息 + errStr := err.Error() + if strings.Contains(errStr, "20015") || strings.Contains(errStr, "AccountBlocked") || strings.Contains(errStr, "账户已被封禁") { + log.ZInfo(ctx, "Detected AccountBlocked error in CheckLogin, returning explicit error", "originalError", errStr) + return nil, eerrs.ErrAccountBlocked.WrapMsg("账户已被封禁") + } + return nil, err + } + var verifyCodeID *string + if req.Password == "" { + var ( + id string + ) + + if req.Email == "" { + account := o.verifyCodeJoin(req.AreaCode, req.PhoneNumber) + id, err = o.verifyCode(ctx, account, req.VerifyCode, phone) + if err != nil { + return nil, err + } + } else { + account := req.Email + id, err = o.verifyCode(ctx, account, req.VerifyCode, mail) + if err != nil { + return nil, err + } + } + + if id != "" { + verifyCodeID = &id + } + } else { + account, err := o.Database.TakeAccount(ctx, credential.UserID) + if err != nil { + + return nil, err + } + if account.Password != req.Password { + + return nil, eerrs.ErrPassword.Wrap() + } + + } + + chatToken, err := o.Admin.CreateToken(ctx, credential.UserID, constant.NormalUser) + if err != nil { + + return nil, err + } + + record := &chatdb.UserLoginRecord{ + UserID: credential.UserID, + LoginTime: time.Now(), + IP: req.Ip, + DeviceID: req.DeviceID, + Platform: constantpb.PlatformIDToName(int(req.Platform)), + } + + if err := o.Database.LoginRecord(ctx, record, verifyCodeID); err != nil { + log.ZError(ctx, "LoginRecord failed", err, "userID", credential.UserID) + return nil, err + } + + if verifyCodeID != nil { + if err := o.Database.DelVerifyCode(ctx, *verifyCodeID); err != nil { + log.ZError(ctx, "DelVerifyCode failed", err, "verifyCodeID", *verifyCodeID) + return nil, err + } + } + + // 检查系统配置是否开启钱包功能 + walletConfig, err := o.Database.GetSystemConfig(ctx, "wallet.enabled") + if err == nil && walletConfig.Value == "true" { + // 检查用户钱包是否存在 + _, err := o.Database.GetWallet(ctx, credential.UserID) + if err != nil { + if dbutil.IsDBNotFound(err) { + // 钱包不存在,创建默认钱包 + wallet := &chatdb.Wallet{ + UserID: credential.UserID, + Balance: 0, + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + if err := o.Database.CreateWallet(ctx, wallet); err != nil { + log.ZError(ctx, "CreateWallet failed", err, "userID", credential.UserID) + // 不影响登录流程,只记录错误 + } else { + log.ZInfo(ctx, "Auto created wallet for user on login", "userID", credential.UserID) + } + } else { + // 其他错误,只记录 + log.ZError(ctx, "GetWallet failed", err, "userID", credential.UserID) + } + } + } + + resp.UserID = credential.UserID + resp.ChatToken = chatToken.Token + return resp, nil +} + +func (o *chatSvr) GetCaptchaImage(ctx context.Context, req *chat.GetCaptchaImageReq) (*chat.GetCaptchaImageResp, error) { + // 生成6位随机数字验证码 + code := o.genVerifyCode() + + // 生成唯一的验证码ID + captchaID := uuid.New().String() + + // 将验证码存储到Redis,过期时间5分钟 + if err := o.storeCaptchaToRedis(ctx, captchaID, code); err != nil { + log.ZError(ctx, "store captcha to redis failed", err, "captchaID", captchaID) + return nil, err + } + + log.ZDebug(ctx, "generate captcha code success", "captchaID", captchaID) + + return &chat.GetCaptchaImageResp{ + CaptchaID: captchaID, + Code: code, + }, nil +} + +// storeCaptchaToRedis 将验证码存储到Redis,过期时间5分钟 +func (o *chatSvr) storeCaptchaToRedis(ctx context.Context, captchaID, code string) error { + if o.rdb == nil { + return errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "captcha:" + captchaID + return errs.Wrap(o.rdb.Set(ctx, key, code, 5*time.Minute).Err()) +} + +// storePhoneToRedis 将手机号存储到Redis,过期时间5分钟 +func (o *chatSvr) storePhoneToRedis(ctx context.Context, key, phoneNumber string) error { + if o.rdb == nil { + return errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + return errs.Wrap(o.rdb.Set(ctx, key, phoneNumber, 5*time.Minute).Err()) +} + +// getCaptchaFromRedis 从Redis获取图片验证码 +func (o *chatSvr) getCaptchaFromRedis(ctx context.Context, captchaID string) (string, error) { + if o.rdb == nil { + return "", errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "captcha:" + captchaID + code, err := o.rdb.Get(ctx, key).Result() + if err != nil { + return "", errs.WrapMsg(err, "验证码不存在或已过期") + } + return code, nil +} + +// delCaptchaFromRedis 从Redis删除图片验证码 +func (o *chatSvr) delCaptchaFromRedis(ctx context.Context, captchaID string) error { + if o.rdb == nil { + return errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "captcha:" + captchaID + return errs.Wrap(o.rdb.Del(ctx, key).Err()) +} + +// getPhoneFromRedis 从Redis获取手机号 +func (o *chatSvr) getPhoneFromRedis(ctx context.Context, key string) (string, error) { + if o.rdb == nil { + return "", errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + phone, err := o.rdb.Get(ctx, key).Result() + if err != nil { + return "", errs.WrapMsg(err, "手机号不存在或已过期") + } + return phone, nil +} + +// storeRegisterTokenToRedis 将注册token存储到Redis,关联手机号,有效期120秒 +func (o *chatSvr) storeRegisterTokenToRedis(ctx context.Context, token, phoneNumber string) error { + if o.rdb == nil { + return errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "h5_register_token:" + token + return errs.Wrap(o.rdb.Set(ctx, key, phoneNumber, 120*time.Second).Err()) +} + +// getRegisterTokenFromRedis 从Redis获取注册token关联的手机号 +func (o *chatSvr) getRegisterTokenFromRedis(ctx context.Context, token string) (string, error) { + if o.rdb == nil { + return "", errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "h5_register_token:" + token + phone, err := o.rdb.Get(ctx, key).Result() + if err != nil { + return "", errs.WrapMsg(err, "token不存在或已过期") + } + return phone, nil +} + +// delRegisterTokenFromRedis 从Redis删除注册token(一次性使用) +func (o *chatSvr) delRegisterTokenFromRedis(ctx context.Context, token string) error { + if o.rdb == nil { + return errs.ErrInternalServer.WrapMsg("redis client not initialized") + } + key := "h5_register_token:" + token + return errs.Wrap(o.rdb.Del(ctx, key).Err()) +} + +// handleRegisterReward 处理注册奖励:查询系统配置,如果启用则给用户钱包赠送金额 +func (o *chatSvr) handleRegisterReward(ctx context.Context, userID string) { + // 查询系统配置 key="register" + config, err := o.Database.GetSystemConfig(ctx, "register") + if err != nil { + // 配置不存在或查询失败,记录日志但不影响注册流程 + if dbutil.IsDBNotFound(err) { + log.ZDebug(ctx, "Register reward config not found", "key", "register") + } else { + log.ZWarn(ctx, "Get register reward config failed", err, "key", "register", "userID", userID) + } + return + } + + // 检查配置是否启用 + if !config.Enabled { + log.ZDebug(ctx, "Register reward config is disabled", "key", "register", "userID", userID) + return + } + + // 解析配置值中的金额 + var amount int64 + switch config.ValueType { + case chatdb.ConfigValueTypeNumber: + // 数字类型:直接解析为整数(单位:分) + amountFloat, err := strconv.ParseFloat(config.Value, 64) + if err != nil { + log.ZWarn(ctx, "Parse register reward amount failed", err, "value", config.Value, "valueType", config.ValueType, "userID", userID) + return + } + amount = int64(amountFloat) + log.ZDebug(ctx, "Parsed register reward amount from number type", "value", config.Value, "amount", amount, "userID", userID) + case chatdb.ConfigValueTypeString: + // 字符串类型:尝试解析为数字 + amountFloat, err := strconv.ParseFloat(config.Value, 64) + if err != nil { + log.ZWarn(ctx, "Parse register reward amount from string failed", err, "value", config.Value, "valueType", config.ValueType, "userID", userID) + return + } + amount = int64(amountFloat) + log.ZDebug(ctx, "Parsed register reward amount from string type", "value", config.Value, "amount", amount, "userID", userID) + default: + log.ZWarn(ctx, "Register reward config value type not supported", nil, "valueType", config.ValueType, "userID", userID) + return + } + + // 金额必须大于0 + if amount <= 0 { + log.ZDebug(ctx, "Register reward amount is zero or negative", "amount", amount, "userID", userID) + return + } + + // 给用户钱包充值 + beforeBalance, afterBalance, err := o.Database.IncrementWalletBalance(ctx, userID, amount) + if err != nil { + log.ZError(ctx, "Increment wallet balance for register reward failed", err, "userID", userID, "amount", amount) + return + } + + // 创建余额变动记录 + record := &chatdb.WalletBalanceRecord{ + ID: uuid.New().String(), + UserID: userID, + Amount: amount, + Type: 5, // 5-奖励 + BeforeBalance: beforeBalance, + AfterBalance: afterBalance, + Remark: "注册奖励", + CreateTime: time.Now(), + } + if err := o.Database.CreateWalletBalanceRecord(ctx, record); err != nil { + // 记录创建失败不影响充值,只记录警告日志 + log.ZWarn(ctx, "Create wallet balance record for register reward failed", err, "userID", userID, "amount", amount) + } else { + log.ZInfo(ctx, "Register reward granted successfully", "userID", userID, "amount", amount, "beforeBalance", beforeBalance, "afterBalance", afterBalance) + } +} + +// checkSMSTypeFromDB 检查数据库中的 sms_type 配置 +// 返回: true 表示 sms_type 为 true(使用明文验证码),false 表示 sms_type 为 false 或不存在(需要解密) +func (o *chatSvr) checkSMSTypeFromDB(ctx context.Context) (bool, error) { + // 从 SystemConfig 集合(system_configs)中读取 sms_type 配置 + smsTypeConfig, err := o.Database.GetSystemConfig(ctx, "sms_type") + if err != nil { + if dbutil.IsDBNotFound(err) { + // SystemConfig 集合中没有 sms_type 配置,返回 false(需要解密,保持原有逻辑) + return false, nil + } + // 从 SystemConfig 集合查询出错,返回错误 + return false, errs.WrapMsg(err, "failed to get sms_type config") + } + + // 检查 sms_type 的值 + var usePlainText bool + switch smsTypeConfig.ValueType { + case chatdb.ConfigValueTypeBool: + // 布尔类型:直接解析 + usePlainText = smsTypeConfig.Value == "true" || smsTypeConfig.Value == "1" + case chatdb.ConfigValueTypeString: + // 字符串类型:检查是否为 "true" 或 "1" + usePlainText = strings.ToLower(smsTypeConfig.Value) == "true" || smsTypeConfig.Value == "1" + case chatdb.ConfigValueTypeNumber: + // 数字类型:1 表示 true,0 表示 false + val, err := strconv.ParseInt(smsTypeConfig.Value, 10, 64) + if err == nil { + usePlainText = val != 0 + } else { + usePlainText = false + } + default: + // 其他类型,默认使用加密格式(false) + usePlainText = false + } + + return usePlainText, nil +} + +// getSMSClientFromDB 从数据库读取短信配置 +// 逻辑:先读数据库,如果数据库没有 sms_type 配置,返回 nil 使用 yml 配置 +// 如果数据库有 sms_type 且为 true,使用数据库中的 sms_info 配置创建 SMS 客户端 +// 如果数据库有 sms_type 但为 false,返回 nil 使用 yml 配置 +func (o *chatSvr) getSMSClientFromDB(ctx context.Context) (sms.SMS, error) { + // 从 SystemConfig 集合(system_configs)中读取 sms_type 配置 + smsTypeConfig, err := o.Database.GetSystemConfig(ctx, "sms_type") + if err != nil { + if dbutil.IsDBNotFound(err) { + // SystemConfig 集合中没有 sms_type 配置,返回 nil 使用 yml 配置 + return nil, nil + } + // 从 SystemConfig 集合查询出错,返回错误 + log.ZError(ctx, "Failed to get sms_type config from SystemConfig collection", err) + return nil, errs.WrapMsg(err, "failed to get sms_type config") + } + + // 检查 sms_type 的值 + var useDBSMS bool + switch smsTypeConfig.ValueType { + case chatdb.ConfigValueTypeBool: + // 布尔类型:直接解析 + useDBSMS = smsTypeConfig.Value == "true" || smsTypeConfig.Value == "1" + case chatdb.ConfigValueTypeString: + // 字符串类型:检查是否为 "true" 或 "1" + useDBSMS = strings.ToLower(smsTypeConfig.Value) == "true" || smsTypeConfig.Value == "1" + case chatdb.ConfigValueTypeNumber: + // 数字类型:1 表示 true,0 表示 false + val, err := strconv.ParseInt(smsTypeConfig.Value, 10, 64) + if err == nil { + useDBSMS = val != 0 + } + default: + // 其他类型,默认不使用数据库配置 + return nil, nil + } + + // 如果 sms_type 为 false,返回 nil 使用 yml 配置 + if !useDBSMS { + return nil, nil + } + + // sms_type 为 true,从 SystemConfig 集合读取 sms_info 配置 + smsInfoConfig, err := o.Database.GetSystemConfig(ctx, "sms_info") + if err != nil { + if dbutil.IsDBNotFound(err) { + log.ZWarn(ctx, "sms_info config not found but sms_type is true, will use yml config", nil) + return nil, nil + } + log.ZError(ctx, "Failed to get sms_info config from SystemConfig collection", err) + return nil, errs.WrapMsg(err, "failed to get sms_info config") + } + + // 解析 sms_info JSON + type SMSInfo struct { + AccessKeyID string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` + Endpoint string `json:"endpoint"` + SignName string `json:"signName"` + Type string `json:"type"` + VerificationCodeTemplateCode string `json:"verificationCodeTemplateCode"` + } + + var smsInfo SMSInfo + if err := json.Unmarshal([]byte(smsInfoConfig.Value), &smsInfo); err != nil { + log.ZError(ctx, "Failed to parse sms_info JSON", err) + return nil, errs.WrapMsg(err, "failed to parse sms_info JSON") + } + + // 根据 type 字段创建对应的 SMS 客户端 + switch strings.ToLower(smsInfo.Type) { + case "bao": + client, err := sms.NewBao( + smsInfo.Endpoint, + smsInfo.AccessKeyID, + smsInfo.AccessKeySecret, + smsInfo.SignName, + smsInfo.VerificationCodeTemplateCode, + ) + if err != nil { + log.ZError(ctx, "Failed to create Bao SMS client from database config", err) + return nil, errs.WrapMsg(err, "failed to create Bao SMS client") + } + log.ZInfo(ctx, "Created Bao SMS client from database config") + return client, nil + case "ali": + client, err := sms.NewAli( + smsInfo.Endpoint, + smsInfo.AccessKeyID, + smsInfo.AccessKeySecret, + smsInfo.SignName, + smsInfo.VerificationCodeTemplateCode, + ) + if err != nil { + log.ZError(ctx, "Failed to create Ali SMS client from database config", err) + return nil, errs.WrapMsg(err, "failed to create Ali SMS client") + } + log.ZInfo(ctx, "Created Ali SMS client from database config") + return client, nil + default: + log.ZWarn(ctx, "Unknown SMS type in sms_info config, using default SMS client", nil, "type", smsInfo.Type) + return nil, nil + } +} diff --git a/internal/rpc/chat/password.go b/internal/rpc/chat/password.go new file mode 100644 index 0000000..9b04923 --- /dev/null +++ b/internal/rpc/chat/password.go @@ -0,0 +1,109 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +func (o *chatSvr) ResetPassword(ctx context.Context, req *chat.ResetPasswordReq) (*chat.ResetPasswordResp, error) { + if req.Password == "" { + return nil, errs.ErrArgs.WrapMsg("password must be set") + } + if req.AreaCode == "" || req.PhoneNumber == "" { + if !(req.AreaCode == "" && req.PhoneNumber == "") { + return nil, errs.ErrArgs.WrapMsg("area code and phone number must set together") + } + } + var verifyCodeID string + var err error + if req.Email == "" { + verifyCodeID, err = o.verifyCode(ctx, o.verifyCodeJoin(req.AreaCode, req.PhoneNumber), req.VerifyCode, phone) + } else { + verifyCodeID, err = o.verifyCode(ctx, req.Email, req.VerifyCode, mail) + } + + if err != nil { + return nil, err + } + var account string + if req.Email == "" { + account = BuildCredentialPhone(req.AreaCode, req.PhoneNumber) + } else { + account = req.Email + } + cred, err := o.Database.TakeCredentialByAccount(ctx, account) + if err != nil { + return nil, err + } + err = o.Database.UpdatePasswordAndDeleteVerifyCode(ctx, cred.UserID, req.Password, verifyCodeID) + if err != nil { + return nil, err + } + return &chat.ResetPasswordResp{}, nil +} + +func (o *chatSvr) ChangePassword(ctx context.Context, req *chat.ChangePasswordReq) (*chat.ChangePasswordResp, error) { + if req.NewPassword == "" { + return nil, errs.ErrArgs.WrapMsg("new password must be set") + } + if req.NewPassword == req.CurrentPassword { + return nil, errs.ErrArgs.WrapMsg("new password == current password") + } + opUserID, userType, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + switch userType { + case constant.NormalUser: + if req.UserID == "" { + req.UserID = opUserID + } + if req.UserID != opUserID { + return nil, errs.ErrNoPermission.WrapMsg("no permission change other user password") + } + case constant.AdminUser: + if req.UserID == "" { + return nil, errs.ErrArgs.WrapMsg("user id must be set") + } + default: + return nil, errs.ErrInternalServer.WrapMsg("invalid user type") + } + user, err := o.Database.GetUser(ctx, req.UserID) + if err != nil { + return nil, err + } + if userType != constant.AdminUser { + if user.Password != req.CurrentPassword { + return nil, errs.ErrNoPermission.WrapMsg("current password is wrong") + } + } + if user.Password != req.NewPassword { + if err := o.Database.UpdatePassword(ctx, req.UserID, req.NewPassword); err != nil { + return nil, err + } + } + if err := o.Admin.InvalidateToken(ctx, req.UserID); err != nil { + return nil, err + } + + return &chat.ChangePasswordResp{}, nil +} diff --git a/internal/rpc/chat/register.go b/internal/rpc/chat/register.go new file mode 100644 index 0000000..f98c365 --- /dev/null +++ b/internal/rpc/chat/register.go @@ -0,0 +1,16 @@ +package chat + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +func (o *chatSvr) SetAllowRegister(ctx context.Context, req *chat.SetAllowRegisterReq) (*chat.SetAllowRegisterResp, error) { + o.AllowRegister = req.AllowRegister + return &chat.SetAllowRegisterResp{}, nil +} + +func (o *chatSvr) GetAllowRegister(ctx context.Context, req *chat.GetAllowRegisterReq) (*chat.GetAllowRegisterResp, error) { + return &chat.GetAllowRegisterResp{AllowRegister: o.AllowRegister}, nil +} diff --git a/internal/rpc/chat/rtc.go b/internal/rpc/chat/rtc.go new file mode 100644 index 0000000..b252faf --- /dev/null +++ b/internal/rpc/chat/rtc.go @@ -0,0 +1,22 @@ +package chat + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +func (o *chatSvr) GetTokenForVideoMeeting(ctx context.Context, req *chat.GetTokenForVideoMeetingReq) (*chat.GetTokenForVideoMeetingResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + token, err := o.Livekit.GetLiveKitToken(req.Room, req.Identity) + if err != nil { + return nil, err + } + return &chat.GetTokenForVideoMeetingResp{ + ServerUrl: o.Livekit.GetLiveKitURL(), + Token: token, + }, err +} diff --git a/internal/rpc/chat/scheduled_task.go b/internal/rpc/chat/scheduled_task.go new file mode 100644 index 0000000..e3c9543 --- /dev/null +++ b/internal/rpc/chat/scheduled_task.go @@ -0,0 +1,288 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/errs" +) + +// ==================== 定时任务相关 RPC ==================== + +// CreateScheduledTask 创建定时任务 +func (o *chatSvr) CreateScheduledTask(ctx context.Context, req *chat.CreateScheduledTaskReq) (*chat.CreateScheduledTaskResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if req.Name == "" { + return nil, errs.ErrArgs.WrapMsg("task name is required") + } + if req.CronExpression == "" { + return nil, errs.ErrArgs.WrapMsg("cron expression is required") + } + if len(req.Messages) == 0 { + return nil, errs.ErrArgs.WrapMsg("messages is required") + } + if len(req.RecvIDs) == 0 && len(req.GroupIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("recvIDs or groupIDs is required") + } + + // 验证消息类型 + for _, msg := range req.Messages { + if msg.Type < 1 || msg.Type > 3 { + return nil, errs.ErrArgs.WrapMsg("invalid message type") + } + } + + // 转换消息列表 + messages := make([]chatdb.Message, 0, len(req.Messages)) + for _, msg := range req.Messages { + messages = append(messages, chatdb.Message{ + Type: msg.Type, + Content: msg.Content, + Thumbnail: msg.Thumbnail, + Duration: msg.Duration, + FileSize: msg.FileSize, + Width: msg.Width, + Height: msg.Height, + }) + } + + // 创建定时任务对象 + task := &chatdb.ScheduledTask{ + UserID: userID, + Name: req.Name, + CronExpression: req.CronExpression, + Messages: messages, + RecvIDs: req.RecvIDs, + GroupIDs: req.GroupIDs, + Status: req.Status, + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + + // 如果状态未设置,默认为启用 + if task.Status == 0 { + task.Status = 1 + } + + // 保存到数据库 + if err := o.Database.CreateScheduledTask(ctx, task); err != nil { + return nil, err + } + + return &chat.CreateScheduledTaskResp{ + TaskID: task.ID, + }, nil +} + +// GetScheduledTask 获取定时任务详情 +func (o *chatSvr) GetScheduledTask(ctx context.Context, req *chat.GetScheduledTaskReq) (*chat.GetScheduledTaskResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取任务 + task, err := o.Database.GetScheduledTask(ctx, req.TaskID) + if err != nil { + return nil, err + } + + // 验证是否为当前用户的任务 + if task.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your task") + } + + return &chat.GetScheduledTaskResp{ + Task: convertScheduledTaskToProto(task), + }, nil +} + +// GetScheduledTasks 获取定时任务列表 +func (o *chatSvr) GetScheduledTasks(ctx context.Context, req *chat.GetScheduledTasksReq) (*chat.GetScheduledTasksResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取任务列表 + total, tasks, err := o.Database.GetScheduledTasksByUserID(ctx, userID, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + taskInfos := make([]*chat.ScheduledTaskInfo, 0, len(tasks)) + for _, task := range tasks { + taskInfos = append(taskInfos, convertScheduledTaskToProto(task)) + } + + return &chat.GetScheduledTasksResp{ + Total: uint32(total), + Tasks: taskInfos, + }, nil +} + +// UpdateScheduledTask 更新定时任务 +func (o *chatSvr) UpdateScheduledTask(ctx context.Context, req *chat.UpdateScheduledTaskReq) (*chat.UpdateScheduledTaskResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取任务,验证所有权 + task, err := o.Database.GetScheduledTask(ctx, req.TaskID) + if err != nil { + return nil, err + } + + if task.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your task") + } + + // 构建更新数据 + updateData := make(map[string]any) + if req.Name != "" { + updateData["name"] = req.Name + } + if req.CronExpression != "" { + updateData["cron_expression"] = req.CronExpression + } + if len(req.Messages) > 0 { + // 验证消息类型 + for _, msg := range req.Messages { + if msg.Type < 1 || msg.Type > 3 { + return nil, errs.ErrArgs.WrapMsg("invalid message type") + } + } + // 转换消息列表 + messages := make([]chatdb.Message, 0, len(req.Messages)) + for _, msg := range req.Messages { + messages = append(messages, chatdb.Message{ + Type: msg.Type, + Content: msg.Content, + Thumbnail: msg.Thumbnail, + Duration: msg.Duration, + FileSize: msg.FileSize, + Width: msg.Width, + Height: msg.Height, + }) + } + updateData["messages"] = messages + } + if req.RecvIDs != nil { + updateData["recv_ids"] = req.RecvIDs + } + if req.GroupIDs != nil { + updateData["group_ids"] = req.GroupIDs + } + // status字段:0-已禁用,1-已启用,允许设置为0 + if req.Status == 0 || req.Status == 1 { + updateData["status"] = req.Status + } + + // 验证:如果更新后没有接收者,返回错误 + if req.RecvIDs != nil && req.GroupIDs != nil { + if len(req.RecvIDs) == 0 && len(req.GroupIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("recvIDs or groupIDs is required") + } + } else if req.RecvIDs != nil && len(req.RecvIDs) == 0 { + // 如果只更新了RecvIDs且为空,检查GroupIDs是否也为空 + if len(task.GroupIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("recvIDs or groupIDs is required") + } + } else if req.GroupIDs != nil && len(req.GroupIDs) == 0 { + // 如果只更新了GroupIDs且为空,检查RecvIDs是否也为空 + if len(task.RecvIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("recvIDs or groupIDs is required") + } + } + + // 更新任务 + if err := o.Database.UpdateScheduledTask(ctx, req.TaskID, updateData); err != nil { + return nil, err + } + + return &chat.UpdateScheduledTaskResp{}, nil +} + +// DeleteScheduledTask 删除定时任务 +func (o *chatSvr) DeleteScheduledTask(ctx context.Context, req *chat.DeleteScheduledTaskReq) (*chat.DeleteScheduledTaskResp, error) { + // 获取当前用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证所有权(批量验证) + for _, taskID := range req.TaskIDs { + task, err := o.Database.GetScheduledTask(ctx, taskID) + if err != nil { + return nil, err + } + if task.UserID != userID { + return nil, errs.ErrNoPermission.WrapMsg("not your task") + } + } + + // 删除任务 + if err := o.Database.DeleteScheduledTask(ctx, req.TaskIDs); err != nil { + return nil, err + } + + return &chat.DeleteScheduledTaskResp{}, nil +} + +// convertScheduledTaskToProto 将数据库模型转换为 protobuf 消息 +func convertScheduledTaskToProto(task *chatdb.ScheduledTask) *chat.ScheduledTaskInfo { + messages := make([]*chat.ScheduledTaskMessage, 0, len(task.Messages)) + for _, msg := range task.Messages { + messages = append(messages, &chat.ScheduledTaskMessage{ + Type: msg.Type, + Content: msg.Content, + Thumbnail: msg.Thumbnail, + Duration: msg.Duration, + FileSize: msg.FileSize, + Width: msg.Width, + Height: msg.Height, + }) + } + + return &chat.ScheduledTaskInfo{ + Id: task.ID, + UserID: task.UserID, + Name: task.Name, + CronExpression: task.CronExpression, + Messages: messages, + RecvIDs: task.RecvIDs, + GroupIDs: task.GroupIDs, + Status: task.Status, + CreateTime: task.CreateTime.UnixMilli(), + UpdateTime: task.UpdateTime.UnixMilli(), + } +} diff --git a/internal/rpc/chat/sensitive_word.go b/internal/rpc/chat/sensitive_word.go new file mode 100644 index 0000000..291905d --- /dev/null +++ b/internal/rpc/chat/sensitive_word.go @@ -0,0 +1,107 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "strings" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +// ==================== 敏感词检测相关 RPC ==================== + +// GetSensitiveWords 获取敏感词列表 +func (o *chatSvr) GetSensitiveWords(ctx context.Context, req *chat.GetSensitiveWordsReq) (*chat.GetSensitiveWordsResp, error) { + // 验证用户身份 + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + + // 获取启用的敏感词列表 + words, err := o.Database.GetSensitiveWords(ctx) + if err != nil { + return nil, err + } + + // 转换为响应格式(客户端只需要基本信息) + var wordInfos []*chat.SensitiveWordInfo + for _, word := range words { + wordInfos = append(wordInfos, &chat.SensitiveWordInfo{ + Word: word.Word, + Action: word.Action, + ReplaceChar: "", // 敏感词本身没有替换字符,使用配置中的默认值 + }) + } + + // 获取敏感词配置 + config, err := o.Database.GetSensitiveWordConfig(ctx) + if err != nil { + // 如果配置不存在,使用默认值 + config = &chatdb.SensitiveWordConfig{ + EnableFilter: true, + ReplaceChar: "***", + } + } + + return &chat.GetSensitiveWordsResp{ + Words: wordInfos, + EnableFilter: config.EnableFilter, + DefaultReplaceChar: config.ReplaceChar, + }, nil +} + +// CheckSensitiveWords 检测敏感词 +func (o *chatSvr) CheckSensitiveWords(ctx context.Context, req *chat.CheckSensitiveWordsReq) (*chat.CheckSensitiveWordsResp, error) { + // 验证用户身份 + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + + // 检测敏感词 + matchedWords, hasSensitive, err := o.Database.CheckSensitiveWords(ctx, req.Content) + if err != nil { + return nil, err + } + + // 如果检测到敏感词,进行内容过滤 + filteredContent := req.Content + var matchedWordStrings []string + + if hasSensitive { + for _, word := range matchedWords { + matchedWordStrings = append(matchedWordStrings, word.Word) + + // 根据处理动作进行替换 + if word.Action == 1 { // 替换模式 + // 获取配置中的替换字符 + config, err := o.Database.GetSensitiveWordConfig(ctx) + replaceChar := "***" + if err == nil && config.ReplaceChar != "" { + replaceChar = config.ReplaceChar + } + filteredContent = strings.ReplaceAll(filteredContent, word.Word, replaceChar) + } + } + } + + return &chat.CheckSensitiveWordsResp{ + HasSensitive: hasSensitive, + FilteredContent: filteredContent, + MatchedWords: matchedWordStrings, + }, nil +} diff --git a/internal/rpc/chat/sensitive_word_admin.go b/internal/rpc/chat/sensitive_word_admin.go new file mode 100644 index 0000000..beb7881 --- /dev/null +++ b/internal/rpc/chat/sensitive_word_admin.go @@ -0,0 +1,573 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "fmt" + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + chatpb "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/google/uuid" +) + +// ==================== 敏感词管理相关 RPC ==================== + +// AddSensitiveWord 添加敏感词 +func (o *chatSvr) AddSensitiveWord(ctx context.Context, req *chatpb.AddSensitiveWordReq) (*chatpb.AddSensitiveWordResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 创建敏感词对象 + word := &chat.SensitiveWord{ + ID: uuid.New().String(), + Word: req.Word, + Level: req.Level, + Type: req.Type, + Action: req.Action, + Status: req.Status, + Creator: getAdminUserID(ctx), + Updater: getAdminUserID(ctx), + CreateTime: time.Now(), + UpdateTime: time.Now(), + Remark: req.Remark, + } + + // 保存到数据库 + err := o.Database.CreateSensitiveWord(ctx, word) + if err != nil { + return nil, err + } + + return &chatpb.AddSensitiveWordResp{}, nil +} + +// UpdateSensitiveWord 更新敏感词 +func (o *chatSvr) UpdateSensitiveWord(ctx context.Context, req *chatpb.UpdateSensitiveWordReq) (*chatpb.UpdateSensitiveWordResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 构建更新数据 + data := make(map[string]any) + if req.Word != "" { + data["word"] = req.Word + } + if req.Level > 0 { + data["level"] = req.Level + } + if req.Type > 0 { + data["type"] = req.Type + } + if req.Action > 0 { + data["action"] = req.Action + } + if req.Status >= 0 { + data["status"] = req.Status + } + if req.Remark != "" { + data["remark"] = req.Remark + } + data["updater"] = getAdminUserID(ctx) + + // 更新数据库 + err := o.Database.UpdateSensitiveWord(ctx, req.Id, data) + if err != nil { + return nil, err + } + + return &chatpb.UpdateSensitiveWordResp{}, nil +} + +// DeleteSensitiveWord 删除敏感词 +func (o *chatSvr) DeleteSensitiveWord(ctx context.Context, req *chatpb.DeleteSensitiveWordReq) (*chatpb.DeleteSensitiveWordResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 删除数据 + err := o.Database.DeleteSensitiveWord(ctx, req.Ids) + if err != nil { + return nil, err + } + + return &chatpb.DeleteSensitiveWordResp{}, nil +} + +// GetSensitiveWord 获取敏感词 +func (o *chatSvr) GetSensitiveWord(ctx context.Context, req *chatpb.GetSensitiveWordReq) (*chatpb.GetSensitiveWordResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + word, err := o.Database.GetSensitiveWord(ctx, req.Id) + if err != nil { + return nil, err + } + + return &chatpb.GetSensitiveWordResp{ + Word: convertToSensitiveWordDetailInfo(word), + }, nil +} + +// SearchSensitiveWords 搜索敏感词 +func (o *chatSvr) SearchSensitiveWords(ctx context.Context, req *chatpb.SearchSensitiveWordsReq) (*chatpb.SearchSensitiveWordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 搜索数据 + total, words, err := o.Database.SearchSensitiveWords(ctx, req.Keyword, req.Action, req.Status, req.Pagination) + if err != nil { + return nil, err + } + + // 转换结果 + var wordInfos []*chatpb.SensitiveWordDetailInfo + for _, word := range words { + wordInfos = append(wordInfos, convertToSensitiveWordDetailInfo(word)) + } + + return &chatpb.SearchSensitiveWordsResp{ + Total: uint32(total), + Words: wordInfos, + }, nil +} + +// BatchAddSensitiveWords 批量添加敏感词 +func (o *chatSvr) BatchAddSensitiveWords(ctx context.Context, req *chatpb.BatchAddSensitiveWordsReq) (*chatpb.BatchAddSensitiveWordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 转换为数据库模型 + var words []*chat.SensitiveWord + now := time.Now() + adminID := getAdminUserID(ctx) + for _, wordInfo := range req.Words { + words = append(words, &chat.SensitiveWord{ + ID: uuid.New().String(), + Word: wordInfo.Word, + Level: wordInfo.Level, + Type: wordInfo.Type, + Action: wordInfo.Action, + Status: wordInfo.Status, + Creator: adminID, + Updater: adminID, + CreateTime: now, + UpdateTime: now, + Remark: wordInfo.Remark, + }) + } + + // 批量保存 + err := o.Database.BatchAddSensitiveWords(ctx, words) + if err != nil { + return nil, err + } + + return &chatpb.BatchAddSensitiveWordsResp{}, nil +} + +// BatchUpdateSensitiveWords 批量更新敏感词 +func (o *chatSvr) BatchUpdateSensitiveWords(ctx context.Context, req *chatpb.BatchUpdateSensitiveWordsReq) (*chatpb.BatchUpdateSensitiveWordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 转换为数据库模型 + updates := make(map[string]map[string]any) + adminID := getAdminUserID(ctx) + for id, wordInfo := range req.Updates { + data := make(map[string]any) + if wordInfo.Word != "" { + data["word"] = wordInfo.Word + } + if wordInfo.Level > 0 { + data["level"] = wordInfo.Level + } + if wordInfo.Type > 0 { + data["type"] = wordInfo.Type + } + if wordInfo.Action > 0 { + data["action"] = wordInfo.Action + } + if wordInfo.Status >= 0 { + data["status"] = wordInfo.Status + } + if wordInfo.Remark != "" { + data["remark"] = wordInfo.Remark + } + data["updater"] = adminID + updates[id] = data + } + + // 批量更新 + err := o.Database.BatchUpdateSensitiveWords(ctx, updates) + if err != nil { + return nil, err + } + + return &chatpb.BatchUpdateSensitiveWordsResp{}, nil +} + +// BatchDeleteSensitiveWords 批量删除敏感词 +func (o *chatSvr) BatchDeleteSensitiveWords(ctx context.Context, req *chatpb.BatchDeleteSensitiveWordsReq) (*chatpb.BatchDeleteSensitiveWordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 批量删除 + err := o.Database.BatchDeleteSensitiveWords(ctx, req.Ids) + if err != nil { + return nil, err + } + + return &chatpb.BatchDeleteSensitiveWordsResp{}, nil +} + +// ==================== 敏感词分组管理相关 RPC ==================== + +// AddSensitiveWordGroup 添加敏感词分组 +func (o *chatSvr) AddSensitiveWordGroup(ctx context.Context, req *chatpb.AddSensitiveWordGroupReq) (*chatpb.AddSensitiveWordGroupResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 创建分组对象 + group := &chat.SensitiveWordGroup{ + ID: primitive.NewObjectID(), + Name: req.Name, + Remark: req.Remark, + CreateTime: time.Now(), + UpdateTime: time.Now(), + } + + // 保存到数据库 + err := o.Database.CreateSensitiveWordGroup(ctx, group) + if err != nil { + return nil, err + } + + return &chatpb.AddSensitiveWordGroupResp{}, nil +} + +// UpdateSensitiveWordGroup 更新敏感词分组 +func (o *chatSvr) UpdateSensitiveWordGroup(ctx context.Context, req *chatpb.UpdateSensitiveWordGroupReq) (*chatpb.UpdateSensitiveWordGroupResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 构建更新数据 + data := make(map[string]any) + if req.Name != "" { + data["name"] = req.Name + } + if req.Remark != "" { + data["remark"] = req.Remark + } + + // 更新数据库 + err := o.Database.UpdateSensitiveWordGroup(ctx, req.Id, data) + if err != nil { + return nil, err + } + + return &chatpb.UpdateSensitiveWordGroupResp{}, nil +} + +// DeleteSensitiveWordGroup 删除敏感词分组 +func (o *chatSvr) DeleteSensitiveWordGroup(ctx context.Context, req *chatpb.DeleteSensitiveWordGroupReq) (*chatpb.DeleteSensitiveWordGroupResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 删除数据 + err := o.Database.DeleteSensitiveWordGroup(ctx, req.Ids) + if err != nil { + return nil, err + } + + return &chatpb.DeleteSensitiveWordGroupResp{}, nil +} + +// GetSensitiveWordGroup 获取敏感词分组 +func (o *chatSvr) GetSensitiveWordGroup(ctx context.Context, req *chatpb.GetSensitiveWordGroupReq) (*chatpb.GetSensitiveWordGroupResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + group, err := o.Database.GetSensitiveWordGroup(ctx, req.Id) + if err != nil { + return nil, err + } + + return &chatpb.GetSensitiveWordGroupResp{ + Group: convertToSensitiveWordGroupInfo(group), + }, nil +} + +// GetAllSensitiveWordGroups 获取所有敏感词分组 +func (o *chatSvr) GetAllSensitiveWordGroups(ctx context.Context, req *chatpb.GetAllSensitiveWordGroupsReq) (*chatpb.GetAllSensitiveWordGroupsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + groups, err := o.Database.GetAllSensitiveWordGroups(ctx) + if err != nil { + return nil, err + } + + // 转换结果 + var groupInfos []*chatpb.SensitiveWordGroupInfo + for _, group := range groups { + groupInfos = append(groupInfos, convertToSensitiveWordGroupInfo(group)) + } + + return &chatpb.GetAllSensitiveWordGroupsResp{ + Groups: groupInfos, + }, nil +} + +// ==================== 敏感词配置管理相关 RPC ==================== + +// GetSensitiveWordConfig 获取敏感词配置 +func (o *chatSvr) GetSensitiveWordConfig(ctx context.Context, req *chatpb.GetSensitiveWordConfigReq) (*chatpb.GetSensitiveWordConfigResp, error) { + fmt.Println("GetSensitiveWordConfig", "_________11", req) + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + fmt.Println("GetSensitiveWordConfig", "_________22", err) + return nil, err + } + fmt.Println("GetSensitiveWordConfig", "_________33") + // 查询数据 + config, err := o.Database.GetSensitiveWordConfig(ctx) + if err != nil { + fmt.Println("GetSensitiveWordConfig", "_________44", err) + return nil, err + } + + return &chatpb.GetSensitiveWordConfigResp{ + Config: convertToSensitiveWordConfigInfo(config), + }, nil +} + +// UpdateSensitiveWordConfig 更新敏感词配置 +func (o *chatSvr) UpdateSensitiveWordConfig(ctx context.Context, req *chatpb.UpdateSensitiveWordConfigReq) (*chatpb.UpdateSensitiveWordConfigResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 转换为数据库模型 + config := &chat.SensitiveWordConfig{ + ID: req.Config.Id, + EnableFilter: req.Config.EnableFilter, + FilterMode: req.Config.FilterMode, + ReplaceChar: req.Config.ReplaceChar, + WhitelistUsers: req.Config.WhitelistUsers, + WhitelistGroups: req.Config.WhitelistGroups, + LogEnabled: req.Config.LogEnabled, + AutoApprove: req.Config.AutoApprove, + UpdateTime: time.Now(), + } + + // 更新数据库 + err := o.Database.UpdateSensitiveWordConfig(ctx, config) + if err != nil { + return nil, err + } + + return &chatpb.UpdateSensitiveWordConfigResp{}, nil +} + +// ==================== 敏感词日志管理相关 RPC ==================== + +// GetSensitiveWordLogs 获取敏感词日志 +func (o *chatSvr) GetSensitiveWordLogs(ctx context.Context, req *chatpb.GetSensitiveWordLogsReq) (*chatpb.GetSensitiveWordLogsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + total, logs, err := o.Database.GetSensitiveWordLogs(ctx, req.UserId, req.GroupId, req.Pagination) + if err != nil { + return nil, err + } + + // 转换结果 + var logInfos []*chatpb.SensitiveWordLogInfo + for _, log := range logs { + logInfos = append(logInfos, convertToSensitiveWordLogInfo(log)) + } + + return &chatpb.GetSensitiveWordLogsResp{ + Total: uint32(total), + Logs: logInfos, + }, nil +} + +// DeleteSensitiveWordLogs 删除敏感词日志 +func (o *chatSvr) DeleteSensitiveWordLogs(ctx context.Context, req *chatpb.DeleteSensitiveWordLogsReq) (*chatpb.DeleteSensitiveWordLogsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 删除数据 + err := o.Database.DeleteSensitiveWordLogs(ctx, req.Ids) + if err != nil { + return nil, err + } + + return &chatpb.DeleteSensitiveWordLogsResp{}, nil +} + +// ==================== 敏感词统计相关 RPC ==================== + +// GetSensitiveWordStats 获取敏感词统计 +func (o *chatSvr) GetSensitiveWordStats(ctx context.Context, req *chatpb.GetSensitiveWordStatsReq) (*chatpb.GetSensitiveWordStatsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + stats, err := o.Database.GetSensitiveWordStats(ctx) + if err != nil { + return nil, err + } + + return &chatpb.GetSensitiveWordStatsResp{ + Stats: &chatpb.SensitiveWordStatsInfo{ + Total: stats["total"], + Enabled: stats["enabled"], + Disabled: stats["disabled"], + Replace: stats["replace"], + Block: stats["block"], + }, + }, nil +} + +// GetSensitiveWordLogStats 获取敏感词日志统计 +func (o *chatSvr) GetSensitiveWordLogStats(ctx context.Context, req *chatpb.GetSensitiveWordLogStatsReq) (*chatpb.GetSensitiveWordLogStatsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询数据 + startTime := time.Unix(req.StartTime, 0) + endTime := time.Unix(req.EndTime, 0) + stats, err := o.Database.GetSensitiveWordLogStats(ctx, startTime, endTime) + if err != nil { + return nil, err + } + + return &chatpb.GetSensitiveWordLogStatsResp{ + Stats: &chatpb.SensitiveWordLogStatsInfo{ + Total: stats["total"], + Replace: stats["replace"], + Block: stats["block"], + }, + }, nil +} + +// ==================== 辅助函数 ==================== + +// getAdminUserID 获取当前管理员用户ID +func getAdminUserID(ctx context.Context) string { + userID, _ := mctx.CheckAdmin(ctx) + return userID +} + +// convertToSensitiveWordDetailInfo 转换为敏感词详细信息 +func convertToSensitiveWordDetailInfo(word *chat.SensitiveWord) *chatpb.SensitiveWordDetailInfo { + return &chatpb.SensitiveWordDetailInfo{ + Id: word.ID, + Word: word.Word, + Level: word.Level, + Type: word.Type, + Action: word.Action, + Status: word.Status, + Creator: word.Creator, + Updater: word.Updater, + CreateTime: word.CreateTime.UnixMilli(), + UpdateTime: word.UpdateTime.UnixMilli(), + Remark: word.Remark, + } +} + +// convertToSensitiveWordGroupInfo 转换为敏感词分组信息 +func convertToSensitiveWordGroupInfo(group *chat.SensitiveWordGroup) *chatpb.SensitiveWordGroupInfo { + return &chatpb.SensitiveWordGroupInfo{ + Id: group.ID.Hex(), + Name: group.Name, + Remark: group.Remark, + CreateTime: group.CreateTime.UnixMilli(), + UpdateTime: group.UpdateTime.UnixMilli(), + } +} + +// convertToSensitiveWordConfigInfo 转换为敏感词配置信息 +func convertToSensitiveWordConfigInfo(config *chat.SensitiveWordConfig) *chatpb.SensitiveWordConfigInfo { + return &chatpb.SensitiveWordConfigInfo{ + Id: config.ID, + EnableFilter: config.EnableFilter, + FilterMode: config.FilterMode, + ReplaceChar: config.ReplaceChar, + WhitelistUsers: config.WhitelistUsers, + WhitelistGroups: config.WhitelistGroups, + LogEnabled: config.LogEnabled, + AutoApprove: config.AutoApprove, + UpdateTime: config.UpdateTime.UnixMilli(), + } +} + +// convertToSensitiveWordLogInfo 转换为敏感词日志信息 +func convertToSensitiveWordLogInfo(log *chat.SensitiveWordLog) *chatpb.SensitiveWordLogInfo { + return &chatpb.SensitiveWordLogInfo{ + Id: log.ID.Hex(), + UserId: log.UserID, + GroupId: log.GroupID, + Content: log.Content, + MatchedWords: log.MatchedWords, + Action: log.Action, + ProcessedText: log.ProcessedText, + CreateTime: log.CreateTime.UnixMilli(), + } +} diff --git a/internal/rpc/chat/start.go b/internal/rpc/chat/start.go new file mode 100644 index 0000000..c247ca2 --- /dev/null +++ b/internal/rpc/chat/start.go @@ -0,0 +1,119 @@ +package chat + +import ( + "context" + "strings" + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/common/rtc" + "git.imall.cloud/openim/chat/pkg/protocol/admin" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/db/database" + "git.imall.cloud/openim/chat/pkg/email" + chatClient "git.imall.cloud/openim/chat/pkg/rpclient/chat" + "git.imall.cloud/openim/chat/pkg/sms" + "github.com/openimsdk/tools/db/redisutil" + "github.com/redis/go-redis/v9" +) + +type Config struct { + RpcConfig config.Chat + RedisConfig config.Redis + MongodbConfig config.Mongo + Discovery config.Discovery + Share config.Share +} + +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + if len(config.Share.ChatAdmin) == 0 { + return errs.New("share chat admin not configured") + } + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) + if err != nil { + return err + } + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + if err != nil { + return err + } + var srv chatSvr + srv.rdb = rdb + config.RpcConfig.VerifyCode.Phone.Use = strings.ToLower(config.RpcConfig.VerifyCode.Phone.Use) + config.RpcConfig.VerifyCode.Mail.Use = strings.ToLower(config.RpcConfig.VerifyCode.Mail.Use) + srv.conf = config.RpcConfig.VerifyCode + switch config.RpcConfig.VerifyCode.Phone.Use { + case "ali": + ali := config.RpcConfig.VerifyCode.Phone.Ali + srv.SMS, err = sms.NewAli(ali.Endpoint, ali.AccessKeyID, ali.AccessKeySecret, ali.SignName, ali.VerificationCodeTemplateCode) + if err != nil { + return err + } + case "bao": + bao := config.RpcConfig.VerifyCode.Phone.Bao + srv.SMS, err = sms.NewBao(bao.Endpoint, bao.AccessKeyID, bao.AccessKeySecret, bao.SignName, bao.VerificationCodeTemplateCode) + if err != nil { + return err + } + } + if mail := config.RpcConfig.VerifyCode.Mail; mail.Use == constant.VerifyMail { + srv.Mail = email.NewMail(mail.SMTPAddr, mail.SMTPPort, mail.SenderMail, mail.SenderAuthorizationCode, mail.Title) + } + srv.Database, err = database.NewChatDatabase(mgocli, rdb) + if err != nil { + return err + } + conn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + srv.Admin = chatClient.NewAdminClient(admin.NewAdminClient(conn)) + srv.Code = verifyCode{ + UintTime: time.Duration(config.RpcConfig.VerifyCode.UintTime) * time.Second, + MaxCount: config.RpcConfig.VerifyCode.MaxCount, + ValidCount: config.RpcConfig.VerifyCode.ValidCount, + SuperCode: config.RpcConfig.VerifyCode.SuperCode, + ValidTime: time.Duration(config.RpcConfig.VerifyCode.ValidTime) * time.Second, + Len: config.RpcConfig.VerifyCode.Len, + } + srv.Livekit = rtc.NewLiveKit(config.RpcConfig.LiveKit.Key, config.RpcConfig.LiveKit.Secret, config.RpcConfig.LiveKit.URL) + srv.AllowRegister = config.RpcConfig.AllowRegister + chat.RegisterChatServer(server, &srv) + return nil +} + +type chatSvr struct { + chat.UnimplementedChatServer + conf config.VerifyCode + Database database.ChatDatabaseInterface + Admin *chatClient.AdminClient + SMS sms.SMS + Mail email.Mail + Code verifyCode + Livekit *rtc.LiveKit + ChatAdminUserID string + AllowRegister bool + rdb redis.UniversalClient +} + +func (o *chatSvr) WithAdminUser(ctx context.Context) context.Context { + return mctx.WithAdminUser(ctx, o.ChatAdminUserID) +} + +type verifyCode struct { + UintTime time.Duration // sec + MaxCount int + ValidCount int + SuperCode string + ValidTime time.Duration + Len int +} diff --git a/internal/rpc/chat/statistic.go b/internal/rpc/chat/statistic.go new file mode 100644 index 0000000..88261b1 --- /dev/null +++ b/internal/rpc/chat/statistic.go @@ -0,0 +1,44 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/errs" +) + +func (o *chatSvr) UserLoginCount(ctx context.Context, req *chat.UserLoginCountReq) (*chat.UserLoginCountResp, error) { + resp := &chat.UserLoginCountResp{} + if req.Start > req.End { + return nil, errs.ErrArgs.WrapMsg("start > end") + } + total, err := o.Database.NewUserCountTotal(ctx, nil) + if err != nil { + return nil, err + } + start := time.UnixMilli(req.Start) + end := time.UnixMilli(req.End) + count, loginCount, err := o.Database.UserLoginCountRangeEverydayTotal(ctx, &start, &end) + if err != nil { + return nil, err + } + resp.LoginCount = loginCount + resp.UnloginCount = total - loginCount + resp.Count = count + return resp, nil +} diff --git a/internal/rpc/chat/system_config.go b/internal/rpc/chat/system_config.go new file mode 100644 index 0000000..1260045 --- /dev/null +++ b/internal/rpc/chat/system_config.go @@ -0,0 +1,46 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + + chatpb "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +// GetAppSystemConfigs 获取APP端配置(返回所有 show_in_app=true 且 enabled=true 的配置) +func (o *chatSvr) GetAppSystemConfigs(ctx context.Context, req *chatpb.GetAppSystemConfigsReq) (*chatpb.GetAppSystemConfigsResp, error) { + // 获取所有 show_in_app=true 且 enabled=true 的配置 + configs, err := o.Database.GetAppSystemConfigs(ctx) + if err != nil { + return nil, err + } + + // 转换为响应格式 + configInfos := make([]*chatpb.SystemConfigInfo, 0, len(configs)) + for _, config := range configs { + configInfos = append(configInfos, &chatpb.SystemConfigInfo{ + Key: config.Key, + Title: config.Title, + Value: config.Value, + ValueType: config.ValueType, + Description: config.Description, + }) + } + + return &chatpb.GetAppSystemConfigsResp{ + Configs: configInfos, + }, nil +} diff --git a/internal/rpc/chat/update.go b/internal/rpc/chat/update.go new file mode 100644 index 0000000..b9361a9 --- /dev/null +++ b/internal/rpc/chat/update.go @@ -0,0 +1,132 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/protocol/chat" +) + +func ToDBAttributeUpdate(req *chat.UpdateUserInfoReq) (map[string]any, error) { + update := make(map[string]any) + if req.Account != nil { + update["account"] = req.Account.Value + } + if req.AreaCode != nil { + update["area_code"] = req.AreaCode.Value + } + if req.Email != nil { + update["email"] = req.Email.Value + } + if req.Nickname != nil { + if req.Nickname.Value == "" { + return nil, errs.ErrArgs.WrapMsg("nickname can not be empty") + } + update["nickname"] = req.Nickname.Value + } + if req.FaceURL != nil { + update["face_url"] = req.FaceURL.Value + } + if req.Gender != nil { + update["gender"] = req.Gender.Value + } + if req.Level != nil { + update["level"] = req.Level.Value + } + // userType 现在是 int32 类型,直接使用值 + update["user_type"] = req.UserType + if req.UserFlag != nil { + update["user_flag"] = req.UserFlag.Value + } + + if req.Birth != nil { + update["birth_time"] = time.UnixMilli(req.Birth.Value) + } + if req.AllowAddFriend != nil { + update["allow_add_friend"] = req.AllowAddFriend.Value + } + if req.AllowBeep != nil { + update["allow_beep"] = req.AllowBeep.Value + } + if req.AllowVibration != nil { + update["allow_vibration"] = req.AllowVibration.Value + } + if req.GlobalRecvMsgOpt != nil { + update["global_recv_msg_opt"] = req.GlobalRecvMsgOpt.Value + } + //if len(update) == 0 { + // return nil, errs.ErrArgs.WrapMsg("no update info") + //} + return update, nil +} + +func ToDBCredentialUpdate(req *chat.UpdateUserInfoReq, allowChange bool) ([]*chatdb.Credential, []*chatdb.Credential, error) { + update := make([]*chatdb.Credential, 0) + del := make([]*chatdb.Credential, 0) + if req.Account != nil { + if req.Account.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialAccount, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: req.Account.GetValue(), + Type: constant.CredentialAccount, + AllowChange: allowChange, + }) + } + } + + if req.Email != nil { + if req.Email.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialEmail, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: req.Email.GetValue(), + Type: constant.CredentialEmail, + AllowChange: allowChange, + }) + } + } + if req.PhoneNumber != nil { + if req.PhoneNumber.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialPhone, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: BuildCredentialPhone(req.AreaCode.GetValue(), req.PhoneNumber.GetValue()), + Type: constant.CredentialPhone, + AllowChange: allowChange, + }) + } + } + + return update, del, nil +} diff --git a/internal/rpc/chat/user.go b/internal/rpc/chat/user.go new file mode 100644 index 0000000..4157a0b --- /dev/null +++ b/internal/rpc/chat/user.go @@ -0,0 +1,623 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "errors" + "regexp" + "strconv" + "strings" + "time" + + "git.imall.cloud/openim/protocol/wrapperspb" + "github.com/openimsdk/tools/utils/stringutil" + + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/mcontext" + "go.mongodb.org/mongo-driver/mongo" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" +) + +func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoReq) error { + if req.AreaCode != nil || req.PhoneNumber != nil { + if !(req.AreaCode != nil && req.PhoneNumber != nil) { + return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { + if req.AreaCode.Value != req.PhoneNumber.Value { + return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + } + } + if req.UserID == "" { + return errs.ErrArgs.WrapMsg("user id is empty") + } + + credentials, err := o.Database.TakeCredentialsByUserID(ctx, req.UserID) + if err != nil { + return err + } else if len(credentials) == 0 { + return errs.ErrArgs.WrapMsg("user not found") + } + var ( + credNum, delNum, addNum = len(credentials), 0, 0 + ) + + addFunc := func(s *wrapperspb.StringValue) { + if s != nil { + if s.Value != "" { + addNum++ + } + } + } + + for _, s := range []*wrapperspb.StringValue{req.Account, req.PhoneNumber, req.Email} { + addFunc(s) + } + + for _, credential := range credentials { + switch credential.Type { + case constant.CredentialAccount: + if req.Account != nil { + if req.Account.Value == credential.Account { + req.Account = nil + } else if req.Account.Value == "" { + delNum += 1 + } + } + case constant.CredentialPhone: + if req.PhoneNumber != nil { + phoneAccount := BuildCredentialPhone(req.AreaCode.Value, req.PhoneNumber.Value) + if phoneAccount == credential.Account { + req.AreaCode = nil + req.PhoneNumber = nil + } else if req.PhoneNumber.Value == "" { + delNum += 1 + } + } + case constant.CredentialEmail: + if req.Email != nil { + if req.Email.Value == credential.Account { + req.Email = nil + } else if req.Email.Value == "" { + delNum += 1 + } + } + } + } + + if addNum+credNum-delNum <= 0 { + return errs.ErrArgs.WrapMsg("a login method must exist") + } + + if req.PhoneNumber.GetValue() != "" { + if !strings.HasPrefix(req.AreaCode.GetValue(), "+") { + req.AreaCode.Value = "+" + req.AreaCode.Value + } + if _, err := strconv.ParseUint(req.AreaCode.Value[1:], 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("area code must be number") + } + if _, err := strconv.ParseUint(req.PhoneNumber.GetValue(), 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("phone number must be number") + } + phoneAccount := BuildCredentialPhone(req.AreaCode.GetValue(), req.PhoneNumber.GetValue()) + existingCredential, err := o.Database.TakeCredentialByAccount(ctx, phoneAccount) + if err == nil { + // 如果手机号已存在,检查是否是当前用户的手机号 + if existingCredential.UserID == req.UserID { + // 是当前用户的手机号,允许更新(实际上是相同值,不需要更新) + req.AreaCode = nil + req.PhoneNumber = nil + } else { + // 是其他用户的手机号,返回错误 + return eerrs.ErrPhoneAlreadyRegister.Wrap() + } + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if req.Account.GetValue() != "" { + accountValue := req.Account.GetValue() + // 验证长度:6到20位 + if len(accountValue) < 6 || len(accountValue) > 20 { + return errs.ErrArgs.WrapMsg("account must be between 6 and 20 characters") + } + // 验证格式:只能包含数字、字母、下划线(_)、横线(-) + pattern := `^[a-zA-Z0-9_-]+$` + matched, err := regexp.MatchString(pattern, accountValue) + if err != nil || !matched { + return errs.ErrArgs.WrapMsg("account must contain only letters, numbers, underscores, and hyphens") + } + existingCredential, err := o.Database.TakeCredentialByAccount(ctx, accountValue) + if err == nil { + // 如果账户已存在,检查是否是当前用户的账户 + if existingCredential.UserID == req.UserID { + // 是当前用户的账户,允许更新(实际上是相同值,不需要更新) + req.Account = nil + + } else { + // 是其他用户的账户,返回错误 + return eerrs.ErrAccountAlreadyRegister.Wrap() + } + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if req.Email.GetValue() != "" { + if !stringutil.IsValidEmail(req.Email.GetValue()) { + return errs.ErrArgs.WrapMsg("invalid email") + } + existingCredential, err := o.Database.TakeCredentialByAccount(ctx, req.Email.GetValue()) + if err == nil { + // 如果邮箱已存在,检查是否是当前用户的邮箱 + if existingCredential.UserID == req.UserID { + // 是当前用户的邮箱,允许更新(实际上是相同值,不需要更新) + req.Email = nil + } else { + // 是其他用户的邮箱,返回错误 + return eerrs.ErrEmailAlreadyRegister.Wrap() + } + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil +} + +func (o *chatSvr) UpdateUserInfo(ctx context.Context, req *chat.UpdateUserInfoReq) (*chat.UpdateUserInfoResp, error) { + opUserID, userType, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + if err = o.checkUpdateInfo(ctx, req); err != nil { + return nil, err + } + + switch userType { + case constant.NormalUser: + if req.RegisterType != nil { + return nil, errs.ErrNoPermission.WrapMsg("registerType can not be updated") + } + if req.UserID != opUserID { + return nil, errs.ErrNoPermission.WrapMsg("only admin can update other user info") + } + // 普通用户不能修改自己的用户类型 + if req.UserType != 0 { + return nil, errs.ErrNoPermission.WrapMsg("normal user can not update userType") + } + + case constant.AdminUser: + // 管理员可以修改用户类型,但需要验证值 + if req.UserType < 0 || req.UserType > 3 { + return nil, errs.ErrArgs.WrapMsg("invalid userType: must be 0-3") + } + default: + return nil, errs.ErrNoPermission.WrapMsg("user type error") + } + + update, err := ToDBAttributeUpdate(req) + if err != nil { + return nil, err + } + + if userType == constant.NormalUser { + delete(update, "user_flag") + delete(update, "user_type") + } + + credUpdate, credDel, err := ToDBCredentialUpdate(req, true) + if err != nil { + return nil, err + } + if len(update) > 0 { + if err := o.Database.UpdateUseInfo(ctx, req.UserID, update, credUpdate, credDel); err != nil { + return nil, err + } + } + return &chat.UpdateUserInfoResp{}, nil +} + +func (o *chatSvr) FindUserPublicInfo(ctx context.Context, req *chat.FindUserPublicInfoReq) (*chat.FindUserPublicInfoResp, error) { + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("UserIDs is empty") + } + attributes, err := o.Database.FindAttribute(ctx, req.UserIDs) + if err != nil { + return nil, err + } + return &chat.FindUserPublicInfoResp{ + Users: DbToPbAttributes(attributes), + }, nil +} + +func (o *chatSvr) AddUserAccount(ctx context.Context, req *chat.AddUserAccountReq) (*chat.AddUserAccountResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + + if err := o.checkRegisterInfo(ctx, req.User, true); err != nil { + return nil, err + } + + if req.User.UserID == "" { + for i := 0; i < 20; i++ { + userID := o.genUserID() + _, err := o.Database.GetUser(ctx, userID) + if err == nil { + continue + } else if dbutil.IsDBNotFound(err) { + req.User.UserID = userID + break + } else { + return nil, err + } + } + if req.User.UserID == "" { + return nil, errs.ErrInternalServer.WrapMsg("gen user id failed") + } + } else { + _, err := o.Database.GetUser(ctx, req.User.UserID) + if err == nil { + return nil, errs.ErrArgs.WrapMsg("appoint user id already register") + } else if !dbutil.IsDBNotFound(err) { + return nil, err + } + } + + var ( + credentials []*chatdb.Credential + ) + + if req.User.PhoneNumber != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) + } + + if req.User.Account != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + } + + if req.User.Email != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) + } + + register := &chatdb.Register{ + UserID: req.User.UserID, + DeviceID: req.DeviceID, + IP: req.Ip, + Platform: constantpb.PlatformID2Name[int(req.Platform)], + AccountType: "", + Mode: constant.UserMode, + CreateTime: time.Now(), + } + account := &chatdb.Account{ + UserID: req.User.UserID, + Password: req.User.Password, + OperatorUserID: mcontext.GetOpUserID(ctx), + ChangeTime: register.CreateTime, + CreateTime: register.CreateTime, + } + attribute := &chatdb.Attribute{ + UserID: req.User.UserID, + Account: req.User.Account, + PhoneNumber: req.User.PhoneNumber, + AreaCode: req.User.AreaCode, + Email: req.User.Email, + Nickname: req.User.Nickname, + FaceURL: req.User.FaceURL, + Gender: req.User.Gender, + BirthTime: time.UnixMilli(req.User.Birth), + ChangeTime: register.CreateTime, + CreateTime: register.CreateTime, + AllowVibration: constant.DefaultAllowVibration, + AllowBeep: constant.DefaultAllowBeep, + AllowAddFriend: constant.DefaultAllowAddFriend, + } + + if err := o.Database.RegisterUser(ctx, register, account, attribute, credentials); err != nil { + return nil, err + } + return &chat.AddUserAccountResp{}, nil +} + +func (o *chatSvr) SearchUserPublicInfo(ctx context.Context, req *chat.SearchUserPublicInfoReq) (*chat.SearchUserPublicInfoResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + total, list, err := o.Database.Search(ctx, constant.FinDAllUser, req.Keyword, req.Genders, nil, nil, req.Pagination) + if err != nil { + return nil, err + } + return &chat.SearchUserPublicInfoResp{ + Total: uint32(total), + Users: DbToPbAttributes(list), + }, nil +} + +func (o *chatSvr) FindUserFullInfo(ctx context.Context, req *chat.FindUserFullInfoReq) (*chat.FindUserFullInfoResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("UserIDs is empty") + } + attributes, err := o.Database.FindAttribute(ctx, req.UserIDs) + if err != nil { + return nil, err + } + + // 获取每个用户的最新登录IP + userIPMap := make(map[string]string) + for _, attr := range attributes { + ip, err := o.Database.GetLatestLoginIP(ctx, attr.UserID) + if err != nil { + // 如果获取IP失败,记录错误但继续处理其他用户 + continue + } + userIPMap[attr.UserID] = ip + } + + return &chat.FindUserFullInfoResp{Users: DbToPbUserFullInfosWithIP(attributes, userIPMap)}, nil +} + +func (o *chatSvr) SearchUserFullInfo(ctx context.Context, req *chat.SearchUserFullInfoReq) (*chat.SearchUserFullInfoResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + // 解析时间戳为 time.Time(毫秒时间戳) + var startTime, endTime *time.Time + if req.StartTime > 0 { + st := time.UnixMilli(req.StartTime) + startTime = &st + } + if req.EndTime > 0 { + // 将endTime加1000毫秒,确保包含到当天的最后一毫秒 + // 例如:endTime=1727740799000 (2025-11-01 23:59:59) 会被转换为 1727740800000 (2025-11-02 00:00:00) + // 这样使用 $lt 查询时,会包含 2025-11-01 23:59:59.999 但不包含 2025-11-02 00:00:00 + et := time.UnixMilli(req.EndTime + 1000) + endTime = &et + } + // 使用支持实名信息搜索的方法 + total, list, err := o.Database.SearchWithRealNameAuth(ctx, req.Normal, req.Keyword, req.Genders, startTime, endTime, req.RealNameKeyword, req.IdCardKeyword, req.Pagination) + if err != nil { + return nil, err + } + + // 批量获取钱包信息(用于填充实名信息) + userIDs := make([]string, 0, len(list)) + for _, attr := range list { + userIDs = append(userIDs, attr.UserID) + } + walletMap := make(map[string]*chatdb.Wallet) + if len(userIDs) > 0 { + wallets, err := o.Database.GetWalletsByUserIDs(ctx, userIDs) + if err != nil { + log.ZWarn(ctx, "Failed to get wallets for user search", err, "userIDs", userIDs) + } else { + for _, wallet := range wallets { + walletMap[wallet.UserID] = wallet + } + } + } + + // 获取每个用户的最新登录IP + userIPMap := make(map[string]string) + for _, attr := range list { + ip, err := o.Database.GetLatestLoginIP(ctx, attr.UserID) + if err != nil { + // 如果获取IP失败,记录错误但继续处理其他用户 + log.ZWarn(ctx, "Failed to get latest login IP for user", err, "userID", attr.UserID) + // 即使出错也设置空字符串,确保map中有该用户的记录 + userIPMap[attr.UserID] = "" + continue + } + // 记录获取到的IP(用于调试) + if ip != "" { + log.ZDebug(ctx, "Got latest login IP for user", "userID", attr.UserID, "ip", ip) + } else { + log.ZDebug(ctx, "No login IP found for user (empty string)", "userID", attr.UserID) + } + userIPMap[attr.UserID] = ip + } + // 统计有IP的用户数量 + usersWithIP := 0 + for _, ip := range userIPMap { + if ip != "" { + usersWithIP++ + } + } + log.ZInfo(ctx, "User IP map summary", "totalUsers", len(list), "ipMapSize", len(userIPMap), "usersWithIP", usersWithIP) + + return &chat.SearchUserFullInfoResp{ + Total: uint32(total), + Users: DbToPbUserFullInfosWithRealNameAuthAndIP(list, walletMap, userIPMap), + }, nil +} + +// GetUserLoginRecords 查询用户登录记录 +func (o *chatSvr) GetUserLoginRecords(ctx context.Context, req *chat.GetUserLoginRecordsReq) (*chat.GetUserLoginRecordsResp, error) { + // 检查管理员权限 + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + + // 查询登录记录 + total, records, err := o.Database.SearchUserLoginRecords(ctx, req.UserId, req.Ip, req.Pagination) + if err != nil { + return nil, err + } + + // 收集所有用户ID + userIDs := make([]string, 0, len(records)) + userIDSet := make(map[string]bool) + for _, record := range records { + if !userIDSet[record.UserID] { + userIDs = append(userIDs, record.UserID) + userIDSet[record.UserID] = true + } + } + + // 批量获取用户属性(头像和昵称) + userAttrMap := make(map[string]*chatdb.Attribute) + if len(userIDs) > 0 { + attributes, err := o.Database.FindAttribute(ctx, userIDs) + if err != nil { + log.ZWarn(ctx, "Failed to get user attributes for login records", err, "userIDs", userIDs) + } else { + for _, attr := range attributes { + userAttrMap[attr.UserID] = attr + } + } + } + + // 转换结果 + var recordInfos []*chat.UserLoginRecordInfo + for _, record := range records { + recordInfo := &chat.UserLoginRecordInfo{ + UserId: record.UserID, + LoginTime: record.LoginTime.UnixMilli(), + Ip: record.IP, + DeviceId: record.DeviceID, + Platform: record.Platform, + } + // 填充用户头像和昵称 + if attr, ok := userAttrMap[record.UserID]; ok { + recordInfo.FaceUrl = attr.FaceURL + recordInfo.Nickname = attr.Nickname + } + recordInfos = append(recordInfos, recordInfo) + } + + return &chat.GetUserLoginRecordsResp{ + Total: uint32(total), + Records: recordInfos, + }, nil +} + +func (o *chatSvr) FindUserAccount(ctx context.Context, req *chat.FindUserAccountReq) (*chat.FindUserAccountResp, error) { + if len(req.UserIDs) == 0 { + return nil, errs.ErrArgs.WrapMsg("user id list must be set") + } + if _, _, err := mctx.CheckAdminOrUser(ctx); err != nil { + return nil, err + } + attributes, err := o.Database.FindAttribute(ctx, req.UserIDs) + if err != nil { + return nil, err + } + userAccountMap := make(map[string]string) + for _, attribute := range attributes { + userAccountMap[attribute.UserID] = attribute.Account + } + return &chat.FindUserAccountResp{UserAccountMap: userAccountMap}, nil +} + +func (o *chatSvr) FindAccountUser(ctx context.Context, req *chat.FindAccountUserReq) (*chat.FindAccountUserResp, error) { + if len(req.Accounts) == 0 { + return nil, errs.ErrArgs.WrapMsg("account list must be set") + } + if _, _, err := mctx.CheckAdminOrUser(ctx); err != nil { + return nil, err + } + attributes, err := o.Database.FindAttribute(ctx, req.Accounts) + if err != nil { + return nil, err + } + accountUserMap := make(map[string]string) + for _, attribute := range attributes { + accountUserMap[attribute.Account] = attribute.UserID + } + return &chat.FindAccountUserResp{AccountUserMap: accountUserMap}, nil +} + +func (o *chatSvr) SearchUserInfo(ctx context.Context, req *chat.SearchUserInfoReq) (*chat.SearchUserInfoResp, error) { + if _, _, err := mctx.Check(ctx); err != nil { + return nil, err + } + total, list, err := o.Database.SearchUser(ctx, req.Keyword, req.UserIDs, req.Genders, req.Pagination) + if err != nil { + return nil, err + } + return &chat.SearchUserInfoResp{ + Total: uint32(total), + Users: DbToPbUserFullInfos(list), + }, nil +} + +func (o *chatSvr) CheckUserExist(ctx context.Context, req *chat.CheckUserExistReq) (resp *chat.CheckUserExistResp, err error) { + if req.User == nil { + return nil, errs.ErrArgs.WrapMsg("user is nil") + } + if req.User.PhoneNumber != "" { + account, err := o.Database.TakeCredentialByAccount(ctx, BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber)) + // err != nil is not found User + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + if account != nil { + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil + } + } + if req.User.Email != "" { + account, err := o.Database.TakeCredentialByAccount(ctx, req.User.AreaCode) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + if account != nil { + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil + } + } + if req.User.Account != "" { + account, err := o.Database.TakeCredentialByAccount(ctx, req.User.Account) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + if account != nil { + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil + } + } + return nil, nil +} + +func (o *chatSvr) DelUserAccount(ctx context.Context, req *chat.DelUserAccountReq) (resp *chat.DelUserAccountResp, err error) { + if err := o.Database.DelUserAccount(ctx, req.UserIDs); err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments { + return nil, err + } + return nil, nil +} diff --git a/internal/rpc/chat/utils.go b/internal/rpc/chat/utils.go new file mode 100644 index 0000000..b6f792f --- /dev/null +++ b/internal/rpc/chat/utils.go @@ -0,0 +1,202 @@ +package chat + +import ( + "context" + "regexp" + "strconv" + "strings" + + "git.imall.cloud/openim/chat/pkg/common/db/dbutil" + table "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "git.imall.cloud/openim/chat/pkg/protocol/common" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" +) + +func DbToPbAttribute(attribute *table.Attribute) *common.UserPublicInfo { + if attribute == nil { + return nil + } + return &common.UserPublicInfo{ + UserID: attribute.UserID, + Account: attribute.Account, + Email: attribute.Email, + Nickname: attribute.Nickname, + FaceURL: attribute.FaceURL, + Gender: attribute.Gender, + Level: attribute.Level, + UserType: attribute.UserType, + } +} + +func DbToPbAttributes(attributes []*table.Attribute) []*common.UserPublicInfo { + return datautil.Slice(attributes, DbToPbAttribute) +} + +func DbToPbUserFullInfo(attribute *table.Attribute) *common.UserFullInfo { + return &common.UserFullInfo{ + UserID: attribute.UserID, + Password: "", + Account: attribute.Account, + PhoneNumber: attribute.PhoneNumber, + AreaCode: attribute.AreaCode, + Email: attribute.Email, + Nickname: attribute.Nickname, + FaceURL: attribute.FaceURL, + Gender: attribute.Gender, + Level: attribute.Level, + UserType: attribute.UserType, + Birth: attribute.BirthTime.UnixMilli(), + AllowAddFriend: attribute.AllowAddFriend, + AllowBeep: attribute.AllowBeep, + AllowVibration: attribute.AllowVibration, + GlobalRecvMsgOpt: attribute.GlobalRecvMsgOpt, + RegisterType: attribute.RegisterType, + UserFlag: attribute.UserFlag, + CreateTime: attribute.CreateTime.UnixMilli(), + Ip: "", // 默认空字符串 + } +} + +func DbToPbUserFullInfos(attributes []*table.Attribute) []*common.UserFullInfo { + return datautil.Slice(attributes, DbToPbUserFullInfo) +} + +func DbToPbUserFullInfoWithIP(attribute *table.Attribute, ip string) *common.UserFullInfo { + return &common.UserFullInfo{ + UserID: attribute.UserID, + Password: "", + Account: attribute.Account, + PhoneNumber: attribute.PhoneNumber, + AreaCode: attribute.AreaCode, + Email: attribute.Email, + Nickname: attribute.Nickname, + FaceURL: attribute.FaceURL, + Gender: attribute.Gender, + Level: attribute.Level, + UserType: attribute.UserType, + Birth: attribute.BirthTime.UnixMilli(), + AllowAddFriend: attribute.AllowAddFriend, + AllowBeep: attribute.AllowBeep, + AllowVibration: attribute.AllowVibration, + GlobalRecvMsgOpt: attribute.GlobalRecvMsgOpt, + RegisterType: attribute.RegisterType, + UserFlag: attribute.UserFlag, + CreateTime: attribute.CreateTime.UnixMilli(), + Ip: ip, + } +} + +func DbToPbUserFullInfosWithIP(attributes []*table.Attribute, userIPMap map[string]string) []*common.UserFullInfo { + result := make([]*common.UserFullInfo, 0, len(attributes)) + for _, attr := range attributes { + ip := userIPMap[attr.UserID] + result = append(result, DbToPbUserFullInfoWithIP(attr, ip)) + } + return result +} + +// DbToPbUserFullInfosWithRealNameAuth 转换用户信息(包含实名认证信息) +func DbToPbUserFullInfosWithRealNameAuth(attributes []*table.Attribute, walletMap map[string]*table.Wallet) []*common.UserFullInfo { + result := make([]*common.UserFullInfo, 0, len(attributes)) + for _, attr := range attributes { + userInfo := DbToPbUserFullInfo(attr) + // 填充实名认证信息 + if wallet, ok := walletMap[attr.UserID]; ok { + userInfo.IdCard = wallet.RealNameAuth.IDCard + userInfo.RealName = wallet.RealNameAuth.Name + userInfo.IdCardPhotoFront = wallet.RealNameAuth.IDCardPhotoFront + userInfo.IdCardPhotoBack = wallet.RealNameAuth.IDCardPhotoBack + userInfo.AuditStatus = wallet.RealNameAuth.AuditStatus + } + result = append(result, userInfo) + } + return result +} + +// DbToPbUserFullInfosWithRealNameAuthAndIP 转换用户信息(包含实名认证信息和IP) +func DbToPbUserFullInfosWithRealNameAuthAndIP(attributes []*table.Attribute, walletMap map[string]*table.Wallet, userIPMap map[string]string) []*common.UserFullInfo { + result := make([]*common.UserFullInfo, 0, len(attributes)) + for _, attr := range attributes { + ip := userIPMap[attr.UserID] + userInfo := DbToPbUserFullInfoWithIP(attr, ip) + // 填充实名认证信息 + if wallet, ok := walletMap[attr.UserID]; ok { + userInfo.IdCard = wallet.RealNameAuth.IDCard + userInfo.RealName = wallet.RealNameAuth.Name + userInfo.IdCardPhotoFront = wallet.RealNameAuth.IDCardPhotoFront + userInfo.IdCardPhotoBack = wallet.RealNameAuth.IDCardPhotoBack + userInfo.AuditStatus = wallet.RealNameAuth.AuditStatus + } + result = append(result, userInfo) + } + return result +} + +func BuildCredentialPhone(areaCode, phone string) string { + return areaCode + " " + phone +} + +func (o *chatSvr) checkRegisterInfo(ctx context.Context, user *chat.RegisterUserInfo, isAdmin bool) error { + if user == nil { + return errs.ErrArgs.WrapMsg("user is nil") + } + user.Account = strings.TrimSpace(user.Account) + // 如果提供了account,则不需要验证phone和email + if user.Account != "" { + // account验证逻辑在后面,这里直接跳过"至少需要一个账号"的检查 + } else if user.Email == "" && !(user.PhoneNumber != "" && user.AreaCode != "") && !isAdmin { + // 如果没有account,也没有email,也没有完整的phone(phoneNumber和areaCode都提供),且不是管理员,则报错 + return errs.ErrArgs.WrapMsg("at least one valid account is required") + } + if user.PhoneNumber != "" { + if !strings.HasPrefix(user.AreaCode, "+") { + user.AreaCode = "+" + user.AreaCode + } + if _, err := strconv.ParseUint(user.AreaCode[1:], 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("area code must be number") + } + if _, err := strconv.ParseUint(user.PhoneNumber, 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("phone number must be number") + } + _, err := o.Database.TakeAttributeByPhone(ctx, user.AreaCode, user.PhoneNumber) + if err == nil { + return eerrs.ErrPhoneAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if user.Account != "" { + // 验证长度:6到20位 + if len(user.Account) < 6 || len(user.Account) > 20 { + return errs.ErrArgs.WrapMsg("account must be between 6 and 20 characters") + } + // 验证格式:只能包含数字、字母、下划线(_)、横线(-) + pattern := `^[a-zA-Z0-9_-]+$` + matched, err := regexp.MatchString(pattern, user.Account) + if err != nil || !matched { + return errs.ErrArgs.WrapMsg("account must contain only letters, numbers, underscores, and hyphens") + } + _, err = o.Database.TakeAttributeByAccount(ctx, user.Account) + if err == nil { + return eerrs.ErrAccountAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if user.Email != "" { + if !stringutil.IsValidEmail(user.Email) { + return errs.ErrArgs.WrapMsg("invalid email") + } + _, err := o.Database.TakeAttributeByAccount(ctx, user.Email) + if err == nil { + return eerrs.ErrEmailAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil +} diff --git a/internal/rpc/chat/wallet.go b/internal/rpc/chat/wallet.go new file mode 100644 index 0000000..53300d0 --- /dev/null +++ b/internal/rpc/chat/wallet.go @@ -0,0 +1,753 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "regexp" + "strconv" + "strings" + "time" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/common/util" + "git.imall.cloud/openim/chat/pkg/eerrs" + chatpb "git.imall.cloud/openim/chat/pkg/protocol/chat" + "github.com/google/uuid" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "go.mongodb.org/mongo-driver/mongo" +) + +// GetWalletBalance 获取钱包余额 +func (o *chatSvr) GetWalletBalance(ctx context.Context, req *chatpb.GetWalletBalanceReq) (*chatpb.GetWalletBalanceResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取钱包信息 + wallet, err := o.Database.GetWallet(ctx, userID) + if err != nil { + // 如果钱包不存在,返回余额为0 + if errors.Is(err, mongo.ErrNoDocuments) { + return &chatpb.GetWalletBalanceResp{ + Balance: 0, + }, nil + } + return nil, err + } + + return &chatpb.GetWalletBalanceResp{ + Balance: wallet.Balance, + }, nil +} + +// GetWalletInfo 获取钱包详细信息 +func (o *chatSvr) GetWalletInfo(ctx context.Context, req *chatpb.GetWalletInfoReq) (*chatpb.GetWalletInfoResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取钱包信息 + wallet, err := o.Database.GetWallet(ctx, userID) + if err != nil { + // 如果钱包不存在,返回默认值 + if errors.Is(err, mongo.ErrNoDocuments) { + return &chatpb.GetWalletInfoResp{ + Balance: 0, + WithdrawAccount: "", + WithdrawAccountType: 0, + RealNameAuth: nil, + WithdrawReceiveAccount: "", + HasPaymentPassword: false, + }, nil + } + return nil, err + } + + // 转换实名认证信息 + var realNameAuth *chatpb.RealNameAuthInfo + if wallet.RealNameAuth.IDCard != "" { + realNameAuth = &chatpb.RealNameAuthInfo{ + IdCard: wallet.RealNameAuth.IDCard, + IdCardPhotoFront: wallet.RealNameAuth.IDCardPhotoFront, + IdCardPhotoBack: wallet.RealNameAuth.IDCardPhotoBack, + Name: wallet.RealNameAuth.Name, + AuditStatus: wallet.RealNameAuth.AuditStatus, + } + } + + return &chatpb.GetWalletInfoResp{ + Balance: wallet.Balance, + WithdrawAccount: wallet.WithdrawAccount, + WithdrawAccountType: wallet.WithdrawAccountType, + RealNameAuth: realNameAuth, + WithdrawReceiveAccount: wallet.WithdrawReceiveAccount, + HasPaymentPassword: wallet.PaymentPassword != "", + }, nil +} + +// GetWalletBalanceRecords 获取余额明细(余额变动记录) +func (o *chatSvr) GetWalletBalanceRecords(ctx context.Context, req *chatpb.GetWalletBalanceRecordsReq) (*chatpb.GetWalletBalanceRecordsResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + var total int64 + var records []*chatdb.WalletBalanceRecord + + // 根据类型查询或查询所有 + if req.Type > 0 { + // 按类型查询 + total, records, err = o.Database.GetWalletBalanceRecordsByUserIDAndType(ctx, userID, req.Type, req.Pagination) + } else { + // 查询所有 + total, records, err = o.Database.GetWalletBalanceRecords(ctx, userID, req.Pagination) + } + + if err != nil { + return nil, err + } + + // 转换为响应格式 + recordInfos := make([]*chatpb.WalletBalanceRecordInfo, 0, len(records)) + for _, record := range records { + recordInfos = append(recordInfos, &chatpb.WalletBalanceRecordInfo{ + Id: record.ID, + UserID: record.UserID, + Amount: record.Amount, + Type: record.Type, + BeforeBalance: record.BeforeBalance, + AfterBalance: record.AfterBalance, + OrderID: record.OrderID, + TransactionID: record.TransactionID, + RedPacketID: record.RedPacketID, + Remark: record.Remark, + CreateTime: record.CreateTime.UnixMilli(), + }) + } + + return &chatpb.GetWalletBalanceRecordsResp{ + Total: uint32(total), + Records: recordInfos, + }, nil +} + +// SetWithdrawAccount 设置提现账号 +func (o *chatSvr) SetWithdrawAccount(ctx context.Context, req *chatpb.SetWithdrawAccountReq) (*chatpb.SetWithdrawAccountResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if req.Account == "" { + return nil, errs.ErrArgs.WrapMsg("提现账号不能为空") + } + if req.AccountType <= 0 || req.AccountType > 3 { + return nil, errs.ErrArgs.WrapMsg("账号类型无效,必须是1-支付宝,2-微信,3-银行卡") + } + + // 更新提现账号 + if err := o.Database.UpdateWalletWithdrawAccountWithType(ctx, userID, req.Account, req.AccountType); err != nil { + return nil, err + } + + return &chatpb.SetWithdrawAccountResp{}, nil +} + +// SetPaymentPassword 设置支付密码(首次设置或修改) +func (o *chatSvr) SetPaymentPassword(ctx context.Context, req *chatpb.SetPaymentPasswordReq) (*chatpb.SetPaymentPasswordResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if req.NewPassword == "" { + return nil, errs.ErrArgs.WrapMsg("新支付密码不能为空") + } + + // 清理新密码(去除首尾空格) + newPassword := strings.TrimSpace(req.NewPassword) + if newPassword == "" { + return nil, errs.ErrArgs.WrapMsg("新支付密码不能为空") + } + + // 获取钱包信息 + wallet, err := o.Database.GetWallet(ctx, userID) + if err != nil { + // 如果钱包不存在,创建钱包并设置支付密码 + if errors.Is(err, mongo.ErrNoDocuments) { + // 首次设置,不需要验证旧密码 + if req.OldPassword != "" { + return nil, errs.ErrArgs.WrapMsg("首次设置支付密码不需要提供旧密码") + } + + // 创建钱包并设置支付密码 + now := time.Now() + newWallet := &chatdb.Wallet{ + UserID: userID, + Balance: 0, + PaymentPassword: newPassword, + CreateTime: now, + UpdateTime: now, + } + if err := o.Database.CreateWallet(ctx, newWallet); err != nil { + return nil, err + } + + return &chatpb.SetPaymentPasswordResp{}, nil + } + return nil, err + } + + // 钱包已存在,判断是首次设置还是修改 + hasPaymentPassword := wallet.PaymentPassword != "" + + if hasPaymentPassword { + // 修改支付密码,需要验证旧密码 + if req.OldPassword == "" { + return nil, errs.ErrArgs.WrapMsg("修改支付密码需要提供旧密码") + } + // 清理旧密码和存储的密码(去除首尾空格) + oldPassword := strings.TrimSpace(req.OldPassword) + storedPassword := strings.TrimSpace(wallet.PaymentPassword) + if storedPassword != oldPassword { + return nil, errs.ErrArgs.WrapMsg("旧支付密码错误") + } + if newPassword == oldPassword { + return nil, errs.ErrArgs.WrapMsg("新密码不能与旧密码相同") + } + } else { + // 首次设置支付密码,不需要验证旧密码 + if req.OldPassword != "" { + return nil, errs.ErrArgs.WrapMsg("首次设置支付密码不需要提供旧密码") + } + } + + // 更新支付密码 + if err := o.Database.UpdateWalletPaymentPassword(ctx, userID, newPassword); err != nil { + return nil, err + } + + return &chatpb.SetPaymentPasswordResp{}, nil +} + +// CreateWithdrawApplication 申请提现 +func (o *chatSvr) CreateWithdrawApplication(ctx context.Context, req *chatpb.CreateWithdrawApplicationReq) (*chatpb.CreateWithdrawApplicationResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 验证必填字段 + if req.Amount <= 0 { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现金额必须大于0") + } + if req.PaymentPassword == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "支付密码不能为空") + } + + // 从数据库 SystemConfig 集合读取 withdraw_limit 配置并验证提现限额 + withdrawLimitConfig, _ := o.Database.GetSystemConfig(ctx, "withdraw_limit") + if withdrawLimitConfig != nil { + // 如果配置存在但未启用,跳过验证 + if !withdrawLimitConfig.Enabled { + log.ZInfo(ctx, "withdraw_limit config is disabled, skipping validation") + } else { + // 配置存在且启用,必须验证 + limitValue := strings.TrimSpace(withdrawLimitConfig.Value) + if limitValue == "" { + log.ZWarn(ctx, "withdraw_limit config value is empty", nil) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现限额配置错误,请联系管理员") + } + + // 解析提现限制配置(格式:最低限制-最高限制,单位:元,需要转换为分) + parts := strings.Split(limitValue, "-") + if len(parts) != 2 { + log.ZWarn(ctx, "Invalid withdraw_limit config format, expected 'min-max'", nil, + "value", limitValue) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现限额配置格式错误,请联系管理员") + } + + minLimitStr := strings.TrimSpace(parts[0]) + maxLimitStr := strings.TrimSpace(parts[1]) + minLimitYuan, err1 := strconv.ParseFloat(minLimitStr, 64) + maxLimitYuan, err2 := strconv.ParseFloat(maxLimitStr, 64) + + if err1 != nil || err2 != nil { + log.ZWarn(ctx, "Failed to parse withdraw_limit config values", nil, + "minLimitStr", minLimitStr, + "maxLimitStr", maxLimitStr, + "minLimitErr", err1, + "maxLimitErr", err2) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现限额配置解析失败,请联系管理员") + } + + // 将元转换为分(乘以100) + minLimit := int64(minLimitYuan * 100) + maxLimit := int64(maxLimitYuan * 100) + + // 验证配置值的有效性 + if minLimit <= 0 { + log.ZWarn(ctx, "Invalid withdraw_limit minLimit, must be greater than 0", nil, + "minLimitYuan", minLimitYuan, + "minLimit", minLimit) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现最低限额配置无效,请联系管理员") + } + if maxLimit <= 0 { + log.ZWarn(ctx, "Invalid withdraw_limit maxLimit, must be greater than 0", nil, + "maxLimitYuan", maxLimitYuan, + "maxLimit", maxLimit) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现最高限额配置无效,请联系管理员") + } + if minLimit > maxLimit { + log.ZWarn(ctx, "Invalid withdraw_limit config, minLimit > maxLimit", nil, + "minLimitYuan", minLimitYuan, + "maxLimitYuan", maxLimitYuan, + "minLimit", minLimit, + "maxLimit", maxLimit) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "提现限额配置错误(最低限额不能大于最高限额),请联系管理员") + } + + // 验证提现金额是否在限制范围内(req.Amount 单位是分) + if req.Amount < minLimit { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), fmt.Sprintf("提现金额不能少于 %.2f 元(%d 分)", minLimitYuan, minLimit)) + } + if req.Amount > maxLimit { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), fmt.Sprintf("提现金额不能超过 %.2f 元(%d 分)", maxLimitYuan, maxLimit)) + } + + log.ZInfo(ctx, "Withdraw amount validated against withdraw_limit config", + "amount", req.Amount, + "minLimit", minLimit, + "maxLimit", maxLimit) + } + } + + // 清理支付密码(去除首尾空格) + paymentPassword := strings.TrimSpace(req.PaymentPassword) + if paymentPassword == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "支付密码不能为空") + } + + // 获取钱包信息,验证余额是否足够 + wallet, err := o.Database.GetWallet(ctx, userID) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "钱包不存在,无法申请提现") + } + return nil, err + } + + // 检查是否已完成实名认证 + if wallet.RealNameAuth.IDCard == "" || wallet.RealNameAuth.Name == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "请先完成实名认证才能申请提现") + } + + // 检查实名认证审核状态,必须为审核通过(1)才能提现 + if wallet.RealNameAuth.AuditStatus != 1 { + switch wallet.RealNameAuth.AuditStatus { + case 0: + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "实名认证正在审核中,请等待审核通过后再申请提现") + case 2: + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "实名认证审核未通过,无法申请提现") + default: + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "实名认证状态异常,无法申请提现") + } + } + + // 检查是否设置了支付密码 + if wallet.PaymentPassword == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "请先设置支付密码") + } + + // 清理数据库中存储的支付密码(去除首尾空格) + storedPassword := strings.TrimSpace(wallet.PaymentPassword) + + // 调试日志:打印支付密码验证信息 + log.ZInfo(ctx, "支付密码验证调试", + "userID", userID, + "inputPassword", paymentPassword, + "inputPasswordLen", len(paymentPassword), + "storedPassword", storedPassword, + "storedPasswordLen", len(storedPassword), + "storedPasswordRaw", wallet.PaymentPassword, + "storedPasswordRawLen", len(wallet.PaymentPassword), + "match", storedPassword == paymentPassword, + ) + + // 验证支付密码 + if storedPassword != paymentPassword { + log.ZWarn(ctx, "支付密码验证失败", nil, + "userID", userID, + "inputPassword", paymentPassword, + "storedPassword", storedPassword, + ) + return nil, eerrs.ErrPaymentPassword.WrapMsg("支付密码错误") + } + + // 检查余额是否足够 + if wallet.Balance < req.Amount { + return nil, eerrs.ErrInsufficientBalance.WrapMsg("余额不足,无法申请提现") + } + + // 从钱包中获取提现账号 + if wallet.WithdrawAccount == "" { + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "请先在钱包中设置提现账号") + } + + // 使用事务:扣减余额、创建余额变动记录、创建提现申请 + applicationID := uuid.New().String() + now := time.Now() + + // 扣减余额(使用负数表示扣款) + beforeBalance, afterBalance, err := o.Database.IncrementWalletBalance(ctx, userID, -req.Amount) + if err != nil { + // IncrementWalletBalance 已经返回了具体的错误信息(如余额不足),直接返回 + return nil, err + } + + // 创建余额变动记录 + balanceRecord := &chatdb.WalletBalanceRecord{ + ID: uuid.New().String(), + UserID: userID, + Amount: -req.Amount, // 负数表示减少 + Type: chatdb.BalanceRecordTypeWithdraw, // 提现/提款 + BeforeBalance: beforeBalance, + AfterBalance: afterBalance, + Remark: "提现申请", + CreateTime: now, + } + if err := o.Database.CreateWalletBalanceRecord(ctx, balanceRecord); err != nil { + // 如果创建记录失败,回滚余额(增加回去) + _, _, _ = o.Database.IncrementWalletBalance(ctx, userID, req.Amount) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "创建余额变动记录失败") + } + + // 创建提现申请 + application := &chatdb.WithdrawApplication{ + ID: applicationID, + UserID: userID, + Amount: req.Amount, + WithdrawAccount: wallet.WithdrawAccount, + WithdrawAccountType: wallet.WithdrawAccountType, + Status: chatdb.WithdrawApplicationStatusPending, // 待审核 + IP: req.Ip, + DeviceID: req.DeviceID, + Platform: req.Platform, + DeviceModel: req.DeviceModel, + DeviceBrand: req.DeviceBrand, + OSVersion: req.OsVersion, + AppVersion: req.AppVersion, + Remark: "", // 备注由后台管理员填写 + CreateTime: now, + UpdateTime: now, + } + + // 保存提现申请 + if err := o.Database.CreateWithdrawApplication(ctx, application); err != nil { + // 如果创建申请失败,回滚余额(增加回去) + // 注意:余额变动记录保留,因为余额确实已经扣减了 + // 如果后续需要,可以通过记录ID删除余额变动记录 + _, _, _ = o.Database.IncrementWalletBalance(ctx, userID, req.Amount) + return nil, errs.NewCodeError(errs.ErrArgs.Code(), "创建提现申请失败,余额已回滚") + } + + return &chatpb.CreateWithdrawApplicationResp{ + ApplicationID: applicationID, + }, nil +} + +// GetWithdrawApplications 获取用户的提现申请列表 +func (o *chatSvr) GetWithdrawApplications(ctx context.Context, req *chatpb.GetWithdrawApplicationsReq) (*chatpb.GetWithdrawApplicationsResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 获取提现申请列表 + total, applications, err := o.Database.GetWithdrawApplicationsByUserID(ctx, userID, req.Pagination) + if err != nil { + return nil, err + } + + // 转换为响应格式 + applicationInfos := make([]*chatpb.WithdrawApplicationInfo, 0, len(applications)) + for _, app := range applications { + var auditTime int64 + if !app.AuditTime.IsZero() { + auditTime = app.AuditTime.UnixMilli() + } + applicationInfos = append(applicationInfos, &chatpb.WithdrawApplicationInfo{ + Id: app.ID, + UserID: app.UserID, + Amount: app.Amount, + WithdrawAccount: app.WithdrawAccount, + WithdrawAccountType: app.WithdrawAccountType, + Status: app.Status, + AuditorID: app.AuditorID, + AuditTime: auditTime, + AuditRemark: app.AuditRemark, + Ip: app.IP, + DeviceID: app.DeviceID, + Platform: app.Platform, + DeviceModel: app.DeviceModel, + DeviceBrand: app.DeviceBrand, + OsVersion: app.OSVersion, + AppVersion: app.AppVersion, + Remark: app.Remark, + CreateTime: app.CreateTime.UnixMilli(), + UpdateTime: app.UpdateTime.UnixMilli(), + }) + } + + return &chatpb.GetWithdrawApplicationsResp{ + Total: uint32(total), + Applications: applicationInfos, + }, nil +} + +// RealNameAuth 实名认证 +func (o *chatSvr) RealNameAuth(ctx context.Context, req *chatpb.RealNameAuthReq) (*chatpb.RealNameAuthResp, error) { + // 获取用户ID + userID, _, err := mctx.Check(ctx) + if err != nil { + return nil, err + } + + // 检查用户是否已经实名认证且审核通过 + wallet, err := o.Database.GetWallet(ctx, userID) + if err == nil && wallet != nil { + // 如果已经实名认证且审核状态为通过(1),不允许重新认证 + if wallet.RealNameAuth.IDCard != "" && wallet.RealNameAuth.AuditStatus == 1 { + return nil, errs.ErrArgs.WrapMsg("您已经完成实名认证,不能重新认证") + } + } else if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + // 如果不是"文档不存在"的错误,返回错误 + return nil, err + } + + // 验证必填字段 + if req.IdCard == "" { + return nil, errs.ErrArgs.WrapMsg("身份证号不能为空") + } + if req.Name == "" { + return nil, errs.ErrArgs.WrapMsg("真实姓名不能为空") + } + if req.IdCardPhotoFront == "" { + return nil, errs.ErrArgs.WrapMsg("身份证正面照片不能为空") + } + if req.IdCardPhotoBack == "" { + return nil, errs.ErrArgs.WrapMsg("身份证反面照片不能为空") + } + + // 清理输入(去除首尾空格) + idCard := strings.TrimSpace(req.IdCard) + name := strings.TrimSpace(req.Name) + idCardPhotoFront := strings.TrimSpace(req.IdCardPhotoFront) + idCardPhotoBack := strings.TrimSpace(req.IdCardPhotoBack) + + if idCard == "" || name == "" { + return nil, errs.ErrArgs.WrapMsg("身份证号和姓名不能为空") + } + if idCardPhotoFront == "" || idCardPhotoBack == "" { + return nil, errs.ErrArgs.WrapMsg("身份证正面照片和反面照片不能为空") + } + + // 验证姓名只能包含中文字符(不允许英文、数字和标点符号) + chineseRegex := regexp.MustCompile(`^[\p{Han}]+$`) + if !chineseRegex.MatchString(name) { + return nil, errs.ErrArgs.WrapMsg("真实姓名只能包含中文,不能包含英文、数字或标点符号") + } + + // 构建原始数据 JSON + rawData := map[string]string{ + "cardNo": idCard, + "realName": name, + } + rawDataJSON, err := json.Marshal(rawData) + if err != nil { + return nil, errs.WrapMsg(err, "构建数据失败") + } + + // AES 密钥(32字节的十六进制字符串) + aesKey := "a7f3c9e2b8d4f1a6c3e9b2d7f4a1c8e5b2d9f6a3c8e1b4d7f2a9c5e8b1d4f7a2" + + // 在客户端本地加密数据(使用 AES-GCM 模式) + log.ZInfo(ctx, "开始本地加密实名认证数据", "userID", userID, "rawData", string(rawDataJSON), "idCard", idCard, "name", name) + encryptedData, err := util.EncryptRealNameAuthData(string(rawDataJSON), aesKey) + if err != nil { + log.ZError(ctx, "本地加密失败", err, "userID", userID) + return nil, errs.WrapMsg(err, "加密数据失败") + } + log.ZInfo(ctx, "本地加密成功", "userID", userID, "encryptedLength", len(encryptedData), "encryptedData", encryptedData) + + // 调用验证接口(直接发送加密后的字符串) + baseURL := "http://95.40.154.128" + verifyURL := baseURL + "/idcheck" + + log.ZInfo(ctx, "准备调用验证接口", "userID", userID, "url", verifyURL, "encryptedLength", len(encryptedData)) + + // 创建请求,请求体直接是加密后的字符串 + httpReq, err := http.NewRequest("POST", verifyURL, bytes.NewBufferString(encryptedData)) + if err != nil { + log.ZError(ctx, "创建验证请求失败", err, "userID", userID, "url", verifyURL) + return nil, errs.WrapMsg(err, "创建验证请求失败") + } + httpReq.Header.Set("Content-Type", "application/json") + + // 发送请求 + client := &http.Client{Timeout: 30 * time.Second} + verifyResp, err := client.Do(httpReq) + if err != nil { + log.ZError(ctx, "调用验证接口失败", err, "userID", userID, "url", verifyURL) + return nil, errs.WrapMsg(err, "调用验证接口失败") + } + defer verifyResp.Body.Close() + + verifyRespBody, err := io.ReadAll(verifyResp.Body) + if err != nil { + return nil, errs.WrapMsg(err, "读取验证接口响应失败") + } + + log.ZInfo(ctx, "验证接口响应", "userID", userID, "statusCode", verifyResp.StatusCode, "responseBody", string(verifyRespBody), "responseLength", len(verifyRespBody)) + + // 检查 HTTP 状态码 + if verifyResp.StatusCode != http.StatusOK { + log.ZWarn(ctx, "验证接口返回错误状态码", nil, "userID", userID, "statusCode", verifyResp.StatusCode, "response", string(verifyRespBody)) + return &chatpb.RealNameAuthResp{ + Success: false, + Message: fmt.Sprintf("验证请求失败,状态码: %d, 响应: %s", verifyResp.StatusCode, string(verifyRespBody)), + }, nil + } + + // 解析响应(格式:{"success": bool, "data": interface{}, "error": string, "message": string}) + var verifyResult struct { + Success bool `json:"success"` + Data interface{} `json:"data"` + Error string `json:"error,omitempty"` + Message string `json:"message,omitempty"` + } + if err := json.Unmarshal(verifyRespBody, &verifyResult); err != nil { + log.ZWarn(ctx, "解析验证接口响应失败", err, "userID", userID, "response", string(verifyRespBody)) + return &chatpb.RealNameAuthResp{ + Success: false, + Message: fmt.Sprintf("解析验证结果失败: %s, 响应: %s", err.Error(), string(verifyRespBody)), + }, nil + } + + // 检查验证结果 + if !verifyResult.Success { + errorMsg := verifyResult.Error + if errorMsg == "" { + errorMsg = verifyResult.Message + } + if errorMsg == "" { + errorMsg = "验证失败" + } + + return &chatpb.RealNameAuthResp{ + Success: false, + Message: errorMsg, + }, nil + } + + // 验证成功,保存实名认证信息到数据库 + if verifyResult.Success { + // 获取或创建钱包 + _, err := o.Database.GetWallet(ctx, userID) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + // 钱包不存在,创建钱包 + now := time.Now() + newWallet := &chatdb.Wallet{ + UserID: userID, + Balance: 0, + RealNameAuth: chatdb.RealNameAuth{ + IDCard: idCard, + Name: name, + IDCardPhotoFront: idCardPhotoFront, + IDCardPhotoBack: idCardPhotoBack, + AuditStatus: 0, // 0-未审核 + }, + CreateTime: now, + UpdateTime: now, + } + if err := o.Database.CreateWallet(ctx, newWallet); err != nil { + return nil, errs.WrapMsg(err, "创建钱包失败") + } + } else { + return nil, err + } + } else { + // 更新实名认证信息(重新提交后,审核状态重置为待审核) + realNameAuth := chatdb.RealNameAuth{ + IDCard: idCard, + Name: name, + IDCardPhotoFront: idCardPhotoFront, + IDCardPhotoBack: idCardPhotoBack, + AuditStatus: 0, // 0-未审核(重新提交后重置为待审核状态) + } + if err := o.Database.UpdateWalletRealNameAuth(ctx, userID, realNameAuth); err != nil { + return nil, errs.WrapMsg(err, "更新实名认证信息失败") + } + log.ZInfo(ctx, "实名认证信息已更新,审核状态重置为待审核", "userID", userID, "idCard", idCard, "name", name, "auditStatus", 0) + } + + log.ZInfo(ctx, "实名认证成功并已保存", "userID", userID, "idCard", idCard, "name", name) + + // 获取更新后的钱包信息,返回身份证照片URL + updatedWallet, err := o.Database.GetWallet(ctx, userID) + var idCardPhotoFront, idCardPhotoBack string + if err == nil && updatedWallet != nil { + idCardPhotoFront = updatedWallet.RealNameAuth.IDCardPhotoFront + idCardPhotoBack = updatedWallet.RealNameAuth.IDCardPhotoBack + } + + return &chatpb.RealNameAuthResp{ + Success: true, + Message: "提交成功了,请等待审核", + IdCardPhotoFront: idCardPhotoFront, + IdCardPhotoBack: idCardPhotoBack, + }, nil + } + + // 这行代码永远不会执行到,因为如果 verifyResult.Success 为 false,已经在前面返回了 + // 但为了代码完整性保留 + log.ZError(ctx, "代码逻辑错误:验证失败但未返回", nil, "userID", userID, "verifyResult", verifyResult) + return &chatpb.RealNameAuthResp{ + Success: false, + Message: "验证失败", + }, nil +} diff --git a/livekit/livekit.yaml b/livekit/livekit.yaml new file mode 100644 index 0000000..b6243f2 --- /dev/null +++ b/livekit/livekit.yaml @@ -0,0 +1,9 @@ +port: 7880 +rtc: + tcp_port: 7881 + port_range_start: 50000 + port_range_end: 60000 + use_external_ip: false + enable_loopback_candidate: false +keys: + APIGPW3gnFTzqHH: 23ztfSqsfQ8hKkHzHTl3Z4bvaxro0snjk5jwbp5p6Q3 \ No newline at end of file diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000..2b2ef7c --- /dev/null +++ b/magefile.go @@ -0,0 +1,104 @@ +//go:build mage +// +build mage + +package main + +import ( + "flag" + "os" + + "github.com/openimsdk/gomake/mageutil" +) + +var Default = Build + +var Aliases = map[string]any{ + "buildcc": BuildWithCustomConfig, + "startcc": StartWithCustomConfig, +} + +var ( + customRootDir = "." // workDir in mage, default is "./"(project root directory) + customSrcDir = "cmd" // source code directory, default is "cmd" + customOutputDir = "_output" // output directory, default is "_output" + customConfigDir = "config" // configuration directory, default is "config" + customToolsDir = "tools" // tools source code directory, default is "tools" +) + +// Build support specifical binary build. +// +// Example: `mage build chat-api chat-rpc check-component` +func Build() { + flag.Parse() + bin := flag.Args() + if len(bin) != 0 { + bin = bin[1:] + } + + mageutil.Build(bin, nil) +} + +func BuildWithCustomConfig() { + flag.Parse() + bin := flag.Args() + if len(bin) != 0 { + bin = bin[1:] + } + + config := &mageutil.PathOptions{ + RootDir: &customRootDir, + OutputDir: &customOutputDir, + SrcDir: &customSrcDir, + ToolsDir: &customToolsDir, + } + + mageutil.Build(bin, config) +} + +func Start() { + mageutil.InitForSSC() + err := setMaxOpenFiles() + if err != nil { + mageutil.PrintRed("setMaxOpenFiles failed " + err.Error()) + os.Exit(1) + } + + flag.Parse() + bin := flag.Args() + if len(bin) != 0 { + bin = bin[1:] + } + + mageutil.StartToolsAndServices(bin, nil) +} + +func StartWithCustomConfig() { + mageutil.InitForSSC() + err := setMaxOpenFiles() + if err != nil { + mageutil.PrintRed("setMaxOpenFiles failed " + err.Error()) + os.Exit(1) + } + + flag.Parse() + bin := flag.Args() + if len(bin) != 0 { + bin = bin[1:] + } + + config := &mageutil.PathOptions{ + RootDir: &customRootDir, + OutputDir: &customOutputDir, + ConfigDir: &customConfigDir, + } + + mageutil.StartToolsAndServices(bin, config) +} + +func Stop() { + mageutil.StopAndCheckBinaries() +} + +func Check() { + mageutil.CheckAndReportBinariesStatus() +} diff --git a/magefile_unix.go b/magefile_unix.go new file mode 100644 index 0000000..ff6b6de --- /dev/null +++ b/magefile_unix.go @@ -0,0 +1,20 @@ +//go:build mage && !windows +// +build mage,!windows + +package main + +import ( + "github.com/openimsdk/gomake/mageutil" + "syscall" +) + +func setMaxOpenFiles() error { + var rLimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + rLimit.Max = uint64(mageutil.MaxFileDescriptors) + rLimit.Cur = uint64(mageutil.MaxFileDescriptors) + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) +} diff --git a/magefile_windows.go b/magefile_windows.go new file mode 100644 index 0000000..7441bfd --- /dev/null +++ b/magefile_windows.go @@ -0,0 +1,8 @@ +//go:build mage +// +build mage + +package main + +func setMaxOpenFiles() error { + return nil +} diff --git a/pkg/botstruct/check.go b/pkg/botstruct/check.go new file mode 100644 index 0000000..b107a1c --- /dev/null +++ b/pkg/botstruct/check.go @@ -0,0 +1,11 @@ +package botstruct + +import ( + "strings" + + "git.imall.cloud/openim/chat/pkg/common/constant" +) + +func IsAgentUserID(userID string) bool { + return strings.HasPrefix(userID, constant.AgentUserIDPrefix) +} diff --git a/pkg/botstruct/const.go b/pkg/botstruct/const.go new file mode 100644 index 0000000..ac5296f --- /dev/null +++ b/pkg/botstruct/const.go @@ -0,0 +1,11 @@ +package botstruct + +const ( + Key = "key" + AgentIDPrefix = "agent_" +) + +const ( + RoleDeveloper = "developer" + RoleUser = "user" +) diff --git a/pkg/botstruct/msg.go b/pkg/botstruct/msg.go new file mode 100644 index 0000000..053269e --- /dev/null +++ b/pkg/botstruct/msg.go @@ -0,0 +1,13 @@ +package botstruct + +// see openim-sdk-core\sdk_struct\sdk_struct.go + +type TextElem struct { + Content string `json:"content"` +} + +type AtElem struct { + Text string `mapstructure:"text"` + AtUserList []string `mapstructure:"atUserList" validate:"required,max=1000"` + IsAtSelf bool `mapstructure:"isAtSelf"` +} diff --git a/pkg/common/apistruct/admin.go b/pkg/common/apistruct/admin.go new file mode 100644 index 0000000..5664027 --- /dev/null +++ b/pkg/common/apistruct/admin.go @@ -0,0 +1,38 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apistruct + +import "git.imall.cloud/openim/protocol/sdkws" + +type AdminLoginResp struct { + AdminAccount string `json:"adminAccount"` + AdminToken string `json:"adminToken"` + Nickname string `json:"nickname"` + FaceURL string `json:"faceURL"` + Level int32 `json:"level"` + AdminUserID string `json:"adminUserID"` + ImUserID string `json:"imUserID"` + ImToken string `json:"imToken"` +} + +type SearchDefaultGroupResp struct { + Total uint32 `json:"total"` + Groups []*sdkws.GroupInfo `json:"groups"` +} + +type NewUserCountResp struct { + Total int64 `json:"total"` + DateCount map[string]int64 `json:"date_count"` +} diff --git a/pkg/common/apistruct/chat.go b/pkg/common/apistruct/chat.go new file mode 100644 index 0000000..1681ca7 --- /dev/null +++ b/pkg/common/apistruct/chat.go @@ -0,0 +1,133 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apistruct + +import "git.imall.cloud/openim/protocol/sdkws" + +type UserRegisterResp struct { + ImToken string `json:"imToken"` + ChatToken string `json:"chatToken"` + UserID string `json:"userID"` +} + +type LoginResp struct { + ImToken string `json:"imToken"` + ChatToken string `json:"chatToken"` + UserID string `json:"userID"` +} + +type UpdateUserInfoResp struct{} + +type CallbackAfterSendSingleMsgReq struct { + CommonCallbackReq + RecvID string `json:"recvID"` +} + +type CommonCallbackReq struct { + SendID string `json:"sendID"` + CallbackCommand string `json:"callbackCommand"` + ServerMsgID string `json:"serverMsgID"` + ClientMsgID string `json:"clientMsgID"` + OperationID string `json:"operationID"` + SenderPlatformID int32 `json:"senderPlatformID"` + SenderNickname string `json:"senderNickname"` + SessionType int32 `json:"sessionType"` + MsgFrom int32 `json:"msgFrom"` + ContentType int32 `json:"contentType"` + Status int32 `json:"status"` + CreateTime int64 `json:"createTime"` + Content string `json:"content"` + Seq uint32 `json:"seq"` + AtUserIDList []string `json:"atUserList"` + SenderFaceURL string `json:"faceURL"` + Ex string `json:"ex"` +} + +type CallbackAfterSendSingleMsgResp struct { + CommonCallbackResp +} + +type CommonCallbackResp struct { + ActionCode int32 `json:"actionCode"` + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` + ErrDlt string `json:"errDlt"` + NextCode int32 `json:"nextCode"` +} + +type TextElem struct { + Content string `json:"content" validate:"required"` +} + +type PictureElem struct { + SourcePath string `mapstructure:"sourcePath"` + SourcePicture PictureBaseInfo `mapstructure:"sourcePicture" validate:"required"` + BigPicture PictureBaseInfo `mapstructure:"bigPicture" validate:"required"` + SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture" validate:"required"` +} + +type PictureBaseInfo struct { + UUID string `mapstructure:"uuid"` + Type string `mapstructure:"type" validate:"required"` + Size int64 `mapstructure:"size"` + Width int32 `mapstructure:"width" validate:"required"` + Height int32 `mapstructure:"height" validate:"required"` + Url string `mapstructure:"url" validate:"required"` +} + +type SendMsgReq struct { + // RecvID uniquely identifies the receiver and is required for one-on-one or notification chat types. + RecvID string `json:"recvID" binding:"required_if" message:"recvID is required if sessionType is SingleChatType or NotificationChatType"` + SendMsg +} + +// SendMsg defines the structure for sending messages with various metadata. +type SendMsg struct { + // SendID uniquely identifies the sender. + SendID string `json:"sendID" binding:"required"` + + // GroupID is the identifier for the group, required if SessionType is 2 or 3. + GroupID string `json:"groupID" binding:"required_if=SessionType 2|required_if=SessionType 3"` + + // SenderNickname is the nickname of the sender. + SenderNickname string `json:"senderNickname"` + + // SenderFaceURL is the URL to the sender's avatar. + SenderFaceURL string `json:"senderFaceURL"` + + // SenderPlatformID is an integer identifier for the sender's platform. + SenderPlatformID int32 `json:"senderPlatformID"` + + // Content is the actual content of the message, required and excluded from Swagger documentation. + Content map[string]any `json:"content" binding:"required" swaggerignore:"true"` + + // ContentType is an integer that represents the type of the content. + ContentType int32 `json:"contentType" binding:"required"` + + // SessionType is an integer that represents the type of session for the message. + SessionType int32 `json:"sessionType" binding:"required"` + + // IsOnlineOnly specifies if the message is only sent when the receiver is online. + IsOnlineOnly bool `json:"isOnlineOnly"` + + // NotOfflinePush specifies if the message should not trigger offline push notifications. + NotOfflinePush bool `json:"notOfflinePush"` + + // SendTime is a timestamp indicating when the message was sent. + SendTime int64 `json:"sendTime"` + + // OfflinePushInfo contains information for offline push notifications. + OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"` +} diff --git a/pkg/common/apistruct/config_manager.go b/pkg/common/apistruct/config_manager.go new file mode 100644 index 0000000..ca5683a --- /dev/null +++ b/pkg/common/apistruct/config_manager.go @@ -0,0 +1,28 @@ +package apistruct + +type GetConfigReq struct { + ConfigName string `json:"configName"` +} + +type GetConfigListResp struct { + Environment string `json:"environment"` + Version string `json:"version"` + ConfigNames []string `json:"configNames"` +} + +type SetConfigReq struct { + ConfigName string `json:"configName"` + Data string `json:"data"` +} + +type SetConfigsReq struct { + Configs []SetConfigReq `json:"configs"` +} + +type SetEnableConfigManagerReq struct { + Enable bool `json:"enable"` +} + +type GetEnableConfigManagerResp struct { + Enable bool `json:"enable"` +} diff --git a/pkg/common/cmd/admin_api.go b/pkg/common/cmd/admin_api.go new file mode 100644 index 0000000..c177188 --- /dev/null +++ b/pkg/common/cmd/admin_api.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/api/admin" + "git.imall.cloud/openim/chat/pkg/common/config" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type AdminApiCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + apiConfig admin.Config +} + +func NewAdminApiCmd() *AdminApiCmd { + ret := AdminApiCmd{apiConfig: admin.Config{ + AllConfig: &config.AllConfig{}, + }} + ret.configMap = map[string]any{ + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.LogConfigFileName: &ret.apiConfig.Log, + config.MongodbConfigFileName: &ret.apiConfig.Mongo, + config.ChatAPIAdminCfgFileName: &ret.apiConfig.AdminAPI, + config.ChatAPIChatCfgFileName: &ret.apiConfig.ChatAPI, + config.ChatRPCAdminCfgFileName: &ret.apiConfig.Admin, + config.ChatRPCChatCfgFileName: &ret.apiConfig.Chat, + config.RedisConfigFileName: &ret.apiConfig.Redis, + config.ShareFileName: &ret.apiConfig.Share, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + ret.apiConfig.ConfigPath = ret.configPath + return ret.runE() + } + return &ret +} + +func (a *AdminApiCmd) Exec() error { + return a.Execute() +} + +func (a *AdminApiCmd) runE() error { + return admin.Start(a.ctx, a.Index(), &a.apiConfig) +} diff --git a/pkg/common/cmd/admin_rpc.go b/pkg/common/cmd/admin_rpc.go new file mode 100644 index 0000000..a7a69d0 --- /dev/null +++ b/pkg/common/cmd/admin_rpc.go @@ -0,0 +1,68 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/rpc/admin" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type AdminRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + adminConfig admin.Config +} + +func NewAdminRpcCmd() *AdminRpcCmd { + var ret AdminRpcCmd + ret.configMap = map[string]any{ + config.ChatRPCAdminCfgFileName: &ret.adminConfig.RpcConfig, + config.RedisConfigFileName: &ret.adminConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.adminConfig.Discovery, + config.MongodbConfigFileName: &ret.adminConfig.MongodbConfig, + config.ShareFileName: &ret.adminConfig.Share, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *AdminRpcCmd) Exec() error { + return a.Execute() +} + +func (a *AdminRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.adminConfig.Discovery, a.adminConfig.RpcConfig.RPC.ListenIP, + a.adminConfig.RpcConfig.RPC.RegisterIP, a.adminConfig.RpcConfig.RPC.Ports, + a.Index(), a.adminConfig.Discovery.RpcService.Admin, &a.adminConfig.Share, &a.adminConfig, + []string{ + config.ChatRPCAdminCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, nil, + admin.Start) +} diff --git a/pkg/common/cmd/bot_api.go b/pkg/common/cmd/bot_api.go new file mode 100644 index 0000000..80b5b18 --- /dev/null +++ b/pkg/common/cmd/bot_api.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/api/bot" + "git.imall.cloud/openim/chat/pkg/common/config" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type BotApiCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + apiConfig bot.Config +} + +func NewBotApiCmd() *BotApiCmd { + ret := BotApiCmd{apiConfig: bot.Config{}} + ret.configMap = map[string]any{ + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.ChatAPIBotCfgFileName: &ret.apiConfig.ApiConfig, + config.ShareFileName: &ret.apiConfig.Share, + config.RedisConfigFileName: &ret.apiConfig.Redis, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *BotApiCmd) Exec() error { + return a.Execute() +} + +func (a *BotApiCmd) runE() error { + return bot.Start(a.ctx, a.Index(), &a.apiConfig) +} diff --git a/pkg/common/cmd/bot_rpc.go b/pkg/common/cmd/bot_rpc.go new file mode 100644 index 0000000..3cf2a8f --- /dev/null +++ b/pkg/common/cmd/bot_rpc.go @@ -0,0 +1,54 @@ +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/rpc/bot" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type BotRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + botConfig bot.Config +} + +func NewBotRpcCmd() *BotRpcCmd { + var ret BotRpcCmd + ret.configMap = map[string]any{ + config.ChatRPCBotCfgFileName: &ret.botConfig.RpcConfig, + config.RedisConfigFileName: &ret.botConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.botConfig.Discovery, + config.MongodbConfigFileName: &ret.botConfig.MongodbConfig, + config.ShareFileName: &ret.botConfig.Share, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *BotRpcCmd) Exec() error { + return a.Execute() +} + +func (a *BotRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.botConfig.Discovery, a.botConfig.RpcConfig.RPC.ListenIP, + a.botConfig.RpcConfig.RPC.RegisterIP, a.botConfig.RpcConfig.RPC.Ports, + a.Index(), a.botConfig.Discovery.RpcService.Bot, &a.botConfig.Share, &a.botConfig, + []string{ + config.ChatRPCBotCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, nil, + bot.Start) +} diff --git a/pkg/common/cmd/chat_api.go b/pkg/common/cmd/chat_api.go new file mode 100644 index 0000000..300a409 --- /dev/null +++ b/pkg/common/cmd/chat_api.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/api/chat" + "git.imall.cloud/openim/chat/pkg/common/config" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type ChatApiCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + apiConfig chat.Config +} + +func NewChatApiCmd() *ChatApiCmd { + var ret ChatApiCmd + ret.configMap = map[string]any{ + config.ShareFileName: &ret.apiConfig.Share, + config.ChatAPIChatCfgFileName: &ret.apiConfig.ApiConfig, + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.RedisConfigFileName: &ret.apiConfig.Redis, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *ChatApiCmd) Exec() error { + return a.Execute() +} + +func (a *ChatApiCmd) runE() error { + return chat.Start(a.ctx, a.Index(), &a.apiConfig) +} diff --git a/pkg/common/cmd/chat_rpc.go b/pkg/common/cmd/chat_rpc.go new file mode 100644 index 0000000..75e9e8f --- /dev/null +++ b/pkg/common/cmd/chat_rpc.go @@ -0,0 +1,68 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + + "git.imall.cloud/openim/chat/internal/rpc/chat" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type ChatRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + chatConfig chat.Config +} + +func NewChatRpcCmd() *ChatRpcCmd { + var ret ChatRpcCmd + ret.configMap = map[string]any{ + config.ChatRPCChatCfgFileName: &ret.chatConfig.RpcConfig, + config.RedisConfigFileName: &ret.chatConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.chatConfig.Discovery, + config.MongodbConfigFileName: &ret.chatConfig.MongodbConfig, + config.ShareFileName: &ret.chatConfig.Share, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *ChatRpcCmd) Exec() error { + return a.Execute() +} + +func (a *ChatRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.chatConfig.Discovery, a.chatConfig.RpcConfig.RPC.ListenIP, + a.chatConfig.RpcConfig.RPC.RegisterIP, a.chatConfig.RpcConfig.RPC.Ports, + a.Index(), a.chatConfig.Discovery.RpcService.Chat, &a.chatConfig.Share, &a.chatConfig, + []string{ + config.ChatRPCChatCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, nil, + chat.Start) +} diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go new file mode 100644 index 0000000..3fc4beb --- /dev/null +++ b/pkg/common/cmd/root.go @@ -0,0 +1,266 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + "encoding/json" + "fmt" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + "git.imall.cloud/openim/chat/version" + "github.com/openimsdk/tools/discovery/etcd" + clientv3 "go.etcd.io/etcd/client/v3" + + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/runtimeenv" + + "github.com/spf13/cobra" +) + +type RootCmd struct { + Command cobra.Command + processName string + port int + prometheusPort int + log config.Log + index int + configPath string + etcdClient *clientv3.Client +} + +func (r *RootCmd) Index() int { + return r.index +} + +func (r *RootCmd) Port() int { + return r.port +} + +type CmdOpts struct { + loggerPrefixName string + configMap map[string]any +} + +func WithLogName(logName string) func(*CmdOpts) { + return func(opts *CmdOpts) { + opts.loggerPrefixName = logName + } +} +func WithConfigMap(configMap map[string]any) func(*CmdOpts) { + return func(opts *CmdOpts) { + opts.configMap = configMap + } +} + +func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd { + rootCmd := &RootCmd{processName: processName} + cmd := cobra.Command{ + Use: "Start openIM chat application", + Long: fmt.Sprintf(`Start %s `, processName), + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + return rootCmd.persistentPreRun(cmd, opts...) + }, + SilenceUsage: true, + SilenceErrors: false, + } + cmd.Flags().StringP(config.FlagConf, "c", "", "path of config directory") + cmd.Flags().IntP(config.FlagTransferIndex, "i", 0, "process startup sequence number") + + rootCmd.Command = cmd + return rootCmd +} + +func (r *RootCmd) initEtcd() error { + configDirectory, _, err := r.getFlag(&r.Command) + if err != nil { + return err + } + disConfig := config.Discovery{} + env := runtimeenv.PrintRuntimeEnvironment() + err = config.Load(configDirectory, config.DiscoveryConfigFileName, config.EnvPrefixMap[config.DiscoveryConfigFileName], + env, &disConfig) + if err != nil { + return err + } + if disConfig.Enable == kdisc.ETCDCONST { + discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env, nil) + // 安全类型断言:仅当为 etcd 实现时才获取客户端,避免在 K8s 模式下崩溃 + if etcdDiscov, ok := discov.(*etcd.SvcDiscoveryRegistryImpl); ok { + r.etcdClient = etcdDiscov.GetClient() + } + } + return nil +} + +func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error { + if err := r.initEtcd(); err != nil { + return err + } + cmdOpts := r.applyOptions(opts...) + if err := r.initializeConfiguration(cmd, cmdOpts); err != nil { + return err + } + if err := r.updateConfigFromEtcd(cmdOpts); err != nil { + return err + } + if err := r.initializeLogger(cmdOpts); err != nil { + return errs.WrapMsg(err, "failed to initialize logger") + } + if r.etcdClient != nil { + if err := r.etcdClient.Close(); err != nil { + return errs.WrapMsg(err, "failed to close etcd client") + } + } + + return nil +} + +func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) error { + configDirectory, _, err := r.getFlag(cmd) + if err != nil { + return err + } + r.configPath = configDirectory + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + // Load common configuration file + //opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share} + for configFileName, configStruct := range opts.configMap { + err := config.Load(configDirectory, configFileName, + config.EnvPrefixMap[configFileName], runtimeEnv, configStruct) + if err != nil { + return err + } + } + // Load common log configuration file + return config.Load(configDirectory, config.LogConfigFileName, + config.EnvPrefixMap[config.LogConfigFileName], runtimeEnv, &r.log) +} + +func (r *RootCmd) updateConfigFromEtcd(opts *CmdOpts) error { + if r.etcdClient == nil { + return nil + } + ctx := context.TODO() + + res, err := r.etcdClient.Get(ctx, disetcd.BuildKey(disetcd.EnableConfigCenterKey)) + if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get EnableConfigCenterKey err: %v", errs.Wrap(err)) + return nil + } + if res.Count == 0 { + return nil + } else { + if string(res.Kvs[0].Value) == disetcd.Disable { + return nil + } else if string(res.Kvs[0].Value) != disetcd.Enable { + return errs.New("unknown EnableConfigCenter value").Wrap() + } + } + + update := func(configFileName string, configStruct any) error { + key := disetcd.BuildKey(configFileName) + etcdRes, err := r.etcdClient.Get(ctx, key) + if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get err: %v", errs.Wrap(err)) + return nil + } + if etcdRes.Count == 0 { + data, err := json.Marshal(configStruct) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + _, err = r.etcdClient.Put(ctx, disetcd.BuildKey(configFileName), string(data)) + if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Put err: %v", errs.Wrap(err)) + } + return nil + } + err = json.Unmarshal(etcdRes.Kvs[0].Value, configStruct) + if err != nil { + return errs.WrapMsg(err, "failed to unmarshal config from etcd") + } + return nil + } + for configFileName, configStruct := range opts.configMap { + if err := update(configFileName, configStruct); err != nil { + return err + } + } + if err := update(config.LogConfigFileName, &r.log); err != nil { + return err + } + // Load common log configuration file + return nil + +} + +func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { + cmdOpts := defaultCmdOpts() + for _, opt := range opts { + opt(cmdOpts) + } + + return cmdOpts +} + +func (r *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { + err := log.InitLoggerFromConfig( + cmdOpts.loggerPrefixName, + r.processName, + "", "", + r.log.RemainLogLevel, + r.log.IsStdout, + r.log.IsJson, + r.log.StorageLocation, + r.log.RemainRotationCount, + r.log.RotationTime, + version.Version, + r.log.IsSimplify, + ) + if err != nil { + return errs.Wrap(err) + } + return errs.Wrap(log.InitConsoleLogger(r.processName, r.log.RemainLogLevel, r.log.IsJson, config.Version)) + +} + +func defaultCmdOpts() *CmdOpts { + return &CmdOpts{ + loggerPrefixName: "openim-chat-log", + } +} + +func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) { + configDirectory, err := cmd.Flags().GetString(config.FlagConf) + if err != nil { + return "", 0, errs.Wrap(err) + } + index, err := cmd.Flags().GetInt(config.FlagTransferIndex) + if err != nil { + return "", 0, errs.Wrap(err) + } + r.index = index + return configDirectory, index, nil +} + +func (r *RootCmd) Execute() error { + return r.Command.Execute() +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go new file mode 100644 index 0000000..dd38cdd --- /dev/null +++ b/pkg/common/config/config.go @@ -0,0 +1,247 @@ +package config + +import ( + _ "embed" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" +) + +var ( + //go:embed version + Version string + //go:embed template.xlsx + ImportTemplate []byte +) + +type Share struct { + OpenIM struct { + ApiURL string `mapstructure:"apiURL"` + Secret string `mapstructure:"secret"` + AdminUserID string `mapstructure:"adminUserID"` + TokenRefreshInterval int `mapstructure:"tokenRefreshInterval"` + } `mapstructure:"openIM"` + ChatAdmin []string `mapstructure:"chatAdmin"` + ProxyHeader string `mapstructure:"proxyHeader"` +} + +type RpcService struct { + Chat string `mapstructure:"chat"` + Admin string `mapstructure:"admin"` + Bot string `mapstructure:"bot"` +} + +func (r *RpcService) GetServiceNames() []string { + return []string{ + r.Chat, + r.Admin, + } +} + +type API struct { + Api struct { + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"api"` +} + +type APIBot struct { + Api struct { + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"api"` +} + +type Mongo struct { + URI string `mapstructure:"uri"` + Address []string `mapstructure:"address"` + Database string `mapstructure:"database"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + AuthSource string `mapstructure:"authSource"` + MaxPoolSize int `mapstructure:"maxPoolSize"` + MaxRetry int `mapstructure:"maxRetry"` +} + +func (m *Mongo) Build() *mongoutil.Config { + return &mongoutil.Config{ + Uri: m.URI, + Address: m.Address, + Database: m.Database, + Username: m.Username, + Password: m.Password, + AuthSource: m.AuthSource, + MaxPoolSize: m.MaxPoolSize, + MaxRetry: m.MaxRetry, + } +} + +type Redis struct { + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + EnablePipeline bool `mapstructure:"enablePipeline"` + ClusterMode bool `mapstructure:"clusterMode"` + DB int `mapstructure:"db"` + MaxRetry int `mapstructure:"MaxRetry"` +} + +func (r *Redis) Build() *redisutil.Config { + return &redisutil.Config{ + ClusterMode: r.ClusterMode, + Address: r.Address, + Username: r.Username, + Password: r.Password, + DB: r.DB, + MaxRetry: r.MaxRetry, + } +} + +type Discovery struct { + Enable string `mapstructure:"enable"` + Etcd Etcd `mapstructure:"etcd"` + Kubernetes Kubernetes `mapstructure:"kubernetes"` + RpcService RpcService `mapstructure:"rpcService"` +} + +type Kubernetes struct { + Namespace string `mapstructure:"namespace"` +} + +type Etcd struct { + RootDirectory string `mapstructure:"rootDirectory"` + Address []string `mapstructure:"address"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` +} + +type Chat struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + VerifyCode VerifyCode `mapstructure:"verifyCode"` + LiveKit struct { + URL string `mapstructure:"url"` + Key string `mapstructure:"key"` + Secret string `mapstructure:"secret"` + } `mapstructure:"liveKit"` + AllowRegister bool `mapstructure:"allowRegister"` +} + +type Bot struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Timeout int `mapstructure:"timeout"` +} +type VerifyCode struct { + ValidTime int `mapstructure:"validTime"` + ValidCount int `mapstructure:"validCount"` + UintTime int `mapstructure:"uintTime"` + MaxCount int `mapstructure:"maxCount"` + SuperCode string `mapstructure:"superCode"` + Len int `mapstructure:"len"` + Phone struct { + Use string `mapstructure:"use"` + Ali struct { + Endpoint string `mapstructure:"endpoint"` + AccessKeyID string `mapstructure:"accessKeyId"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + SignName string `mapstructure:"signName"` + VerificationCodeTemplateCode string `mapstructure:"verificationCodeTemplateCode"` + } `mapstructure:"ali"` + Bao struct { + Endpoint string `mapstructure:"endpoint"` + AccessKeyID string `mapstructure:"accessKeyId"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + SignName string `mapstructure:"signName"` + VerificationCodeTemplateCode string `mapstructure:"verificationCodeTemplateCode"` + } `mapstructure:"bao"` + } `mapstructure:"phone"` + Mail struct { + Use string `mapstructure:"use"` + Title string `mapstructure:"title"` + SenderMail string `mapstructure:"senderMail"` + SenderAuthorizationCode string `mapstructure:"senderAuthorizationCode"` + SMTPAddr string `mapstructure:"smtpAddr"` + SMTPPort int `mapstructure:"smtpPort"` + } `mapstructure:"mail"` +} + +type Admin struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + TokenPolicy struct { + Expire int `mapstructure:"expire"` + } `mapstructure:"tokenPolicy"` + Secret string `mapstructure:"secret"` +} + +type Log struct { + StorageLocation string `mapstructure:"storageLocation"` + RotationTime uint `mapstructure:"rotationTime"` + RemainRotationCount uint `mapstructure:"remainRotationCount"` + RemainLogLevel int `mapstructure:"remainLogLevel"` + IsStdout bool `mapstructure:"isStdout"` + IsJson bool `mapstructure:"isJson"` + IsSimplify bool `mapstructure:"isSimplify"` + WithStack bool `mapstructure:"withStack"` +} + +type AllConfig struct { + AdminAPI API + ChatAPI API + Admin Admin + Chat Chat + Discovery Discovery + Log Log + Mongo Mongo + Redis Redis + Share Share +} + +func (a *AllConfig) Name2Config(name string) any { + switch name { + case ChatAPIAdminCfgFileName: + return a.AdminAPI + case ChatAPIChatCfgFileName: + return a.ChatAPI + case ChatRPCAdminCfgFileName: + return a.Admin + case ChatRPCChatCfgFileName: + return a.Chat + case DiscoveryConfigFileName: + return a.Discovery + case LogConfigFileName: + return a.Log + case MongodbConfigFileName: + return a.Mongo + case RedisConfigFileName: + return a.Redis + case ShareFileName: + return a.Share + default: + return nil + } +} + +func (a *AllConfig) GetConfigNames() []string { + return []string{ + ShareFileName, + RedisConfigFileName, + DiscoveryConfigFileName, + MongodbConfigFileName, + LogConfigFileName, + ChatAPIAdminCfgFileName, + ChatAPIChatCfgFileName, + ChatRPCAdminCfgFileName, + ChatRPCChatCfgFileName, + } +} diff --git a/pkg/common/config/env.go b/pkg/common/config/env.go new file mode 100644 index 0000000..33f0d07 --- /dev/null +++ b/pkg/common/config/env.go @@ -0,0 +1,48 @@ +package config + +import ( + "strings" +) + +var ( + ShareFileName = "share.yml" + RedisConfigFileName = "redis.yml" + DiscoveryConfigFileName = "discovery.yml" + MongodbConfigFileName = "mongodb.yml" + LogConfigFileName = "log.yml" + ChatAPIAdminCfgFileName = "chat-api-admin.yml" + ChatAPIChatCfgFileName = "chat-api-chat.yml" + ChatAPIBotCfgFileName = "chat-api-bot.yml" + ChatRPCAdminCfgFileName = "chat-rpc-admin.yml" + ChatRPCChatCfgFileName = "chat-rpc-chat.yml" + ChatRPCBotCfgFileName = "chat-rpc-bot.yml" +) + +var EnvPrefixMap map[string]string + +func init() { + EnvPrefixMap = make(map[string]string) + fileNames := []string{ + ShareFileName, + RedisConfigFileName, + DiscoveryConfigFileName, + MongodbConfigFileName, + LogConfigFileName, + ChatAPIAdminCfgFileName, + ChatAPIChatCfgFileName, + ChatRPCAdminCfgFileName, + ChatRPCChatCfgFileName, + } + + for _, fileName := range fileNames { + envKey := strings.TrimSuffix(strings.TrimSuffix(fileName, ".yml"), ".yaml") + envKey = "CHATENV_" + envKey + envKey = strings.ToUpper(strings.ReplaceAll(envKey, "-", "_")) + EnvPrefixMap[fileName] = envKey + } +} + +const ( + FlagConf = "config_folder_path" + FlagTransferIndex = "index" +) diff --git a/pkg/common/config/load.go b/pkg/common/config/load.go new file mode 100644 index 0000000..355bb6c --- /dev/null +++ b/pkg/common/config/load.go @@ -0,0 +1,45 @@ +package config + +import ( + "os" + "path/filepath" + "strings" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "github.com/mitchellh/mapstructure" + "github.com/openimsdk/tools/errs" + "github.com/spf13/viper" +) + +func Load(configDirectory string, configFileName string, envPrefix string, runtimeEnv string, config any) error { + if runtimeEnv == constant.KUBERNETES { + mountPath := os.Getenv(constant.MountConfigFilePath) + if mountPath == "" { + return errs.ErrArgs.WrapMsg(constant.MountConfigFilePath + " env is empty") + } + + return loadConfig(filepath.Join(mountPath, configFileName), envPrefix, config) + } + + return loadConfig(filepath.Join(configDirectory, configFileName), envPrefix, config) +} + +func loadConfig(path string, envPrefix string, config any) error { + v := viper.New() + v.SetConfigFile(path) + v.SetEnvPrefix(envPrefix) + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + if err := v.ReadInConfig(); err != nil { + return errs.WrapMsg(err, "failed to read config file", "path", path, "envPrefix", envPrefix) + } + + if err := v.Unmarshal(config, func(config *mapstructure.DecoderConfig) { + config.TagName = "mapstructure" + }); err != nil { + return errs.WrapMsg(err, "failed to unmarshal config", "path", path, "envPrefix", envPrefix) + } + + return nil +} diff --git a/pkg/common/config/template.xlsx b/pkg/common/config/template.xlsx new file mode 100644 index 0000000..7f40078 Binary files /dev/null and b/pkg/common/config/template.xlsx differ diff --git a/pkg/common/config/version b/pkg/common/config/version new file mode 100644 index 0000000..4e2cea3 --- /dev/null +++ b/pkg/common/config/version @@ -0,0 +1 @@ +v1.8.0 \ No newline at end of file diff --git a/pkg/common/constant/constant.go b/pkg/common/constant/constant.go new file mode 100644 index 0000000..d4bd18e --- /dev/null +++ b/pkg/common/constant/constant.go @@ -0,0 +1,128 @@ +package constant + +import "git.imall.cloud/openim/protocol/constant" + +const ( + MountConfigFilePath = "CONFIG_PATH" + KUBERNETES = "kubernetes" + ETCD = "etcd" +) + +const ( + // verificationCode used for. + VerificationCodeForRegister = 1 // Register + VerificationCodeForResetPassword = 2 // Reset password + VerificationCodeForLogin = 3 // Login + VerificationCodeForH5Register = 4 // H5 register +) + +const LogFileName = "chat.log" + +// block unblock. +const ( + BlockUser = 1 + UnblockUser = 2 +) + +// AccountType. +const ( + Email = "email" + Phone = "phone" + Account = "account" +) + +// Mode. +const ( + UserMode = "user" + AdminMode = "admin" +) + +const DefaultAdminLevel = 100 + +// user level. +const ( + NormalAdmin = 80 + AdvancedUserLevel = 100 +) + +// AddFriendCtrl. +const ( + OrdinaryUserAddFriendEnable = 1 // Allow ordinary users to add friends + OrdinaryUserAddFriendDisable = -1 // Do not allow ordinary users to add friends +) + +const ( + NormalUser = 1 + AdminUser = 2 +) + +// mini-app +const ( + StatusOnShelf = 1 // OnShelf + StatusUnShelf = 2 // UnShelf +) + +const ( + LimitNil = 0 // None + LimitEmpty = 1 // Neither are restricted + LimitOnlyLoginIP = 2 // Only login is restricted + LimitOnlyRegisterIP = 3 // Only registration is restricted + LimitLoginIP = 4 // Restrict login + LimitRegisterIP = 5 // Restrict registration + LimitLoginRegisterIP = 6 // Restrict both login and registration +) + +const ( + InvitationCodeAll = 0 // All + InvitationCodeUsed = 1 // Used + InvitationCodeUnused = 2 // Unused +) + +const ( + RpcOpUserID = constant.OpUserID + RpcOpUserType = "opUserType" +) + +const RpcCustomHeader = constant.RpcCustomHeader + +const NeedInvitationCodeRegisterConfigKey = "needInvitationCodeRegister" + +const ( + DefaultAllowVibration = 1 + DefaultAllowBeep = 1 + DefaultAllowAddFriend = 1 +) + +const ( + FinDAllUser = 0 + FindNormalUser = 1 +) + +const CtxApiToken = "api-token" + +const ( + AccountRegister = iota + EmailRegister + PhoneRegister +) + +const ( + GenderFemale = 0 // female + GenderMale = 1 // male + GenderUnknown = 2 // unknown +) + +// Credential Type +const ( + CredentialAccount = iota + CredentialPhone + CredentialEmail +) + +// verifyCode use +const ( + VerifySuperCode = "supercode" + VerifyALi = "ali" + VerifyBao = "bao" + VerifyMail = "mail" +) diff --git a/pkg/common/constant/limit.go b/pkg/common/constant/limit.go new file mode 100644 index 0000000..090ddbe --- /dev/null +++ b/pkg/common/constant/limit.go @@ -0,0 +1,21 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package constant + +const ( + ShowNumber = 1000 + StatisticsTimeInterval = 60 + MaxNotificationNum = 500 +) diff --git a/pkg/common/constant/user_id.go b/pkg/common/constant/user_id.go new file mode 100644 index 0000000..5cc00da --- /dev/null +++ b/pkg/common/constant/user_id.go @@ -0,0 +1,5 @@ +package constant + +const ( + AgentUserIDPrefix = "bot_" +) diff --git a/pkg/common/convert/agent.go b/pkg/common/convert/agent.go new file mode 100644 index 0000000..b73fafb --- /dev/null +++ b/pkg/common/convert/agent.go @@ -0,0 +1,41 @@ +package convert + +import ( + "time" + + "git.imall.cloud/openim/chat/pkg/common/db/table/bot" + pbbot "git.imall.cloud/openim/chat/pkg/protocol/bot" + "github.com/openimsdk/tools/utils/datautil" +) + +func DB2PBAgent(a *bot.Agent) *pbbot.Agent { + return &pbbot.Agent{ + UserID: a.UserID, + Nickname: a.NickName, + FaceURL: a.FaceURL, + Url: a.Url, + Key: a.Key, + Identity: a.Identity, + Model: a.Model, + Prompts: a.Prompts, + CreateTime: a.CreateTime.UnixMilli(), + } +} + +func PB2DBAgent(a *pbbot.Agent) *bot.Agent { + return &bot.Agent{ + UserID: a.UserID, + NickName: a.Nickname, + FaceURL: a.FaceURL, + Key: a.Key, + Url: a.Url, + Identity: a.Identity, + Model: a.Model, + Prompts: a.Prompts, + CreateTime: time.UnixMilli(a.CreateTime), + } +} + +func BatchDB2PBAgent(a []*bot.Agent) []*pbbot.Agent { + return datautil.Batch(DB2PBAgent, a) +} diff --git a/pkg/common/db/cache/imtoken.go b/pkg/common/db/cache/imtoken.go new file mode 100644 index 0000000..3d038d0 --- /dev/null +++ b/pkg/common/db/cache/imtoken.go @@ -0,0 +1,50 @@ +package cache + +import ( + "context" + "time" + + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" +) + +const ( + chatPrefix = "CHAT:" + imToken = chatPrefix + "IM_TOKEN:" +) + +func getIMTokenKey(userID string) string { + return imToken + userID +} + +type IMTokenInterface interface { + GetToken(ctx context.Context, userID string) (string, error) + SetToken(ctx context.Context, userID, token string) error +} + +type imTokenCacheRedis struct { + rdb redis.UniversalClient + expire time.Duration +} + +func NewIMTokenInterface(rdb redis.UniversalClient, expire int) IMTokenInterface { + return &imTokenCacheRedis{rdb: rdb, expire: time.Duration(expire) * time.Minute} +} + +func (i *imTokenCacheRedis) GetToken(ctx context.Context, userID string) (string, error) { + key := getIMTokenKey(userID) + token, err := i.rdb.Get(ctx, key).Result() + if err != nil { + return "", errs.Wrap(err) + } + return token, nil +} + +func (i *imTokenCacheRedis) SetToken(ctx context.Context, userID, token string) error { + key := getIMTokenKey(userID) + err := i.rdb.Set(ctx, key, token, i.expire).Err() + if err != nil { + return errs.Wrap(err) + } + return nil +} diff --git a/pkg/common/db/cache/token.go b/pkg/common/db/cache/token.go new file mode 100644 index 0000000..1857b12 --- /dev/null +++ b/pkg/common/db/cache/token.go @@ -0,0 +1,84 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cache + +import ( + "context" + "time" + + "github.com/openimsdk/tools/utils/stringutil" + + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" +) + +const ( + chatToken = "CHAT_UID_TOKEN_STATUS:" +) + +type TokenInterface interface { + AddTokenFlag(ctx context.Context, userID string, token string, flag int) error + AddTokenFlagNXEx(ctx context.Context, userID string, token string, flag int, expire time.Duration) (bool, error) + GetTokensWithoutError(ctx context.Context, userID string) (map[string]int32, error) + DeleteTokenByUid(ctx context.Context, userID string) error +} + +type TokenCacheRedis struct { + rdb redis.UniversalClient + accessExpire int64 +} + +func NewTokenInterface(rdb redis.UniversalClient) *TokenCacheRedis { + return &TokenCacheRedis{rdb: rdb} +} + +func (t *TokenCacheRedis) AddTokenFlag(ctx context.Context, userID string, token string, flag int) error { + key := chatToken + userID + return errs.Wrap(t.rdb.HSet(ctx, key, token, flag).Err()) +} + +func (t *TokenCacheRedis) AddTokenFlagNXEx(ctx context.Context, userID string, token string, flag int, expire time.Duration) (bool, error) { + key := chatToken + userID + isSet, err := t.rdb.HSetNX(ctx, key, token, flag).Result() + if err != nil { + return false, errs.Wrap(err) + } + if !isSet { + // key already exists + return false, nil + } + if err = t.rdb.Expire(ctx, key, expire).Err(); err != nil { + return false, errs.Wrap(err) + } + return isSet, nil +} + +func (t *TokenCacheRedis) GetTokensWithoutError(ctx context.Context, userID string) (map[string]int32, error) { + key := chatToken + userID + m, err := t.rdb.HGetAll(ctx, key).Result() + if err != nil { + return nil, errs.Wrap(err) + } + mm := make(map[string]int32) + for k, v := range m { + mm[k] = stringutil.StringToInt32(v) + } + return mm, nil +} + +func (t *TokenCacheRedis) DeleteTokenByUid(ctx context.Context, userID string) error { + key := chatToken + userID + return errs.Wrap(t.rdb.Del(ctx, key).Err()) +} diff --git a/pkg/common/db/cache/user_login_ip.go b/pkg/common/db/cache/user_login_ip.go new file mode 100644 index 0000000..d8598f0 --- /dev/null +++ b/pkg/common/db/cache/user_login_ip.go @@ -0,0 +1,86 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cache + +import ( + "context" + "time" + + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" +) + +const ( + userLoginIPPrefix = "CHAT:USER_LOGIN_IP:" + // 缓存过期时间:7天(用户登录IP变化不频繁,可以设置较长的过期时间) + userLoginIPExpire = 7 * 24 * time.Hour +) + +func getUserLoginIPKey(userID string) string { + return userLoginIPPrefix + userID +} + +type UserLoginIPInterface interface { + // GetLatestLoginIP 获取用户最新登录IP(从缓存) + // 返回值:(ip, found, error) + // - ip: 缓存的IP值(如果found为false,则ip为空字符串) + // - found: 是否在缓存中找到(true表示缓存命中,false表示缓存未命中) + // - error: 错误信息 + GetLatestLoginIP(ctx context.Context, userID string) (string, bool, error) + // SetLatestLoginIP 设置用户最新登录IP到缓存 + SetLatestLoginIP(ctx context.Context, userID, ip string) error + // DeleteLatestLoginIP 删除用户最新登录IP缓存(用于保证缓存一致性) + DeleteLatestLoginIP(ctx context.Context, userID string) error +} + +type userLoginIPCacheRedis struct { + rdb redis.UniversalClient +} + +func NewUserLoginIPInterface(rdb redis.UniversalClient) UserLoginIPInterface { + return &userLoginIPCacheRedis{rdb: rdb} +} + +func (u *userLoginIPCacheRedis) GetLatestLoginIP(ctx context.Context, userID string) (string, bool, error) { + key := getUserLoginIPKey(userID) + ip, err := u.rdb.Get(ctx, key).Result() + if err != nil { + if err == redis.Nil { + // 缓存不存在,返回 false 表示缓存未命中 + return "", false, nil + } + return "", false, errs.Wrap(err) + } + // 缓存命中,返回 true + return ip, true, nil +} + +func (u *userLoginIPCacheRedis) SetLatestLoginIP(ctx context.Context, userID, ip string) error { + key := getUserLoginIPKey(userID) + err := u.rdb.Set(ctx, key, ip, userLoginIPExpire).Err() + if err != nil { + return errs.Wrap(err) + } + return nil +} + +func (u *userLoginIPCacheRedis) DeleteLatestLoginIP(ctx context.Context, userID string) error { + key := getUserLoginIPKey(userID) + err := u.rdb.Del(ctx, key).Err() + if err != nil { + return errs.Wrap(err) + } + return nil +} diff --git a/pkg/common/db/database/admin.go b/pkg/common/db/database/admin.go new file mode 100644 index 0000000..5343c18 --- /dev/null +++ b/pkg/common/db/database/admin.go @@ -0,0 +1,407 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package database + +import ( + "context" + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" + + "git.imall.cloud/openim/chat/pkg/common/db/cache" + "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/redis/go-redis/v9" + + "git.imall.cloud/openim/chat/pkg/common/db/model/admin" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" +) + +type AdminDatabaseInterface interface { + GetAdmin(ctx context.Context, account string) (*admindb.Admin, error) + GetAdminUserID(ctx context.Context, userID string) (*admindb.Admin, error) + UpdateAdmin(ctx context.Context, userID string, update map[string]any) error + ChangePassword(ctx context.Context, userID string, newPassword string) error + ChangeOperationPassword(ctx context.Context, userID string, newPassword string) error + ClearGoogleAuthKey(ctx context.Context, userID string) error + AddAdminAccount(ctx context.Context, admin []*admindb.Admin) error + DelAdminAccount(ctx context.Context, userIDs []string) error + SearchAdminAccount(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.Admin, error) + CreateApplet(ctx context.Context, applets []*admindb.Applet) error + DelApplet(ctx context.Context, appletIDs []string) error + GetApplet(ctx context.Context, appletID string) (*admindb.Applet, error) + FindApplet(ctx context.Context, appletIDs []string) ([]*admindb.Applet, error) + SearchApplet(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.Applet, error) + FindOnShelf(ctx context.Context) ([]*admindb.Applet, error) + UpdateApplet(ctx context.Context, appletID string, update map[string]any) error + GetConfig(ctx context.Context) (map[string]string, error) + SetConfig(ctx context.Context, cs map[string]string) error + DelConfig(ctx context.Context, keys []string) error + FindInvitationRegister(ctx context.Context, codes []string) ([]*admindb.InvitationRegister, error) + DelInvitationRegister(ctx context.Context, codes []string) error + UpdateInvitationRegister(ctx context.Context, code string, fields map[string]any) error + CreatInvitationRegister(ctx context.Context, invitationRegisters []*admindb.InvitationRegister) error + SearchInvitationRegister(ctx context.Context, keyword string, state int32, userIDs []string, codes []string, pagination pagination.Pagination) (int64, []*admindb.InvitationRegister, error) + SearchIPForbidden(ctx context.Context, keyword string, state int32, pagination pagination.Pagination) (int64, []*admindb.IPForbidden, error) + AddIPForbidden(ctx context.Context, ms []*admindb.IPForbidden) error + FindIPForbidden(ctx context.Context, ms []string) ([]*admindb.IPForbidden, error) + DelIPForbidden(ctx context.Context, ips []string) error + FindDefaultFriend(ctx context.Context, userIDs []string) ([]string, error) + AddDefaultFriend(ctx context.Context, ms []*admindb.RegisterAddFriend) error + DelDefaultFriend(ctx context.Context, userIDs []string) error + SearchDefaultFriend(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.RegisterAddFriend, error) + FindDefaultGroup(ctx context.Context, groupIDs []string) ([]string, error) + AddDefaultGroup(ctx context.Context, ms []*admindb.RegisterAddGroup) error + DelDefaultGroup(ctx context.Context, groupIDs []string) error + SearchDefaultGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.RegisterAddGroup, error) + CountTotalGroups(ctx context.Context) (int64, error) // 统计群组总数 + CountTodayNewGroups(ctx context.Context) (int64, error) // 统计今天新建的群组数 + CountTotalFriends(ctx context.Context) (int64, error) // 统计好友总数 + FindBlockInfo(ctx context.Context, userIDs []string) ([]*admindb.ForbiddenAccount, error) + GetBlockInfo(ctx context.Context, userID string) (*admindb.ForbiddenAccount, error) + BlockUser(ctx context.Context, f []*admindb.ForbiddenAccount) error + DelBlockUser(ctx context.Context, userID []string) error + SearchBlockUser(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.ForbiddenAccount, error) + FindBlockUser(ctx context.Context, userIDs []string) ([]*admindb.ForbiddenAccount, error) + SearchUserLimitLogin(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.LimitUserLoginIP, error) + AddUserLimitLogin(ctx context.Context, ms []*admindb.LimitUserLoginIP) error + DelUserLimitLogin(ctx context.Context, ms []*admindb.LimitUserLoginIP) error + CountLimitUserLoginIP(ctx context.Context, userID string) (uint32, error) + GetLimitUserLoginIP(ctx context.Context, userID string, ip string) (*admindb.LimitUserLoginIP, error) + CacheToken(ctx context.Context, userID string, token string, expire time.Duration) error + GetTokens(ctx context.Context, userID string) (map[string]int32, error) + DeleteToken(ctx context.Context, userID string) error + LatestVersion(ctx context.Context, platform string) (*admindb.Application, error) + AddVersion(ctx context.Context, val *admindb.Application) error + UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error + DeleteVersion(ctx context.Context, id []primitive.ObjectID) error + PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admindb.Application, error) +} + +func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient) (AdminDatabaseInterface, error) { + a, err := admin.NewAdmin(cli.GetDB()) + if err != nil { + return nil, err + } + forbidden, err := admin.NewIPForbidden(cli.GetDB()) + if err != nil { + return nil, err + } + forbiddenAccount, err := admin.NewForbiddenAccount(cli.GetDB()) + if err != nil { + return nil, err + } + limitUserLoginIP, err := admin.NewLimitUserLoginIP(cli.GetDB()) + if err != nil { + return nil, err + } + invitationRegister, err := admin.NewInvitationRegister(cli.GetDB()) + if err != nil { + return nil, err + } + registerAddFriend, err := admin.NewRegisterAddFriend(cli.GetDB()) + if err != nil { + return nil, err + } + registerAddGroup, err := admin.NewRegisterAddGroup(cli.GetDB()) + if err != nil { + return nil, err + } + applet, err := admin.NewApplet(cli.GetDB()) + if err != nil { + return nil, err + } + clientConfig, err := admin.NewClientConfig(cli.GetDB()) + if err != nil { + return nil, err + } + application, err := admin.NewApplication(cli.GetDB()) + if err != nil { + return nil, err + } + return &AdminDatabase{ + tx: cli.GetTx(), + admin: a, + ipForbidden: forbidden, + forbiddenAccount: forbiddenAccount, + limitUserLoginIP: limitUserLoginIP, + invitationRegister: invitationRegister, + registerAddFriend: registerAddFriend, + registerAddGroup: registerAddGroup, + applet: applet, + clientConfig: clientConfig, + application: application, + cache: cache.NewTokenInterface(rdb), + }, nil +} + +type AdminDatabase struct { + tx tx.Tx + admin admindb.AdminInterface + ipForbidden admindb.IPForbiddenInterface + forbiddenAccount admindb.ForbiddenAccountInterface + limitUserLoginIP admindb.LimitUserLoginIPInterface + invitationRegister admindb.InvitationRegisterInterface + registerAddFriend admindb.RegisterAddFriendInterface + registerAddGroup admindb.RegisterAddGroupInterface + applet admindb.AppletInterface + clientConfig admindb.ClientConfigInterface + application admindb.ApplicationInterface + cache cache.TokenInterface +} + +func (o *AdminDatabase) GetAdmin(ctx context.Context, account string) (*admindb.Admin, error) { + return o.admin.Take(ctx, account) +} + +func (o *AdminDatabase) GetAdminUserID(ctx context.Context, userID string) (*admindb.Admin, error) { + return o.admin.TakeUserID(ctx, userID) +} + +func (o *AdminDatabase) UpdateAdmin(ctx context.Context, userID string, update map[string]any) error { + return o.admin.Update(ctx, userID, update) +} + +func (o *AdminDatabase) ChangePassword(ctx context.Context, userID string, newPassword string) error { + return o.admin.ChangePassword(ctx, userID, newPassword) +} + +func (o *AdminDatabase) ChangeOperationPassword(ctx context.Context, userID string, newPassword string) error { + return o.admin.ChangeOperationPassword(ctx, userID, newPassword) +} + +func (o *AdminDatabase) ClearGoogleAuthKey(ctx context.Context, userID string) error { + return o.admin.ClearGoogleAuthKey(ctx, userID) +} + +func (o *AdminDatabase) AddAdminAccount(ctx context.Context, admins []*admindb.Admin) error { + return o.admin.Create(ctx, admins) +} + +func (o *AdminDatabase) DelAdminAccount(ctx context.Context, userIDs []string) error { + return o.admin.Delete(ctx, userIDs) +} + +func (o *AdminDatabase) SearchAdminAccount(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.Admin, error) { + return o.admin.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) CreateApplet(ctx context.Context, applets []*admindb.Applet) error { + return o.applet.Create(ctx, applets) +} + +func (o *AdminDatabase) DelApplet(ctx context.Context, appletIDs []string) error { + return o.applet.Del(ctx, appletIDs) +} + +func (o *AdminDatabase) GetApplet(ctx context.Context, appletID string) (*admindb.Applet, error) { + return o.applet.Take(ctx, appletID) +} + +func (o *AdminDatabase) FindApplet(ctx context.Context, appletIDs []string) ([]*admindb.Applet, error) { + return o.applet.FindID(ctx, appletIDs) +} + +func (o *AdminDatabase) SearchApplet(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.Applet, error) { + return o.applet.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) FindOnShelf(ctx context.Context) ([]*admindb.Applet, error) { + return o.applet.FindOnShelf(ctx) +} + +func (o *AdminDatabase) UpdateApplet(ctx context.Context, appletID string, update map[string]any) error { + return o.applet.Update(ctx, appletID, update) +} + +func (o *AdminDatabase) GetConfig(ctx context.Context) (map[string]string, error) { + return o.clientConfig.Get(ctx) +} + +func (o *AdminDatabase) SetConfig(ctx context.Context, cs map[string]string) error { + return o.clientConfig.Set(ctx, cs) +} + +func (o *AdminDatabase) DelConfig(ctx context.Context, keys []string) error { + return o.clientConfig.Del(ctx, keys) +} + +func (o *AdminDatabase) FindInvitationRegister(ctx context.Context, codes []string) ([]*admindb.InvitationRegister, error) { + return o.invitationRegister.Find(ctx, codes) +} + +func (o *AdminDatabase) DelInvitationRegister(ctx context.Context, codes []string) error { + return o.invitationRegister.Del(ctx, codes) +} + +func (o *AdminDatabase) UpdateInvitationRegister(ctx context.Context, code string, fields map[string]any) error { + return o.invitationRegister.Update(ctx, code, fields) +} + +func (o *AdminDatabase) CreatInvitationRegister(ctx context.Context, invitationRegisters []*admindb.InvitationRegister) error { + return o.invitationRegister.Create(ctx, invitationRegisters) +} + +func (o *AdminDatabase) SearchInvitationRegister(ctx context.Context, keyword string, state int32, userIDs []string, codes []string, pagination pagination.Pagination) (int64, []*admindb.InvitationRegister, error) { + return o.invitationRegister.Search(ctx, keyword, state, userIDs, codes, pagination) +} + +func (o *AdminDatabase) SearchIPForbidden(ctx context.Context, keyword string, state int32, pagination pagination.Pagination) (int64, []*admindb.IPForbidden, error) { + return o.ipForbidden.Search(ctx, keyword, state, pagination) +} + +func (o *AdminDatabase) AddIPForbidden(ctx context.Context, ms []*admindb.IPForbidden) error { + return o.ipForbidden.Create(ctx, ms) +} + +func (o *AdminDatabase) FindIPForbidden(ctx context.Context, ms []string) ([]*admindb.IPForbidden, error) { + return o.ipForbidden.Find(ctx, ms) +} + +func (o *AdminDatabase) DelIPForbidden(ctx context.Context, ips []string) error { + return o.ipForbidden.Delete(ctx, ips) +} + +func (o *AdminDatabase) FindDefaultFriend(ctx context.Context, userIDs []string) ([]string, error) { + return o.registerAddFriend.FindUserID(ctx, userIDs) +} + +func (o *AdminDatabase) AddDefaultFriend(ctx context.Context, ms []*admindb.RegisterAddFriend) error { + return o.registerAddFriend.Add(ctx, ms) +} + +func (o *AdminDatabase) DelDefaultFriend(ctx context.Context, userIDs []string) error { + return o.registerAddFriend.Del(ctx, userIDs) +} + +func (o *AdminDatabase) SearchDefaultFriend(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.RegisterAddFriend, error) { + return o.registerAddFriend.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) FindDefaultGroup(ctx context.Context, groupIDs []string) ([]string, error) { + return o.registerAddGroup.FindGroupID(ctx, groupIDs) +} + +func (o *AdminDatabase) AddDefaultGroup(ctx context.Context, ms []*admindb.RegisterAddGroup) error { + return o.registerAddGroup.Add(ctx, ms) +} + +func (o *AdminDatabase) DelDefaultGroup(ctx context.Context, groupIDs []string) error { + return o.registerAddGroup.Del(ctx, groupIDs) +} + +func (o *AdminDatabase) SearchDefaultGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.RegisterAddGroup, error) { + return o.registerAddGroup.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) CountTotalGroups(ctx context.Context) (int64, error) { + return o.registerAddGroup.CountTotal(ctx) +} + +func (o *AdminDatabase) CountTodayNewGroups(ctx context.Context) (int64, error) { + return o.registerAddGroup.CountToday(ctx) +} + +func (o *AdminDatabase) CountTotalFriends(ctx context.Context) (int64, error) { + return o.registerAddFriend.CountTotal(ctx) +} + +func (o *AdminDatabase) FindBlockInfo(ctx context.Context, userIDs []string) ([]*admindb.ForbiddenAccount, error) { + return o.forbiddenAccount.Find(ctx, userIDs) +} + +func (o *AdminDatabase) GetBlockInfo(ctx context.Context, userID string) (*admindb.ForbiddenAccount, error) { + return o.forbiddenAccount.Take(ctx, userID) +} + +func (o *AdminDatabase) BlockUser(ctx context.Context, f []*admindb.ForbiddenAccount) error { + return o.forbiddenAccount.Create(ctx, f) +} + +func (o *AdminDatabase) DelBlockUser(ctx context.Context, userID []string) error { + return o.forbiddenAccount.Delete(ctx, userID) +} + +func (o *AdminDatabase) SearchBlockUser(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.ForbiddenAccount, error) { + return o.forbiddenAccount.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) FindBlockUser(ctx context.Context, userIDs []string) ([]*admindb.ForbiddenAccount, error) { + return o.forbiddenAccount.Find(ctx, userIDs) +} + +func (o *AdminDatabase) SearchUserLimitLogin(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.LimitUserLoginIP, error) { + return o.limitUserLoginIP.Search(ctx, keyword, pagination) +} + +func (o *AdminDatabase) AddUserLimitLogin(ctx context.Context, ms []*admindb.LimitUserLoginIP) error { + return o.limitUserLoginIP.Create(ctx, ms) +} + +func (o *AdminDatabase) DelUserLimitLogin(ctx context.Context, ms []*admindb.LimitUserLoginIP) error { + return o.limitUserLoginIP.Delete(ctx, ms) +} + +func (o *AdminDatabase) CountLimitUserLoginIP(ctx context.Context, userID string) (uint32, error) { + return o.limitUserLoginIP.Count(ctx, userID) +} + +func (o *AdminDatabase) GetLimitUserLoginIP(ctx context.Context, userID string, ip string) (*admindb.LimitUserLoginIP, error) { + return o.limitUserLoginIP.Take(ctx, userID, ip) +} + +func (o *AdminDatabase) CacheToken(ctx context.Context, userID string, token string, expire time.Duration) error { + isSet, err := o.cache.AddTokenFlagNXEx(ctx, userID, token, constant.NormalToken, expire) + if err != nil { + return err + } + if !isSet { + // already exists, update + if err = o.cache.AddTokenFlag(ctx, userID, token, constant.NormalToken); err != nil { + return err + } + } + return nil +} + +func (o *AdminDatabase) GetTokens(ctx context.Context, userID string) (map[string]int32, error) { + return o.cache.GetTokensWithoutError(ctx, userID) +} + +func (o *AdminDatabase) DeleteToken(ctx context.Context, userID string) error { + return o.cache.DeleteTokenByUid(ctx, userID) +} + +func (o *AdminDatabase) LatestVersion(ctx context.Context, platform string) (*admindb.Application, error) { + return o.application.LatestVersion(ctx, platform) +} + +func (o *AdminDatabase) AddVersion(ctx context.Context, val *admindb.Application) error { + return o.application.AddVersion(ctx, val) +} + +func (o *AdminDatabase) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error { + return o.application.UpdateVersion(ctx, id, update) +} + +func (o *AdminDatabase) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error { + return o.application.DeleteVersion(ctx, id) +} + +func (o *AdminDatabase) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admindb.Application, error) { + return o.application.PageVersion(ctx, platforms, page) +} diff --git a/pkg/common/db/database/bot.go b/pkg/common/db/database/bot.go new file mode 100644 index 0000000..5dc891d --- /dev/null +++ b/pkg/common/db/database/bot.go @@ -0,0 +1,77 @@ +package database + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/model/bot" + tablebot "git.imall.cloud/openim/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" +) + +type BotDatabase interface { + CreateAgent(ctx context.Context, jobs ...*tablebot.Agent) error + TakeAgent(ctx context.Context, userID string) (*tablebot.Agent, error) + FindAgents(ctx context.Context, userIDs []string) ([]*tablebot.Agent, error) + UpdateAgent(ctx context.Context, userID string, data map[string]any) error + DeleteAgents(ctx context.Context, userIDs []string) error + PageAgents(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*tablebot.Agent, error) + + TakeConversationRespID(ctx context.Context, convID, agentID string) (*tablebot.ConversationRespID, error) + UpdateConversationRespID(ctx context.Context, convID, agentID string, data map[string]any) error +} + +type botDatabase struct { + tx tx.Tx + agent tablebot.AgentInterface + convRespID tablebot.ConversationRespIDInterface +} + +func NewBotDatabase(cli *mongoutil.Client) (BotDatabase, error) { + agent, err := bot.NewAgent(cli.GetDB()) + if err != nil { + return nil, err + } + convRespID, err := bot.NewConversationRespID(cli.GetDB()) + if err != nil { + return nil, err + } + return &botDatabase{ + tx: cli.GetTx(), + agent: agent, + convRespID: convRespID, + }, nil +} + +func (a *botDatabase) CreateAgent(ctx context.Context, agents ...*tablebot.Agent) error { + return a.agent.Create(ctx, agents...) +} + +func (a *botDatabase) TakeAgent(ctx context.Context, userID string) (*tablebot.Agent, error) { + return a.agent.Take(ctx, userID) +} + +func (a *botDatabase) FindAgents(ctx context.Context, userIDs []string) ([]*tablebot.Agent, error) { + return a.agent.Find(ctx, userIDs) +} + +func (a *botDatabase) UpdateAgent(ctx context.Context, userID string, data map[string]any) error { + return a.agent.Update(ctx, userID, data) +} + +func (a *botDatabase) DeleteAgents(ctx context.Context, userIDs []string) error { + return a.agent.Delete(ctx, userIDs) +} + +func (a *botDatabase) PageAgents(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*tablebot.Agent, error) { + return a.agent.Page(ctx, userIDs, pagination) +} + +func (a *botDatabase) UpdateConversationRespID(ctx context.Context, convID, agentID string, data map[string]any) error { + return a.convRespID.Update(ctx, convID, agentID, data) +} + +func (a *botDatabase) TakeConversationRespID(ctx context.Context, convID, agentID string) (*tablebot.ConversationRespID, error) { + return a.convRespID.Take(ctx, convID, agentID) +} diff --git a/pkg/common/db/database/chat.go b/pkg/common/db/database/chat.go new file mode 100644 index 0000000..f27aa4b --- /dev/null +++ b/pkg/common/db/database/chat.go @@ -0,0 +1,867 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package database + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" + "github.com/redis/go-redis/v9" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/db/cache" + admindb "git.imall.cloud/openim/chat/pkg/common/db/model/admin" + "git.imall.cloud/openim/chat/pkg/common/db/model/chat" + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +type ChatDatabaseInterface interface { + GetUser(ctx context.Context, userID string) (account *chatdb.Account, err error) + UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) + FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) + FindAttributeByAccount(ctx context.Context, accounts []string) ([]*chatdb.Attribute, error) + TakeAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) + TakeAttributeByEmail(ctx context.Context, Email string) (*chatdb.Attribute, error) + TakeAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) + TakeAttributeByUserID(ctx context.Context, userID string) (*chatdb.Attribute, error) + TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) + TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) + TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) + TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) + Search(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) + SearchWithRealNameAuth(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, realNameKeyword string, idCardKeyword string, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) // 搜索用户(支持实名信息搜索) + SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) + CountVerifyCodeRange(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) + AddVerifyCode(ctx context.Context, verifyCode *chatdb.VerifyCode, fn func() error) error + UpdateVerifyCodeIncrCount(ctx context.Context, id string) error + DelVerifyCode(ctx context.Context, id string) error + RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error + LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error + UpdatePassword(ctx context.Context, userID string, password string) error + UpdatePasswordAndDeleteVerifyCode(ctx context.Context, userID string, password string, codeID string) error + NewUserCountTotal(ctx context.Context, before *time.Time) (int64, error) + UserLoginCountTotal(ctx context.Context, before *time.Time) (int64, error) + UserLoginCountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) + CountTodayRegisteredUsers(ctx context.Context) (int64, error) + CountTodayActiveUsers(ctx context.Context) (int64, error) + GetLatestLoginIP(ctx context.Context, userID string) (string, error) // 获取用户最新登录IP + SearchUserLoginRecords(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*chatdb.UserLoginRecord, error) // 查询用户登录记录(支持按用户ID或IP查询) + DelUserAccount(ctx context.Context, userIDs []string) error + + // 敏感词相关方法 + GetSensitiveWords(ctx context.Context) ([]*chatdb.SensitiveWord, error) + CheckSensitiveWords(ctx context.Context, content string) ([]*chatdb.SensitiveWord, bool, error) + FilterContent(ctx context.Context, content string) (string, []*chatdb.SensitiveWord, bool, error) + GetSensitiveWordConfig(ctx context.Context) (*chatdb.SensitiveWordConfig, error) + + // 敏感词管理相关方法 + CreateSensitiveWord(ctx context.Context, word *chatdb.SensitiveWord) error + UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error + DeleteSensitiveWord(ctx context.Context, ids []string) error + GetSensitiveWord(ctx context.Context, id string) (*chatdb.SensitiveWord, error) + SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWord, error) + BatchAddSensitiveWords(ctx context.Context, words []*chatdb.SensitiveWord) error + BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error + BatchDeleteSensitiveWords(ctx context.Context, ids []string) error + + // 敏感词分组管理 + CreateSensitiveWordGroup(ctx context.Context, group *chatdb.SensitiveWordGroup) error + UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error + DeleteSensitiveWordGroup(ctx context.Context, ids []string) error + GetSensitiveWordGroup(ctx context.Context, id string) (*chatdb.SensitiveWordGroup, error) + GetAllSensitiveWordGroups(ctx context.Context) ([]*chatdb.SensitiveWordGroup, error) + + // 敏感词配置管理 + UpdateSensitiveWordConfig(ctx context.Context, config *chatdb.SensitiveWordConfig) error + + // 敏感词日志管理 + GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWordLog, error) + DeleteSensitiveWordLogs(ctx context.Context, ids []string) error + + // 敏感词统计 + GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) + GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) + + // 收藏相关方法 + CreateFavorite(ctx context.Context, favorite *chatdb.Favorite) error + GetFavorite(ctx context.Context, favoriteID string) (*chatdb.Favorite, error) + GetFavoritesByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) + GetFavoritesByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) + SearchFavoritesByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) + UpdateFavorite(ctx context.Context, favoriteID string, data map[string]any) error + DeleteFavorite(ctx context.Context, favoriteIDs []string) error + DeleteFavoritesByUserID(ctx context.Context, userID string) error + CountFavoritesByUserID(ctx context.Context, userID string) (int64, error) + GetFavoritesByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) + + // 定时任务相关方法 + CreateScheduledTask(ctx context.Context, task *chatdb.ScheduledTask) error + GetScheduledTask(ctx context.Context, taskID string) (*chatdb.ScheduledTask, error) + GetScheduledTasksByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) + GetAllScheduledTasks(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) + UpdateScheduledTask(ctx context.Context, taskID string, data map[string]any) error + DeleteScheduledTask(ctx context.Context, taskIDs []string) error + + // 系统配置相关方法 + CreateSystemConfig(ctx context.Context, config *chatdb.SystemConfig) error + GetSystemConfig(ctx context.Context, key string) (*chatdb.SystemConfig, error) + GetSystemConfigsByKeys(ctx context.Context, keys []string) ([]*chatdb.SystemConfig, error) + GetAllSystemConfigs(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.SystemConfig, error) + UpdateSystemConfig(ctx context.Context, key string, data map[string]any) error + UpdateSystemConfigValue(ctx context.Context, key string, value string) error + UpdateSystemConfigEnabled(ctx context.Context, key string, enabled bool) error + DeleteSystemConfig(ctx context.Context, keys []string) error + GetEnabledSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) + GetAppSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) // 获取所有 show_in_app=true 且 enabled=true 的配置 + + // 钱包相关方法 + GetWallet(ctx context.Context, userID string) (*chatdb.Wallet, error) // 获取钱包信息 + GetWalletsByUserIDs(ctx context.Context, userIDs []string) ([]*chatdb.Wallet, error) // 根据用户ID列表批量获取钱包 + GetWalletsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) // 分页获取钱包列表 + GetWalletsPageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) // 按实名认证审核状态分页查询钱包(支持用户ID搜索) + CreateWallet(ctx context.Context, wallet *chatdb.Wallet) error // 创建钱包 + UpdateWalletBalance(ctx context.Context, userID string, balance int64) error // 更新钱包余额 + IncrementWalletBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) // 原子更新余额,返回更新前后的余额 + UpdateWalletPaymentPassword(ctx context.Context, userID string, paymentPassword string) error // 更新支付密码 + UpdateWalletWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error // 更新提款账号(兼容旧接口) + UpdateWalletWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error // 更新提款账号(带类型) + UpdateWalletRealNameAuth(ctx context.Context, userID string, realNameAuth chatdb.RealNameAuth) error // 更新实名认证信息 + GetWalletBalanceRecords(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) // 获取钱包余额变动记录 + GetWalletBalanceRecordsByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) // 根据类型获取钱包余额变动记录 + CreateWalletBalanceRecord(ctx context.Context, record *chatdb.WalletBalanceRecord) error // 创建余额变动记录 + + // 提现相关方法 + CreateWithdraw(ctx context.Context, withdraw *chatdb.Withdraw) error // 创建提现记录 + GetWithdraw(ctx context.Context, withdrawID string) (*chatdb.Withdraw, error) // 获取提现记录 + GetWithdrawsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 获取用户的提现记录列表 + GetWithdrawsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 根据状态获取提现记录列表 + UpdateWithdrawStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error // 更新提现状态(审核) + GetWithdrawsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 获取提现记录列表(分页) + + // 提现申请相关方法 + CreateWithdrawApplication(ctx context.Context, application *chatdb.WithdrawApplication) error // 创建提现申请 + GetWithdrawApplication(ctx context.Context, applicationID string) (*chatdb.WithdrawApplication, error) // 获取提现申请 + GetWithdrawApplicationsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 获取用户的提现申请列表 + GetWithdrawApplicationsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 根据状态获取提现申请列表 + UpdateWithdrawApplicationStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error // 更新提现申请状态(审核) + GetWithdrawApplicationsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 获取提现申请列表(分页) + UpdateWithdrawApplication(ctx context.Context, applicationID string, data map[string]any) error // 更新提现申请 +} + +func NewChatDatabase(cli *mongoutil.Client, rdb redis.UniversalClient) (ChatDatabaseInterface, error) { + register, err := chat.NewRegister(cli.GetDB()) + if err != nil { + return nil, err + } + account, err := chat.NewAccount(cli.GetDB()) + if err != nil { + return nil, err + } + attribute, err := chat.NewAttribute(cli.GetDB()) + if err != nil { + return nil, err + } + credential, err := chat.NewCredential(cli.GetDB()) + if err != nil { + return nil, err + } + userLoginRecord, err := chat.NewUserLoginRecord(cli.GetDB()) + if err != nil { + return nil, err + } + verifyCode, err := chat.NewVerifyCode(cli.GetDB()) + if err != nil { + return nil, err + } + forbiddenAccount, err := admindb.NewForbiddenAccount(cli.GetDB()) + if err != nil { + return nil, err + } + sensitiveWord, err := chat.NewSensitiveWord(cli.GetDB()) + if err != nil { + return nil, err + } + favorite, err := chat.NewFavorite(cli.GetDB()) + if err != nil { + return nil, err + } + scheduledTask, err := chat.NewScheduledTask(cli.GetDB()) + if err != nil { + return nil, err + } + systemConfig, err := chat.NewSystemConfig(cli.GetDB()) + if err != nil { + return nil, err + } + wallet, err := chat.NewWallet(cli.GetDB()) + if err != nil { + return nil, err + } + walletBalanceRecord, err := chat.NewWalletBalanceRecord(cli.GetDB()) + if err != nil { + return nil, err + } + withdraw, err := chat.NewWithdraw(cli.GetDB()) + if err != nil { + return nil, err + } + withdrawApplication, err := chat.NewWithdrawApplication(cli.GetDB()) + if err != nil { + return nil, err + } + + var userLoginIPCache cache.UserLoginIPInterface + if rdb != nil { + userLoginIPCache = cache.NewUserLoginIPInterface(rdb) + } + + return &ChatDatabase{ + tx: cli.GetTx(), + register: register, + account: account, + attribute: attribute, + credential: credential, + userLoginRecord: userLoginRecord, + verifyCode: verifyCode, + forbiddenAccount: forbiddenAccount, + sensitiveWord: sensitiveWord, + favorite: favorite, + scheduledTask: scheduledTask, + systemConfig: systemConfig, + wallet: wallet, + walletBalanceRecord: walletBalanceRecord, + withdraw: withdraw, + withdrawApplication: withdrawApplication, + userLoginIPCache: userLoginIPCache, + }, nil +} + +type ChatDatabase struct { + tx tx.Tx + register chatdb.RegisterInterface + account chatdb.AccountInterface + attribute chatdb.AttributeInterface + credential chatdb.CredentialInterface + userLoginRecord chatdb.UserLoginRecordInterface + verifyCode chatdb.VerifyCodeInterface + forbiddenAccount admin.ForbiddenAccountInterface + sensitiveWord chatdb.SensitiveWordInterface + favorite chatdb.FavoriteInterface + scheduledTask chatdb.ScheduledTaskInterface + systemConfig chatdb.SystemConfigInterface + wallet chatdb.WalletInterface + walletBalanceRecord chatdb.WalletBalanceRecordInterface + withdraw chatdb.WithdrawInterface + withdrawApplication chatdb.WithdrawApplicationInterface + userLoginIPCache cache.UserLoginIPInterface // 用户登录IP缓存(可选,如果为nil则不使用缓存) +} + +func (o *ChatDatabase) GetUser(ctx context.Context, userID string) (account *chatdb.Account, err error) { + return o.account.Take(ctx, userID) +} + +func (o *ChatDatabase) UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err = o.attribute.Update(ctx, userID, attribute); err != nil { + return err + } + for _, credential := range updateCred { + if err = o.credential.CreateOrUpdateAccount(ctx, credential); err != nil { + return err + } + } + if err = o.credential.DeleteByUserIDType(ctx, delCred...); err != nil { + return err + } + return nil + }) +} + +func (o *ChatDatabase) FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) { + return o.attribute.Find(ctx, userIDs) +} + +func (o *ChatDatabase) FindAttributeByAccount(ctx context.Context, accounts []string) ([]*chatdb.Attribute, error) { + return o.attribute.FindAccount(ctx, accounts) +} + +func (o *ChatDatabase) TakeAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) { + return o.attribute.TakePhone(ctx, areaCode, phoneNumber) +} + +func (o *ChatDatabase) TakeAttributeByEmail(ctx context.Context, email string) (*chatdb.Attribute, error) { + return o.attribute.TakeEmail(ctx, email) +} + +func (o *ChatDatabase) TakeAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) { + return o.attribute.TakeAccount(ctx, account) +} + +func (o *ChatDatabase) TakeAttributeByUserID(ctx context.Context, userID string) (*chatdb.Attribute, error) { + return o.attribute.Take(ctx, userID) +} + +func (o *ChatDatabase) TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) { + return o.verifyCode.TakeLast(ctx, account) +} + +func (o *ChatDatabase) TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) { + return o.account.Take(ctx, userID) +} + +func (o *ChatDatabase) TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) { + return o.credential.TakeAccount(ctx, account) +} + +func (o *ChatDatabase) TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) { + return o.credential.Find(ctx, userID) +} + +func (o *ChatDatabase) Search(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) { + var forbiddenIDs []string + if int(normalUser) == constant.NormalUser { + forbiddenIDs, err = o.forbiddenAccount.FindAllIDs(ctx) + if err != nil { + return 0, nil, err + } + } + total, totalUser, err := o.attribute.SearchNormalUser(ctx, keyword, forbiddenIDs, genders, startTime, endTime, pagination) + if err != nil { + return 0, nil, err + } + return total, totalUser, nil +} + +// SearchWithRealNameAuth 搜索用户(支持实名信息搜索) +func (o *ChatDatabase) SearchWithRealNameAuth(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, realNameKeyword string, idCardKeyword string, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) { + // 如果提供了实名信息搜索关键词,先查询钱包获取userIDs + var realNameAuthUserIDs []string + if realNameKeyword != "" || idCardKeyword != "" { + realNameAuthUserIDs, err = o.wallet.SearchByRealNameAuth(ctx, realNameKeyword, idCardKeyword) + if err != nil { + return 0, nil, err + } + // 如果没有找到匹配的用户,直接返回空结果 + if len(realNameAuthUserIDs) == 0 { + return 0, []*chatdb.Attribute{}, nil + } + } + + var forbiddenIDs []string + if int(normalUser) == constant.NormalUser { + forbiddenIDs, err = o.forbiddenAccount.FindAllIDs(ctx) + if err != nil { + return 0, nil, err + } + } + + // 如果提供了实名信息搜索,需要在用户ID列表中过滤 + if len(realNameAuthUserIDs) > 0 { + // 修改 SearchNormalUser 方法,支持传入额外的 userIDs 过滤条件 + // 或者创建一个新的方法 + // 这里我们修改 SearchNormalUser 来支持这个功能 + total, totalUser, err := o.attribute.SearchNormalUserWithUserIDs(ctx, keyword, forbiddenIDs, genders, startTime, endTime, realNameAuthUserIDs, pagination) + if err != nil { + return 0, nil, err + } + return total, totalUser, nil + } + + // 没有实名信息搜索,使用原来的方法 + return o.Search(ctx, normalUser, keyword, genders, startTime, endTime, pagination) +} + +func (o *ChatDatabase) SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) { + return o.attribute.SearchUser(ctx, keyword, userIDs, genders, pagination) +} + +func (o *ChatDatabase) CountVerifyCodeRange(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) { + return o.verifyCode.RangeNum(ctx, account, start, end) +} + +func (o *ChatDatabase) AddVerifyCode(ctx context.Context, verifyCode *chatdb.VerifyCode, fn func() error) error { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err := o.verifyCode.Add(ctx, []*chatdb.VerifyCode{verifyCode}); err != nil { + return err + } + if fn != nil { + return fn() + } + return nil + }) +} + +func (o *ChatDatabase) UpdateVerifyCodeIncrCount(ctx context.Context, id string) error { + return o.verifyCode.Incr(ctx, id) +} + +func (o *ChatDatabase) DelVerifyCode(ctx context.Context, id string) error { + return o.verifyCode.Delete(ctx, id) +} + +func (o *ChatDatabase) RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err := o.register.Create(ctx, register); err != nil { + return err + } + if err := o.account.Create(ctx, account); err != nil { + return err + } + if err := o.attribute.Create(ctx, attribute); err != nil { + return err + } + if err := o.credential.Create(ctx, credentials...); err != nil { + return err + } + return nil + }) +} + +func (o *ChatDatabase) LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err := o.userLoginRecord.Create(ctx, record); err != nil { + return err + } + // 创建登录记录后,更新缓存(保证缓存一致性) + if o.userLoginIPCache != nil && record.UserID != "" { + // 先删除旧缓存,然后设置新缓存 + // 使用新IP更新缓存,这样下次查询时可以直接从缓存获取 + _ = o.userLoginIPCache.SetLatestLoginIP(ctx, record.UserID, record.IP) + } + if verifyCodeID != nil { + if err := o.verifyCode.Delete(ctx, *verifyCodeID); err != nil { + return err + } + } + return nil + }) +} + +func (o *ChatDatabase) UpdatePassword(ctx context.Context, userID string, password string) error { + return o.account.UpdatePassword(ctx, userID, password) +} + +func (o *ChatDatabase) UpdatePasswordAndDeleteVerifyCode(ctx context.Context, userID string, password string, codeID string) error { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err := o.account.UpdatePassword(ctx, userID, password); err != nil { + return err + } + if codeID == "" { + return nil + } + if err := o.verifyCode.Delete(ctx, codeID); err != nil { + return err + } + return nil + }) +} + +func (o *ChatDatabase) NewUserCountTotal(ctx context.Context, before *time.Time) (int64, error) { + return o.register.CountTotal(ctx, before) +} + +func (o *ChatDatabase) UserLoginCountTotal(ctx context.Context, before *time.Time) (int64, error) { + return o.userLoginRecord.CountTotal(ctx, before) +} + +func (o *ChatDatabase) UserLoginCountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) { + return o.userLoginRecord.CountRangeEverydayTotal(ctx, start, end) +} + +func (o *ChatDatabase) CountTodayRegisteredUsers(ctx context.Context) (int64, error) { + return o.register.CountToday(ctx) +} + +func (o *ChatDatabase) CountTodayActiveUsers(ctx context.Context) (int64, error) { + return o.userLoginRecord.CountTodayActiveUsers(ctx) +} + +func (o *ChatDatabase) GetLatestLoginIP(ctx context.Context, userID string) (string, error) { + // 如果启用了缓存,先尝试从缓存获取 + if o.userLoginIPCache != nil { + ip, found, err := o.userLoginIPCache.GetLatestLoginIP(ctx, userID) + if err != nil { + // 缓存查询出错,降级到数据库查询 + return o.userLoginRecord.GetLatestLoginIP(ctx, userID) + } + // 如果缓存命中,直接返回(即使IP为空字符串,也表示用户确实没有IP) + if found { + return ip, nil + } + // 缓存未命中,从数据库查询 + ip, err = o.userLoginRecord.GetLatestLoginIP(ctx, userID) + if err != nil { + return "", err + } + // 将查询结果写入缓存(即使为空也缓存,避免频繁查询数据库) + _ = o.userLoginIPCache.SetLatestLoginIP(ctx, userID, ip) + return ip, nil + } + // 未启用缓存,直接从数据库查询 + return o.userLoginRecord.GetLatestLoginIP(ctx, userID) +} + +func (o *ChatDatabase) SearchUserLoginRecords(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*chatdb.UserLoginRecord, error) { + return o.userLoginRecord.Search(ctx, userID, ip, pagination) +} + +func (o *ChatDatabase) DelUserAccount(ctx context.Context, userIDs []string) error { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err := o.register.Delete(ctx, userIDs); err != nil { + return err + } + if err := o.account.Delete(ctx, userIDs); err != nil { + return err + } + if err := o.attribute.Delete(ctx, userIDs); err != nil { + return err + } + return nil + }) +} + +// ==================== 敏感词相关方法实现 ==================== + +// GetSensitiveWords 获取所有启用的敏感词 +func (o *ChatDatabase) GetSensitiveWords(ctx context.Context) ([]*chatdb.SensitiveWord, error) { + return o.sensitiveWord.GetEnabledSensitiveWords(ctx) +} + +// CheckSensitiveWords 检测敏感词 +func (o *ChatDatabase) CheckSensitiveWords(ctx context.Context, content string) ([]*chatdb.SensitiveWord, bool, error) { + words, err := o.sensitiveWord.CheckSensitiveWords(ctx, content) + hasSensitive := len(words) > 0 + return words, hasSensitive, err +} + +// FilterContent 过滤内容 +func (o *ChatDatabase) FilterContent(ctx context.Context, content string) (string, []*chatdb.SensitiveWord, bool, error) { + filteredContent, words, err := o.sensitiveWord.FilterContent(ctx, content) + hasSensitive := len(words) > 0 + return filteredContent, words, hasSensitive, err +} + +// GetSensitiveWordConfig 获取敏感词配置 +func (o *ChatDatabase) GetSensitiveWordConfig(ctx context.Context) (*chatdb.SensitiveWordConfig, error) { + return o.sensitiveWord.GetSensitiveWordConfig(ctx) +} + +// ==================== 敏感词管理相关方法实现 ==================== + +func (o *ChatDatabase) CreateSensitiveWord(ctx context.Context, word *chatdb.SensitiveWord) error { + return o.sensitiveWord.CreateSensitiveWord(ctx, word) +} + +func (o *ChatDatabase) UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error { + return o.sensitiveWord.UpdateSensitiveWord(ctx, id, data) +} + +func (o *ChatDatabase) DeleteSensitiveWord(ctx context.Context, ids []string) error { + return o.sensitiveWord.DeleteSensitiveWord(ctx, ids) +} + +func (o *ChatDatabase) GetSensitiveWord(ctx context.Context, id string) (*chatdb.SensitiveWord, error) { + return o.sensitiveWord.GetSensitiveWord(ctx, id) +} + +func (o *ChatDatabase) SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWord, error) { + return o.sensitiveWord.SearchSensitiveWords(ctx, keyword, action, status, pagination) +} + +func (o *ChatDatabase) BatchAddSensitiveWords(ctx context.Context, words []*chatdb.SensitiveWord) error { + return o.sensitiveWord.BatchCreateSensitiveWords(ctx, words) +} + +func (o *ChatDatabase) BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error { + return o.sensitiveWord.BatchUpdateSensitiveWords(ctx, updates) +} + +func (o *ChatDatabase) BatchDeleteSensitiveWords(ctx context.Context, ids []string) error { + return o.sensitiveWord.BatchDeleteSensitiveWords(ctx, ids) +} + +// ==================== 敏感词分组管理实现 ==================== + +func (o *ChatDatabase) CreateSensitiveWordGroup(ctx context.Context, group *chatdb.SensitiveWordGroup) error { + return o.sensitiveWord.CreateSensitiveWordGroup(ctx, group) +} + +func (o *ChatDatabase) UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error { + return o.sensitiveWord.UpdateSensitiveWordGroup(ctx, id, data) +} + +func (o *ChatDatabase) DeleteSensitiveWordGroup(ctx context.Context, ids []string) error { + return o.sensitiveWord.DeleteSensitiveWordGroup(ctx, ids) +} + +func (o *ChatDatabase) GetSensitiveWordGroup(ctx context.Context, id string) (*chatdb.SensitiveWordGroup, error) { + return o.sensitiveWord.GetSensitiveWordGroup(ctx, id) +} + +func (o *ChatDatabase) GetAllSensitiveWordGroups(ctx context.Context) ([]*chatdb.SensitiveWordGroup, error) { + return o.sensitiveWord.GetAllSensitiveWordGroups(ctx) +} + +// ==================== 敏感词配置管理实现 ==================== + +func (o *ChatDatabase) UpdateSensitiveWordConfig(ctx context.Context, config *chatdb.SensitiveWordConfig) error { + return o.sensitiveWord.UpdateSensitiveWordConfig(ctx, config) +} + +// ==================== 敏感词日志管理实现 ==================== + +func (o *ChatDatabase) GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWordLog, error) { + return o.sensitiveWord.GetSensitiveWordLogs(ctx, userID, groupID, pagination) +} + +func (o *ChatDatabase) DeleteSensitiveWordLogs(ctx context.Context, ids []string) error { + return o.sensitiveWord.DeleteSensitiveWordLogs(ctx, ids) +} + +// ==================== 敏感词统计实现 ==================== + +func (o *ChatDatabase) GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) { + return o.sensitiveWord.GetSensitiveWordStats(ctx) +} + +func (o *ChatDatabase) GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) { + return o.sensitiveWord.GetSensitiveWordLogStats(ctx, startTime, endTime) +} + +// ==================== 收藏相关方法实现 ==================== + +func (o *ChatDatabase) CreateFavorite(ctx context.Context, favorite *chatdb.Favorite) error { + return o.favorite.Create(ctx, favorite) +} + +func (o *ChatDatabase) GetFavorite(ctx context.Context, favoriteID string) (*chatdb.Favorite, error) { + return o.favorite.Take(ctx, favoriteID) +} + +func (o *ChatDatabase) GetFavoritesByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { + return o.favorite.FindByUserID(ctx, userID, pagination) +} + +func (o *ChatDatabase) GetFavoritesByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { + return o.favorite.FindByUserIDAndType(ctx, userID, favoriteType, pagination) +} + +func (o *ChatDatabase) SearchFavoritesByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { + return o.favorite.SearchByKeyword(ctx, userID, keyword, pagination) +} + +func (o *ChatDatabase) UpdateFavorite(ctx context.Context, favoriteID string, data map[string]any) error { + return o.favorite.Update(ctx, favoriteID, data) +} + +func (o *ChatDatabase) DeleteFavorite(ctx context.Context, favoriteIDs []string) error { + return o.favorite.Delete(ctx, favoriteIDs) +} + +func (o *ChatDatabase) DeleteFavoritesByUserID(ctx context.Context, userID string) error { + return o.favorite.DeleteByUserID(ctx, userID) +} + +func (o *ChatDatabase) CountFavoritesByUserID(ctx context.Context, userID string) (int64, error) { + return o.favorite.CountByUserID(ctx, userID) +} + +func (o *ChatDatabase) GetFavoritesByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { + return o.favorite.FindByTags(ctx, userID, tags, pagination) +} + +// ==================== 定时任务相关方法实现 ==================== + +func (o *ChatDatabase) CreateScheduledTask(ctx context.Context, task *chatdb.ScheduledTask) error { + return o.scheduledTask.Create(ctx, task) +} + +func (o *ChatDatabase) GetScheduledTask(ctx context.Context, taskID string) (*chatdb.ScheduledTask, error) { + return o.scheduledTask.Take(ctx, taskID) +} + +func (o *ChatDatabase) GetScheduledTasksByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) { + return o.scheduledTask.FindByUserID(ctx, userID, pagination) +} + +func (o *ChatDatabase) GetAllScheduledTasks(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) { + return o.scheduledTask.FindAll(ctx, pagination) +} + +func (o *ChatDatabase) UpdateScheduledTask(ctx context.Context, taskID string, data map[string]any) error { + return o.scheduledTask.Update(ctx, taskID, data) +} + +func (o *ChatDatabase) DeleteScheduledTask(ctx context.Context, taskIDs []string) error { + return o.scheduledTask.Delete(ctx, taskIDs) +} + +// ==================== 系统配置相关方法实现 ==================== + +func (o *ChatDatabase) CreateSystemConfig(ctx context.Context, config *chatdb.SystemConfig) error { + return o.systemConfig.Create(ctx, config) +} + +func (o *ChatDatabase) GetSystemConfig(ctx context.Context, key string) (*chatdb.SystemConfig, error) { + return o.systemConfig.Take(ctx, key) +} + +func (o *ChatDatabase) GetSystemConfigsByKeys(ctx context.Context, keys []string) ([]*chatdb.SystemConfig, error) { + return o.systemConfig.FindByKeys(ctx, keys) +} + +func (o *ChatDatabase) GetAllSystemConfigs(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.SystemConfig, error) { + return o.systemConfig.FindAll(ctx, pagination) +} + +func (o *ChatDatabase) UpdateSystemConfig(ctx context.Context, key string, data map[string]any) error { + return o.systemConfig.Update(ctx, key, data) +} + +func (o *ChatDatabase) UpdateSystemConfigValue(ctx context.Context, key string, value string) error { + return o.systemConfig.UpdateValue(ctx, key, value) +} + +func (o *ChatDatabase) UpdateSystemConfigEnabled(ctx context.Context, key string, enabled bool) error { + return o.systemConfig.UpdateEnabled(ctx, key, enabled) +} + +func (o *ChatDatabase) DeleteSystemConfig(ctx context.Context, keys []string) error { + return o.systemConfig.Delete(ctx, keys) +} + +func (o *ChatDatabase) GetEnabledSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) { + return o.systemConfig.GetEnabledConfigs(ctx) +} + +func (o *ChatDatabase) GetAppSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) { + return o.systemConfig.GetAppConfigs(ctx) +} + +func (o *ChatDatabase) GetWallet(ctx context.Context, userID string) (*chatdb.Wallet, error) { + return o.wallet.Take(ctx, userID) +} + +func (o *ChatDatabase) GetWalletsByUserIDs(ctx context.Context, userIDs []string) ([]*chatdb.Wallet, error) { + return o.wallet.Find(ctx, userIDs) +} + +func (o *ChatDatabase) GetWalletsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { + return o.wallet.Page(ctx, pagination) +} + +func (o *ChatDatabase) GetWalletsPageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { + return o.wallet.PageByRealNameAuthAuditStatus(ctx, auditStatus, userID, pagination) +} + +func (o *ChatDatabase) UpdateWalletBalance(ctx context.Context, userID string, balance int64) error { + return o.wallet.UpdateBalance(ctx, userID, balance) +} + +func (o *ChatDatabase) IncrementWalletBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) { + return o.wallet.IncrementBalance(ctx, userID, amount) +} + +func (o *ChatDatabase) UpdateWalletPaymentPassword(ctx context.Context, userID string, paymentPassword string) error { + return o.wallet.UpdatePaymentPassword(ctx, userID, paymentPassword) +} + +func (o *ChatDatabase) UpdateWalletWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error { + return o.wallet.UpdateWithdrawAccount(ctx, userID, withdrawAccount) +} + +func (o *ChatDatabase) UpdateWalletWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error { + return o.wallet.UpdateWithdrawAccountWithType(ctx, userID, withdrawAccount, accountType) +} + +func (o *ChatDatabase) UpdateWalletRealNameAuth(ctx context.Context, userID string, realNameAuth chatdb.RealNameAuth) error { + return o.wallet.UpdateRealNameAuth(ctx, userID, realNameAuth) +} + +func (o *ChatDatabase) CreateWallet(ctx context.Context, wallet *chatdb.Wallet) error { + return o.wallet.Create(ctx, wallet) +} + +func (o *ChatDatabase) GetWalletBalanceRecords(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { + return o.walletBalanceRecord.FindByUserID(ctx, userID, pagination) +} + +func (o *ChatDatabase) GetWalletBalanceRecordsByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { + return o.walletBalanceRecord.FindByUserIDAndType(ctx, userID, recordType, pagination) +} + +func (o *ChatDatabase) CreateWalletBalanceRecord(ctx context.Context, record *chatdb.WalletBalanceRecord) error { + return o.walletBalanceRecord.Create(ctx, record) +} + +// ==================== 提现相关方法 ==================== + +func (o *ChatDatabase) CreateWithdraw(ctx context.Context, withdraw *chatdb.Withdraw) error { + return o.withdraw.Create(ctx, withdraw) +} + +func (o *ChatDatabase) GetWithdraw(ctx context.Context, withdrawID string) (*chatdb.Withdraw, error) { + return o.withdraw.Take(ctx, withdrawID) +} + +func (o *ChatDatabase) GetWithdrawsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + return o.withdraw.FindByUserID(ctx, userID, pagination) +} + +func (o *ChatDatabase) GetWithdrawsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + return o.withdraw.FindByStatus(ctx, status, pagination) +} + +func (o *ChatDatabase) UpdateWithdrawStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error { + return o.withdraw.UpdateStatus(ctx, withdrawID, status, auditorID, auditRemark) +} + +func (o *ChatDatabase) GetWithdrawsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + return o.withdraw.Page(ctx, pagination) +} + +// ==================== 提现申请相关方法 ==================== + +func (o *ChatDatabase) CreateWithdrawApplication(ctx context.Context, application *chatdb.WithdrawApplication) error { + return o.withdrawApplication.Create(ctx, application) +} + +func (o *ChatDatabase) GetWithdrawApplication(ctx context.Context, applicationID string) (*chatdb.WithdrawApplication, error) { + return o.withdrawApplication.Take(ctx, applicationID) +} + +func (o *ChatDatabase) GetWithdrawApplicationsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + return o.withdrawApplication.FindByUserID(ctx, userID, pagination) +} + +func (o *ChatDatabase) GetWithdrawApplicationsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + return o.withdrawApplication.FindByStatus(ctx, status, pagination) +} + +func (o *ChatDatabase) UpdateWithdrawApplicationStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error { + return o.withdrawApplication.UpdateStatus(ctx, applicationID, status, auditorID, auditRemark) +} + +func (o *ChatDatabase) GetWithdrawApplicationsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + return o.withdrawApplication.Page(ctx, pagination) +} + +func (o *ChatDatabase) UpdateWithdrawApplication(ctx context.Context, applicationID string, data map[string]any) error { + return o.withdrawApplication.Update(ctx, applicationID, data) +} diff --git a/pkg/common/db/dbutil/gorm.go b/pkg/common/db/dbutil/gorm.go new file mode 100644 index 0000000..1a6cd56 --- /dev/null +++ b/pkg/common/db/dbutil/gorm.go @@ -0,0 +1,24 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbutil + +import ( + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/mongo" +) + +func IsDBNotFound(err error) bool { + return errs.Unwrap(err) == mongo.ErrNoDocuments +} diff --git a/pkg/common/db/model/admin/admin.go b/pkg/common/db/model/admin/admin.go new file mode 100644 index 0000000..2982d40 --- /dev/null +++ b/pkg/common/db/model/admin/admin.go @@ -0,0 +1,103 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewAdmin(db *mongo.Database) (admindb.AdminInterface, error) { + coll := db.Collection("admin") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "account", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Admin{ + coll: coll, + }, nil +} + +type Admin struct { + coll *mongo.Collection +} + +func (o *Admin) Take(ctx context.Context, account string) (*admindb.Admin, error) { + return mongoutil.FindOne[*admindb.Admin](ctx, o.coll, bson.M{"account": account}) +} + +func (o *Admin) TakeUserID(ctx context.Context, userID string) (*admindb.Admin, error) { + return mongoutil.FindOne[*admindb.Admin](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Admin) Update(ctx context.Context, account string, update map[string]any) error { + if len(update) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": account}, bson.M{"$set": update}, false) +} + +func (o *Admin) Create(ctx context.Context, admins []*admindb.Admin) error { + return mongoutil.InsertMany(ctx, o.coll, admins) +} + +func (o *Admin) ChangePassword(ctx context.Context, userID string, newPassword string) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"password": newPassword}}, false) +} + +func (o *Admin) ChangeOperationPassword(ctx context.Context, userID string, newPassword string) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"operation_password": newPassword}}, false) +} + +func (o *Admin) ClearGoogleAuthKey(ctx context.Context, userID string) error { + // 使用 $unset 删除字段,确保字段被完全移除 + // 注意:$unset 操作符的值可以是任意值(通常使用空字符串或1),MongoDB 会忽略值,只删除字段 + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$unset": bson.M{"google_auth_key": 1}}, false) +} + +func (o *Admin) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Admin) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admindb.Admin, error) { + opt := options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}}) + filter := bson.M{} + + // 如果有关键词,则进行模糊搜索(账号、昵称、用户ID) + if keyword != "" { + filter["$or"] = []bson.M{ + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + + return mongoutil.FindPage[*admindb.Admin](ctx, o.coll, filter, pagination, opt) +} diff --git a/pkg/common/db/model/admin/applet.go b/pkg/common/db/model/admin/applet.go new file mode 100644 index 0000000..61d8a48 --- /dev/null +++ b/pkg/common/db/model/admin/applet.go @@ -0,0 +1,95 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewApplet(db *mongo.Database) (admin.AppletInterface, error) { + coll := db.Collection("applet") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Applet{ + coll: coll, + }, nil +} + +type Applet struct { + coll *mongo.Collection +} + +func (o *Applet) Create(ctx context.Context, applets []*admin.Applet) error { + return mongoutil.InsertMany(ctx, o.coll, applets) +} + +func (o *Applet) Del(ctx context.Context, ids []string) error { + if len(ids) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"id": bson.M{"$in": ids}}) +} + +func (o *Applet) Update(ctx context.Context, id string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"id": id}, bson.M{"$set": data}, false) +} + +func (o *Applet) Take(ctx context.Context, id string) (*admin.Applet, error) { + return mongoutil.FindOne[*admin.Applet](ctx, o.coll, bson.M{"id": id}) +} + +func (o *Applet) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admin.Applet, error) { + filter := bson.M{} + + if keyword != "" { + filter = bson.M{ + "$or": []bson.M{ + {"name": bson.M{"$regex": keyword, "$options": "i"}}, + {"id": bson.M{"$regex": keyword, "$options": "i"}}, + {"app_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"version": bson.M{"$regex": keyword, "$options": "i"}}, + }, + } + } + return mongoutil.FindPage[*admin.Applet](ctx, o.coll, filter, pagination) +} + +func (o *Applet) FindOnShelf(ctx context.Context) ([]*admin.Applet, error) { + return mongoutil.Find[*admin.Applet](ctx, o.coll, bson.M{"status": constant.StatusOnShelf}) +} + +func (o *Applet) FindID(ctx context.Context, ids []string) ([]*admin.Applet, error) { + return mongoutil.Find[*admin.Applet](ctx, o.coll, bson.M{"id": bson.M{"$in": ids}}) +} diff --git a/pkg/common/db/model/admin/application.go b/pkg/common/db/model/admin/application.go new file mode 100644 index 0000000..0a3d3c5 --- /dev/null +++ b/pkg/common/db/model/admin/application.go @@ -0,0 +1,84 @@ +package admin + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewApplication(db *mongo.Database) (admindb.ApplicationInterface, error) { + coll := db.Collection("application") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "platform", Value: 1}, + {Key: "version", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "latest", Value: -1}, + }, + }, + }) + if err != nil { + return nil, err + } + return &ApplicationMgo{coll: coll}, nil +} + +type ApplicationMgo struct { + coll *mongo.Collection +} + +func (a *ApplicationMgo) sort() any { + return bson.D{{"latest", -1}, {"_id", -1}} +} + +func (a *ApplicationMgo) LatestVersion(ctx context.Context, platform string) (*admin.Application, error) { + return mongoutil.FindOne[*admin.Application](ctx, a.coll, bson.M{"platform": platform}, options.FindOne().SetSort(a.sort())) +} + +func (a *ApplicationMgo) AddVersion(ctx context.Context, val *admin.Application) error { + if val.ID.IsZero() { + val.ID = primitive.NewObjectID() + } + return mongoutil.InsertMany(ctx, a.coll, []*admin.Application{val}) +} + +func (a *ApplicationMgo) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error { + if len(update) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, a.coll, bson.M{"_id": id}, bson.M{"$set": update}, true) +} + +func (a *ApplicationMgo) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error { + if len(id) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, a.coll, bson.M{"_id": bson.M{"$in": id}}) +} + +func (a *ApplicationMgo) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admin.Application, error) { + filter := bson.M{} + if len(platforms) > 0 { + filter["platform"] = bson.M{"$in": platforms} + } + return mongoutil.FindPage[*admin.Application](ctx, a.coll, filter, page, options.Find().SetSort(a.sort())) +} + +func (a *ApplicationMgo) FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error) { + if len(id) == 0 { + return nil, nil + } + return mongoutil.Find[string](ctx, a.coll, bson.M{"_id": bson.M{"$in": id}}, options.Find().SetProjection(bson.M{"_id": 0, "platform": 1})) +} diff --git a/pkg/common/db/model/admin/client_config.go b/pkg/common/db/model/admin/client_config.go new file mode 100644 index 0000000..46d7c75 --- /dev/null +++ b/pkg/common/db/model/admin/client_config.go @@ -0,0 +1,77 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewClientConfig(db *mongo.Database) (admin.ClientConfigInterface, error) { + coll := db.Collection("client_config") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "key", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ClientConfig{ + coll: coll, + }, nil +} + +type ClientConfig struct { + coll *mongo.Collection +} + +func (o *ClientConfig) Set(ctx context.Context, config map[string]string) error { + for key, value := range config { + filter := bson.M{"key": key} + update := bson.M{ + "value": value, + } + err := mongoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true)) + if err != nil { + return err + } + } + return nil +} + +func (o *ClientConfig) Del(ctx context.Context, keys []string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"key": bson.M{"$in": keys}}) +} + +func (o *ClientConfig) Get(ctx context.Context) (map[string]string, error) { + cs, err := mongoutil.Find[*admin.ClientConfig](ctx, o.coll, bson.M{}) + if err != nil { + return nil, err + } + cm := make(map[string]string) + for _, config := range cs { + cm[config.Key] = config.Value + } + return cm, nil +} diff --git a/pkg/common/db/model/admin/forbidden_account.go b/pkg/common/db/model/admin/forbidden_account.go new file mode 100644 index 0000000..e4fc54e --- /dev/null +++ b/pkg/common/db/model/admin/forbidden_account.go @@ -0,0 +1,86 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewForbiddenAccount(db *mongo.Database) (admin.ForbiddenAccountInterface, error) { + coll := db.Collection("forbidden_account") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ForbiddenAccount{ + coll: coll, + }, nil +} + +type ForbiddenAccount struct { + coll *mongo.Collection +} + +func (o *ForbiddenAccount) Create(ctx context.Context, ms []*admin.ForbiddenAccount) error { + return mongoutil.InsertMany(ctx, o.coll, ms) +} + +func (o *ForbiddenAccount) Take(ctx context.Context, userID string) (*admin.ForbiddenAccount, error) { + return mongoutil.FindOne[*admin.ForbiddenAccount](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *ForbiddenAccount) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *ForbiddenAccount) Find(ctx context.Context, userIDs []string) ([]*admin.ForbiddenAccount, error) { + return mongoutil.Find[*admin.ForbiddenAccount](ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *ForbiddenAccount) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admin.ForbiddenAccount, error) { + filter := bson.M{} + + if keyword != "" { + filter = bson.M{ + "$or": []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"reason": bson.M{"$regex": keyword, "$options": "i"}}, + {"operator_user_id": bson.M{"$regex": keyword, "$options": "i"}}, + }, + } + } + return mongoutil.FindPage[*admin.ForbiddenAccount](ctx, o.coll, filter, pagination) +} + +func (o *ForbiddenAccount) FindAllIDs(ctx context.Context) ([]string, error) { + return mongoutil.Find[string](ctx, o.coll, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) +} diff --git a/pkg/common/db/model/admin/invitation_register.go b/pkg/common/db/model/admin/invitation_register.go new file mode 100644 index 0000000..45bd4a3 --- /dev/null +++ b/pkg/common/db/model/admin/invitation_register.go @@ -0,0 +1,99 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/constant" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewInvitationRegister(db *mongo.Database) (admindb.InvitationRegisterInterface, error) { + coll := db.Collection("invitation_register") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "invitation_code", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &InvitationRegister{ + coll: coll, + }, nil +} + +type InvitationRegister struct { + coll *mongo.Collection +} + +func (o *InvitationRegister) Find(ctx context.Context, codes []string) ([]*admindb.InvitationRegister, error) { + return mongoutil.Find[*admindb.InvitationRegister](ctx, o.coll, bson.M{"invitation_code": bson.M{"$in": codes}}) +} + +func (o *InvitationRegister) Del(ctx context.Context, codes []string) error { + if len(codes) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"invitation_code": bson.M{"$in": codes}}) +} + +func (o *InvitationRegister) Create(ctx context.Context, v []*admindb.InvitationRegister) error { + return mongoutil.InsertMany(ctx, o.coll, v) +} + +func (o *InvitationRegister) Take(ctx context.Context, code string) (*admindb.InvitationRegister, error) { + return mongoutil.FindOne[*admindb.InvitationRegister](ctx, o.coll, bson.M{"code": code}) +} + +func (o *InvitationRegister) Update(ctx context.Context, code string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"invitation_code": code}, bson.M{"$set": data}, false) +} + +func (o *InvitationRegister) Search(ctx context.Context, keyword string, state int32, userIDs []string, codes []string, pagination pagination.Pagination) (int64, []*admindb.InvitationRegister, error) { + filter := bson.M{} + switch state { + case constant.InvitationCodeUsed: + filter = bson.M{"user_id": bson.M{"$ne": ""}} + case constant.InvitationCodeUnused: + filter = bson.M{"user_id": ""} + } + + if len(userIDs) > 0 { + filter["user_id"] = bson.M{"$in": userIDs} + } + if len(codes) > 0 { + filter["invitation_code"] = bson.M{"$in": codes} + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"invitation_code": bson.M{"$regex": keyword, "$options": "i"}}, + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*admindb.InvitationRegister](ctx, o.coll, filter, pagination) +} diff --git a/pkg/common/db/model/admin/ip_forbidden.go b/pkg/common/db/model/admin/ip_forbidden.go new file mode 100644 index 0000000..8b89871 --- /dev/null +++ b/pkg/common/db/model/admin/ip_forbidden.go @@ -0,0 +1,95 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/constant" + admindb "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewIPForbidden(db *mongo.Database) (admindb.IPForbiddenInterface, error) { + coll := db.Collection("ip_forbidden") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "ip", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &IPForbidden{ + coll: coll, + }, nil +} + +type IPForbidden struct { + coll *mongo.Collection +} + +func (o *IPForbidden) Take(ctx context.Context, ip string) (*admindb.IPForbidden, error) { + return mongoutil.FindOne[*admindb.IPForbidden](ctx, o.coll, bson.M{"ip": ip}) +} + +func (o *IPForbidden) Find(ctx context.Context, ips []string) ([]*admindb.IPForbidden, error) { + return mongoutil.Find[*admindb.IPForbidden](ctx, o.coll, bson.M{"ip": bson.M{"$in": ips}}) +} + +func (o *IPForbidden) Search(ctx context.Context, keyword string, state int32, pagination pagination.Pagination) (int64, []*admindb.IPForbidden, error) { + filter := bson.M{} + + switch state { + case constant.LimitNil: + case constant.LimitEmpty: + filter = bson.M{"limit_register": 0, "limit_login": 0} + case constant.LimitOnlyRegisterIP: + filter = bson.M{"limit_register": 1, "limit_login": 0} + case constant.LimitOnlyLoginIP: + filter = bson.M{"limit_register": 0, "limit_login": 1} + case constant.LimitRegisterIP: + filter = bson.M{"limit_register": 1} + case constant.LimitLoginIP: + filter = bson.M{"limit_login": 1} + case constant.LimitLoginRegisterIP: + filter = bson.M{"limit_register": 1, "limit_login": 1} + } + + if keyword != "" { + filter["$or"] = []bson.M{ + {"ip": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*admindb.IPForbidden](ctx, o.coll, filter, pagination) +} + +func (o *IPForbidden) Create(ctx context.Context, ms []*admindb.IPForbidden) error { + return mongoutil.InsertMany(ctx, o.coll, ms) +} + +func (o *IPForbidden) Delete(ctx context.Context, ips []string) error { + if len(ips) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"ip": bson.M{"$in": ips}}) +} diff --git a/pkg/common/db/model/admin/limit_user_login_ip.go b/pkg/common/db/model/admin/limit_user_login_ip.go new file mode 100644 index 0000000..b2a264d --- /dev/null +++ b/pkg/common/db/model/admin/limit_user_login_ip.go @@ -0,0 +1,93 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewLimitUserLoginIP(db *mongo.Database) (admin.LimitUserLoginIPInterface, error) { + coll := db.Collection("limit_user_login_ip") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "ip", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &LimitUserLoginIP{ + coll: coll, + }, nil +} + +type LimitUserLoginIP struct { + coll *mongo.Collection +} + +func (o *LimitUserLoginIP) Create(ctx context.Context, ms []*admin.LimitUserLoginIP) error { + return mongoutil.InsertMany(ctx, o.coll, ms) +} + +func (o *LimitUserLoginIP) Delete(ctx context.Context, ms []*admin.LimitUserLoginIP) error { + return mongoutil.DeleteMany(ctx, o.coll, o.limitUserLoginIPFilter(ms)) +} + +func (o *LimitUserLoginIP) Count(ctx context.Context, userID string) (uint32, error) { + count, err := mongoutil.Count(ctx, o.coll, bson.M{"user_id": userID}) + if err != nil { + return 0, err + } + return uint32(count), nil +} + +func (o *LimitUserLoginIP) Take(ctx context.Context, userID string, ip string) (*admin.LimitUserLoginIP, error) { + return mongoutil.FindOne[*admin.LimitUserLoginIP](ctx, o.coll, bson.M{"user_id": userID, "ip": ip}) +} + +func (o *LimitUserLoginIP) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admin.LimitUserLoginIP, error) { + filter := bson.M{ + "$or": []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"ip": bson.M{"$regex": keyword, "$options": "i"}}, + }, + } + return mongoutil.FindPage[*admin.LimitUserLoginIP](ctx, o.coll, filter, pagination) +} + +func (o *LimitUserLoginIP) limitUserLoginIPFilter(ips []*admin.LimitUserLoginIP) bson.M { + if len(ips) == 0 { + return nil + } + or := make(bson.A, 0, len(ips)) + for _, ip := range ips { + or = append(or, bson.M{ + "user_id": ip.UserID, + "ip": ip.IP, + }) + } + return bson.M{"$or": or} +} diff --git a/pkg/common/db/model/admin/register_add_friend.go b/pkg/common/db/model/admin/register_add_friend.go new file mode 100644 index 0000000..0179bfb --- /dev/null +++ b/pkg/common/db/model/admin/register_add_friend.go @@ -0,0 +1,76 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewRegisterAddFriend(db *mongo.Database) (admin.RegisterAddFriendInterface, error) { + coll := db.Collection("register_add_friend") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &RegisterAddFriend{ + coll: coll, + }, nil +} + +type RegisterAddFriend struct { + coll *mongo.Collection +} + +func (o *RegisterAddFriend) Add(ctx context.Context, registerAddFriends []*admin.RegisterAddFriend) error { + return mongoutil.InsertMany(ctx, o.coll, registerAddFriends) +} + +func (o *RegisterAddFriend) Del(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *RegisterAddFriend) FindUserID(ctx context.Context, userIDs []string) ([]string, error) { + filter := bson.M{} + if len(userIDs) > 0 { + filter["user_id"] = bson.M{"$in": userIDs} + } + return mongoutil.Find[string](ctx, o.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) +} + +func (o *RegisterAddFriend) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admin.RegisterAddFriend, error) { + filter := bson.M{"user_id": bson.M{"$regex": keyword, "$options": "i"}} + return mongoutil.FindPage[*admin.RegisterAddFriend](ctx, o.coll, filter, pagination) +} + +func (o *RegisterAddFriend) CountTotal(ctx context.Context) (int64, error) { + return mongoutil.Count(ctx, o.coll, bson.M{}) +} diff --git a/pkg/common/db/model/admin/register_add_group.go b/pkg/common/db/model/admin/register_add_group.go new file mode 100644 index 0000000..705cd97 --- /dev/null +++ b/pkg/common/db/model/admin/register_add_group.go @@ -0,0 +1,90 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/errs" +) + +func NewRegisterAddGroup(db *mongo.Database) (admin.RegisterAddGroupInterface, error) { + coll := db.Collection("register_add_group") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "group_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &RegisterAddGroup{ + coll: coll, + }, nil +} + +type RegisterAddGroup struct { + coll *mongo.Collection +} + +func (o *RegisterAddGroup) Add(ctx context.Context, registerAddGroups []*admin.RegisterAddGroup) error { + return mongoutil.InsertMany(ctx, o.coll, registerAddGroups) +} + +func (o *RegisterAddGroup) Del(ctx context.Context, groupIDs []string) error { + if len(groupIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) +} + +func (o *RegisterAddGroup) FindGroupID(ctx context.Context, groupIDs []string) ([]string, error) { + filter := bson.M{} + if len(groupIDs) > 0 { + filter["group_id"] = bson.M{"$in": groupIDs} + } + return mongoutil.Find[string](ctx, o.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) +} + +func (o *RegisterAddGroup) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*admin.RegisterAddGroup, error) { + filter := bson.M{"group_id": bson.M{"$regex": keyword, "$options": "i"}} + return mongoutil.FindPage[*admin.RegisterAddGroup](ctx, o.coll, filter, pagination) +} + +func (o *RegisterAddGroup) CountTotal(ctx context.Context) (int64, error) { + return mongoutil.Count(ctx, o.coll, bson.M{}) +} + +func (o *RegisterAddGroup) CountToday(ctx context.Context) (int64, error) { + now := time.Now() + todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + todayEnd := todayStart.Add(24 * time.Hour) + filter := bson.M{ + "create_time": bson.M{ + "$gte": todayStart, + "$lt": todayEnd, + }, + } + return mongoutil.Count(ctx, o.coll, filter) +} diff --git a/pkg/common/db/model/bot/agent.go b/pkg/common/db/model/bot/agent.go new file mode 100644 index 0000000..e3c3ed2 --- /dev/null +++ b/pkg/common/db/model/bot/agent.go @@ -0,0 +1,65 @@ +package bot + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewAgent(db *mongo.Database) (bot.AgentInterface, error) { + coll := db.Collection("agent") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Agent{coll: coll}, nil +} + +type Agent struct { + coll *mongo.Collection +} + +func (o *Agent) Create(ctx context.Context, elems ...*bot.Agent) error { + return mongoutil.InsertMany(ctx, o.coll, elems) +} + +func (o *Agent) Take(ctx context.Context, userId string) (*bot.Agent, error) { + return mongoutil.FindOne[*bot.Agent](ctx, o.coll, bson.M{"user_id": userId}) +} + +func (o *Agent) Find(ctx context.Context, userIDs []string) ([]*bot.Agent, error) { + return mongoutil.Find[*bot.Agent](ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Agent) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Agent) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Agent) Page(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*bot.Agent, error) { + filter := bson.M{} + if len(userIDs) > 0 { + filter["user_id"] = bson.M{"$in": userIDs} + } + return mongoutil.FindPage[*bot.Agent](ctx, o.coll, filter, pagination) +} diff --git a/pkg/common/db/model/bot/conversation_resp_id.go b/pkg/common/db/model/bot/conversation_resp_id.go new file mode 100644 index 0000000..f88754b --- /dev/null +++ b/pkg/common/db/model/bot/conversation_resp_id.go @@ -0,0 +1,50 @@ +package bot + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewConversationRespID(db *mongo.Database) (bot.ConversationRespIDInterface, error) { + coll := db.Collection("conversation_resp_id") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "conversation_id", Value: 1}, + {Key: "agent_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ConversationRespID{coll: coll}, nil +} + +type ConversationRespID struct { + coll *mongo.Collection +} + +func (o *ConversationRespID) Create(ctx context.Context, elems ...*bot.ConversationRespID) error { + return mongoutil.InsertMany(ctx, o.coll, elems) +} + +func (o *ConversationRespID) Take(ctx context.Context, convID, agentID string) (*bot.ConversationRespID, error) { + return mongoutil.FindOne[*bot.ConversationRespID](ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}) +} + +func (o *ConversationRespID) Update(ctx context.Context, convID, agentID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}, bson.M{"$set": data}, false, options.Update().SetUpsert(true)) +} + +func (o *ConversationRespID) Delete(ctx context.Context, convID, agentID string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}) +} diff --git a/pkg/common/db/model/chat/account.go b/pkg/common/db/model/chat/account.go new file mode 100644 index 0000000..d0211f2 --- /dev/null +++ b/pkg/common/db/model/chat/account.go @@ -0,0 +1,72 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewAccount(db *mongo.Database) (chat.AccountInterface, error) { + coll := db.Collection("account") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Account{coll: coll}, nil +} + +type Account struct { + coll *mongo.Collection +} + +func (o *Account) Create(ctx context.Context, accounts ...*chat.Account) error { + return mongoutil.InsertMany(ctx, o.coll, accounts) +} + +func (o *Account) Take(ctx context.Context, userId string) (*chat.Account, error) { + return mongoutil.FindOne[*chat.Account](ctx, o.coll, bson.M{"user_id": userId}) +} + +func (o *Account) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Account) UpdatePassword(ctx context.Context, userId string, password string) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userId}, bson.M{"$set": bson.M{"password": password, "change_time": time.Now()}}, false) +} + +func (o *Account) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} diff --git a/pkg/common/db/model/chat/attribute.go b/pkg/common/db/model/chat/attribute.go new file mode 100644 index 0000000..b306a83 --- /dev/null +++ b/pkg/common/db/model/chat/attribute.go @@ -0,0 +1,247 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewAttribute(db *mongo.Database) (chat.AttributeInterface, error) { + coll := db.Collection("attribute") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "account", Value: 1}, + }, + }, + { + Keys: bson.D{ + {Key: "email", Value: 1}, + }, + }, + { + Keys: bson.D{ + {Key: "area_code", Value: 1}, + {Key: "phone_number", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Attribute{coll: coll}, nil +} + +type Attribute struct { + coll *mongo.Collection +} + +func (o *Attribute) Create(ctx context.Context, attribute ...*chat.Attribute) error { + return mongoutil.InsertMany(ctx, o.coll, attribute) +} + +func (o *Attribute) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Attribute) Find(ctx context.Context, userIds []string) ([]*chat.Attribute, error) { + return mongoutil.Find[*chat.Attribute](ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIds}}) +} + +func (o *Attribute) FindAccount(ctx context.Context, accounts []string) ([]*chat.Attribute, error) { + return mongoutil.Find[*chat.Attribute](ctx, o.coll, bson.M{"account": bson.M{"$in": accounts}}) +} + +func (o *Attribute) FindPhone(ctx context.Context, phoneNumbers []string) ([]*chat.Attribute, error) { + return mongoutil.Find[*chat.Attribute](ctx, o.coll, bson.M{"phone_number": bson.M{"$in": phoneNumbers}}) +} + +func (o *Attribute) Search(ctx context.Context, keyword string, genders []int32, pagination pagination.Pagination) (int64, []*chat.Attribute, error) { + filter := bson.M{} + if len(genders) > 0 { + filter["gender"] = bson.M{ + "$in": genders, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, + {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination) +} + +func (o *Attribute) TakePhone(ctx context.Context, areaCode string, phoneNumber string) (*chat.Attribute, error) { + return mongoutil.FindOne[*chat.Attribute](ctx, o.coll, bson.M{"area_code": areaCode, "phone_number": phoneNumber}) +} + +func (o *Attribute) TakeEmail(ctx context.Context, email string) (*chat.Attribute, error) { + return mongoutil.FindOne[*chat.Attribute](ctx, o.coll, bson.M{"email": email}) +} + +func (o *Attribute) TakeAccount(ctx context.Context, account string) (*chat.Attribute, error) { + return mongoutil.FindOne[*chat.Attribute](ctx, o.coll, bson.M{"account": account}) +} + +func (o *Attribute) Take(ctx context.Context, userID string) (*chat.Attribute, error) { + return mongoutil.FindOne[*chat.Attribute](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Attribute) SearchNormalUser(ctx context.Context, keyword string, forbiddenIDs []string, gender int32, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*chat.Attribute, error) { + filter := bson.M{} + if gender == 0 { + filter["gender"] = bson.M{ + "$in": []int32{0, 1, 2}, + } + } else { + filter["gender"] = gender + } + if len(forbiddenIDs) > 0 { + filter["user_id"] = bson.M{ + "$nin": forbiddenIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, + {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"email": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + // 注册时间范围查询 + if startTime != nil || endTime != nil { + timeFilter := bson.M{} + if startTime != nil { + timeFilter["$gte"] = *startTime + } + if endTime != nil { + // 使用 $lt(小于)而不是 $lte,确保不包含结束时间当天的数据 + // 例如:endTime="2025-11-02 00:00:00" 应该查询到 2025-11-01 23:59:59,不包含 11月2日的数据 + timeFilter["$lt"] = *endTime + } + if len(timeFilter) > 0 { + filter["create_time"] = timeFilter + } + } + return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +// SearchNormalUserWithUserIDs 按条件搜索用户(支持额外的userIDs过滤) +func (o *Attribute) SearchNormalUserWithUserIDs(ctx context.Context, keyword string, forbiddenIDs []string, gender int32, startTime, endTime *time.Time, userIDs []string, pagination pagination.Pagination) (int64, []*chat.Attribute, error) { + filter := bson.M{} + if gender == 0 { + filter["gender"] = bson.M{ + "$in": []int32{0, 1, 2}, + } + } else { + filter["gender"] = gender + } + + // 构建user_id过滤条件:需要同时满足在userIDs中,且不在forbiddenIDs中 + userIDConditions := []bson.M{} + if len(userIDs) > 0 { + userIDConditions = append(userIDConditions, bson.M{"user_id": bson.M{"$in": userIDs}}) + } + if len(forbiddenIDs) > 0 { + userIDConditions = append(userIDConditions, bson.M{"user_id": bson.M{"$nin": forbiddenIDs}}) + } + if len(userIDConditions) > 0 { + if len(userIDConditions) == 1 { + filter["user_id"] = userIDConditions[0]["user_id"] + } else { + // 需要同时满足多个条件,使用 $and + filter["$and"] = userIDConditions + } + } + + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, + {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"email": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + // 注册时间范围查询 + if startTime != nil || endTime != nil { + timeFilter := bson.M{} + if startTime != nil { + timeFilter["$gte"] = *startTime + } + if endTime != nil { + timeFilter["$lt"] = *endTime + } + if len(timeFilter) > 0 { + filter["create_time"] = timeFilter + } + } + return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Attribute) SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chat.Attribute, error) { + filter := bson.M{} + if len(genders) > 0 { + filter["gender"] = bson.M{ + "$in": genders, + } + } + if len(userIDs) > 0 { + filter["user_id"] = bson.M{ + "$in": userIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, + {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"email": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination) +} + +func (o *Attribute) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} diff --git a/pkg/common/db/model/chat/credential.go b/pkg/common/db/model/chat/credential.go new file mode 100644 index 0000000..1145d79 --- /dev/null +++ b/pkg/common/db/model/chat/credential.go @@ -0,0 +1,145 @@ +package chat + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewCredential(db *mongo.Database) (chat.CredentialInterface, error) { + coll := db.Collection("credential") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "type", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "account", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Credential{coll: coll}, nil +} + +type Credential struct { + coll *mongo.Collection +} + +func (o *Credential) Create(ctx context.Context, credential ...*chat.Credential) error { + return mongoutil.InsertMany(ctx, o.coll, credential) +} + +func (o *Credential) CreateOrUpdateAccount(ctx context.Context, credential *chat.Credential) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }, bson.M{ + "$set": bson.M{ + "account": credential.Account, + }, + "$setOnInsert": bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + "allow_change": credential.AllowChange, + }, + }, false, options.Update().SetUpsert(true)) +} + +func (o *Credential) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Credential) Find(ctx context.Context, userID string) ([]*chat.Credential, error) { + return mongoutil.Find[*chat.Credential](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Credential) FindAccount(ctx context.Context, accounts []string) ([]*chat.Credential, error) { + return mongoutil.Find[*chat.Credential](ctx, o.coll, bson.M{"account": bson.M{"$in": accounts}}) +} + +func (o *Credential) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + return o.SearchUser(ctx, keyword, nil, pagination) +} + +func (o *Credential) TakeAccount(ctx context.Context, account string) (*chat.Credential, error) { + return mongoutil.FindOne[*chat.Credential](ctx, o.coll, bson.M{"account": account}) +} + +func (o *Credential) Take(ctx context.Context, userID string) (*chat.Credential, error) { + return mongoutil.FindOne[*chat.Credential](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Credential) SearchNormalUser(ctx context.Context, keyword string, forbiddenIDs []string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + filter := bson.M{} + + if len(forbiddenIDs) > 0 { + filter["user_id"] = bson.M{ + "$nin": forbiddenIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Credential](ctx, o.coll, filter, pagination) +} + +func (o *Credential) SearchUser(ctx context.Context, keyword string, userIDs []string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + filter := bson.M{} + + if len(userIDs) > 0 { + filter["user_id"] = bson.M{ + "$in": userIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Credential](ctx, o.coll, filter, pagination) +} + +func (o *Credential) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Credential) DeleteByUserIDType(ctx context.Context, credentials ...*chat.Credential) error { + if len(credentials) == 0 { + return nil + } + var filters []bson.M + for _, credential := range credentials { + filters = append(filters, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }) + } + + query := bson.M{"$or": filters} + + return mongoutil.DeleteMany(ctx, o.coll, query) +} diff --git a/pkg/common/db/model/chat/favorite.go b/pkg/common/db/model/chat/favorite.go new file mode 100644 index 0000000..327295d --- /dev/null +++ b/pkg/common/db/model/chat/favorite.go @@ -0,0 +1,151 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewFavorite(db *mongo.Database) (chat.FavoriteInterface, error) { + coll := db.Collection("favorite") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "type", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "status", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Favorite{coll: coll}, nil +} + +type Favorite struct { + coll *mongo.Collection +} + +func (o *Favorite) Create(ctx context.Context, favorites ...*chat.Favorite) error { + for _, favorite := range favorites { + if favorite.ID == "" { + favorite.ID = primitive.NewObjectID().Hex() + } + if favorite.CreateTime.IsZero() { + favorite.CreateTime = time.Now() + } + if favorite.UpdateTime.IsZero() { + favorite.UpdateTime = time.Now() + } + if favorite.Status == 0 { + favorite.Status = 1 // 默认为正常状态 + } + } + return mongoutil.InsertMany(ctx, o.coll, favorites) +} + +func (o *Favorite) Take(ctx context.Context, favoriteID string) (*chat.Favorite, error) { + return mongoutil.FindOne[*chat.Favorite](ctx, o.coll, bson.M{"_id": favoriteID, "status": 1}) +} + +func (o *Favorite) FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chat.Favorite, error) { + filter := bson.M{ + "user_id": userID, + "status": 1, + } + return mongoutil.FindPage[*chat.Favorite](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Favorite) FindByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*chat.Favorite, error) { + filter := bson.M{ + "user_id": userID, + "type": favoriteType, + "status": 1, + } + return mongoutil.FindPage[*chat.Favorite](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Favorite) SearchByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*chat.Favorite, error) { + filter := bson.M{ + "user_id": userID, + "status": 1, + "$or": []bson.M{ + {"title": bson.M{"$regex": keyword, "$options": "i"}}, + {"content": bson.M{"$regex": keyword, "$options": "i"}}, + {"description": bson.M{"$regex": keyword, "$options": "i"}}, + }, + } + return mongoutil.FindPage[*chat.Favorite](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Favorite) Update(ctx context.Context, favoriteID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + data["update_time"] = time.Now() + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": favoriteID}, bson.M{"$set": data}, false) +} + +func (o *Favorite) Delete(ctx context.Context, favoriteIDs []string) error { + if len(favoriteIDs) == 0 { + return nil + } + // 软删除:将状态设置为0 + _, err := o.coll.UpdateMany(ctx, bson.M{"_id": bson.M{"$in": favoriteIDs}}, bson.M{"$set": bson.M{"status": 0, "update_time": time.Now()}}) + return errs.Wrap(err) +} + +func (o *Favorite) DeleteByUserID(ctx context.Context, userID string) error { + // 软删除:将状态设置为0 + _, err := o.coll.UpdateMany(ctx, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"status": 0, "update_time": time.Now()}}) + return errs.Wrap(err) +} + +func (o *Favorite) CountByUserID(ctx context.Context, userID string) (int64, error) { + return mongoutil.Count(ctx, o.coll, bson.M{"user_id": userID, "status": 1}) +} + +func (o *Favorite) FindByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*chat.Favorite, error) { + filter := bson.M{ + "user_id": userID, + "status": 1, + "tags": bson.M{"$in": tags}, + } + return mongoutil.FindPage[*chat.Favorite](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} diff --git a/pkg/common/db/model/chat/register.go b/pkg/common/db/model/chat/register.go new file mode 100644 index 0000000..0779b3c --- /dev/null +++ b/pkg/common/db/model/chat/register.go @@ -0,0 +1,81 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "github.com/openimsdk/tools/errs" +) + +func NewRegister(db *mongo.Database) (chat.RegisterInterface, error) { + coll := db.Collection("register") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Register{coll: coll}, nil +} + +type Register struct { + coll *mongo.Collection +} + +func (o *Register) Create(ctx context.Context, registers ...*chat.Register) error { + return mongoutil.InsertMany(ctx, o.coll, registers) +} + +func (o *Register) CountTotal(ctx context.Context, before *time.Time) (int64, error) { + filter := bson.M{} + if before != nil { + filter["create_time"] = bson.M{"$lt": before} + } + return mongoutil.Count(ctx, o.coll, filter) +} + +func (o *Register) CountToday(ctx context.Context) (int64, error) { + now := time.Now() + startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + endOfDay := startOfDay.Add(24 * time.Hour) + + filter := bson.M{ + "create_time": bson.M{ + "$gte": startOfDay, + "$lt": endOfDay, + }, + } + return mongoutil.Count(ctx, o.coll, filter) +} + +func (o *Register) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} diff --git a/pkg/common/db/model/chat/scheduled_task.go b/pkg/common/db/model/chat/scheduled_task.go new file mode 100644 index 0000000..7f12cb8 --- /dev/null +++ b/pkg/common/db/model/chat/scheduled_task.go @@ -0,0 +1,106 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewScheduledTask(db *mongo.Database) (chat.ScheduledTaskInterface, error) { + coll := db.Collection("scheduled_tasks") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "status", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ScheduledTask{coll: coll}, nil +} + +type ScheduledTask struct { + coll *mongo.Collection +} + +func (o *ScheduledTask) Create(ctx context.Context, tasks ...*chat.ScheduledTask) error { + for _, task := range tasks { + if task.ID == "" { + task.ID = primitive.NewObjectID().Hex() + } + if task.CreateTime.IsZero() { + task.CreateTime = time.Now() + } + if task.UpdateTime.IsZero() { + task.UpdateTime = time.Now() + } + if task.Status == 0 { + task.Status = 1 // 默认为启用状态 + } + } + return mongoutil.InsertMany(ctx, o.coll, tasks) +} + +func (o *ScheduledTask) Take(ctx context.Context, taskID string) (*chat.ScheduledTask, error) { + return mongoutil.FindOne[*chat.ScheduledTask](ctx, o.coll, bson.M{"_id": taskID}) +} + +func (o *ScheduledTask) FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chat.ScheduledTask, error) { + filter := bson.M{ + "user_id": userID, + } + return mongoutil.FindPage[*chat.ScheduledTask](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *ScheduledTask) FindAll(ctx context.Context, pagination pagination.Pagination) (int64, []*chat.ScheduledTask, error) { + filter := bson.M{} + return mongoutil.FindPage[*chat.ScheduledTask](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *ScheduledTask) Update(ctx context.Context, taskID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + data["update_time"] = time.Now() + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": taskID}, bson.M{"$set": data}, false) +} + +func (o *ScheduledTask) Delete(ctx context.Context, taskIDs []string) error { + if len(taskIDs) == 0 { + return nil + } + _, err := o.coll.DeleteMany(ctx, bson.M{"_id": bson.M{"$in": taskIDs}}) + return errs.Wrap(err) +} diff --git a/pkg/common/db/model/chat/sensitive_word.go b/pkg/common/db/model/chat/sensitive_word.go new file mode 100644 index 0000000..3f58acb --- /dev/null +++ b/pkg/common/db/model/chat/sensitive_word.go @@ -0,0 +1,422 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "fmt" + "strings" + "time" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewSensitiveWord(db *mongo.Database) (chat.SensitiveWordInterface, error) { + coll := db.Collection("sensitive_words") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "word", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "status", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + + // 创建配置集合 + configColl := db.Collection("sensitive_word_configs") + _, err = configColl.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "enable_filter", Value: 1}, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + + // 检查并初始化默认配置 + ctx := context.Background() + count, err := configColl.CountDocuments(ctx, bson.M{}) + if err != nil { + return nil, errs.Wrap(err) + } + + if count == 0 { + // 创建默认配置 + defaultConfig := &chat.SensitiveWordConfig{ + ID: "default", + EnableFilter: true, + FilterMode: 1, + ReplaceChar: "***", + WhitelistUsers: []string{}, + WhitelistGroups: []string{}, + LogEnabled: true, + AutoApprove: false, + UpdateTime: time.Now(), + } + + _, err = configColl.InsertOne(ctx, defaultConfig) + if err != nil { + return nil, errs.Wrap(err) + } + } + + return &SensitiveWord{coll: coll, configColl: configColl}, nil +} + +type SensitiveWord struct { + coll *mongo.Collection + configColl *mongo.Collection +} + +// ==================== 敏感词管理 ==================== + +func (o *SensitiveWord) CreateSensitiveWord(ctx context.Context, word *chat.SensitiveWord) error { + word.CreateTime = time.Now() + word.UpdateTime = time.Now() + return mongoutil.InsertMany(ctx, o.coll, []*chat.SensitiveWord{word}) +} + +func (o *SensitiveWord) UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error { + data["update_time"] = time.Now() + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": id}, bson.M{"$set": data}, false) +} + +func (o *SensitiveWord) DeleteSensitiveWord(ctx context.Context, ids []string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"_id": bson.M{"$in": ids}}) +} + +func (o *SensitiveWord) GetSensitiveWord(ctx context.Context, id string) (*chat.SensitiveWord, error) { + return mongoutil.FindOne[*chat.SensitiveWord](ctx, o.coll, bson.M{"_id": id}) +} + +func (o *SensitiveWord) SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chat.SensitiveWord, error) { + filter := bson.M{} + if keyword != "" { + filter["word"] = bson.M{"$regex": keyword, "$options": "i"} + } + if action > 0 { + filter["action"] = action + } + if status > 0 { + filter["status"] = status + } + + return mongoutil.FindPage[*chat.SensitiveWord](ctx, o.coll, filter, pagination) +} + +func (o *SensitiveWord) GetAllSensitiveWords(ctx context.Context) ([]*chat.SensitiveWord, error) { + return mongoutil.Find[*chat.SensitiveWord](ctx, o.coll, bson.M{}) +} + +func (o *SensitiveWord) GetEnabledSensitiveWords(ctx context.Context) ([]*chat.SensitiveWord, error) { + return mongoutil.Find[*chat.SensitiveWord](ctx, o.coll, bson.M{"status": chat.SensitiveStatusEnabled}) +} + +// ==================== 敏感词检测和过滤 ==================== + +func (o *SensitiveWord) CheckSensitiveWords(ctx context.Context, content string) ([]*chat.SensitiveWord, error) { + words, err := o.GetEnabledSensitiveWords(ctx) + if err != nil { + return nil, err + } + + var matchedWords []*chat.SensitiveWord + contentLower := strings.ToLower(content) + + for _, word := range words { + if strings.Contains(contentLower, strings.ToLower(word.Word)) { + matchedWords = append(matchedWords, word) + } + } + + return matchedWords, nil +} + +func (o *SensitiveWord) FilterContent(ctx context.Context, content string) (string, []*chat.SensitiveWord, error) { + words, err := o.CheckSensitiveWords(ctx, content) + if err != nil { + return content, nil, err + } + + if len(words) == 0 { + return content, words, nil + } + + filteredContent := content + for _, word := range words { + replaceChar := "***" + filteredContent = strings.ReplaceAll(filteredContent, word.Word, replaceChar) + } + + return filteredContent, words, nil +} + +// ==================== 敏感词日志管理 ==================== + +func (o *SensitiveWord) CreateSensitiveWordLog(ctx context.Context, log *chat.SensitiveWordLog) error { + log.CreateTime = time.Now() + return mongoutil.InsertMany(ctx, o.coll.Database().Collection("sensitive_word_logs"), []*chat.SensitiveWordLog{log}) +} + +func (o *SensitiveWord) GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chat.SensitiveWordLog, error) { + filter := bson.M{} + if userID != "" { + filter["user_id"] = userID + } + if groupID != "" { + filter["group_id"] = groupID + } + + coll := o.coll.Database().Collection("sensitive_word_logs") + return mongoutil.FindPage[*chat.SensitiveWordLog](ctx, coll, filter, pagination) +} + +func (o *SensitiveWord) DeleteSensitiveWordLogs(ctx context.Context, ids []string) error { + coll := o.coll.Database().Collection("sensitive_word_logs") + return mongoutil.DeleteMany(ctx, coll, bson.M{"_id": bson.M{"$in": ids}}) +} + +// ==================== 敏感词分组管理 ==================== + +func (o *SensitiveWord) CreateSensitiveWordGroup(ctx context.Context, group *chat.SensitiveWordGroup) error { + group.CreateTime = time.Now() + group.UpdateTime = time.Now() + return mongoutil.InsertMany(ctx, o.coll.Database().Collection("sensitive_word_groups"), []*chat.SensitiveWordGroup{group}) +} + +func (o *SensitiveWord) UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error { + data["update_time"] = time.Now() + coll := o.coll.Database().Collection("sensitive_word_groups") + return mongoutil.UpdateOne(ctx, coll, bson.M{"_id": id}, bson.M{"$set": data}, false) +} + +func (o *SensitiveWord) DeleteSensitiveWordGroup(ctx context.Context, ids []string) error { + coll := o.coll.Database().Collection("sensitive_word_groups") + return mongoutil.DeleteMany(ctx, coll, bson.M{"_id": bson.M{"$in": ids}}) +} + +func (o *SensitiveWord) GetSensitiveWordGroup(ctx context.Context, id string) (*chat.SensitiveWordGroup, error) { + coll := o.coll.Database().Collection("sensitive_word_groups") + return mongoutil.FindOne[*chat.SensitiveWordGroup](ctx, coll, bson.M{"_id": id}) +} + +func (o *SensitiveWord) GetAllSensitiveWordGroups(ctx context.Context) ([]*chat.SensitiveWordGroup, error) { + coll := o.coll.Database().Collection("sensitive_word_groups") + return mongoutil.Find[*chat.SensitiveWordGroup](ctx, coll, bson.M{}) +} + +// ==================== 敏感词配置管理 ==================== + +func (o *SensitiveWord) GetSensitiveWordConfig(ctx context.Context) (*chat.SensitiveWordConfig, error) { + // 查找配置(默认配置已在初始化时创建) + config, err := mongoutil.FindOne[*chat.SensitiveWordConfig](ctx, o.configColl, bson.M{}) + if err != nil { + return nil, err + } + return config, nil +} + +func (o *SensitiveWord) UpdateSensitiveWordConfig(ctx context.Context, config *chat.SensitiveWordConfig) error { + config.UpdateTime = time.Now() + if config.ID == "" { + config.ID = "default" + } + filter := bson.M{"_id": config.ID} + fmt.Println("UpdateSensitiveWordConfig", "_________55", config, o.configColl.Name()) + err := mongoutil.UpdateOne(ctx, o.configColl, filter, bson.M{"$set": config}, true) + fmt.Println("UpdateSensitiveWordConfig", "_________44", config) + if err != nil { + return err + } + return nil +} + +func (o *SensitiveWord) IsFilterEnabled(ctx context.Context) (bool, error) { + config, err := o.GetSensitiveWordConfig(ctx) + if err != nil { + return false, err + } + return config.EnableFilter, nil +} + +func (o *SensitiveWord) GetFilterMode(ctx context.Context) (int32, error) { + // 简化实现,返回默认值 + return 1, nil +} + +func (o *SensitiveWord) GetReplaceChar(ctx context.Context) (string, error) { + config, err := o.GetSensitiveWordConfig(ctx) + if err != nil { + return "***", err + } + if config.ReplaceChar == "" { + return "***", nil + } + return config.ReplaceChar, nil +} + +func (o *SensitiveWord) IsUserInWhitelist(ctx context.Context, userID string) (bool, error) { + config, err := o.GetSensitiveWordConfig(ctx) + if err != nil { + return false, err + } + for _, id := range config.WhitelistUsers { + if id == userID { + return true, nil + } + } + return false, nil +} + +func (o *SensitiveWord) IsGroupInWhitelist(ctx context.Context, groupID string) (bool, error) { + config, err := o.GetSensitiveWordConfig(ctx) + if err != nil { + return false, err + } + for _, id := range config.WhitelistGroups { + if id == groupID { + return true, nil + } + } + return false, nil +} + +// ==================== 批量操作 ==================== + +func (o *SensitiveWord) BatchCreateSensitiveWords(ctx context.Context, words []*chat.SensitiveWord) error { + now := time.Now() + for _, word := range words { + word.CreateTime = now + word.UpdateTime = now + } + return mongoutil.InsertMany(ctx, o.coll, words) +} + +func (o *SensitiveWord) BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error { + for id, data := range updates { + data["update_time"] = time.Now() + err := mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": id}, bson.M{"$set": data}, false) + if err != nil { + return err + } + } + return nil +} + +func (o *SensitiveWord) BatchDeleteSensitiveWords(ctx context.Context, ids []string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"_id": bson.M{"$in": ids}}) +} + +// ==================== 统计信息 ==================== + +func (o *SensitiveWord) GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) { + stats := make(map[string]int64) + + // 总数 + total, err := mongoutil.Count(ctx, o.coll, bson.M{}) + if err != nil { + return nil, err + } + stats["total"] = total + + // 启用数量 + enabled, err := mongoutil.Count(ctx, o.coll, bson.M{"status": chat.SensitiveStatusEnabled}) + if err != nil { + return nil, err + } + stats["enabled"] = enabled + + // 禁用数量 + disabled, err := mongoutil.Count(ctx, o.coll, bson.M{"status": chat.SensitiveStatusDisabled}) + if err != nil { + return nil, err + } + stats["disabled"] = disabled + + // 替换模式数量 + replace, err := mongoutil.Count(ctx, o.coll, bson.M{"action": chat.SensitiveActionReplace}) + if err != nil { + return nil, err + } + stats["replace"] = replace + + // 拦截模式数量 + block, err := mongoutil.Count(ctx, o.coll, bson.M{"action": chat.SensitiveActionBlock}) + if err != nil { + return nil, err + } + stats["block"] = block + + return stats, nil +} + +func (o *SensitiveWord) GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) { + stats := make(map[string]int64) + coll := o.coll.Database().Collection("sensitive_word_logs") + + filter := bson.M{ + "create_time": bson.M{ + "$gte": startTime, + "$lte": endTime, + }, + } + + // 总数 + total, err := mongoutil.Count(ctx, coll, filter) + if err != nil { + return nil, err + } + stats["total"] = total + + // 替换数量 + replaceFilter := bson.M{} + for k, v := range filter { + replaceFilter[k] = v + } + replaceFilter["action"] = chat.SensitiveActionReplace + replace, err := mongoutil.Count(ctx, coll, replaceFilter) + if err != nil { + return nil, err + } + stats["replace"] = replace + + // 拦截数量 + blockFilter := bson.M{} + for k, v := range filter { + blockFilter[k] = v + } + blockFilter["action"] = chat.SensitiveActionBlock + block, err := mongoutil.Count(ctx, coll, blockFilter) + if err != nil { + return nil, err + } + stats["block"] = block + + return stats, nil +} diff --git a/pkg/common/db/model/chat/system_config.go b/pkg/common/db/model/chat/system_config.go new file mode 100644 index 0000000..f760020 --- /dev/null +++ b/pkg/common/db/model/chat/system_config.go @@ -0,0 +1,121 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewSystemConfig(db *mongo.Database) (chat.SystemConfigInterface, error) { + coll := db.Collection("system_configs") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "key", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "enabled", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &SystemConfig{coll: coll}, nil +} + +type SystemConfig struct { + coll *mongo.Collection +} + +func (o *SystemConfig) Create(ctx context.Context, configs ...*chat.SystemConfig) error { + for _, config := range configs { + if config.CreateTime.IsZero() { + config.CreateTime = time.Now() + } + if config.UpdateTime.IsZero() { + config.UpdateTime = time.Now() + } + } + return mongoutil.InsertMany(ctx, o.coll, configs) +} + +func (o *SystemConfig) Take(ctx context.Context, key string) (*chat.SystemConfig, error) { + return mongoutil.FindOne[*chat.SystemConfig](ctx, o.coll, bson.M{"key": key}) +} + +func (o *SystemConfig) FindByKeys(ctx context.Context, keys []string) ([]*chat.SystemConfig, error) { + if len(keys) == 0 { + return []*chat.SystemConfig{}, nil + } + return mongoutil.Find[*chat.SystemConfig](ctx, o.coll, bson.M{"key": bson.M{"$in": keys}}, options.Find().SetSort(bson.D{{Key: "key", Value: 1}})) +} + +func (o *SystemConfig) FindAll(ctx context.Context, pagination pagination.Pagination) (int64, []*chat.SystemConfig, error) { + filter := bson.M{} + return mongoutil.FindPage[*chat.SystemConfig](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "key", Value: 1}})) +} + +func (o *SystemConfig) Update(ctx context.Context, key string, data map[string]any) error { + if len(data) == 0 { + return nil + } + data["update_time"] = time.Now() + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"key": key}, bson.M{"$set": data}, false) +} + +func (o *SystemConfig) UpdateValue(ctx context.Context, key string, value string) error { + return o.Update(ctx, key, map[string]any{"value": value}) +} + +func (o *SystemConfig) UpdateEnabled(ctx context.Context, key string, enabled bool) error { + return o.Update(ctx, key, map[string]any{"enabled": enabled}) +} + +func (o *SystemConfig) Delete(ctx context.Context, keys []string) error { + if len(keys) == 0 { + return nil + } + _, err := o.coll.DeleteMany(ctx, bson.M{"key": bson.M{"$in": keys}}) + return errs.Wrap(err) +} + +func (o *SystemConfig) GetEnabledConfigs(ctx context.Context) ([]*chat.SystemConfig, error) { + filter := bson.M{ + "enabled": true, + } + return mongoutil.Find[*chat.SystemConfig](ctx, o.coll, filter, options.Find().SetSort(bson.D{{Key: "key", Value: 1}})) +} + +func (o *SystemConfig) GetAppConfigs(ctx context.Context) ([]*chat.SystemConfig, error) { + filter := bson.M{ + "show_in_app": true, + "enabled": true, // 同时要求 enabled=true + } + return mongoutil.Find[*chat.SystemConfig](ctx, o.coll, filter, options.Find().SetSort(bson.D{{Key: "key", Value: 1}})) +} diff --git a/pkg/common/db/model/chat/user_login_record.go b/pkg/common/db/model/chat/user_login_record.go new file mode 100644 index 0000000..4df361c --- /dev/null +++ b/pkg/common/db/model/chat/user_login_record.go @@ -0,0 +1,198 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "errors" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewUserLoginRecord(db *mongo.Database) (chat.UserLoginRecordInterface, error) { + coll := db.Collection("user_login_record") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + // 用于 CountTotal 查询:根据 create_time 范围查询 + { + Keys: bson.D{ + {Key: "create_time", Value: 1}, + }, + }, + // 用于 CountTodayActiveUsers 和 CountRangeEverydayTotal:根据 login_time 范围查询 + { + Keys: bson.D{ + {Key: "login_time", Value: 1}, + }, + }, + // 用于 GetLatestLoginIP:根据 user_id 查询,按 login_time 降序排序 + // 同时优化聚合查询中的 user_id 分组操作 + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "login_time", Value: -1}, + }, + }, + }) + if err != nil { + return nil, err + } + return &UserLoginRecord{ + coll: coll, + }, nil +} + +type UserLoginRecord struct { + coll *mongo.Collection +} + +func (o *UserLoginRecord) Create(ctx context.Context, records ...*chat.UserLoginRecord) error { + return mongoutil.InsertMany(ctx, o.coll, records) +} + +func (o *UserLoginRecord) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { + filter := bson.M{} + if before != nil { + filter["create_time"] = bson.M{"$lt": before} + } + return mongoutil.Count(ctx, o.coll, filter) +} + +func (o *UserLoginRecord) CountTodayActiveUsers(ctx context.Context) (int64, error) { + now := time.Now() + startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + endOfDay := startOfDay.Add(24 * time.Hour) + + filter := bson.M{ + "login_time": bson.M{ + "$gte": startOfDay, + "$lt": endOfDay, + }, + } + + // 使用聚合管道统计不同的用户数 + pipeline := []bson.M{ + {"$match": filter}, + {"$group": bson.M{ + "_id": "$user_id", + }}, + {"$count": "count"}, + } + + type Result struct { + Count int64 `bson:"count"` + } + results, err := mongoutil.Aggregate[Result](ctx, o.coll, pipeline) + if err != nil { + return 0, err + } + if len(results) == 0 { + return 0, nil + } + return results[0].Count, nil +} + +func (o *UserLoginRecord) CountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) { + pipeline := make([]bson.M, 0, 4) + if start != nil || end != nil { + filter := bson.M{} + if start != nil { + filter["$gte"] = start + } + if end != nil { + filter["$lt"] = end + } + pipeline = append(pipeline, bson.M{"$match": bson.M{"login_time": filter}}) + } + pipeline = append(pipeline, + bson.M{ + "$project": bson.M{ + "_id": 0, + "user_id": 1, + "login_time": bson.M{ + "$dateToString": bson.M{ + "format": "%Y-%m-%d", + "date": "$login_time", + }, + }, + }, + }, + + bson.M{ + "$group": bson.M{ + "_id": bson.M{ + "user_id": "$user_id", + "login_time": "$login_time", + }, + }, + }, + + bson.M{ + "$group": bson.M{ + "_id": "$_id.login_time", + "count": bson.M{ + "$sum": 1, + }, + }, + }, + ) + + type Temp struct { + ID string `bson:"_id"` + Count int64 `bson:"count"` + } + res, err := mongoutil.Aggregate[Temp](ctx, o.coll, pipeline) + if err != nil { + return nil, 0, err + } + var loginCount int64 + countMap := make(map[string]int64, len(res)) + for _, r := range res { + loginCount += r.Count + countMap[r.ID] = r.Count + } + return countMap, loginCount, nil +} + +func (o *UserLoginRecord) GetLatestLoginIP(ctx context.Context, userID string) (string, error) { + filter := bson.M{"user_id": userID} + opts := options.FindOne().SetSort(bson.D{{Key: "login_time", Value: -1}}) + + record, err := mongoutil.FindOne[chat.UserLoginRecord](ctx, o.coll, filter, opts) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return "", nil // 用户没有登录记录,返回空字符串 + } + return "", err + } + return record.IP, nil +} + +func (o *UserLoginRecord) Search(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*chat.UserLoginRecord, error) { + filter := bson.M{} + if userID != "" { + filter["user_id"] = userID + } + if ip != "" { + filter["ip"] = ip + } + return mongoutil.FindPage[*chat.UserLoginRecord](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "login_time", Value: -1}})) +} diff --git a/pkg/common/db/model/chat/verify_code.go b/pkg/common/db/model/chat/verify_code.go new file mode 100644 index 0000000..6d78939 --- /dev/null +++ b/pkg/common/db/model/chat/verify_code.go @@ -0,0 +1,146 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "github.com/openimsdk/tools/errs" +) + +type mongoVerifyCode struct { + ID primitive.ObjectID `bson:"_id"` + Account string `bson:"account"` + Platform string `bson:"platform"` + Code string `bson:"code"` + Duration uint `bson:"duration"` + Count int `bson:"count"` + Used bool `bson:"used"` + CreateTime time.Time `bson:"create_time"` +} + +func NewVerifyCode(db *mongo.Database) (chat.VerifyCodeInterface, error) { + coll := db.Collection("verify_code") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "account", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &VerifyCode{ + coll: coll, + }, nil +} + +type VerifyCode struct { + coll *mongo.Collection +} + +func (o *VerifyCode) parseID(s string) (primitive.ObjectID, error) { + objID, err := primitive.ObjectIDFromHex(s) + if err != nil { + var zero primitive.ObjectID + return zero, errs.Wrap(err) + } + return objID, nil +} + +func (o *VerifyCode) Add(ctx context.Context, ms []*chat.VerifyCode) error { + tmp := make([]mongoVerifyCode, 0, len(ms)) + for i, m := range ms { + var objID primitive.ObjectID + if m.ID == "" { + objID = primitive.NewObjectID() + ms[i].ID = objID.Hex() + } else { + var err error + objID, err = o.parseID(m.ID) + if err != nil { + return err + } + } + tmp = append(tmp, mongoVerifyCode{ + ID: objID, + Account: m.Account, + Platform: m.Platform, + Code: m.Code, + Duration: m.Duration, + Count: m.Count, + Used: m.Used, + CreateTime: m.CreateTime, + }) + } + return mongoutil.InsertMany(ctx, o.coll, tmp) +} + +func (o *VerifyCode) RangeNum(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) { + filter := bson.M{ + "account": account, + "create_time": bson.M{ + "$gte": start, + "$lte": end, + }, + } + return mongoutil.Count(ctx, o.coll, filter) +} + +func (o *VerifyCode) TakeLast(ctx context.Context, account string) (*chat.VerifyCode, error) { + filter := bson.M{ + "account": account, + } + opt := options.FindOne().SetSort(bson.M{"_id": -1}) + last, err := mongoutil.FindOne[*mongoVerifyCode](ctx, o.coll, filter, opt) + if err != nil { + return nil, err + } + return &chat.VerifyCode{ + ID: last.ID.Hex(), + Account: last.Account, + Platform: last.Platform, + Code: last.Code, + Duration: last.Duration, + Count: last.Count, + Used: last.Used, + CreateTime: last.CreateTime, + }, nil +} + +func (o *VerifyCode) Incr(ctx context.Context, id string) error { + objID, err := o.parseID(id) + if err != nil { + return err + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": objID}, bson.M{"$inc": bson.M{"count": 1}}, false) +} + +func (o *VerifyCode) Delete(ctx context.Context, id string) error { + objID, err := o.parseID(id) + if err != nil { + return err + } + return mongoutil.DeleteOne(ctx, o.coll, bson.M{"_id": objID}) +} diff --git a/pkg/common/db/model/chat/wallet.go b/pkg/common/db/model/chat/wallet.go new file mode 100644 index 0000000..6ec5560 --- /dev/null +++ b/pkg/common/db/model/chat/wallet.go @@ -0,0 +1,217 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "fmt" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewWallet(db *mongo.Database) (chatdb.WalletInterface, error) { + coll := db.Collection("wallets") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{{Key: "user_id", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Wallet{coll: coll}, nil +} + +type Wallet struct { + coll *mongo.Collection +} + +func (o *Wallet) Create(ctx context.Context, wallets ...*chatdb.Wallet) error { + return mongoutil.InsertMany(ctx, o.coll, wallets) +} + +func (o *Wallet) Take(ctx context.Context, userID string) (*chatdb.Wallet, error) { + return mongoutil.FindOne[*chatdb.Wallet](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Wallet) Find(ctx context.Context, userIDs []string) ([]*chatdb.Wallet, error) { + return mongoutil.Find[*chatdb.Wallet](ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Wallet) Update(ctx context.Context, userID string, data map[string]any) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, true) +} + +func (o *Wallet) UpdateBalance(ctx context.Context, userID string, balance int64) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"balance": balance}}, true) +} + +// IncrementBalance 原子更新余额,使用 $inc 操作符防止并发问题 +// 返回更新前后的余额 +// 如果 amount 是负数(扣款),会检查余额是否足够,余额不足时返回错误 +func (o *Wallet) IncrementBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) { + // 如果 amount 是负数(扣款),需要确保余额不会变为负数 + filter := bson.M{"user_id": userID} + if amount < 0 { + // 扣款时,确保余额足够(balance >= -amount,即 balance + amount >= 0) + // 例如:余额 100,扣款 -150,则 balance >= 150 不满足,更新失败 + filter["balance"] = bson.M{"$gte": -amount} + } + + update := bson.M{ + "$inc": bson.M{"balance": amount}, + "$set": bson.M{"update_time": time.Now()}, + } + + opts := options.FindOneAndUpdate(). + SetReturnDocument(options.After). // 返回更新后的文档 + SetUpsert(true) // 如果不存在则创建 + + var wallet chatdb.Wallet + err = o.coll.FindOneAndUpdate(ctx, filter, update, opts).Decode(&wallet) + if err != nil { + if err == mongo.ErrNoDocuments { + // 如果是因为余额不足导致更新失败(filter 条件不满足) + if amount < 0 { + // 获取当前余额用于错误提示 + currentWallet, takeErr := o.Take(ctx, userID) + if takeErr == nil && currentWallet != nil { + return currentWallet.Balance, currentWallet.Balance, errs.NewCodeError(errs.ErrArgs.Code(), + fmt.Sprintf("余额不足:当前余额为 %d 分,需要 %d 分", currentWallet.Balance, -amount)) + } + // 如果钱包不存在,说明余额为0,无法扣款 + return 0, 0, errs.NewCodeError(errs.ErrArgs.Code(), fmt.Sprintf("余额不足:钱包不存在或余额为0,需要 %d 分", -amount)) + } + // 如果是增加余额但钱包不存在,应该由 upsert 创建,不应该到这里 + // 如果到这里说明有其他问题 + return 0, 0, errs.NewCodeError(errs.ErrArgs.Code(), "更新钱包余额失败") + } + return 0, 0, errs.Wrap(err) + } + + // 计算更新前的余额 + beforeBalance = wallet.Balance - amount + afterBalance = wallet.Balance + + // 双重检查:确保余额不为负数(虽然 filter 已经保证,但为了安全再加一次检查) + if afterBalance < 0 { + // 如果余额为负数,回滚操作 + rollbackUpdate := bson.M{ + "$inc": bson.M{"balance": -amount}, // 回滚 + "$set": bson.M{"update_time": time.Now()}, + } + _ = o.coll.FindOneAndUpdate(ctx, bson.M{"user_id": userID}, rollbackUpdate, options.FindOneAndUpdate().SetReturnDocument(options.After)) + return beforeBalance, beforeBalance, errs.NewCodeError(errs.ErrArgs.Code(), "余额更新后不能为负数") + } + + return beforeBalance, afterBalance, nil +} + +func (o *Wallet) UpdatePaymentPassword(ctx context.Context, userID string, paymentPassword string) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"payment_password": paymentPassword, "update_time": time.Now()}}, true) +} + +func (o *Wallet) UpdateWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"withdraw_account": withdrawAccount, "update_time": time.Now()}}, true) +} + +func (o *Wallet) UpdateWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"withdraw_account": withdrawAccount, "withdraw_account_type": accountType, "update_time": time.Now()}}, true) +} + +func (o *Wallet) UpdateRealNameAuth(ctx context.Context, userID string, realNameAuth chatdb.RealNameAuth) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": bson.M{"real_name_auth": realNameAuth, "update_time": time.Now()}}, true) +} + +func (o *Wallet) Delete(ctx context.Context, userIDs []string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Wallet) Page(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { + return mongoutil.FindPage[*chatdb.Wallet](ctx, o.coll, bson.M{}, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +// PageByRealNameAuthAuditStatus 按实名认证审核状态分页查询钱包 +// auditStatus: 0-所有审核状态,1-审核通过,2-审核拒绝 +// userID: 用户ID搜索(可选,为空时不过滤) +func (o *Wallet) PageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { + filter := bson.M{ + "real_name_auth.id_card": bson.M{"$ne": ""}, // 过滤身份证号不为空的(已完成实名认证) + "$expr": bson.M{ // 身份证长度至少 6,null/非字符串时按空字符串处理,避免 count 报错 + "$gte": []any{ + bson.M{"$strLenCP": bson.M{"$ifNull": []any{"$real_name_auth.id_card", ""}}}, + 6, + }, + }, + } + // 支持按审核状态筛选:0-待审核,1-审核通过,2-审核拒绝;auditStatus < 0 表示不过滤状态 + if auditStatus >= 0 { + filter["real_name_auth.audit_status"] = auditStatus + } + // 支持按用户ID搜索 + if userID != "" { + filter["user_id"] = userID + } + return mongoutil.FindPage[*chatdb.Wallet](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "update_time", Value: -1}})) +} + +// SearchByRealNameAuth 按实名认证信息搜索钱包(返回userIDs) +// realNameKeyword: 真实姓名搜索关键词(可选) +// idCardKeyword: 身份证号搜索关键词(可选) +func (o *Wallet) SearchByRealNameAuth(ctx context.Context, realNameKeyword string, idCardKeyword string) ([]string, error) { + filter := bson.M{ + "real_name_auth.id_card": bson.M{"$ne": ""}, // 过滤身份证号不为空的(已完成实名认证) + "$expr": bson.M{ // 身份证长度至少 6,null/非字符串时按空字符串处理,避免 count 报错 + "$gte": []any{ + bson.M{"$strLenCP": bson.M{"$ifNull": []any{"$real_name_auth.id_card", ""}}}, + 6, + }, + }, + } + + // 构建搜索条件 + orConditions := []bson.M{} + if realNameKeyword != "" { + orConditions = append(orConditions, bson.M{"real_name_auth.name": bson.M{"$regex": realNameKeyword, "$options": "i"}}) + } + if idCardKeyword != "" { + orConditions = append(orConditions, bson.M{"real_name_auth.id_card": bson.M{"$regex": idCardKeyword, "$options": "i"}}) + } + if len(orConditions) > 0 { + filter["$or"] = orConditions + } + + // 只查询 user_id 字段 + opts := options.Find().SetProjection(bson.M{"user_id": 1}) + wallets, err := mongoutil.Find[*chatdb.Wallet](ctx, o.coll, filter, opts) + if err != nil { + return nil, err + } + + userIDs := make([]string, 0, len(wallets)) + for _, wallet := range wallets { + userIDs = append(userIDs, wallet.UserID) + } + return userIDs, nil +} diff --git a/pkg/common/db/model/chat/wallet_balance_record.go b/pkg/common/db/model/chat/wallet_balance_record.go new file mode 100644 index 0000000..b004d9a --- /dev/null +++ b/pkg/common/db/model/chat/wallet_balance_record.go @@ -0,0 +1,123 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewWalletBalanceRecord(db *mongo.Database) (chatdb.WalletBalanceRecordInterface, error) { + coll := db.Collection("wallet_balance_records") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "type", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "order_id", Value: 1}, + }, + }, + { + Keys: bson.D{ + {Key: "transaction_id", Value: 1}, + }, + }, + { + Keys: bson.D{ + {Key: "red_packet_id", Value: 1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &WalletBalanceRecord{coll: coll}, nil +} + +type WalletBalanceRecord struct { + coll *mongo.Collection +} + +func (o *WalletBalanceRecord) Create(ctx context.Context, records ...*chatdb.WalletBalanceRecord) error { + return mongoutil.InsertMany(ctx, o.coll, records) +} + +func (o *WalletBalanceRecord) Take(ctx context.Context, recordID string) (*chatdb.WalletBalanceRecord, error) { + return mongoutil.FindOne[*chatdb.WalletBalanceRecord](ctx, o.coll, bson.M{"_id": recordID}) +} + +func (o *WalletBalanceRecord) FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { + filter := bson.M{"user_id": userID} + return mongoutil.FindPage[*chatdb.WalletBalanceRecord](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WalletBalanceRecord) FindByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { + filter := bson.M{ + "user_id": userID, + "type": recordType, + } + return mongoutil.FindPage[*chatdb.WalletBalanceRecord](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WalletBalanceRecord) FindByOrderID(ctx context.Context, orderID string) (*chatdb.WalletBalanceRecord, error) { + return mongoutil.FindOne[*chatdb.WalletBalanceRecord](ctx, o.coll, bson.M{"order_id": orderID}) +} + +func (o *WalletBalanceRecord) FindByTransactionID(ctx context.Context, transactionID string) (*chatdb.WalletBalanceRecord, error) { + return mongoutil.FindOne[*chatdb.WalletBalanceRecord](ctx, o.coll, bson.M{"transaction_id": transactionID}) +} + +func (o *WalletBalanceRecord) FindByRedPacketID(ctx context.Context, redPacketID string) ([]*chatdb.WalletBalanceRecord, error) { + return mongoutil.Find[*chatdb.WalletBalanceRecord](ctx, o.coll, bson.M{"red_packet_id": redPacketID}, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WalletBalanceRecord) GetUserBalanceHistory(ctx context.Context, userID string, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { + filter := bson.M{"user_id": userID} + if startTime != nil || endTime != nil { + timeFilter := bson.M{} + if startTime != nil { + timeFilter["$gte"] = *startTime + } + if endTime != nil { + timeFilter["$lte"] = *endTime + } + filter["create_time"] = timeFilter + } + return mongoutil.FindPage[*chatdb.WalletBalanceRecord](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WalletBalanceRecord) CountByUserID(ctx context.Context, userID string) (int64, error) { + return mongoutil.Count(ctx, o.coll, bson.M{"user_id": userID}) +} diff --git a/pkg/common/db/model/chat/withdraw.go b/pkg/common/db/model/chat/withdraw.go new file mode 100644 index 0000000..b132aba --- /dev/null +++ b/pkg/common/db/model/chat/withdraw.go @@ -0,0 +1,95 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewWithdraw(db *mongo.Database) (chatdb.WithdrawInterface, error) { + coll := db.Collection("withdraws") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "status", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "create_time", Value: -1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Withdraw{coll: coll}, nil +} + +type Withdraw struct { + coll *mongo.Collection +} + +func (o *Withdraw) Create(ctx context.Context, withdraws ...*chatdb.Withdraw) error { + return mongoutil.InsertMany(ctx, o.coll, withdraws) +} + +func (o *Withdraw) Take(ctx context.Context, withdrawID string) (*chatdb.Withdraw, error) { + return mongoutil.FindOne[*chatdb.Withdraw](ctx, o.coll, bson.M{"_id": withdrawID}) +} + +func (o *Withdraw) FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + filter := bson.M{"user_id": userID} + return mongoutil.FindPage[*chatdb.Withdraw](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Withdraw) FindByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + filter := bson.M{"status": status} + return mongoutil.FindPage[*chatdb.Withdraw](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *Withdraw) UpdateStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error { + update := bson.M{ + "$set": bson.M{ + "status": status, + "auditor_id": auditorID, + "audit_time": time.Now(), + "audit_remark": auditRemark, + "update_time": time.Now(), + }, + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": withdrawID}, update, false) +} + +func (o *Withdraw) Page(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { + return mongoutil.FindPage[*chatdb.Withdraw](ctx, o.coll, bson.M{}, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} diff --git a/pkg/common/db/model/chat/withdraw_application.go b/pkg/common/db/model/chat/withdraw_application.go new file mode 100644 index 0000000..3eac56c --- /dev/null +++ b/pkg/common/db/model/chat/withdraw_application.go @@ -0,0 +1,103 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" +) + +func NewWithdrawApplication(db *mongo.Database) (chatdb.WithdrawApplicationInterface, error) { + coll := db.Collection("withdraw_applications") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "status", Value: 1}, + {Key: "create_time", Value: -1}, + }, + }, + { + Keys: bson.D{ + {Key: "create_time", Value: -1}, + }, + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &WithdrawApplication{coll: coll}, nil +} + +type WithdrawApplication struct { + coll *mongo.Collection +} + +func (o *WithdrawApplication) Create(ctx context.Context, applications ...*chatdb.WithdrawApplication) error { + return mongoutil.InsertMany(ctx, o.coll, applications) +} + +func (o *WithdrawApplication) Take(ctx context.Context, applicationID string) (*chatdb.WithdrawApplication, error) { + return mongoutil.FindOne[*chatdb.WithdrawApplication](ctx, o.coll, bson.M{"_id": applicationID}) +} + +func (o *WithdrawApplication) FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + filter := bson.M{"user_id": userID} + return mongoutil.FindPage[*chatdb.WithdrawApplication](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WithdrawApplication) FindByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + filter := bson.M{"status": status} + return mongoutil.FindPage[*chatdb.WithdrawApplication](ctx, o.coll, filter, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WithdrawApplication) UpdateStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error { + update := bson.M{ + "$set": bson.M{ + "status": status, + "auditor_id": auditorID, + "audit_time": time.Now(), + "audit_remark": auditRemark, + "update_time": time.Now(), + }, + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": applicationID}, update, false) +} + +func (o *WithdrawApplication) Page(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { + return mongoutil.FindPage[*chatdb.WithdrawApplication](ctx, o.coll, bson.M{}, pagination, options.Find().SetSort(bson.D{{Key: "create_time", Value: -1}})) +} + +func (o *WithdrawApplication) Update(ctx context.Context, applicationID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + data["update_time"] = time.Now() + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": applicationID}, bson.M{"$set": data}, false) +} diff --git a/pkg/common/db/table/admin/admin.go b/pkg/common/db/table/admin/admin.go new file mode 100644 index 0000000..59f6562 --- /dev/null +++ b/pkg/common/db/table/admin/admin.go @@ -0,0 +1,51 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// Admin user +type Admin struct { + Account string `bson:"account"` + Password string `bson:"password"` + OperationPassword string `bson:"operation_password"` + FaceURL string `bson:"face_url"` + Nickname string `bson:"nickname"` + UserID string `bson:"user_id"` + Level int32 `bson:"level"` + GoogleAuthKey string `bson:"google_auth_key"` + CreateTime time.Time `bson:"create_time"` +} + +func (Admin) TableName() string { + return "admins" +} + +type AdminInterface interface { + Create(ctx context.Context, admins []*Admin) error + Take(ctx context.Context, account string) (*Admin, error) + TakeUserID(ctx context.Context, userID string) (*Admin, error) + Update(ctx context.Context, account string, update map[string]any) error + ChangePassword(ctx context.Context, userID string, newPassword string) error + ChangeOperationPassword(ctx context.Context, userID string, newPassword string) error + ClearGoogleAuthKey(ctx context.Context, userID string) error + Delete(ctx context.Context, userIDs []string) error + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*Admin, error) +} diff --git a/pkg/common/db/table/admin/applet.go b/pkg/common/db/table/admin/applet.go new file mode 100644 index 0000000..f93a6ad --- /dev/null +++ b/pkg/common/db/table/admin/applet.go @@ -0,0 +1,49 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type Applet struct { + ID string `bson:"id"` + Name string `bson:"name"` + AppID string `bson:"app_id"` + Icon string `bson:"icon"` + URL string `bson:"url"` + MD5 string `bson:"md5"` + Size int64 `bson:"size"` + Version string `bson:"version"` + Priority uint32 `bson:"priority"` + Status uint8 `bson:"status"` + CreateTime time.Time `bson:"create_time"` +} + +func (Applet) TableName() string { + return "applets" +} + +type AppletInterface interface { + Create(ctx context.Context, applets []*Applet) error + Del(ctx context.Context, ids []string) error + Update(ctx context.Context, id string, data map[string]any) error + Take(ctx context.Context, id string) (*Applet, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*Applet, error) + FindOnShelf(ctx context.Context) ([]*Applet, error) + FindID(ctx context.Context, ids []string) ([]*Applet, error) +} diff --git a/pkg/common/db/table/admin/application.go b/pkg/common/db/table/admin/application.go new file mode 100644 index 0000000..44333fa --- /dev/null +++ b/pkg/common/db/table/admin/application.go @@ -0,0 +1,29 @@ +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +type Application struct { + ID primitive.ObjectID `bson:"_id"` + Platform string `bson:"platform"` + Hot bool `bson:"hot"` + Version string `bson:"version"` + Url string `bson:"url"` + Text string `bson:"text"` + Force bool `bson:"force"` + Latest bool `bson:"latest"` + CreateTime time.Time `bson:"create_time"` +} + +type ApplicationInterface interface { + LatestVersion(ctx context.Context, platform string) (*Application, error) + AddVersion(ctx context.Context, val *Application) error + UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error + DeleteVersion(ctx context.Context, id []primitive.ObjectID) error + PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*Application, error) + FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error) +} diff --git a/pkg/common/db/table/admin/client_config.go b/pkg/common/db/table/admin/client_config.go new file mode 100644 index 0000000..4b94100 --- /dev/null +++ b/pkg/common/db/table/admin/client_config.go @@ -0,0 +1,33 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import "context" + +// ClientConfig config +type ClientConfig struct { + Key string `bson:"key"` + Value string `bson:"value"` +} + +func (ClientConfig) TableName() string { + return "client_config" +} + +type ClientConfigInterface interface { + Set(ctx context.Context, config map[string]string) error + Get(ctx context.Context) (map[string]string, error) + Del(ctx context.Context, keys []string) error +} diff --git a/pkg/common/db/table/admin/forbidden_account.go b/pkg/common/db/table/admin/forbidden_account.go new file mode 100644 index 0000000..fb32476 --- /dev/null +++ b/pkg/common/db/table/admin/forbidden_account.go @@ -0,0 +1,42 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +// ForbiddenAccount table +type ForbiddenAccount struct { + UserID string `bson:"user_id"` + Reason string `bson:"reason"` + OperatorUserID string `bson:"operator_user_id"` + CreateTime time.Time `bson:"create_time"` +} + +func (ForbiddenAccount) TableName() string { + return "forbidden_accounts" +} + +type ForbiddenAccountInterface interface { + Create(ctx context.Context, ms []*ForbiddenAccount) error + Take(ctx context.Context, userID string) (*ForbiddenAccount, error) + Delete(ctx context.Context, userIDs []string) error + Find(ctx context.Context, userIDs []string) ([]*ForbiddenAccount, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*ForbiddenAccount, error) + FindAllIDs(ctx context.Context) ([]string, error) +} diff --git a/pkg/common/db/table/admin/invitation_register.go b/pkg/common/db/table/admin/invitation_register.go new file mode 100644 index 0000000..4970b4a --- /dev/null +++ b/pkg/common/db/table/admin/invitation_register.go @@ -0,0 +1,40 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type InvitationRegister struct { + InvitationCode string `bson:"invitation_code"` + UsedByUserID string `bson:"used_by_user_id"` + CreateTime time.Time `bson:"create_time"` +} + +func (InvitationRegister) TableName() string { + return "invitation_registers" +} + +type InvitationRegisterInterface interface { + Find(ctx context.Context, codes []string) ([]*InvitationRegister, error) + Del(ctx context.Context, codes []string) error + Create(ctx context.Context, v []*InvitationRegister) error + Take(ctx context.Context, code string) (*InvitationRegister, error) + Update(ctx context.Context, code string, data map[string]any) error + Search(ctx context.Context, keyword string, state int32, userIDs []string, codes []string, pagination pagination.Pagination) (int64, []*InvitationRegister, error) +} diff --git a/pkg/common/db/table/admin/ip_forbidden.go b/pkg/common/db/table/admin/ip_forbidden.go new file mode 100644 index 0000000..15e299d --- /dev/null +++ b/pkg/common/db/table/admin/ip_forbidden.go @@ -0,0 +1,40 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type IPForbidden struct { + IP string `bson:"ip"` + LimitRegister bool `bson:"limit_register"` + LimitLogin bool `bson:"limit_login"` + CreateTime time.Time `bson:"create_time"` +} + +func (IPForbidden) IPForbidden() string { + return "ip_forbiddens" +} + +type IPForbiddenInterface interface { + Take(ctx context.Context, ip string) (*IPForbidden, error) + Find(ctx context.Context, ips []string) ([]*IPForbidden, error) + Search(ctx context.Context, keyword string, state int32, pagination pagination.Pagination) (int64, []*IPForbidden, error) + Create(ctx context.Context, ms []*IPForbidden) error + Delete(ctx context.Context, ips []string) error +} diff --git a/pkg/common/db/table/admin/limit_user_login_ip.go b/pkg/common/db/table/admin/limit_user_login_ip.go new file mode 100644 index 0000000..b3413f2 --- /dev/null +++ b/pkg/common/db/table/admin/limit_user_login_ip.go @@ -0,0 +1,39 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "time" +) + +type LimitUserLoginIP struct { + UserID string `bson:"user_id"` + IP string `bson:"ip"` + CreateTime time.Time `bson:"create_time"` +} + +func (LimitUserLoginIP) TableName() string { + return "limit_user_login_ips" +} + +type LimitUserLoginIPInterface interface { + Create(ctx context.Context, ms []*LimitUserLoginIP) error + Delete(ctx context.Context, ms []*LimitUserLoginIP) error + Count(ctx context.Context, userID string) (uint32, error) + Take(ctx context.Context, userID string, ip string) (*LimitUserLoginIP, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*LimitUserLoginIP, error) +} diff --git a/pkg/common/db/table/admin/register_add_friend.go b/pkg/common/db/table/admin/register_add_friend.go new file mode 100644 index 0000000..2f472e9 --- /dev/null +++ b/pkg/common/db/table/admin/register_add_friend.go @@ -0,0 +1,39 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type RegisterAddFriend struct { + UserID string `bson:"user_id"` + CreateTime time.Time `bson:"create_time"` +} + +func (RegisterAddFriend) TableName() string { + return "register_add_friends" +} + +type RegisterAddFriendInterface interface { + Add(ctx context.Context, registerAddFriends []*RegisterAddFriend) error + Del(ctx context.Context, userIDs []string) error + FindUserID(ctx context.Context, userIDs []string) ([]string, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*RegisterAddFriend, error) + CountTotal(ctx context.Context) (int64, error) // 统计好友总数 +} diff --git a/pkg/common/db/table/admin/register_add_group.go b/pkg/common/db/table/admin/register_add_group.go new file mode 100644 index 0000000..e9d08a3 --- /dev/null +++ b/pkg/common/db/table/admin/register_add_group.go @@ -0,0 +1,40 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type RegisterAddGroup struct { + GroupID string `bson:"group_id"` + CreateTime time.Time `bson:"create_time"` +} + +func (RegisterAddGroup) TableName() string { + return "register_add_groups" +} + +type RegisterAddGroupInterface interface { + Add(ctx context.Context, registerAddGroups []*RegisterAddGroup) error + Del(ctx context.Context, groupIDs []string) error + FindGroupID(ctx context.Context, groupIDs []string) ([]string, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*RegisterAddGroup, error) + CountTotal(ctx context.Context) (int64, error) // 统计群组总数 + CountToday(ctx context.Context) (int64, error) // 统计今天新建的群组数 +} diff --git a/pkg/common/db/table/bot/agent.go b/pkg/common/db/table/bot/agent.go new file mode 100644 index 0000000..a78dd30 --- /dev/null +++ b/pkg/common/db/table/bot/agent.go @@ -0,0 +1,33 @@ +package bot + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type Agent struct { + UserID string `bson:"user_id"` + NickName string `bson:"nick_name"` + FaceURL string `bson:"face_url"` + Key string `bson:"key"` + Url string `bson:"url"` + Identity string `bson:"identity"` + Model string `bson:"model"` + Prompts string `bson:"prompts"` + CreateTime time.Time `bson:"create_time"` +} + +func (Agent) TableName() string { + return "agent" +} + +type AgentInterface interface { + Create(ctx context.Context, elems ...*Agent) error + Take(ctx context.Context, userID string) (*Agent, error) + Find(ctx context.Context, userIDs []string) ([]*Agent, error) + Update(ctx context.Context, userID string, data map[string]any) error + Delete(ctx context.Context, userIDs []string) error + Page(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*Agent, error) +} diff --git a/pkg/common/db/table/bot/conversation_resp_id.go b/pkg/common/db/table/bot/conversation_resp_id.go new file mode 100644 index 0000000..ada503e --- /dev/null +++ b/pkg/common/db/table/bot/conversation_resp_id.go @@ -0,0 +1,22 @@ +package bot + +import ( + "context" +) + +type ConversationRespID struct { + ConversationID string `bson:"conversation_id"` + AgentID string `bson:"agent_id"` + PreviousResponseID string `bson:"previous_response_id"` +} + +func (ConversationRespID) TableName() string { + return "conversation_resp_id" +} + +type ConversationRespIDInterface interface { + Create(ctx context.Context, elems ...*ConversationRespID) error + Take(ctx context.Context, convID, agentID string) (*ConversationRespID, error) + Update(ctx context.Context, convID, agentID string, data map[string]any) error + Delete(ctx context.Context, convID, agentID string) error +} diff --git a/pkg/common/db/table/chat/account.go b/pkg/common/db/table/chat/account.go new file mode 100644 index 0000000..1629750 --- /dev/null +++ b/pkg/common/db/table/chat/account.go @@ -0,0 +1,40 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" +) + +type Account struct { + UserID string `bson:"user_id"` + Password string `bson:"password"` + CreateTime time.Time `bson:"create_time"` + ChangeTime time.Time `bson:"change_time"` + OperatorUserID string `bson:"operator_user_id"` +} + +func (Account) TableName() string { + return "accounts" +} + +type AccountInterface interface { + Create(ctx context.Context, accounts ...*Account) error + Take(ctx context.Context, userId string) (*Account, error) + Update(ctx context.Context, userID string, data map[string]any) error + UpdatePassword(ctx context.Context, userId string, password string) error + Delete(ctx context.Context, userIDs []string) error +} diff --git a/pkg/common/db/table/chat/attribute.go b/pkg/common/db/table/chat/attribute.go new file mode 100644 index 0000000..3734ac8 --- /dev/null +++ b/pkg/common/db/table/chat/attribute.go @@ -0,0 +1,51 @@ +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type Attribute struct { + UserID string `bson:"user_id"` + Account string `bson:"account"` + PhoneNumber string `bson:"phone_number"` + AreaCode string `bson:"area_code"` + Email string `bson:"email"` + Nickname string `bson:"nickname"` + FaceURL string `bson:"face_url"` + Gender int32 `bson:"gender"` + CreateTime time.Time `bson:"create_time"` + ChangeTime time.Time `bson:"change_time"` + BirthTime time.Time `bson:"birth_time"` + Level int32 `bson:"level"` + UserType int32 `bson:"user_type"` // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + UserFlag string `bson:"user_flag"` // 用户标签/标识,类似UserType的字符串版本 + AllowVibration int32 `bson:"allow_vibration"` + AllowBeep int32 `bson:"allow_beep"` + AllowAddFriend int32 `bson:"allow_add_friend"` + GlobalRecvMsgOpt int32 `bson:"global_recv_msg_opt"` + RegisterType int32 `bson:"register_type"` +} + +func (Attribute) TableName() string { + return "attributes" +} + +type AttributeInterface interface { + // NewTx(tx any) AttributeInterface + Create(ctx context.Context, attribute ...*Attribute) error + Update(ctx context.Context, userID string, data map[string]any) error + Find(ctx context.Context, userIds []string) ([]*Attribute, error) + FindAccount(ctx context.Context, accounts []string) ([]*Attribute, error) + Search(ctx context.Context, keyword string, genders []int32, pagination pagination.Pagination) (int64, []*Attribute, error) + TakePhone(ctx context.Context, areaCode string, phoneNumber string) (*Attribute, error) + TakeEmail(ctx context.Context, email string) (*Attribute, error) + TakeAccount(ctx context.Context, account string) (*Attribute, error) + Take(ctx context.Context, userID string) (*Attribute, error) + SearchNormalUser(ctx context.Context, keyword string, forbiddenID []string, gender int32, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*Attribute, error) + SearchNormalUserWithUserIDs(ctx context.Context, keyword string, forbiddenID []string, gender int32, startTime, endTime *time.Time, userIDs []string, pagination pagination.Pagination) (int64, []*Attribute, error) // 按条件搜索用户(支持额外的userIDs过滤) + SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*Attribute, error) + Delete(ctx context.Context, userIDs []string) error +} diff --git a/pkg/common/db/table/chat/credential.go b/pkg/common/db/table/chat/credential.go new file mode 100644 index 0000000..e4d23d6 --- /dev/null +++ b/pkg/common/db/table/chat/credential.go @@ -0,0 +1,32 @@ +package chat + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" +) + +type Credential struct { + UserID string `bson:"user_id"` + Account string `bson:"account"` + Type int `bson:"type"` // 1:phone;2:email + AllowChange bool `bson:"allow_change"` +} + +func (Credential) TableName() string { + return "credentials" +} + +type CredentialInterface interface { + Create(ctx context.Context, credential ...*Credential) error + CreateOrUpdateAccount(ctx context.Context, credential *Credential) error + Update(ctx context.Context, userID string, data map[string]any) error + Find(ctx context.Context, userID string) ([]*Credential, error) + FindAccount(ctx context.Context, accounts []string) ([]*Credential, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*Credential, error) + TakeAccount(ctx context.Context, account string) (*Credential, error) + Take(ctx context.Context, userID string) (*Credential, error) + SearchNormalUser(ctx context.Context, keyword string, forbiddenID []string, pagination pagination.Pagination) (int64, []*Credential, error) + SearchUser(ctx context.Context, keyword string, userIDs []string, pagination pagination.Pagination) (int64, []*Credential, error) + Delete(ctx context.Context, userIDs []string) error + DeleteByUserIDType(ctx context.Context, credentials ...*Credential) error +} diff --git a/pkg/common/db/table/chat/favorite.go b/pkg/common/db/table/chat/favorite.go new file mode 100644 index 0000000..75a7611 --- /dev/null +++ b/pkg/common/db/table/chat/favorite.go @@ -0,0 +1,69 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// FavoriteType 收藏类型 +const ( + FavoriteTypeText = 1 // 文本 + FavoriteTypeImage = 2 // 图片 + FavoriteTypeLink = 3 // 链接 + FavoriteTypeFile = 4 // 文件 + FavoriteTypeVoice = 5 // 语音 + FavoriteTypeVideo = 6 // 视频 + FavoriteTypeLocation = 7 // 位置 +) + +type Favorite struct { + ID string `bson:"_id"` // 收藏ID(MongoDB ObjectID) + UserID string `bson:"user_id"` // 用户ID(收藏者) + Type int32 `bson:"type"` // 收藏类型:1-文本,2-图片,3-链接,4-文件,5-语音,6-视频,7-位置 + Title string `bson:"title"` // 标题(可选) + Content string `bson:"content"` // 内容(根据类型不同,可能是文本、图片URL、链接URL、文件路径等) + Description string `bson:"description"` // 摘要/描述(可选) + Thumbnail string `bson:"thumbnail"` // 缩略图URL(用于图片、视频、链接等) + LinkURL string `bson:"link_url"` // 链接URL(用于链接类型) + FileSize int64 `bson:"file_size"` // 文件大小(字节,用于文件、语音、视频等) + Duration int32 `bson:"duration"` // 时长(秒,用于语音、视频等) + Location string `bson:"location"` // 位置信息(JSON格式,用于位置类型) + Tags []string `bson:"tags"` // 标签列表 + Remark string `bson:"remark"` // 备注(可选) + Status int32 `bson:"status"` // 状态:0-已删除,1-正常 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +func (Favorite) TableName() string { + return "favorites" +} + +type FavoriteInterface interface { + Create(ctx context.Context, favorites ...*Favorite) error + Take(ctx context.Context, favoriteID string) (*Favorite, error) + FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*Favorite, error) + FindByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*Favorite, error) + SearchByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*Favorite, error) + Update(ctx context.Context, favoriteID string, data map[string]any) error + Delete(ctx context.Context, favoriteIDs []string) error + DeleteByUserID(ctx context.Context, userID string) error + CountByUserID(ctx context.Context, userID string) (int64, error) + FindByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*Favorite, error) +} diff --git a/pkg/common/db/table/chat/livekit.go b/pkg/common/db/table/chat/livekit.go new file mode 100644 index 0000000..19d84d8 --- /dev/null +++ b/pkg/common/db/table/chat/livekit.go @@ -0,0 +1,67 @@ +package chat + +import ( + "context" + "time" +) + +// LiveKit 表示一台LiveKit服务器配置 +type LiveKit struct { + ID string `bson:"_id" json:"id"` // 服务器唯一标识 + Name string `bson:"name" json:"name"` // 服务器名称 + URL string `bson:"url" json:"url"` // LiveKit服务器地址 + Key string `bson:"key" json:"key"` // API Key + Secret string `bson:"secret" json:"secret"` // API Secret + Region string `bson:"region" json:"region"` // 服务器区域 + Status int `bson:"status" json:"status"` // 状态:0-禁用,1-启用 + Priority int `bson:"priority" json:"priority"` // 优先级,数字越小优先级越高 + MaxRooms int `bson:"max_rooms" json:"max_rooms"` // 最大房间数 + MaxUsers int `bson:"max_users" json:"max_users"` // 最大用户数 + Description string `bson:"description" json:"description"` // 描述信息 + CreateTime time.Time `bson:"create_time" json:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time" json:"update_time"` // 更新时间 +} + +// TableName 返回表名 +func (LiveKit) TableName() string { + return "livekits" +} + +// LiveKitInterface 定义LiveKit数据库操作接口 +type LiveKitInterface interface { + // Create 创建LiveKit服务器配置 + Create(ctx context.Context, livekits ...*LiveKit) error + // Delete 删除LiveKit服务器配置 + Delete(ctx context.Context, ids []string) error + // Update 更新LiveKit服务器配置 + Update(ctx context.Context, livekit *LiveKit) error + // FindByID 根据ID查找LiveKit配置 + FindByID(ctx context.Context, id string) (*LiveKit, error) + // FindByStatus 根据状态查找LiveKit配置列表 + FindByStatus(ctx context.Context, status int) ([]*LiveKit, error) + // FindAll 查找所有LiveKit配置 + FindAll(ctx context.Context) ([]*LiveKit, error) + // FindAvailable 查找可用的LiveKit服务器(按优先级排序) + FindAvailable(ctx context.Context) ([]*LiveKit, error) + // FindByRegion 根据区域查找LiveKit配置 + FindByRegion(ctx context.Context, region string) ([]*LiveKit, error) + // UpdateStatus 更新服务器状态 + UpdateStatus(ctx context.Context, id string, status int) error + // UpdatePriority 更新服务器优先级 + UpdatePriority(ctx context.Context, id string, priority int) error + // GetNextAvailable 获取下一个可用的LiveKit服务器(负载均衡) + GetNextAvailable(ctx context.Context) (*LiveKit, error) +} + +// 状态常量 +const ( + LiveKitStatusDisabled = 0 // 禁用 + LiveKitStatusEnabled = 1 // 启用 +) + +// 默认值 +const ( + DefaultMaxRooms = 1000 // 默认最大房间数 + DefaultMaxUsers = 100 // 默认最大用户数 + DefaultPriority = 100 // 默认优先级 +) diff --git a/pkg/common/db/table/chat/register.go b/pkg/common/db/table/chat/register.go new file mode 100644 index 0000000..be0d928 --- /dev/null +++ b/pkg/common/db/table/chat/register.go @@ -0,0 +1,42 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" +) + +type Register struct { + UserID string `bson:"user_id"` + DeviceID string `bson:"device_id"` + IP string `bson:"ip"` + Platform string `bson:"platform"` + AccountType string `bson:"account_type"` + Mode string `bson:"mode"` + CreateTime time.Time `bson:"create_time"` +} + +func (Register) TableName() string { + return "registers" +} + +type RegisterInterface interface { + // NewTx(tx any) RegisterInterface + Create(ctx context.Context, registers ...*Register) error + CountTotal(ctx context.Context, before *time.Time) (int64, error) + CountToday(ctx context.Context) (int64, error) // 统计今天注册的用户数 + Delete(ctx context.Context, userIDs []string) error +} diff --git a/pkg/common/db/table/chat/scheduled_task.go b/pkg/common/db/table/chat/scheduled_task.go new file mode 100644 index 0000000..c1e8c04 --- /dev/null +++ b/pkg/common/db/table/chat/scheduled_task.go @@ -0,0 +1,78 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// ScheduledTaskStatus 定时任务状态 +const ( + ScheduledTaskStatusDisabled = 0 // 已禁用 + ScheduledTaskStatusEnabled = 1 // 已启用 +) + +// MessageType 消息类型 +const ( + MessageTypeText = 1 // 文本消息 + MessageTypeImage = 2 // 图片消息 + MessageTypeVideo = 3 // 视频消息 +) + +// ScheduledTask 定时任务配置 +// CronExpression格式:分 时 日 月 周 +// 例如:"0 9 * * *" 表示每天9点执行 +// +// "*/5 * * * *" 表示每5分钟执行 +// "0 0 * * 1" 表示每周一0点执行 +type ScheduledTask struct { + ID string `bson:"_id"` // 任务ID + UserID string `bson:"user_id"` // 用户ID + Name string `bson:"name"` // 任务名称 + CronExpression string `bson:"cron_expression"` // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + Messages []Message `bson:"messages"` // 消息列表(支持多条消息一起发送) + RecvIDs []string `bson:"recv_ids"` // 接收者ID列表(单聊,可以多个) + GroupIDs []string `bson:"group_ids"` // 群组ID列表(群聊,可以多个) + Status int32 `bson:"status"` // 状态:0-已禁用,1-已启用 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +// Message 消息内容 +type Message struct { + Type int32 `bson:"type"` // 消息类型:1-文本,2-图片,3-视频 + Content string `bson:"content"` // 消息内容(文本内容、图片URL、视频URL等) + Thumbnail string `bson:"thumbnail"` // 缩略图URL(用于图片和视频) + Duration int32 `bson:"duration"` // 时长(秒,用于视频) + FileSize int64 `bson:"file_size"` // 文件大小(字节,用于图片和视频) + Width int32 `bson:"width"` // 宽度(像素,用于图片和视频) + Height int32 `bson:"height"` // 高度(像素,用于图片和视频) +} + +func (ScheduledTask) TableName() string { + return "scheduled_tasks" +} + +type ScheduledTaskInterface interface { + Create(ctx context.Context, tasks ...*ScheduledTask) error + Take(ctx context.Context, taskID string) (*ScheduledTask, error) + FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*ScheduledTask, error) + FindAll(ctx context.Context, pagination pagination.Pagination) (int64, []*ScheduledTask, error) + Update(ctx context.Context, taskID string, data map[string]any) error + Delete(ctx context.Context, taskIDs []string) error +} diff --git a/pkg/common/db/table/chat/sensitive_word.go b/pkg/common/db/table/chat/sensitive_word.go new file mode 100644 index 0000000..9cd986d --- /dev/null +++ b/pkg/common/db/table/chat/sensitive_word.go @@ -0,0 +1,144 @@ +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +// 敏感词相关结构体定义 +type SensitiveWord struct { + ID string `bson:"_id" json:"id"` // 主键ID + Word string `bson:"word" json:"word"` // 敏感词内容 + Level int32 `bson:"level" json:"level"` // 敏感词级别 1:低 2:中 3:高 + Type int32 `bson:"type" json:"type"` // 敏感词类型 1:政治 2:色情 3:暴力 4:广告 5:其他 + Action int32 `bson:"action" json:"action"` // 处理动作 1:替换为*** 2:拦截不发 + Status int32 `bson:"status" json:"status"` // 状态 1:启用 0:禁用 + Creator string `bson:"creator" json:"creator"` // 创建者 + Updater string `bson:"updater" json:"updater"` // 更新者 + CreateTime time.Time `bson:"create_time" json:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time" json:"update_time"` // 更新时间 + Remark string `bson:"remark" json:"remark"` // 备注 +} + +func (SensitiveWord) TableName() string { + return "sensitive_words" +} + +type SensitiveWordLog struct { + ID primitive.ObjectID `bson:"_id,omitempty"` + UserID string `bson:"user_id"` // 触发用户ID + GroupID string `bson:"group_id"` // 触发群组ID (如果是在群聊中) + Content string `bson:"content"` // 原始消息内容 + MatchedWords []string `bson:"matched_words"` // 匹配到的敏感词 + Action int32 `bson:"action"` // 采取的动作 + ProcessedText string `bson:"processed_text"` // 处理后的文本 (如果被替换) + CreateTime time.Time `bson:"create_time"` +} + +func (SensitiveWordLog) TableName() string { + return "sensitive_word_logs" +} + +type SensitiveWordGroup struct { + ID primitive.ObjectID `bson:"_id,omitempty"` + Name string `bson:"name"` // 分组名称 + Remark string `bson:"remark"` // 备注 + CreateTime time.Time `bson:"create_time"` + UpdateTime time.Time `bson:"update_time"` +} + +func (SensitiveWordGroup) TableName() string { + return "sensitive_word_groups" +} + +type SensitiveWordConfig struct { + ID string `bson:"_id" json:"id"` // 主键ID + EnableFilter bool `bson:"enable_filter" json:"enable_filter"` // 是否启用过滤 + FilterMode int32 `bson:"filter_mode" json:"filter_mode"` // 过滤模式 + ReplaceChar string `bson:"replace_char" json:"replace_char"` // 替换字符,默认*** + WhitelistUsers []string `bson:"whitelist_users" json:"whitelist_users"` // 白名单用户 + WhitelistGroups []string `bson:"whitelist_groups" json:"whitelist_groups"` // 白名单群组 + LogEnabled bool `bson:"log_enabled" json:"log_enabled"` // 是否记录日志 + AutoApprove bool `bson:"auto_approve" json:"auto_approve"` // 是否自动审核 + UpdateTime time.Time `bson:"update_time" json:"update_time"` // 更新时间 +} + +func (SensitiveWordConfig) TableName() string { + return "sensitive_word_configs" +} + +// 敏感词级别常量 +const ( + SensitiveLevelLow = 1 // 低级别 + SensitiveLevelMedium = 2 // 中级别 + SensitiveLevelHigh = 3 // 高级别 +) + +// 敏感词类型常量 +const ( + SensitiveTypePolitical = 1 // 政治 + SensitiveTypePorn = 2 // 色情 + SensitiveTypeViolence = 3 // 暴力 + SensitiveTypeAd = 4 // 广告 + SensitiveTypeOther = 5 // 其他 +) + +// 处理动作常量 +const ( + SensitiveActionReplace = 1 // 替换为*** + SensitiveActionBlock = 2 // 拦截不发 +) + +// 状态常量 +const ( + SensitiveStatusDisabled = 0 // 禁用 + SensitiveStatusEnabled = 1 // 启用 +) + +type SensitiveWordInterface interface { + // 敏感词管理 + CreateSensitiveWord(ctx context.Context, word *SensitiveWord) error + UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error + DeleteSensitiveWord(ctx context.Context, ids []string) error + GetSensitiveWord(ctx context.Context, id string) (*SensitiveWord, error) + SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*SensitiveWord, error) + GetAllSensitiveWords(ctx context.Context) ([]*SensitiveWord, error) + GetEnabledSensitiveWords(ctx context.Context) ([]*SensitiveWord, error) + + // 敏感词检测 + CheckSensitiveWords(ctx context.Context, content string) ([]*SensitiveWord, error) + FilterContent(ctx context.Context, content string) (string, []*SensitiveWord, error) + + // 敏感词日志 + CreateSensitiveWordLog(ctx context.Context, log *SensitiveWordLog) error + GetSensitiveWordLogs(ctx context.Context, userID string, groupID string, pagination pagination.Pagination) (int64, []*SensitiveWordLog, error) + DeleteSensitiveWordLogs(ctx context.Context, ids []string) error + + // 敏感词分组管理 + CreateSensitiveWordGroup(ctx context.Context, group *SensitiveWordGroup) error + UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error + DeleteSensitiveWordGroup(ctx context.Context, ids []string) error + GetSensitiveWordGroup(ctx context.Context, id string) (*SensitiveWordGroup, error) + GetAllSensitiveWordGroups(ctx context.Context) ([]*SensitiveWordGroup, error) + + // 敏感词配置管理 + GetSensitiveWordConfig(ctx context.Context) (*SensitiveWordConfig, error) + UpdateSensitiveWordConfig(ctx context.Context, config *SensitiveWordConfig) error + IsFilterEnabled(ctx context.Context) (bool, error) + GetFilterMode(ctx context.Context) (int32, error) + GetReplaceChar(ctx context.Context) (string, error) + IsUserInWhitelist(ctx context.Context, userID string) (bool, error) + IsGroupInWhitelist(ctx context.Context, groupID string) (bool, error) + + // 批量操作 + BatchCreateSensitiveWords(ctx context.Context, words []*SensitiveWord) error + BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error + BatchDeleteSensitiveWords(ctx context.Context, ids []string) error + + // 统计信息 + GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) + GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) +} diff --git a/pkg/common/db/table/chat/system_config.go b/pkg/common/db/table/chat/system_config.go new file mode 100644 index 0000000..0b4189a --- /dev/null +++ b/pkg/common/db/table/chat/system_config.go @@ -0,0 +1,69 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// ConfigValueType 配置值类型 +const ( + ConfigValueTypeString = 1 // 字符串类型 + ConfigValueTypeNumber = 2 // 数字类型 + ConfigValueTypeBool = 3 // 布尔类型 + ConfigValueTypeJSON = 4 // JSON类型 +) + +// ConfigKey 常用配置键 +const ( + // 钱包相关配置 + ConfigKeyWalletEnabled = "wallet.enabled" // 是否开启钱包功能 + + // 注册相关配置 + ConfigKeyPhoneRegisterVerifyCodeEnabled = "register.phone.verify_code.enabled" // 手机号注册验证码功能是否开启 +) + +// SystemConfig 系统配置模型 +type SystemConfig struct { + Key string `bson:"key"` // 配置键(唯一标识) + Title string `bson:"title"` // 配置标题 + Value string `bson:"value"` // 配置值(字符串形式存储,根据ValueType解析) + ValueType int32 `bson:"value_type"` // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + Description string `bson:"description"` // 配置描述 + Enabled bool `bson:"enabled"` // 是否启用(用于开关类配置) + ShowInApp bool `bson:"show_in_app"` // 是否在APP端展示 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +func (SystemConfig) TableName() string { + return "system_configs" +} + +type SystemConfigInterface interface { + Create(ctx context.Context, configs ...*SystemConfig) error + Take(ctx context.Context, key string) (*SystemConfig, error) + FindByKeys(ctx context.Context, keys []string) ([]*SystemConfig, error) + FindAll(ctx context.Context, pagination pagination.Pagination) (int64, []*SystemConfig, error) + Update(ctx context.Context, key string, data map[string]any) error + UpdateValue(ctx context.Context, key string, value string) error + UpdateEnabled(ctx context.Context, key string, enabled bool) error + Delete(ctx context.Context, keys []string) error + GetEnabledConfigs(ctx context.Context) ([]*SystemConfig, error) + GetAppConfigs(ctx context.Context) ([]*SystemConfig, error) // 获取所有 show_in_app=true 的配置 +} diff --git a/pkg/common/db/table/chat/user_login_record.go b/pkg/common/db/table/chat/user_login_record.go new file mode 100644 index 0000000..88544d7 --- /dev/null +++ b/pkg/common/db/table/chat/user_login_record.go @@ -0,0 +1,43 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type UserLoginRecord struct { + UserID string `bson:"user_id"` + LoginTime time.Time `bson:"login_time"` + IP string `bson:"ip"` + DeviceID string `bson:"device_id"` + Platform string `bson:"platform"` +} + +func (UserLoginRecord) TableName() string { + return "user_login_records" +} + +type UserLoginRecordInterface interface { + Create(ctx context.Context, records ...*UserLoginRecord) error + CountTotal(ctx context.Context, before *time.Time) (int64, error) + CountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) + CountTodayActiveUsers(ctx context.Context) (int64, error) // 统计今天活跃用户数(今天登录的不同用户数) + GetLatestLoginIP(ctx context.Context, userID string) (string, error) // 获取用户最新登录IP + Search(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*UserLoginRecord, error) // 查询登录记录(支持按用户ID或IP查询) +} diff --git a/pkg/common/db/table/chat/verify_code.go b/pkg/common/db/table/chat/verify_code.go new file mode 100644 index 0000000..5ae6394 --- /dev/null +++ b/pkg/common/db/table/chat/verify_code.go @@ -0,0 +1,43 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" +) + +type VerifyCode struct { + ID string `bson:"_id"` + Account string `bson:"account"` + Platform string `bson:"platform"` + Code string `bson:"code"` + Duration uint `bson:"duration"` + Count int `bson:"count"` + Used bool `bson:"used"` + CreateTime time.Time `bson:"create_time"` +} + +func (VerifyCode) TableName() string { + return "verify_codes" +} + +type VerifyCodeInterface interface { + Add(ctx context.Context, ms []*VerifyCode) error + RangeNum(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) + TakeLast(ctx context.Context, account string) (*VerifyCode, error) + Incr(ctx context.Context, id string) error + Delete(ctx context.Context, id string) error +} diff --git a/pkg/common/db/table/chat/wallet.go b/pkg/common/db/table/chat/wallet.go new file mode 100644 index 0000000..7a07a39 --- /dev/null +++ b/pkg/common/db/table/chat/wallet.go @@ -0,0 +1,116 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// BalanceRecordType 余额变动类型 +const ( + BalanceRecordTypeRecharge = 1 // 充值 + BalanceRecordTypeWithdraw = 2 // 提现/提款 + BalanceRecordTypeConsume = 3 // 消费 + BalanceRecordTypeRefund = 4 // 退款 + BalanceRecordTypeReward = 5 // 奖励 + BalanceRecordTypeAdminRecharge = 6 // 后台充值 + BalanceRecordTypeSendRedPacket = 7 // 发红包(减少余额) + BalanceRecordTypeGrabRedPacket = 8 // 抢红包(增加余额) + BalanceRecordTypeOther = 99 // 其他 +) + +// WithdrawAccountType 提现账号类型 +const ( + WithdrawAccountTypeAlipay = 1 // 支付宝 + WithdrawAccountTypeWeChat = 2 // 微信 + WithdrawAccountTypeBankCard = 3 // 银行卡 +) + +// RealNameAuth 实名认证信息 +type RealNameAuth struct { + IDCard string `bson:"id_card"` // 身份证号 + IDCardPhotoFront string `bson:"id_card_photo_front"` // 身份证正面照片URL + IDCardPhotoBack string `bson:"id_card_photo_back"` // 身份证反面照片URL + Name string `bson:"name"` // 真实姓名 + AuditStatus int32 `bson:"audit_status"` // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +// Wallet 钱包模型 +type Wallet struct { + UserID string `bson:"user_id"` // 用户ID + Balance int64 `bson:"balance"` // 用户余额(单位:分) + PaymentPassword string `bson:"payment_password"` // 支付密码(加密存储) + WithdrawAccount string `bson:"withdraw_account"` // 提现账号 + WithdrawAccountType int32 `bson:"withdraw_account_type"` // 提现账号类型:1-支付宝,2-微信,3-银行卡 + RealNameAuth RealNameAuth `bson:"real_name_auth"` // 实名认证信息 + WithdrawReceiveAccount string `bson:"withdraw_receive_account"` // 提现收款账号 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +func (Wallet) TableName() string { + return "wallets" +} + +type WalletInterface interface { + Create(ctx context.Context, wallets ...*Wallet) error + Take(ctx context.Context, userID string) (*Wallet, error) + Find(ctx context.Context, userIDs []string) ([]*Wallet, error) + Update(ctx context.Context, userID string, data map[string]any) error + UpdateBalance(ctx context.Context, userID string, balance int64) error + IncrementBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) // 原子更新余额,返回更新前后的余额 + UpdatePaymentPassword(ctx context.Context, userID string, paymentPassword string) error + UpdateWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error // 更新提款账号(兼容旧接口) + UpdateWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error // 更新提款账号(带类型) + UpdateRealNameAuth(ctx context.Context, userID string, realNameAuth RealNameAuth) error // 更新实名认证信息 + Delete(ctx context.Context, userIDs []string) error + Page(ctx context.Context, pagination pagination.Pagination) (int64, []*Wallet, error) + PageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*Wallet, error) // 按实名认证审核状态分页查询(支持用户ID搜索) + SearchByRealNameAuth(ctx context.Context, realNameKeyword string, idCardKeyword string) ([]string, error) // 按实名认证信息搜索钱包(返回userIDs) +} + +// WalletBalanceRecord 钱包余额记录 +type WalletBalanceRecord struct { + ID string `bson:"_id"` // 记录ID + UserID string `bson:"user_id"` // 用户ID + Amount int64 `bson:"amount"` // 变动金额(单位:分,正数表示增加,负数表示减少) + Type int32 `bson:"type"` // 变动类型:1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 + BeforeBalance int64 `bson:"before_balance"` // 变动前余额(单位:分) + AfterBalance int64 `bson:"after_balance"` // 变动后余额(单位:分) + OrderID string `bson:"order_id"` // 关联订单ID(可选) + TransactionID string `bson:"transaction_id"` // 交易ID(可选) + RedPacketID string `bson:"red_packet_id"` // 红包ID(用于发红包和抢红包记录关联,可选) + Remark string `bson:"remark"` // 备注 + CreateTime time.Time `bson:"create_time"` // 创建时间 +} + +func (WalletBalanceRecord) TableName() string { + return "wallet_balance_records" +} + +type WalletBalanceRecordInterface interface { + Create(ctx context.Context, records ...*WalletBalanceRecord) error + Take(ctx context.Context, recordID string) (*WalletBalanceRecord, error) + FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*WalletBalanceRecord, error) + FindByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*WalletBalanceRecord, error) + FindByOrderID(ctx context.Context, orderID string) (*WalletBalanceRecord, error) + FindByTransactionID(ctx context.Context, transactionID string) (*WalletBalanceRecord, error) + FindByRedPacketID(ctx context.Context, redPacketID string) ([]*WalletBalanceRecord, error) + GetUserBalanceHistory(ctx context.Context, userID string, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*WalletBalanceRecord, error) + CountByUserID(ctx context.Context, userID string) (int64, error) +} diff --git a/pkg/common/db/table/chat/withdraw.go b/pkg/common/db/table/chat/withdraw.go new file mode 100644 index 0000000..5a75fab --- /dev/null +++ b/pkg/common/db/table/chat/withdraw.go @@ -0,0 +1,63 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// WithdrawStatus 提现状态 +const ( + WithdrawStatusPending = 1 // 待审核 + WithdrawStatusApproved = 2 // 已通过 + WithdrawStatusRejected = 3 // 已拒绝 +) + +// Withdraw 提现记录 +type Withdraw struct { + ID string `bson:"_id"` // 提现ID + UserID string `bson:"user_id"` // 用户ID + Amount int64 `bson:"amount"` // 提现金额(单位:分) + WithdrawAccount string `bson:"withdraw_account"` // 提现账号 + Status int32 `bson:"status"` // 审核状态:1-待审核,2-已通过,3-已拒绝 + AuditorID string `bson:"auditor_id"` // 审核人ID(管理员ID) + AuditTime time.Time `bson:"audit_time"` // 审核时间 + AuditRemark string `bson:"audit_remark"` // 审核备注 + IP string `bson:"ip"` // 提现IP + DeviceID string `bson:"device_id"` // 设备ID + Platform string `bson:"platform"` // 平台(iOS、Android、Web等) + DeviceModel string `bson:"device_model"` // 设备型号(如:iPhone 14 Pro、Samsung Galaxy S23等) + DeviceBrand string `bson:"device_brand"` // 设备品牌(如:Apple、Samsung、Huawei等) + OSVersion string `bson:"os_version"` // 操作系统版本(如:iOS 17.0、Android 13等) + AppVersion string `bson:"app_version"` // 应用版本 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +func (Withdraw) TableName() string { + return "withdraws" +} + +type WithdrawInterface interface { + Create(ctx context.Context, withdraws ...*Withdraw) error + Take(ctx context.Context, withdrawID string) (*Withdraw, error) + FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*Withdraw, error) + FindByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*Withdraw, error) + UpdateStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error + Page(ctx context.Context, pagination pagination.Pagination) (int64, []*Withdraw, error) +} diff --git a/pkg/common/db/table/chat/withdraw_application.go b/pkg/common/db/table/chat/withdraw_application.go new file mode 100644 index 0000000..9e3c2c9 --- /dev/null +++ b/pkg/common/db/table/chat/withdraw_application.go @@ -0,0 +1,68 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +// WithdrawApplicationStatus 提现申请状态 +const ( + WithdrawApplicationStatusPending = 1 // 待审核 + WithdrawApplicationStatusApproved = 2 // 已通过 + WithdrawApplicationStatusRejected = 3 // 已拒绝 + WithdrawApplicationStatusProcessing = 4 // 处理中 + WithdrawApplicationStatusCompleted = 5 // 已完成 +) + +// WithdrawApplication 提现申请 +type WithdrawApplication struct { + ID string `bson:"_id"` // 申请ID + UserID string `bson:"user_id"` // 用户ID + Amount int64 `bson:"amount"` // 提现金额(单位:分) + WithdrawAccount string `bson:"withdraw_account"` // 提现账号 + WithdrawAccountType int32 `bson:"withdraw_account_type"` // 提现账号类型:1-支付宝,2-微信,3-银行卡 + Status int32 `bson:"status"` // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + AuditorID string `bson:"auditor_id"` // 审核人ID(管理员ID) + AuditTime time.Time `bson:"audit_time"` // 审核时间 + AuditRemark string `bson:"audit_remark"` // 审核备注 + IP string `bson:"ip"` // 申请IP + DeviceID string `bson:"device_id"` // 设备ID + Platform string `bson:"platform"` // 平台(iOS、Android、Web等) + DeviceModel string `bson:"device_model"` // 设备型号(如:iPhone 14 Pro、Samsung Galaxy S23等) + DeviceBrand string `bson:"device_brand"` // 设备品牌(如:Apple、Samsung、Huawei等) + OSVersion string `bson:"os_version"` // 操作系统版本(如:iOS 17.0、Android 13等) + AppVersion string `bson:"app_version"` // 应用版本 + Remark string `bson:"remark"` // 申请备注 + CreateTime time.Time `bson:"create_time"` // 创建时间 + UpdateTime time.Time `bson:"update_time"` // 更新时间 +} + +func (WithdrawApplication) TableName() string { + return "withdraw_applications" +} + +type WithdrawApplicationInterface interface { + Create(ctx context.Context, applications ...*WithdrawApplication) error + Take(ctx context.Context, applicationID string) (*WithdrawApplication, error) + FindByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*WithdrawApplication, error) + FindByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*WithdrawApplication, error) + UpdateStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error + Page(ctx context.Context, pagination pagination.Pagination) (int64, []*WithdrawApplication, error) + Update(ctx context.Context, applicationID string, data map[string]any) error +} diff --git a/pkg/common/imapi/api.go b/pkg/common/imapi/api.go new file mode 100644 index 0000000..abbe239 --- /dev/null +++ b/pkg/common/imapi/api.go @@ -0,0 +1,53 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package imapi + +import ( + "git.imall.cloud/openim/protocol/auth" + "git.imall.cloud/openim/protocol/group" + "git.imall.cloud/openim/protocol/relation" + "git.imall.cloud/openim/protocol/user" +) + +// im caller. +var ( + getAdminToken = NewApiCaller[auth.GetAdminTokenReq, auth.GetAdminTokenResp]("/auth/get_admin_token") + getuserToken = NewApiCaller[auth.GetUserTokenReq, auth.GetUserTokenResp]("/auth/get_user_token") + forceOffLine = NewApiCaller[auth.ForceLogoutReq, auth.ForceLogoutResp]("/auth/force_logout") + + updateUserInfo = NewApiCaller[user.UpdateUserInfoReq, user.UpdateUserInfoResp]("/user/update_user_info") + updateUserInfoEx = NewApiCaller[user.UpdateUserInfoExReq, user.UpdateUserInfoExResp]("/user/update_user_info_ex") + registerUser = NewApiCaller[user.UserRegisterReq, user.UserRegisterResp]("/user/user_register") + getUserInfo = NewApiCaller[user.GetDesignateUsersReq, user.GetDesignateUsersResp]("/user/get_users_info") + accountCheck = NewApiCaller[user.AccountCheckReq, user.AccountCheckResp]("/user/account_check") + addNotificationAccount = NewApiCaller[user.AddNotificationAccountReq, user.AddNotificationAccountResp]("/user/add_notification_account") + updateNotificationAccount = NewApiCaller[user.UpdateNotificationAccountInfoReq, user.UpdateNotificationAccountInfoResp]("/user/update_notification_account") + + getGroupsInfo = NewApiCaller[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") + inviteToGroup = NewApiCaller[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") + + registerUserCount = NewApiCaller[user.UserRegisterCountReq, user.UserRegisterCountResp]("/statistics/user/register") + + onlineUserCount = NewApiCaller[OnlineUserCountReq, OnlineUserCountResp]("/statistics/online_user_count") + onlineUserCountTrend = NewApiCaller[OnlineUserCountTrendReq, OnlineUserCountTrendResp]("/statistics/online_user_count_trend") + userSendMsgCount = NewApiCaller[UserSendMsgCountReq, UserSendMsgCountResp]("/statistics/user_send_msg_count") + userSendMsgCountTrend = NewApiCaller[UserSendMsgCountTrendReq, UserSendMsgCountTrendResp]("/statistics/user_send_msg_count_trend") + userSendMsgQuery = NewApiCaller[UserSendMsgQueryReq, UserSendMsgQueryResp]("/statistics/user_send_msg_query") + + friendUserIDs = NewApiCaller[relation.GetFriendIDsReq, relation.GetFriendIDsResp]("/friend/get_friend_id") + importFriend = NewApiCaller[relation.ImportFriendReq, relation.ImportFriendResp]("/friend/import_friend") + + sendSimpleMsg = NewApiCaller[SendSingleMsgReq, SendSingleMsgResp]("/msg/send_simple_msg") +) diff --git a/pkg/common/imapi/call.go b/pkg/common/imapi/call.go new file mode 100644 index 0000000..dd3b6b4 --- /dev/null +++ b/pkg/common/imapi/call.go @@ -0,0 +1,160 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package imapi + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "net/url" + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "gorm.io/gorm/utils" +) + +type baseApiResponse[T any] struct { + ErrCode int `json:"errCode"` + ErrMsg string `json:"errMsg"` + ErrDlt string `json:"errDlt"` + Data *T `json:"data"` +} + +var client = &http.Client{ + Timeout: time.Second * 10, +} + +type ApiCaller[Req, Resp any] interface { + Call(ctx context.Context, apiPrefix string, req *Req) (*Resp, error) + CallWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) +} + +func NewApiCaller[Req, Resp any](api string) ApiCaller[Req, Resp] { + return &caller[Req, Resp]{ + api: api, + } +} + +type caller[Req, Resp any] struct { + api string +} + +func (a caller[Req, Resp]) Call(ctx context.Context, apiPrefix string, req *Req) (*Resp, error) { + start := time.Now() + resp, err := a.call(ctx, apiPrefix, req) + if err != nil { + log.ZError(ctx, "api caller failed", err, "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return nil, err + } + log.ZInfo(ctx, "api caller success resp", "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return resp, nil +} + +func (a caller[Req, Resp]) call(ctx context.Context, apiPrefix string, req *Req) (*Resp, error) { + url := apiPrefix + a.api + reqBody, err := json.Marshal(req) + if err != nil { + return nil, err + } + request, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(reqBody)) + if err != nil { + return nil, err + } + operationID := utils.ToString(ctx.Value(constantpb.OperationID)) + request.Header.Set(constantpb.OperationID, operationID) + if token, _ := ctx.Value(constant.CtxApiToken).(string); token != "" { + request.Header.Set(constantpb.Token, token) + } + response, err := client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + data, err := io.ReadAll(response.Body) + if err != nil { + return nil, errs.WrapMsg(err, "read http response body", "url", url, "code", response.StatusCode) + } + var resp baseApiResponse[Resp] + if err := json.Unmarshal(data, &resp); err != nil { + return nil, errs.WrapMsg(err, string(data)) + } + if resp.ErrCode != 0 { + return nil, errs.NewCodeError(resp.ErrCode, resp.ErrMsg).WithDetail(resp.ErrDlt).Wrap() + } + return resp.Data, nil +} + +func (a caller[Req, Resp]) CallWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) { + start := time.Now() + resp, err := a.callWithQuery(ctx, apiPrefix, req, queryParams) + if err != nil { + log.ZError(ctx, "api caller failed", err, "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return nil, err + } + log.ZInfo(ctx, "api caller success resp", "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return resp, nil +} + +func (a caller[Req, Resp]) callWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) { + fullURL := apiPrefix + a.api + parsedURL, err := url.Parse(fullURL) + if err != nil { + return nil, errs.WrapMsg(err, "failed to parse URL", fullURL) + } + + query := parsedURL.Query() + + for key, value := range queryParams { + query.Set(key, value) + } + + parsedURL.RawQuery = query.Encode() + fullURL = parsedURL.String() + reqBody, err := json.Marshal(req) + if err != nil { + return nil, err + } + request, err := http.NewRequestWithContext(ctx, http.MethodPost, fullURL, bytes.NewReader(reqBody)) + if err != nil { + return nil, err + } + operationID := utils.ToString(ctx.Value(constantpb.OperationID)) + request.Header.Set(constantpb.OperationID, operationID) + if token, _ := ctx.Value(constant.CtxApiToken).(string); token != "" { + request.Header.Set(constantpb.Token, token) + } + response, err := client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + data, err := io.ReadAll(response.Body) + if err != nil { + return nil, errs.WrapMsg(err, "read http response body", "fullUrl", fullURL, "code", response.StatusCode) + } + var resp baseApiResponse[Resp] + if err := json.Unmarshal(data, &resp); err != nil { + return nil, errs.WrapMsg(err, string(data)) + } + if resp.ErrCode != 0 { + return nil, errs.NewCodeError(resp.ErrCode, resp.ErrMsg).WithDetail(resp.ErrDlt).Wrap() + } + return resp.Data, nil +} diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go new file mode 100644 index 0000000..4e896be --- /dev/null +++ b/pkg/common/imapi/caller.go @@ -0,0 +1,281 @@ +package imapi + +import ( + "context" + "sync" + "time" + + "git.imall.cloud/openim/chat/pkg/botstruct" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/protocol/auth" + "git.imall.cloud/openim/protocol/constant" + "git.imall.cloud/openim/protocol/group" + "git.imall.cloud/openim/protocol/relation" + "git.imall.cloud/openim/protocol/sdkws" + "git.imall.cloud/openim/protocol/user" + wrapperspb "git.imall.cloud/openim/protocol/wrapperspb" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" +) + +type CallerInterface interface { + ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) + ImportFriend(ctx context.Context, ownerUserID string, friendUserID []string) error + GetUserToken(ctx context.Context, userID string, platform int32) (string, error) + GetAdminTokenCache(ctx context.Context, userID string) (string, error) + GetAdminTokenServer(ctx context.Context, userID string) (string, error) + InviteToGroup(ctx context.Context, userID string, groupIDs []string) error + + UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string, userType int32, userFlag string) error + UpdateUserInfoEx(ctx context.Context, userID string, ex string) error + GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) + GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) + AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error + UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error + + ForceOffLine(ctx context.Context, userID string) error + RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error + FindGroupInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) + UserRegisterCount(ctx context.Context, start int64, end int64) (map[string]int64, int64, error) + OnlineUserCount(ctx context.Context) (*OnlineUserCountResp, error) + OnlineUserCountTrend(ctx context.Context, req *OnlineUserCountTrendReq) (*OnlineUserCountTrendResp, error) + UserSendMsgCount(ctx context.Context, req *UserSendMsgCountReq) (*UserSendMsgCountResp, error) + UserSendMsgCountTrend(ctx context.Context, req *UserSendMsgCountTrendReq) (*UserSendMsgCountTrendResp, error) + UserSendMsgQuery(ctx context.Context, req *UserSendMsgQueryReq) (*UserSendMsgQueryResp, error) + FriendUserIDs(ctx context.Context, userID string) ([]string, error) + AccountCheckSingle(ctx context.Context, userID string) (bool, error) + SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error +} + +type authToken struct { + token string + expired time.Time +} + +type Caller struct { + imApi string + imSecret string + defaultIMUserID string + tokenCache map[string]*authToken + lock sync.RWMutex +} + +func New(imApi string, imSecret string, defaultIMUserID string) CallerInterface { + return &Caller{ + imApi: imApi, + imSecret: imSecret, + defaultIMUserID: defaultIMUserID, + tokenCache: make(map[string]*authToken), + lock: sync.RWMutex{}, + } +} + +func (c *Caller) ImportFriend(ctx context.Context, ownerUserID string, friendUserIDs []string) error { + if len(friendUserIDs) == 0 { + return nil + } + _, err := importFriend.Call(ctx, c.imApi, &relation.ImportFriendReq{ + OwnerUserID: ownerUserID, + FriendUserIDs: friendUserIDs, + }) + return err +} + +func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) { + return c.GetAdminTokenCache(ctx, c.defaultIMUserID) +} + +func (c *Caller) GetAdminTokenCache(ctx context.Context, userID string) (string, error) { + c.lock.RLock() + t, ok := c.tokenCache[userID] + c.lock.RUnlock() + if ok && t.expired.After(time.Now()) { + return t.token, nil + } + c.lock.Lock() + defer c.lock.Unlock() + t, ok = c.tokenCache[userID] + if ok && t.expired.After(time.Now()) { + return t.token, nil + } + token, err := c.GetAdminTokenServer(ctx, userID) + if err != nil { + return "", err + } + c.tokenCache[userID] = &authToken{token: token, expired: time.Now().Add(time.Minute * 4)} + return token, nil +} + +func (c *Caller) GetAdminTokenServer(ctx context.Context, userID string) (string, error) { + resp, err := getAdminToken.Call(ctx, c.imApi, &auth.GetAdminTokenReq{ + Secret: c.imSecret, + UserID: userID, + }) + if err != nil { + return "", err + } + log.ZDebug(ctx, "get im admin token from server", "userID", userID, "token", resp.Token) + return resp.Token, nil +} + +func (c *Caller) GetUserToken(ctx context.Context, userID string, platformID int32) (string, error) { + resp, err := getuserToken.Call(ctx, c.imApi, &auth.GetUserTokenReq{ + PlatformID: platformID, + UserID: userID, + }) + if err != nil { + return "", err + } + return resp.Token, nil +} + +func (c *Caller) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error { + for _, groupID := range groupIDs { + _, _ = inviteToGroup.Call(ctx, c.imApi, &group.InviteUserToGroupReq{ + GroupID: groupID, + Reason: "", + InvitedUserIDs: []string{userID}, + }) + } + return nil +} + +func (c *Caller) UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string, userType int32, userFlag string) error { + _, err := updateUserInfo.Call(ctx, c.imApi, &user.UpdateUserInfoReq{UserInfo: &sdkws.UserInfo{ + UserID: userID, + Nickname: nickName, + FaceURL: faceURL, + UserType: userType, + UserFlag: userFlag, + }}) + return err +} + +func (c *Caller) UpdateUserInfoEx(ctx context.Context, userID string, ex string) error { + _, err := updateUserInfoEx.Call(ctx, c.imApi, &user.UpdateUserInfoExReq{ + UserInfo: &sdkws.UserInfoWithEx{ + UserID: userID, + Ex: &wrapperspb.StringValue{Value: ex}, + }, + }) + return err +} + +func (c *Caller) GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) { + resp, err := c.GetUsersInfo(ctx, []string{userID}) + if err != nil { + return nil, err + } + if len(resp) == 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("record not found") + } + return resp[0], nil +} + +func (c *Caller) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) { + resp, err := getUserInfo.Call(ctx, c.imApi, &user.GetDesignateUsersReq{ + UserIDs: userIDs, + }) + if err != nil { + return nil, err + } + return resp.UsersInfo, nil +} + +func (c *Caller) RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error { + _, err := registerUser.Call(ctx, c.imApi, &user.UserRegisterReq{ + Users: users, + }) + return err +} + +func (c *Caller) ForceOffLine(ctx context.Context, userID string) error { + for id := range constant.PlatformID2Name { + _, _ = forceOffLine.Call(ctx, c.imApi, &auth.ForceLogoutReq{ + PlatformID: int32(id), + UserID: userID, + }) + } + return nil +} + +func (c *Caller) FindGroupInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) { + resp, err := getGroupsInfo.Call(ctx, c.imApi, &group.GetGroupsInfoReq{ + GroupIDs: groupIDs, + }) + if err != nil { + return nil, err + } + return resp.GroupInfos, nil +} + +func (c *Caller) UserRegisterCount(ctx context.Context, start int64, end int64) (map[string]int64, int64, error) { + resp, err := registerUserCount.Call(ctx, c.imApi, &user.UserRegisterCountReq{ + Start: start, + End: end, + }) + if err != nil { + return nil, 0, err + } + return resp.Count, resp.Total, nil +} + +// OnlineUserCount 获取在线人数统计 +func (c *Caller) OnlineUserCount(ctx context.Context) (*OnlineUserCountResp, error) { + return onlineUserCount.Call(ctx, c.imApi, &OnlineUserCountReq{}) +} + +// OnlineUserCountTrend 获取在线人数走势统计 +func (c *Caller) OnlineUserCountTrend(ctx context.Context, req *OnlineUserCountTrendReq) (*OnlineUserCountTrendResp, error) { + return onlineUserCountTrend.Call(ctx, c.imApi, req) +} + +// UserSendMsgCount 获取用户发送消息统计 +func (c *Caller) UserSendMsgCount(ctx context.Context, req *UserSendMsgCountReq) (*UserSendMsgCountResp, error) { + return userSendMsgCount.Call(ctx, c.imApi, req) +} + +// UserSendMsgCountTrend 获取用户发送消息走势统计 +func (c *Caller) UserSendMsgCountTrend(ctx context.Context, req *UserSendMsgCountTrendReq) (*UserSendMsgCountTrendResp, error) { + return userSendMsgCountTrend.Call(ctx, c.imApi, req) +} + +// UserSendMsgQuery 获取用户发送消息查询列表 +func (c *Caller) UserSendMsgQuery(ctx context.Context, req *UserSendMsgQueryReq) (*UserSendMsgQueryResp, error) { + return userSendMsgQuery.Call(ctx, c.imApi, req) +} + +func (c *Caller) FriendUserIDs(ctx context.Context, userID string) ([]string, error) { + resp, err := friendUserIDs.Call(ctx, c.imApi, &relation.GetFriendIDsReq{UserID: userID}) + if err != nil { + return nil, err + } + return resp.FriendIDs, nil +} + +// return true when isUserNotExist. +func (c *Caller) AccountCheckSingle(ctx context.Context, userID string) (bool, error) { + resp, err := accountCheck.Call(ctx, c.imApi, &user.AccountCheckReq{CheckUserIDs: []string{userID}}) + if err != nil { + return false, err + } + if resp.Results[0].AccountStatus == constant.Registered { + return false, eerrs.ErrAccountAlreadyRegister.Wrap() + } + return true, nil +} + +func (c *Caller) SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error { + _, err := sendSimpleMsg.CallWithQuery(ctx, c.imApi, req, map[string]string{botstruct.Key: key}) + return err +} + +func (c *Caller) AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error { + _, err := addNotificationAccount.Call(ctx, c.imApi, req) + return err +} + +func (c *Caller) UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error { + _, err := updateNotificationAccount.Call(ctx, c.imApi, req) + return err +} diff --git a/pkg/common/imapi/model.go b/pkg/common/imapi/model.go new file mode 100644 index 0000000..a662acd --- /dev/null +++ b/pkg/common/imapi/model.go @@ -0,0 +1,139 @@ +package imapi + +import "git.imall.cloud/openim/protocol/sdkws" + +// SendSingleMsgReq defines the structure for sending a message to multiple recipients. +type SendSingleMsgReq struct { + // groupMsg should appoint sendID + SendID string `json:"sendID"` + Content string `json:"content" binding:"required"` + OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"` + Ex string `json:"ex"` +} +type SendSingleMsgResp struct{} + +// OnlineUserCountReq 在线人数统计请求 +type OnlineUserCountReq struct{} + +// OnlineUserCountResp 在线人数统计返回 +type OnlineUserCountResp struct { + OnlineCount int64 `json:"onlineCount"` +} + +// OnlineUserCountTrendReq 在线人数走势统计请求 +type OnlineUserCountTrendReq struct { + // StartTime 统计开始时间(毫秒时间戳),为空时默认最近24小时 + StartTime int64 `json:"startTime"` + // EndTime 统计结束时间(毫秒时间戳),为空时默认当前时间 + EndTime int64 `json:"endTime"` + // IntervalMinutes 统计间隔(分钟),仅支持15/30/60 + IntervalMinutes int32 `json:"intervalMinutes"` +} + +// OnlineUserCountTrendItem 在线人数走势数据点 +type OnlineUserCountTrendItem struct { + // Timestamp 区间起始时间(毫秒时间戳) + Timestamp int64 `json:"timestamp"` + // OnlineCount 区间内平均在线人数 + OnlineCount int64 `json:"onlineCount"` +} + +// OnlineUserCountTrendResp 在线人数走势统计返回 +type OnlineUserCountTrendResp struct { + // IntervalMinutes 统计间隔(分钟) + IntervalMinutes int32 `json:"intervalMinutes"` + // Points 走势数据点 + Points []*OnlineUserCountTrendItem `json:"points"` +} + +// UserSendMsgCountReq 用户发送消息总数统计请求 +type UserSendMsgCountReq struct{} + +// UserSendMsgCountResp 用户发送消息总数统计返回 +type UserSendMsgCountResp struct { + // Count24h 最近24小时发送消息总数 + Count24h int64 `json:"count24h"` + // Count7d 最近7天发送消息总数 + Count7d int64 `json:"count7d"` + // Count30d 最近30天发送消息总数 + Count30d int64 `json:"count30d"` +} + +// UserSendMsgCountTrendReq 用户发送消息走势统计请求 +type UserSendMsgCountTrendReq struct { + // UserID 发送者用户ID + UserID string `json:"userID"` + // ChatType 聊天类型:1-单聊,2-群聊 + ChatType int32 `json:"chatType"` + // StartTime 统计开始时间(毫秒时间戳),为空时默认最近24小时 + StartTime int64 `json:"startTime"` + // EndTime 统计结束时间(毫秒时间戳),为空时默认当前时间 + EndTime int64 `json:"endTime"` + // IntervalMinutes 统计间隔(分钟),仅支持15/30/60 + IntervalMinutes int32 `json:"intervalMinutes"` +} + +// UserSendMsgCountTrendItem 用户发送消息走势数据点 +type UserSendMsgCountTrendItem struct { + // Timestamp 区间起始时间(毫秒时间戳) + Timestamp int64 `json:"timestamp"` + // Count 区间内发送消息数 + Count int64 `json:"count"` +} + +// UserSendMsgCountTrendResp 用户发送消息走势统计返回 +type UserSendMsgCountTrendResp struct { + // UserID 发送者用户ID + UserID string `json:"userID"` + // ChatType 聊天类型:1-单聊,2-群聊 + ChatType int32 `json:"chatType"` + // IntervalMinutes 统计间隔(分钟) + IntervalMinutes int32 `json:"intervalMinutes"` + // Points 走势数据点 + Points []*UserSendMsgCountTrendItem `json:"points"` +} + +// UserSendMsgQueryReq 用户发送消息查询请求 +type UserSendMsgQueryReq struct { + UserID string `json:"userID"` + StartTime int64 `json:"startTime"` + EndTime int64 `json:"endTime"` + Content string `json:"content"` + PageNumber int32 `json:"pageNumber"` + // ShowNumber 每页条数 默认50 最大200 + ShowNumber int32 `json:"showNumber"` +} + +// UserSendMsgQueryRecord 用户发送消息查询记录 +type UserSendMsgQueryRecord struct { + // MsgID 使用服务端消息ID + MsgID string `json:"msgID"` + // SendID 发送者ID + SendID string `json:"sendID"` + // SenderName 发送者昵称或名称 + SenderName string `json:"senderName"` + // RecvID 接收者ID 群聊为群ID + RecvID string `json:"recvID"` + // RecvName 接收者昵称或名称 群聊为群名称 + RecvName string `json:"recvName"` + // ContentType 消息类型编号 + ContentType int32 `json:"contentType"` + // ContentTypeName 消息类型名称 + ContentTypeName string `json:"contentTypeName"` + // SessionType 聊天类型编号 + SessionType int32 `json:"sessionType"` + // ChatTypeName 聊天类型名称 + ChatTypeName string `json:"chatTypeName"` + // Content 消息内容 + Content string `json:"content"` + // SendTime 消息发送时间 + SendTime int64 `json:"sendTime"` +} + +// UserSendMsgQueryResp 用户发送消息查询返回 +type UserSendMsgQueryResp struct { + Count int64 `json:"count"` + PageNumber int32 `json:"pageNumber"` + ShowNumber int32 `json:"showNumber"` + Records []*UserSendMsgQueryRecord `json:"records"` +} diff --git a/pkg/common/imwebhook/message.go b/pkg/common/imwebhook/message.go new file mode 100644 index 0000000..f09280a --- /dev/null +++ b/pkg/common/imwebhook/message.go @@ -0,0 +1,48 @@ +package imwebhook + +type CommonCallbackReq struct { + SendID string `json:"sendID"` + CallbackCommand string `json:"callbackCommand"` + ServerMsgID string `json:"serverMsgID"` + ClientMsgID string `json:"clientMsgID"` + OperationID string `json:"operationID"` + SenderPlatformID int32 `json:"senderPlatformID"` + SenderNickname string `json:"senderNickname"` + SessionType int32 `json:"sessionType"` + MsgFrom int32 `json:"msgFrom"` + ContentType int32 `json:"contentType"` + Status int32 `json:"status"` + SendTime int64 `json:"sendTime"` + CreateTime int64 `json:"createTime"` + Content string `json:"content"` + Seq uint32 `json:"seq"` + AtUserIDList []string `json:"atUserList"` + SenderFaceURL string `json:"faceURL"` + Ex string `json:"ex"` +} + +type CommonCallbackResp struct { + ActionCode int32 `json:"actionCode"` + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` + ErrDlt string `json:"errDlt"` + NextCode int32 `json:"nextCode"` +} + +type CallbackAfterSendSingleMsgReq struct { + CommonCallbackReq + RecvID string `json:"recvID"` +} + +type CallbackAfterSendSingleMsgResp struct { + CommonCallbackResp +} + +type CallbackAfterSendGroupMsgReq struct { + CommonCallbackReq + GroupID string `json:"groupID"` +} + +type CallbackAfterSendGroupMsgResp struct { + CommonCallbackResp +} diff --git a/pkg/common/kdisc/direct/direct_resolver.go b/pkg/common/kdisc/direct/direct_resolver.go new file mode 100644 index 0000000..8213782 --- /dev/null +++ b/pkg/common/kdisc/direct/direct_resolver.go @@ -0,0 +1,96 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package direct + +import ( + "context" + "math/rand" + "strings" + + "github.com/openimsdk/tools/log" + "google.golang.org/grpc/resolver" +) + +const ( + slashSeparator = "/" + // EndpointSepChar is the separator char in endpoints. + EndpointSepChar = ',' + + subsetSize = 32 + scheme = "direct" +) + +type ResolverDirect struct { +} + +func NewResolverDirect() *ResolverDirect { + return &ResolverDirect{} +} + +func (rd *ResolverDirect) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) ( + resolver.Resolver, error) { + log.ZDebug(context.Background(), "Build", "target", target) + endpoints := strings.FieldsFunc(GetEndpoints(target), func(r rune) bool { + return r == EndpointSepChar + }) + endpoints = subset(endpoints, subsetSize) + addrs := make([]resolver.Address, 0, len(endpoints)) + + for _, val := range endpoints { + addrs = append(addrs, resolver.Address{ + Addr: val, + }) + } + if err := cc.UpdateState(resolver.State{ + Addresses: addrs, + }); err != nil { + return nil, err + } + + return &nopResolver{cc: cc}, nil +} +func init() { + resolver.Register(&ResolverDirect{}) +} +func (rd *ResolverDirect) Scheme() string { + return scheme // return your custom scheme name +} + +// GetEndpoints returns the endpoints from the given target. +func GetEndpoints(target resolver.Target) string { + return strings.Trim(target.URL.Path, slashSeparator) +} +func subset(set []string, sub int) []string { + rand.Shuffle(len(set), func(i, j int) { + set[i], set[j] = set[j], set[i] + }) + if len(set) <= sub { + return set + } + + return set[:sub] +} + +type nopResolver struct { + cc resolver.ClientConn +} + +func (n nopResolver) ResolveNow(options resolver.ResolveNowOptions) { + +} + +func (n nopResolver) Close() { + +} diff --git a/pkg/common/kdisc/direct/directconn.go b/pkg/common/kdisc/direct/directconn.go new file mode 100644 index 0000000..430044d --- /dev/null +++ b/pkg/common/kdisc/direct/directconn.go @@ -0,0 +1,174 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package direct + +//import ( +// "context" +// "fmt" +// +// config2 "github.com/openimsdk/chat-deploy/v3/pkg/common/config" +// "github.com/openimsdk/tools/errs" +// "google.golang.org/grpc" +// "google.golang.org/grpc/credentials/insecure" +//) +// +//type ServiceAddresses map[string][]int +// +//func getServiceAddresses(rpcRegisterName *config2.RpcRegisterName, +// rpcPort *config2.RpcPort, longConnSvrPort []int) ServiceAddresses { +// return ServiceAddresses{ +// rpcRegisterName.OpenImUserName: rpcPort.OpenImUserPort, +// rpcRegisterName.OpenImFriendName: rpcPort.OpenImFriendPort, +// rpcRegisterName.OpenImMsgName: rpcPort.OpenImMessagePort, +// rpcRegisterName.OpenImMessageGatewayName: longConnSvrPort, +// rpcRegisterName.OpenImGroupName: rpcPort.OpenImGroupPort, +// rpcRegisterName.OpenImAuthName: rpcPort.OpenImAuthPort, +// rpcRegisterName.OpenImPushName: rpcPort.OpenImPushPort, +// rpcRegisterName.OpenImConversationName: rpcPort.OpenImConversationPort, +// rpcRegisterName.OpenImThirdName: rpcPort.OpenImThirdPort, +// } +//} +// +//type ConnDirect struct { +// additionalOpts []grpc.DialOption +// currentServiceAddress string +// conns map[string][]*grpc.ClientConn +// resolverDirect *ResolverDirect +// config *config2.GlobalConfig +//} +// +//func (cd *ConnDirect) GetClientLocalConns() map[string][]*grpc.ClientConn { +// return nil +//} +// +//func (cd *ConnDirect) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) { +// return "", nil +//} +// +//func (cd *ConnDirect) Register(serviceName, host string, port int, opts ...grpc.DialOption) error { +// return nil +//} +// +//func (cd *ConnDirect) UnRegister() error { +// return nil +//} +// +//func (cd *ConnDirect) CreateRpcRootNodes(serviceNames []string) error { +// return nil +//} +// +//func (cd *ConnDirect) RegisterConf2Registry(key string, conf []byte) error { +// return nil +//} +// +//func (cd *ConnDirect) GetConfFromRegistry(key string) ([]byte, error) { +// return nil, nil +//} +// +//func (cd *ConnDirect) Close() { +// +//} +// +//func NewConnDirect(config *config2.GlobalConfig) (*ConnDirect, error) { +// return &ConnDirect{ +// conns: make(map[string][]*grpc.ClientConn), +// resolverDirect: NewResolverDirect(), +// config: config, +// }, nil +//} +// +//func (cd *ConnDirect) GetConns(ctx context.Context, +// serviceName string, opts ...grpc.DialOption) ([]*grpc.ClientConn, error) { +// +// if conns, exists := cd.conns[serviceName]; exists { +// return conns, nil +// } +// ports := getServiceAddresses(&cd.config.RpcRegisterName, +// &cd.config.RpcPort, cd.config.LongConnSvr.OpenImMessageGatewayPort)[serviceName] +// var connections []*grpc.ClientConn +// for _, port := range ports { +// conn, err := cd.dialServiceWithoutResolver(ctx, fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", port), append(cd.additionalOpts, opts...)...) +// if err != nil { +// return nil, errs.Wrap(fmt.Errorf("connect to port %d failed,serviceName %s, IP %s", port, serviceName, cd.config.Rpc.ListenIP)) +// } +// connections = append(connections, conn) +// } +// +// if len(connections) == 0 { +// return nil, errs.New("no connections found for service", "serviceName", serviceName).Wrap() +// } +// return connections, nil +//} +// +//func (cd *ConnDirect) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// // Get service addresses +// addresses := getServiceAddresses(&cd.config.RpcRegisterName, +// &cd.config.RpcPort, cd.config.LongConnSvr.OpenImMessageGatewayPort) +// address, ok := addresses[serviceName] +// if !ok { +// return nil, errs.New("unknown service name", "serviceName", serviceName).Wrap() +// } +// var result string +// for _, addr := range address { +// if result != "" { +// result = result + "," + fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) +// } else { +// result = fmt.Sprintf(cd.config.Rpc.ListenIP+":%d", addr) +// } +// } +// // Try to dial a new connection +// conn, err := cd.dialService(ctx, result, append(cd.additionalOpts, opts...)...) +// if err != nil { +// return nil, errs.WrapMsg(err, "address", result) +// } +// +// // Store the new connection +// cd.conns[serviceName] = append(cd.conns[serviceName], conn) +// return conn, nil +//} +// +//func (cd *ConnDirect) GetSelfConnTarget() string { +// return cd.currentServiceAddress +//} +// +//func (cd *ConnDirect) AddOption(opts ...grpc.DialOption) { +// cd.additionalOpts = append(cd.additionalOpts, opts...) +//} +// +//func (cd *ConnDirect) CloseConn(conn *grpc.ClientConn) { +// if conn != nil { +// conn.Close() +// } +//} +// +//func (cd *ConnDirect) dialService(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) +// conn, err := grpc.DialContext(ctx, cd.resolverDirect.Scheme()+":///"+address, options...) +// +// if err != nil { +// return nil, errs.WrapMsg(err, "address", address) +// } +// return conn, nil +//} +// +//func (cd *ConnDirect) dialServiceWithoutResolver(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { +// options := append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) +// conn, err := grpc.DialContext(ctx, address, options...) +// +// if err != nil { +// return nil, errs.Wrap(err) +// } +// return conn, nil +//} diff --git a/pkg/common/kdisc/direct/doc.go b/pkg/common/kdisc/direct/doc.go new file mode 100644 index 0000000..5c956b0 --- /dev/null +++ b/pkg/common/kdisc/direct/doc.go @@ -0,0 +1,15 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package direct // import "github.com/openimsdk/chat-deploy/v3/pkg/common/discoveryregister/direct" diff --git a/pkg/common/kdisc/discoveryregister.go b/pkg/common/kdisc/discoveryregister.go new file mode 100644 index 0000000..247447f --- /dev/null +++ b/pkg/common/kdisc/discoveryregister.go @@ -0,0 +1,51 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kdisc + +import ( + "time" + + "git.imall.cloud/openim/chat/pkg/common/config" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/discovery/kubernetes" + "github.com/openimsdk/tools/errs" +) + +const ( + ETCDCONST = "etcd" + KUBERNETESCONST = "kubernetes" + DIRECTCONST = "direct" +) + +// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. +func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string, watchNames []string) (discovery.SvcDiscoveryRegistry, error) { + if runtimeEnv == KUBERNETESCONST { + return kubernetes.NewKubernetesConnManager(discovery.Kubernetes.Namespace) + } + + switch discovery.Enable { + case ETCDCONST: + return etcd.NewSvcDiscoveryRegistry( + discovery.Etcd.RootDirectory, + discovery.Etcd.Address, + watchNames, + etcd.WithDialTimeout(10*time.Second), + etcd.WithMaxCallSendMsgSize(20*1024*1024), + etcd.WithUsernameAndPassword(discovery.Etcd.Username, discovery.Etcd.Password)) + default: + return nil, errs.New("unsupported discovery type", "type", discovery.Enable).Wrap() + } +} diff --git a/pkg/common/kdisc/etcd/config_manager.go b/pkg/common/kdisc/etcd/config_manager.go new file mode 100644 index 0000000..70d37c3 --- /dev/null +++ b/pkg/common/kdisc/etcd/config_manager.go @@ -0,0 +1,106 @@ +package etcd + +import ( + "context" + "os" + "os/exec" + "runtime" + "sync" + "syscall" + + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + clientv3 "go.etcd.io/etcd/client/v3" +) + +var ( + ShutDowns []func() error +) + +func RegisterShutDown(shutDown ...func() error) { + ShutDowns = append(ShutDowns, shutDown...) +} + +type ConfigManager struct { + client *clientv3.Client + watchConfigNames []string + lock sync.Mutex +} + +func BuildKey(s string) string { + return ConfigKeyPrefix + s +} + +func NewConfigManager(client *clientv3.Client, configNames []string) *ConfigManager { + return &ConfigManager{ + client: client, + watchConfigNames: datautil.Batch(func(s string) string { return BuildKey(s) }, append(configNames, RestartKey))} +} + +func (c *ConfigManager) Watch(ctx context.Context) { + chans := make([]clientv3.WatchChan, 0, len(c.watchConfigNames)) + for _, name := range c.watchConfigNames { + chans = append(chans, c.client.Watch(ctx, name, clientv3.WithPrefix())) + } + + doWatch := func(watchChan clientv3.WatchChan) { + for watchResp := range watchChan { + if watchResp.Err() != nil { + log.ZError(ctx, "watch err", errs.Wrap(watchResp.Err())) + continue + } + for _, event := range watchResp.Events { + if event.IsModify() { + if datautil.Contain(string(event.Kv.Key), c.watchConfigNames...) { + c.lock.Lock() + err := restartServer(ctx) + if err != nil { + log.ZError(ctx, "restart server err", err) + } + c.lock.Unlock() + } + } + } + } + } + for _, ch := range chans { + go doWatch(ch) + } +} + +func restartServer(ctx context.Context) error { + exePath, err := os.Executable() + if err != nil { + return errs.New("get executable path fail").Wrap() + } + + args := os.Args + env := os.Environ() + + cmd := exec.Command(exePath, args[1:]...) + cmd.Env = env + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + if runtime.GOOS != "windows" { + cmd.SysProcAttr = &syscall.SysProcAttr{} + } + log.ZInfo(ctx, "shutdown server") + for _, f := range ShutDowns { + if err = f(); err != nil { + log.ZError(ctx, "shutdown fail", err) + } + } + + log.ZInfo(ctx, "restart server") + err = cmd.Start() + if err != nil { + return errs.New("restart server fail").Wrap() + } + log.ZInfo(ctx, "cmd start over") + + os.Exit(0) + return nil +} diff --git a/pkg/common/kdisc/etcd/const.go b/pkg/common/kdisc/etcd/const.go new file mode 100644 index 0000000..bae8be9 --- /dev/null +++ b/pkg/common/kdisc/etcd/const.go @@ -0,0 +1,9 @@ +package etcd + +const ( + ConfigKeyPrefix = "/chat/config/" + RestartKey = "restart" + EnableConfigCenterKey = "enable-config-center" + Enable = "enable" + Disable = "disable" +) diff --git a/pkg/common/mctx/get.go b/pkg/common/mctx/get.go new file mode 100644 index 0000000..d675c5d --- /dev/null +++ b/pkg/common/mctx/get.go @@ -0,0 +1,136 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mctx + +import ( + "context" + "strconv" + + "github.com/openimsdk/tools/utils/datautil" + + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/errs" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "git.imall.cloud/openim/chat/pkg/common/tokenverify" +) + +func HaveOpUser(ctx context.Context) bool { + return ctx.Value(constant.RpcOpUserID) != nil +} + +func Check(ctx context.Context) (string, int32, error) { + opUserIDVal := ctx.Value(constant.RpcOpUserID) + opUserID, ok := opUserIDVal.(string) + if !ok { + return "", 0, errs.ErrNoPermission.WrapMsg("no opUserID") + } + if opUserID == "" { + return "", 0, errs.ErrNoPermission.WrapMsg("opUserID empty") + } + opUserTypeArr, ok := ctx.Value(constant.RpcOpUserType).([]string) + if !ok { + return "", 0, errs.ErrNoPermission.WrapMsg("missing user type") + } + if len(opUserTypeArr) == 0 { + return "", 0, errs.ErrNoPermission.WrapMsg("user type empty") + } + userType, err := strconv.Atoi(opUserTypeArr[0]) + if err != nil { + return "", 0, errs.ErrNoPermission.WrapMsg("user type invalid " + err.Error()) + } + if !(userType == constant.AdminUser || userType == constant.NormalUser) { + return "", 0, errs.ErrNoPermission.WrapMsg("user type invalid") + } + return opUserID, int32(userType), nil +} + +func CheckAdmin(ctx context.Context) (string, error) { + userID, userType, err := Check(ctx) + if err != nil { + return "", err + } + if userType != constant.AdminUser { + return "", errs.ErrNoPermission.WrapMsg("not admin") + } + return userID, nil +} + +func CheckUser(ctx context.Context) (string, error) { + userID, userType, err := Check(ctx) + if err != nil { + return "", err + } + if userType != constant.NormalUser { + return "", errs.ErrNoPermission.WrapMsg("not user") + } + return userID, nil +} + +func CheckAdminOrUser(ctx context.Context) (string, int32, error) { + userID, userType, err := Check(ctx) + if err != nil { + return "", 0, err + } + return userID, userType, nil +} + +func CheckAdminOr(ctx context.Context, userIDs ...string) error { + userID, userType, err := Check(ctx) + if err != nil { + return err + } + if userType == tokenverify.TokenAdmin { + return nil + } + for _, id := range userIDs { + if userID == id { + return nil + } + } + return errs.ErrNoPermission.WrapMsg("not admin or not in userIDs") +} + +func GetOpUserID(ctx context.Context) string { + userID, _ := ctx.Value(constantpb.OpUserID).(string) + return userID +} + +func GetUserType(ctx context.Context) (int, error) { + userTypeArr, _ := ctx.Value(constant.RpcOpUserType).([]string) + userType, err := strconv.Atoi(userTypeArr[0]) + if err != nil { + return 0, errs.ErrNoPermission.WrapMsg("user type invalid " + err.Error()) + } + return userType, nil +} + +func WithOpUserID(ctx context.Context, opUserID string, userType int) context.Context { + headers, _ := ctx.Value(constant.RpcCustomHeader).([]string) + ctx = context.WithValue(ctx, constant.RpcOpUserID, opUserID) + ctx = context.WithValue(ctx, constant.RpcOpUserType, []string{strconv.Itoa(userType)}) + if datautil.IndexOf(constant.RpcOpUserType, headers...) < 0 { + ctx = context.WithValue(ctx, constant.RpcCustomHeader, append(headers, constant.RpcOpUserType)) + } + return ctx +} + +func WithAdminUser(ctx context.Context, userID string) context.Context { + return WithOpUserID(ctx, userID, constant.AdminUser) +} + +func WithApiToken(ctx context.Context, token string) context.Context { + return context.WithValue(ctx, constant.CtxApiToken, token) +} diff --git a/pkg/common/mw/gin_log.go b/pkg/common/mw/gin_log.go new file mode 100644 index 0000000..13d19a3 --- /dev/null +++ b/pkg/common/mw/gin_log.go @@ -0,0 +1,57 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mw + +import ( + "bytes" + "io" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/openimsdk/tools/log" +) + +type responseWriter struct { + gin.ResponseWriter + buf *bytes.Buffer +} + +func (w *responseWriter) Write(b []byte) (int, error) { + w.buf.Write(b) + return w.ResponseWriter.Write(b) +} + +func GinLog() gin.HandlerFunc { + return func(c *gin.Context) { + req, err := io.ReadAll(c.Request.Body) + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + c.Abort() + return + } + start := time.Now() + log.ZDebug(c, "gin request", "method", c.Request.Method, "uri", c.Request.RequestURI, "req", string(req)) + c.Request.Body = io.NopCloser(bytes.NewReader(req)) + writer := &responseWriter{ + ResponseWriter: c.Writer, + buf: bytes.NewBuffer(nil), + } + c.Writer = writer + c.Next() + resp := writer.buf.Bytes() + log.ZDebug(c, "gin response", "time", time.Since(start), "status", c.Writer.Status(), "resp", string(resp)) + } +} diff --git a/pkg/common/mw/user.go b/pkg/common/mw/user.go new file mode 100644 index 0000000..62dc440 --- /dev/null +++ b/pkg/common/mw/user.go @@ -0,0 +1,36 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mw + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "github.com/openimsdk/tools/log" + "google.golang.org/grpc" +) + +func AddUserType() grpc.DialOption { + return grpc.WithChainUnaryInterceptor(func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + log.ZInfo(ctx, "add user type", "method", method) + if arr, _ := ctx.Value(constant.RpcOpUserType).([]string); len(arr) > 0 { + log.ZInfo(ctx, "add user type", "method", method, "userType", arr) + headers, _ := ctx.Value(constant.RpcCustomHeader).([]string) + ctx = context.WithValue(ctx, constant.RpcCustomHeader, append(headers, constant.RpcOpUserType)) + ctx = context.WithValue(ctx, constant.RpcOpUserType, arr) + } + return invoker(ctx, method, req, reply, cc, opts...) + }) +} diff --git a/pkg/common/rtc/rtc.go b/pkg/common/rtc/rtc.go new file mode 100644 index 0000000..7feca7e --- /dev/null +++ b/pkg/common/rtc/rtc.go @@ -0,0 +1,30 @@ +package rtc + +import ( + "github.com/livekit/protocol/auth" + "time" +) + +func NewLiveKit(key, secret, url string) *LiveKit { + return &LiveKit{ + token: auth.NewAccessToken(key, secret), + url: url, + } +} + +type LiveKit struct { + token *auth.AccessToken + url string +} + +func (l *LiveKit) GetLiveKitURL() string { + return l.url +} + +func (l *LiveKit) GetLiveKitToken(room string, identity string) (string, error) { + grant := &auth.VideoGrant{ + RoomJoin: true, + Room: room, + } + return l.token.AddGrant(grant).SetIdentity(identity).SetValidFor(time.Hour).ToJWT() +} diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go new file mode 100644 index 0000000..90a6e94 --- /dev/null +++ b/pkg/common/startrpc/start.go @@ -0,0 +1,129 @@ +package startrpc + +import ( + "context" + "fmt" + "net" + "os" + "os/signal" + "strconv" + "sync" + "syscall" + "time" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/kdisc" + disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/network" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// Start rpc server. +func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, + registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config.Share, config T, + watchConfigNames []string, watchServiceNames []string, + rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + rpcPort, err := datautil.GetElemByIndex(rpcPorts, index) + if err != nil { + return err + } + log.CInfo(ctx, "RPC server is initializing", " runtimeEnv ", runtimeEnv, "rpcRegisterName", rpcRegisterName, "rpcPort", rpcPort) + rpcTcpAddr := net.JoinHostPort(network.GetListenIP(listenIP), strconv.Itoa(rpcPort)) + listener, err := net.Listen( + "tcp", + rpcTcpAddr, + ) + if err != nil { + return errs.WrapMsg(err, "listen err", "rpcTcpAddr", rpcTcpAddr) + } + + defer listener.Close() + client, err := kdisc.NewDiscoveryRegister(discovery, runtimeEnv, watchServiceNames) + if err != nil { + return err + } + defer client.Close() + client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) + registerIP, err = network.GetRpcRegisterIP(registerIP) + if err != nil { + return err + } + + options = append(options, mw.GrpcServer()) + srv := grpc.NewServer(options...) + once := sync.Once{} + defer func() { + once.Do(srv.GracefulStop) + }() + + err = rpcFn(ctx, config, client, srv) + if err != nil { + return err + } + + if err := client.Register(rpcRegisterName, registerIP, rpcPort, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil { + return err + } + + var ( + netDone = make(chan struct{}, 2) + netErr error + ) + + go func() { + err := srv.Serve(listener) + if err != nil { + netErr = errs.WrapMsg(err, "rpc start err: ", rpcTcpAddr) + netDone <- struct{}{} + } + }() + if discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), watchConfigNames) + cm.Watch(ctx) + } + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + if err := gracefulStopWithCtx(ctx, srv.GracefulStop); err != nil { + return err + } + ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + return nil + case <-netDone: + close(netDone) + return netErr + } +} + +func gracefulStopWithCtx(ctx context.Context, f func()) error { + done := make(chan struct{}, 1) + go func() { + f() + close(done) + }() + select { + case <-ctx.Done(): + return errs.New("timeout, ctx graceful stop") + case <-done: + return nil + } +} diff --git a/pkg/common/tokenverify/token_verify.go b/pkg/common/tokenverify/token_verify.go new file mode 100644 index 0000000..f3e9012 --- /dev/null +++ b/pkg/common/tokenverify/token_verify.go @@ -0,0 +1,132 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tokenverify + +import ( + "time" + + "git.imall.cloud/openim/chat/pkg/common/constant" + "github.com/golang-jwt/jwt/v4" + "github.com/openimsdk/tools/errs" +) + +const ( + TokenUser = constant.NormalUser + TokenAdmin = constant.AdminUser +) + +type claims struct { + UserID string + UserType int32 + PlatformID int32 + jwt.RegisteredClaims +} + +type Token struct { + Expires time.Duration + Secret string +} + +func (t *Token) secret() jwt.Keyfunc { + return func(token *jwt.Token) (any, error) { + return []byte(t.Secret), nil + } +} + +func (t *Token) buildClaims(userID string, userType int32) claims { + now := time.Now() + return claims{ + UserID: userID, + UserType: userType, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(now.Add(t.Expires)), // Expiration time + IssuedAt: jwt.NewNumericDate(now), // Issuing time + NotBefore: jwt.NewNumericDate(now.Add(-time.Minute)), // Begin Effective time + }, + } +} + +func (t *Token) getToken(str string) (string, int32, error) { + token, err := jwt.ParseWithClaims(str, &claims{}, t.secret()) + if err != nil { + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + return "", 0, errs.ErrTokenMalformed.Wrap() + } else if ve.Errors&jwt.ValidationErrorExpired != 0 { + return "", 0, errs.ErrTokenExpired.Wrap() + } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { + return "", 0, errs.ErrTokenNotValidYet.Wrap() + } else { + return "", 0, errs.ErrTokenUnknown.Wrap() + } + } else { + return "", 0, errs.ErrTokenNotValidYet.Wrap() + } + } else { + claims, ok := token.Claims.(*claims) + if claims.PlatformID != 0 { + return "", 0, errs.ErrTokenExpired.Wrap() + } + if ok && token.Valid { + return claims.UserID, claims.UserType, nil + } + return "", 0, errs.ErrTokenNotValidYet.Wrap() + } +} + +func (t *Token) CreateToken(UserID string, userType int32) (string, time.Duration, error) { + if !(userType == TokenUser || userType == TokenAdmin) { + return "", 0, errs.ErrTokenUnknown.WrapMsg("token type unknown") + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, t.buildClaims(UserID, userType)) + str, err := token.SignedString([]byte(t.Secret)) + if err != nil { + return "", 0, errs.Wrap(err) + } + return str, t.Expires, nil +} + +func (t *Token) GetToken(token string) (string, int32, error) { + userID, userType, err := t.getToken(token) + if err != nil { + return "", 0, err + } + if !(userType == TokenUser || userType == TokenAdmin) { + return "", 0, errs.ErrTokenUnknown.WrapMsg("token type unknown") + } + return userID, userType, nil +} + +//func (t *Token) GetAdminTokenCache(token string) (string, error) { +// userID, userType, err := getToken(token) +// if err != nil { +// return "", err +// } +// if userType != TokenAdmin { +// return "", errs.ErrTokenUnknown.WrapMsg("token type error") +// } +// return userID, nil +//} +// +//func (t *Token) GetUserToken(token string) (string, error) { +// userID, userType, err := getToken(token) +// if err != nil { +// return "", err +// } +// if userType != TokenUser { +// return "", errs.ErrTokenUnknown.WrapMsg("token type error") +// } +// return userID, nil +//} diff --git a/pkg/common/util/aes.go b/pkg/common/util/aes.go new file mode 100644 index 0000000..6479cb3 --- /dev/null +++ b/pkg/common/util/aes.go @@ -0,0 +1,248 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "fmt" + "io" + "time" + + "github.com/openimsdk/tools/errs" +) + +const ( + // AES密钥字符串 + aesKeyString = "F9cLjK3FgkvcR6vaWZKEj3DYJfwrIHMULLwpmDAj553mpmlvMYoLNIqajLnhIsWq" +) + +// DecryptVerifyCode 解密验证码 +// encryptedText: Base64编码的加密字符串 +// 返回: 解密后的明文(格式:验证码-时间戳) +func DecryptVerifyCode(encryptedText string) (string, error) { + // 解码Base64 + encrypted, err := base64.StdEncoding.DecodeString(encryptedText) + if err != nil { + return "", errs.WrapMsg(err, "base64解码失败") + } + + // 使用SHA-256哈希密钥字符串 + keyBytes := sha256.Sum256([]byte(aesKeyString)) + key := keyBytes[:] + + // 创建AES cipher + block, err := aes.NewCipher(key) + if err != nil { + return "", errs.WrapMsg(err, "创建AES cipher失败") + } + + // 检查密文长度 + if len(encrypted) < aes.BlockSize { + return "", errs.New("密文长度不足") + } + + // 使用CBC模式,固定IV(全零) + iv := make([]byte, aes.BlockSize) // 全零IV + mode := cipher.NewCBCDecrypter(block, iv) + + // 解密 + decrypted := make([]byte, len(encrypted)) + mode.CryptBlocks(decrypted, encrypted) + + // 去除PKCS7填充 + decrypted = unpadPKCS7(decrypted) + + return string(decrypted), nil +} + +// unpadPKCS7 去除PKCS7填充 +func unpadPKCS7(data []byte) []byte { + if len(data) == 0 { + return data + } + padLen := int(data[len(data)-1]) + if padLen > len(data) || padLen == 0 { + return data + } + // 验证填充 + for i := len(data) - padLen; i < len(data); i++ { + if data[i] != byte(padLen) { + return data + } + } + return data[:len(data)-padLen] +} + +// ParseVerifyCodeWithTimestamp 解析验证码和时间戳 +// format: "验证码-时间戳" +// 返回: 验证码字符串和时间戳(毫秒) +func ParseVerifyCodeWithTimestamp(decryptedText string) (string, int64, error) { + var code string + var timestamp int64 + + // 查找最后一个 "-" 分隔符 + lastDashIndex := -1 + for i := len(decryptedText) - 1; i >= 0; i-- { + if decryptedText[i] == '-' { + lastDashIndex = i + break + } + } + + if lastDashIndex == -1 { + return "", 0, errs.New("格式错误:未找到时间戳分隔符") + } + + code = decryptedText[:lastDashIndex] + timestampStr := decryptedText[lastDashIndex+1:] + + // 解析时间戳 + _, err := fmt.Sscanf(timestampStr, "%d", ×tamp) + if err != nil { + return "", 0, errs.WrapMsg(err, "解析时间戳失败") + } + + return code, timestamp, nil +} + +// ValidateTimestamp 验证时间戳是否在有效期内 +// timestamp: 毫秒级时间戳 +// maxAgeSeconds: 最大允许的秒数(允许的时间差,默认30秒) +// 返回: 是否有效 +func ValidateTimestamp(timestamp int64, maxAgeSeconds int64) bool { + if timestamp <= 0 { + return false + } + + currentTime := getCurrentTimestamp() + diff := currentTime - timestamp + + // 转换为毫秒 + maxAgeMillis := maxAgeSeconds * 1000 + + // 时间戳不能是未来的(允许5秒的时钟偏差) + if diff < -5000 { + return false + } + + // 时间差不能超过maxAgeSeconds秒 + if diff > maxAgeMillis { + return false + } + + return true +} + +// getCurrentTimestamp 获取当前时间戳(毫秒) +func getCurrentTimestamp() int64 { + return time.Now().UnixMilli() +} + +// padPKCS7 添加PKCS7填充 +func padPKCS7(data []byte, blockSize int) []byte { + padLen := blockSize - len(data)%blockSize + pad := make([]byte, padLen) + for i := range pad { + pad[i] = byte(padLen) + } + return append(data, pad...) +} + +// EncryptPhone 加密手机号 +// phoneNumber: 手机号明文 +// 返回: Base64编码的加密字符串 +func EncryptPhone(phoneNumber string) (string, error) { + if phoneNumber == "" { + return "", errs.New("手机号不能为空") + } + + // 使用SHA-256哈希密钥字符串 + keyBytes := sha256.Sum256([]byte(aesKeyString)) + key := keyBytes[:] + + // 创建AES cipher + block, err := aes.NewCipher(key) + if err != nil { + return "", errs.WrapMsg(err, "创建AES cipher失败") + } + + // 使用CBC模式,固定IV(全零) + iv := make([]byte, aes.BlockSize) // 全零IV + + // 添加PKCS7填充 + plaintext := padPKCS7([]byte(phoneNumber), aes.BlockSize) + + // 加密 + mode := cipher.NewCBCEncrypter(block, iv) + encrypted := make([]byte, len(plaintext)) + mode.CryptBlocks(encrypted, plaintext) + + // 编码为Base64 + return base64.StdEncoding.EncodeToString(encrypted), nil +} + +// DecryptPhone 解密手机号 +// encryptedText: Base64编码的加密字符串 +// 返回: 解密后的手机号明文 +func DecryptPhone(encryptedText string) (string, error) { + // 复用DecryptVerifyCode的解密逻辑(手机号没有时间戳格式,直接解密) + return DecryptVerifyCode(encryptedText) +} + +// EncryptRealNameAuthData 加密实名认证数据(使用 AES-GCM 模式) +// data: JSON字符串,例如: {"cardNo":"330329199001021122","realName":"李四"} +// key: AES密钥字符串(与服务端相同的默认密钥) +// 返回: Base64编码的加密字符串 +func EncryptRealNameAuthData(data string, key string) (string, error) { + if data == "" { + return "", errs.New("数据不能为空") + } + if key == "" { + return "", errs.New("密钥不能为空") + } + + // 使用 SHA256 哈希密钥字符串(与服务端保持一致) + // 注意:直接对密钥字符串进行哈希,而不是先转换为字节 + hash := sha256.Sum256([]byte(key)) + aesKey := hash[:] + + // 创建AES cipher + block, err := aes.NewCipher(aesKey) + if err != nil { + return "", errs.WrapMsg(err, "创建AES cipher失败") + } + + // 使用 GCM 模式 + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", errs.WrapMsg(err, "创建 GCM 失败") + } + + // 生成随机 nonce + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return "", errs.WrapMsg(err, "生成 nonce 失败") + } + + // 加密 + ciphertext := gcm.Seal(nonce, nonce, []byte(data), nil) + + // 编码为Base64 + return base64.StdEncoding.EncodeToString(ciphertext), nil +} diff --git a/pkg/common/version/base.go b/pkg/common/version/base.go new file mode 100644 index 0000000..0ca04cd --- /dev/null +++ b/pkg/common/version/base.go @@ -0,0 +1,61 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +// Base version information. +// +// This is the fallback data used when version information from git is not +// provided via go ldflags. It provides an approximation of the Kubernetes +// version for ad-hoc builds (e.g. `go build`) that cannot get the version +// information from git. +// +// If you are looking at these fields in the git tree, they look +// strange. They are modified on the fly by the build process. The +// in-tree values are dummy values used for "git archive", which also +// works for GitHub tar downloads. +// +// When releasing a new Kubernetes version, this file is updated by +// build/mark_new_version.sh to reflect the new version, and then a +// git annotated tag (using format vX.Y where X == Major version and Y +// == Minor version) is created to point to the commit that updates +var ( + // TODO: Deprecate gitMajor and gitMinor, use only gitVersion + // instead. First step in deprecation, keep the fields but make + // them irrelevant. (Next we'll take it out, which may muck with + // scripts consuming the kubectl version output - but most of + // these should be looking at gitVersion already anyways.) + gitMajor string = "" // major version, always numeric + gitMinor string = "" // minor version, numeric possibly followed by "+" + + // semantic version, derived by build scripts (see + // https://github.com/kubernetes/sig-release/blob/master/release-engineering/versioning.md#kubernetes-release-versioning + // https://kubernetes.io/releases/version-skew-policy/ + // for a detailed discussion of this field) + // + // TODO: This field is still called "gitVersion" for legacy + // reasons. For prerelease versions, the build metadata on the + // semantic version is a git hash, but the version itself is no + // longer the direct output of "git describe", but a slight + // translation to be semver compliant. + + // NOTE: The $Format strings are replaced during 'git archive' thanks to the + // companion .gitattributes file containing 'export-subst' in this same + // directory. See also https://git-scm.com/docs/gitattributes + gitVersion string = "latest" + gitCommit string = "" // sha1 from git, output of $(git rev-parse HEAD) + gitTreeState string = "" // state of git tree, either "clean" or "dirty" + + buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') +) \ No newline at end of file diff --git a/pkg/common/version/types.go b/pkg/common/version/types.go new file mode 100644 index 0000000..c2bd8bb --- /dev/null +++ b/pkg/common/version/types.go @@ -0,0 +1,34 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +// Info contains versioning information. +// TODO: Add []string of api versions supported? It's still unclear +// how we'll want to distribute that information. +type Info struct { + Major string `json:"major,omitempty"` + Minor string `json:"minor,omitempty"` + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit,omitempty"` + BuildDate string `json:"buildDate"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` +} + +// String returns info as a human-friendly version string. +func (info Info) String() string { + return info.GitVersion +} \ No newline at end of file diff --git a/pkg/common/version/version.go b/pkg/common/version/version.go new file mode 100644 index 0000000..24cfee7 --- /dev/null +++ b/pkg/common/version/version.go @@ -0,0 +1,52 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +import ( + "fmt" + "runtime" +) + +// Get returns the overall codebase version. It's for detecting +// what code a binary was built from. +func Get() Info { + // These variables typically come from -ldflags settings and in + // their absence fallback to the settings in ./base.go + return Info{ + Major: gitMajor, + Minor: gitMinor, + GitVersion: gitVersion, + GitCommit: gitCommit, + BuildDate: buildDate, + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } +} + +// GetSingleVersion returns single version of sealer +func GetSingleVersion() string { + return gitVersion +} + +type Output struct { + OpenIMChatVersion Info `json:"OpenIMChatVersion,omitempty" yaml:"OpenIMChatVersion,omitempty"` + OpenIMServerVersion *OpenIMServerVersion `json:"OpenIMServerVersion,omitempty" yaml:"OpenIMServerVersion,omitempty"` +} + +type OpenIMServerVersion struct { + ServerVersion string `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"` + ClientVersion string `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"` //sdk core version +} \ No newline at end of file diff --git a/pkg/common/xlsx/main.go b/pkg/common/xlsx/main.go new file mode 100644 index 0000000..3606d8b --- /dev/null +++ b/pkg/common/xlsx/main.go @@ -0,0 +1,115 @@ +package xlsx + +import ( + "errors" + "github.com/xuri/excelize/v2" + "io" + "reflect" +) + +func ParseSheet(file *excelize.File, v interface{}) error { + val := reflect.ValueOf(v) + if val.Kind() != reflect.Ptr { + return errors.New("not ptr") + } + val = val.Elem() + if val.Kind() != reflect.Slice { + return errors.New("not slice") + } + itemType := val.Type().Elem() + if itemType.Kind() != reflect.Struct { + return errors.New("not struct") + } + newItemValue := func() reflect.Value { + return reflect.New(itemType).Elem() + } + putItem := func(v reflect.Value) { + val.Set(reflect.Append(val, v)) + } + var sheetName string + if s, ok := newItemValue().Interface().(SheetName); ok { + sheetName = s.SheetName() + } else { + sheetName = itemType.Name() + } + + if sheetIndex, err := file.GetSheetIndex(sheetName); err != nil { + return err + } else if sheetIndex < 0 { + return nil + } + fieldIndex := make(map[string]int) + for i := 0; i < itemType.NumField(); i++ { + field := itemType.Field(i) + alias := field.Tag.Get("column") + switch alias { + case "": + fieldIndex[field.Name] = i + case "-": + continue + default: + fieldIndex[alias] = i + } + } + if len(fieldIndex) == 0 { + return errors.New("empty column struct") + } + sheetIndex := make(map[string]int) + for i := 1; ; i++ { + name, err := file.GetCellValue(sheetName, GetAxis(i, 1)) + if err != nil { + return err + } + if name == "" { + break + } + if _, ok := fieldIndex[name]; ok { + sheetIndex[name] = i + } + } + if len(sheetIndex) == 0 { + return errors.New("sheet column empty") + } + for i := 2; ; i++ { + var ( + notEmpty int + item = newItemValue() + ) + for column, index := range sheetIndex { + s, err := file.GetCellValue(sheetName, GetAxis(index, i)) + if err != nil { + return err + } + if s == "" { + continue + } + notEmpty++ + if err = String2Value(s, item.Field(fieldIndex[column])); err != nil { + return err + } + } + if notEmpty > 0 { + putItem(item) + } else { + break + } + } + return nil +} + +func ParseAll(r io.Reader, models ...interface{}) error { + if len(models) == 0 { + return errors.New("empty models") + } + file, err := excelize.OpenReader(r) + if err != nil { + return err + } + defer file.Close() + for i := 0; i < len(models); i++ { + if err := ParseSheet(file, models[i]); err != nil { + return err + } + } + return nil +} diff --git a/pkg/common/xlsx/model/user.go b/pkg/common/xlsx/model/user.go new file mode 100644 index 0000000..ada74bf --- /dev/null +++ b/pkg/common/xlsx/model/user.go @@ -0,0 +1,18 @@ +package model + +type User struct { + UserID string `column:"user_id"` + Nickname string `column:"nickname"` + FaceURL string `column:"face_url"` + Birth string `column:"birth"` + Gender string `column:"gender"` + AreaCode string `column:"area_code"` + PhoneNumber string `column:"phone_number"` + Email string `column:"email"` + Account string `column:"account"` + Password string `column:"password"` +} + +func (User) SheetName() string { + return "user" +} diff --git a/pkg/common/xlsx/sheet.go b/pkg/common/xlsx/sheet.go new file mode 100644 index 0000000..f5a90d6 --- /dev/null +++ b/pkg/common/xlsx/sheet.go @@ -0,0 +1,5 @@ +package xlsx + +type SheetName interface { + SheetName() string +} diff --git a/pkg/common/xlsx/utils.go b/pkg/common/xlsx/utils.go new file mode 100644 index 0000000..fea67dc --- /dev/null +++ b/pkg/common/xlsx/utils.go @@ -0,0 +1,199 @@ +package xlsx + +import ( + "errors" + "fmt" + "github.com/xuri/excelize/v2" + "io" + "reflect" + "strconv" + "strings" +) + +func Open(r io.Reader) (*excelize.File, error) { + return excelize.OpenReader(r) +} + +func GetAxis(x, y int) string { + return Num2AZ(x) + strconv.Itoa(y) +} + +func Num2AZ(num int) string { + var ( + str string + k int + temp []int + ) + slices := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"} + + if num > 26 { + for { + k = num % 26 + if k == 0 { + temp = append(temp, 26) + k = 26 + } else { + temp = append(temp, k) + } + num = (num - k) / 26 + if num <= 26 { + temp = append(temp, num) + break + } + } + } else { + return slices[num] + } + for _, value := range temp { + str = slices[value] + str + } + return str +} + +func String2Value(s string, rv reflect.Value) error { + var ( + val interface{} + err error + ) + if s == "" { + val = reflect.Zero(rv.Type()).Interface() + } else { + switch rv.Kind() { + case reflect.Bool: + switch strings.ToLower(s) { + case "false", "f", "0": + val = false + case "true", "t", "1": + val = true + default: + return fmt.Errorf("parse %s to bool error", s) + } + case reflect.Int: + val, err = strconv.Atoi(s) + case reflect.Int8: + t, err := strconv.ParseInt(s, 10, 8) + if err != nil { + return err + } + val = int8(t) + case reflect.Int16: + t, err := strconv.ParseInt(s, 10, 16) + if err != nil { + return err + } + val = int16(t) + case reflect.Int32: + t, err := strconv.ParseInt(s, 10, 32) + if err != nil { + return err + } + val = int32(t) + case reflect.Int64: + val, err = strconv.ParseInt(s, 10, 64) + case reflect.Uint: + t, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return err + } + val = uint(t) + case reflect.Uint8: + t, err := strconv.ParseUint(s, 10, 8) + if err != nil { + return err + } + val = uint8(t) + case reflect.Uint16: + t, err := strconv.ParseUint(s, 10, 16) + if err != nil { + return err + } + val = uint16(t) + case reflect.Uint32: + t, err := strconv.ParseUint(s, 10, 32) + if err != nil { + return err + } + val = uint32(t) + case reflect.Uint64: + val, err = strconv.ParseUint(s, 10, 64) + case reflect.Float32: + t, err := strconv.ParseFloat(s, 32) + if err != nil { + return err + } + val = float32(t) + case reflect.Float64: + val, err = strconv.ParseFloat(s, 64) + case reflect.String: + val = s + default: + return errors.New("not Supported " + rv.Kind().String()) + } + } + if err != nil { + return err + } + rv.Set(reflect.ValueOf(val)) + return nil +} + +func ZeroValue(kind reflect.Kind) (interface{}, error) { + var v interface{} + switch kind { + case reflect.Bool: + v = false + case reflect.Int: + v = int(0) + case reflect.Int8: + v = int8(0) + case reflect.Int16: + v = int16(0) + case reflect.Int32: + v = int32(0) + case reflect.Int64: + v = int64(0) + case reflect.Uint: + v = uint(0) + case reflect.Uint8: + v = uint8(0) + case reflect.Uint16: + v = uint16(0) + case reflect.Uint32: + v = uint32(0) + case reflect.Uint64: + v = uint64(0) + case reflect.Float32: + v = float32(0) + case reflect.Float64: + v = float64(0) + case reflect.String: + v = "" + default: + return nil, errors.New("not Supported " + kind.String()) + } + return v, nil +} + +func GetSheetName(v interface{}) string { + return getSheetName(reflect.TypeOf(v)) +} + +func getSheetName(t reflect.Type) string { + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.Slice { + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return "" + } + if s, ok := reflect.New(t).Interface().(SheetName); ok { + return s.SheetName() + } else { + return t.Name() + } +} diff --git a/pkg/eerrs/predefine.go b/pkg/eerrs/predefine.go new file mode 100644 index 0000000..7134137 --- /dev/null +++ b/pkg/eerrs/predefine.go @@ -0,0 +1,41 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eerrs + +import "github.com/openimsdk/tools/errs" + +var ( + ErrPassword = errs.NewCodeError(20001, "PasswordError") + ErrAccountNotFound = errs.NewCodeError(20002, "AccountNotFound") + ErrPhoneAlreadyRegister = errs.NewCodeError(20003, "PhoneAlreadyRegister") + ErrAccountAlreadyRegister = errs.NewCodeError(20004, "AccountAlreadyRegister") + ErrVerifyCodeSendFrequently = errs.NewCodeError(20005, "VerifyCodeSendFrequently") + ErrVerifyCodeNotMatch = errs.NewCodeError(20006, "VerifyCodeNotMatch") + ErrVerifyCodeExpired = errs.NewCodeError(20007, "VerifyCodeExpired") + ErrVerifyCodeMaxCount = errs.NewCodeError(20008, "VerifyCodeMaxCount") + ErrVerifyCodeUsed = errs.NewCodeError(20009, "VerifyCodeUsed") + ErrInvitationCodeUsed = errs.NewCodeError(20010, "InvitationCodeUsed") + ErrInvitationNotFound = errs.NewCodeError(20011, "InvitationNotFound") + ErrForbidden = errs.NewCodeError(20012, "Forbidden") + ErrAccountBlocked = errs.NewCodeError(20015, "AccountBlocked") + ErrRefuseFriend = errs.NewCodeError(20013, "RefuseFriend") + ErrEmailAlreadyRegister = errs.NewCodeError(20014, "EmailAlreadyRegister") + ErrGoogleAuthCodeRequired = errs.NewCodeError(20016, "GoogleAuthCodeRequired") + ErrGoogleAuthCodeNotMatch = errs.NewCodeError(20017, "GoogleAuthCodeNotMatch") + ErrPaymentPassword = errs.NewCodeError(20018, "PaymentPasswordError") // 支付密码错误 + ErrInsufficientBalance = errs.NewCodeError(20019, "InsufficientBalance") // 余额不足 + + ErrTokenNotExist = errs.NewCodeError(20101, "ErrTokenNotExist") +) diff --git a/pkg/email/mail.go b/pkg/email/mail.go new file mode 100644 index 0000000..1c1d2d1 --- /dev/null +++ b/pkg/email/mail.go @@ -0,0 +1,55 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package email + +import ( + "context" + "fmt" + "github.com/openimsdk/tools/errs" + "gopkg.in/gomail.v2" +) + +type Mail interface { + Name() string + SendMail(ctx context.Context, mail string, verifyCode string) error +} + +func NewMail(smtpAddr string, smtpPort int, senderMail, senderAuthorizationCode, title string) Mail { + dail := gomail.NewDialer(smtpAddr, smtpPort, senderMail, senderAuthorizationCode) + return &mail{ + title: title, + senderMail: senderMail, + dail: dail, + } +} + +type mail struct { + senderMail string + title string + dail *gomail.Dialer +} + +func (m *mail) Name() string { + return "mail" +} + +func (m *mail) SendMail(ctx context.Context, mail string, verifyCode string) error { + msg := gomail.NewMessage() + msg.SetHeader(`From`, m.senderMail) + msg.SetHeader(`To`, []string{mail}...) + msg.SetHeader(`Subject`, m.title) + msg.SetBody(`text/html`, fmt.Sprintf("Your verification code is: %s. This code is valid for 5 minutes and should not be shared with others", verifyCode)) + return errs.Wrap(m.dail.DialAndSend(msg)) +} diff --git a/pkg/email/mail_test.go b/pkg/email/mail_test.go new file mode 100644 index 0000000..0f9ebe3 --- /dev/null +++ b/pkg/email/mail_test.go @@ -0,0 +1,51 @@ +package email + +//func TestEmail(T *testing.T) { +// if err := InitConfig(); err != nil { +// fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) +// os.Exit(-1) +// } +// tests := []struct { +// name string +// ctx context.Context +// mail string +// code string +// want error +// }{ +// { +// name: "success send email", +// ctx: context.Background(), +// mail: "test@gmail.com", +// code: "5555", +// want: errors.New("nil"), +// }, +// { +// name: "fail send email", +// ctx: context.Background(), +// mail: "", +// code: "5555", +// want: errors.New("dial tcp :0: connectex: The requested address is not valid in its context."), +// }, +// } +// mail := NewMail() +// +// for _, tt := range tests { +// T.Run(tt.name, func(t *testing.T) { +// if got := mail.SendMail(tt.ctx, tt.mail, tt.code); errors.Is(got, tt.want) { +// t.Errorf("%v have a err,%v", tt.name, tt.want) +// } +// }) +// } +//} +// +//func InitConfig() error { +// yam, err := ioutil.ReadFile("../../config/config.yaml") +// if err != nil { +// return err +// } +// err = yaml.Unmarshal(yam, &config.Config) +// if err != nil { +// return err +// } +// return nil +//} diff --git a/pkg/protocol/admin/admin.go b/pkg/protocol/admin/admin.go new file mode 100644 index 0000000..1f4490e --- /dev/null +++ b/pkg/protocol/admin/admin.go @@ -0,0 +1,518 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import ( + "git.imall.cloud/openim/chat/pkg/common/constant" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" +) + +func (x *LoginReq) Check() error { + if x.Account == "" { + return errs.ErrArgs.WrapMsg("account is empty") + } + if x.Password == "" { + return errs.ErrArgs.WrapMsg("password is empty") + } + return nil +} + +func (x *ChangePasswordReq) Check() error { + if x.Password == "" { + return errs.ErrArgs.WrapMsg("password is empty") + } + return nil +} + +func (x *AddDefaultFriendReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + if datautil.Duplicate(x.UserIDs) { + return errs.ErrArgs.WrapMsg("userIDs has duplicate") + } + return nil +} + +func (x *DelDefaultFriendReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *SearchDefaultFriendReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *AddDefaultGroupReq) Check() error { + if x.GroupIDs == nil { + return errs.ErrArgs.WrapMsg("GroupIDs is empty") + } + if datautil.Duplicate(x.GroupIDs) { + return errs.ErrArgs.WrapMsg("GroupIDs has duplicate") + } + return nil +} + +func (x *DelDefaultGroupReq) Check() error { + if x.GroupIDs == nil { + return errs.ErrArgs.WrapMsg("GroupIDs is empty") + } + return nil +} + +func (x *SearchDefaultGroupReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *AddInvitationCodeReq) Check() error { + if x.Codes == nil { + return errs.ErrArgs.WrapMsg("codes is invalid") + } + return nil +} + +func (x *GenInvitationCodeReq) Check() error { + if x.Len < 1 { + return errs.ErrArgs.WrapMsg("len is invalid") + } + if x.Num < 1 { + return errs.ErrArgs.WrapMsg("num is invalid") + } + if x.Chars == "" { + return errs.ErrArgs.WrapMsg("chars is in invalid") + } + return nil +} + +func (x *FindInvitationCodeReq) Check() error { + if x.Codes == nil { + return errs.ErrArgs.WrapMsg("codes is empty") + } + return nil +} + +func (x *UseInvitationCodeReq) Check() error { + if x.Code == "" { + return errs.ErrArgs.WrapMsg("code is empty") + } + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + return nil +} + +func (x *DelInvitationCodeReq) Check() error { + if x.Codes == nil { + return errs.ErrArgs.WrapMsg("codes is empty") + } + return nil +} + +func (x *SearchInvitationCodeReq) Check() error { + if !datautil.Contain(x.Status, constant.InvitationCodeUnused, constant.InvitationCodeUsed, constant.InvitationCodeAll) { + return errs.ErrArgs.WrapMsg("state invalid") + } + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *SearchUserIPLimitLoginReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *AddUserIPLimitLoginReq) Check() error { + if x.Limits == nil { + return errs.ErrArgs.WrapMsg("limits is empty") + } + return nil +} + +func (x *DelUserIPLimitLoginReq) Check() error { + if x.Limits == nil { + return errs.ErrArgs.WrapMsg("limits is empty") + } + return nil +} + +func (x *SearchIPForbiddenReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *AddIPForbiddenReq) Check() error { + if x.Forbiddens == nil { + return errs.ErrArgs.WrapMsg("forbiddens is empty") + } + return nil +} + +func (x *DelIPForbiddenReq) Check() error { + if x.Ips == nil { + return errs.ErrArgs.WrapMsg("ips is empty") + } + return nil +} + +func (x *CheckRegisterForbiddenReq) Check() error { + if x.Ip == "" { + return errs.ErrArgs.WrapMsg("ip is empty") + } + return nil +} + +func (x *CheckLoginForbiddenReq) Check() error { + if x.Ip == "" && x.UserID == "" { + return errs.ErrArgs.WrapMsg("ip and userID is empty") + } + return nil +} + +func (x *CancellationUserReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + return nil +} + +func (x *BlockUserReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + return nil +} + +func (x *UnblockUserReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *SearchBlockUserReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *FindUserBlockInfoReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *CreateTokenReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + if x.UserType > constant.AdminUser || x.UserType < constant.NormalUser { + return errs.ErrArgs.WrapMsg("userType is invalid") + } + return nil +} + +func (x *ParseTokenReq) Check() error { + if x.Token == "" { + return errs.ErrArgs.WrapMsg("token is empty") + } + return nil +} + +func (x *AddAppletReq) Check() error { + if x.Name == "" { + return errs.ErrArgs.WrapMsg("name is empty") + } + if x.AppID == "" { + return errs.ErrArgs.WrapMsg("appID is empty") + } + if x.Icon == "" { + return errs.ErrArgs.WrapMsg("icon is empty") + } + if x.Url == "" { + return errs.ErrArgs.WrapMsg("url is empty") + } + if x.Md5 == "" { + return errs.ErrArgs.WrapMsg("md5 is empty") + } + if x.Size <= 0 { + return errs.ErrArgs.WrapMsg("size is invalid") + } + if x.Version == "" { + return errs.ErrArgs.WrapMsg("version is empty") + } + if x.Status < constant.StatusOnShelf || x.Status > constant.StatusUnShelf { + return errs.ErrArgs.WrapMsg("status is invalid") + } + return nil +} + +func (x *DelAppletReq) Check() error { + if x.AppletIds == nil { + return errs.ErrArgs.WrapMsg("appletIds is empty") + } + return nil +} + +func (x *UpdateAppletReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *SearchAppletReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *SetClientConfigReq) Check() error { + if x.Config == nil { + return errs.ErrArgs.WrapMsg("config is empty") + } + return nil +} + +func (x *ChangeAdminPasswordReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + if x.CurrentPassword == "" { + return errs.ErrArgs.WrapMsg("currentPassword is empty") + } + if x.NewPassword == "" { + return errs.ErrArgs.WrapMsg("newPassword is empty") + } + if x.CurrentPassword == x.NewPassword { + return errs.ErrArgs.WrapMsg("currentPassword is equal to newPassword") + } + return nil +} + +func (x *AddAdminAccountReq) Check() error { + if x.Account == "" { + return errs.ErrArgs.WrapMsg("account is empty") + } + if x.Password == "" { + return errs.ErrArgs.WrapMsg("password is empty") + } + return nil +} + +func (x *DelAdminAccountReq) Check() error { + if len(x.UserIDs) == 0 { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *SearchAdminAccountReq) Check() error { + if x.Pagination.ShowNumber == 0 { + return errs.ErrArgs.WrapMsg("showNumber is empty") + } + if x.Pagination.PageNumber == 0 { + return errs.ErrArgs.WrapMsg("pageNumber is empty") + } + return nil +} + +// ==================== 敏感词管理相关 Check() 方法 ==================== + +func (x *AddSensitiveWordReq) Check() error { + if x.Word == "" { + return errs.ErrArgs.WrapMsg("word is empty") + } + return nil +} + +func (x *UpdateSensitiveWordReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *DeleteSensitiveWordReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *SearchSensitiveWordsReq) Check() error { + if x.Pagination.ShowNumber == 0 { + return errs.ErrArgs.WrapMsg("showNumber is empty") + } + if x.Pagination.PageNumber == 0 { + return errs.ErrArgs.WrapMsg("pageNumber is empty") + } + return nil +} + +func (x *BatchAddSensitiveWordsReq) Check() error { + if len(x.Words) == 0 { + return errs.ErrArgs.WrapMsg("words is empty") + } + return nil +} + +func (x *BatchUpdateSensitiveWordsReq) Check() error { + if len(x.Updates) == 0 { + return errs.ErrArgs.WrapMsg("updates is empty") + } + return nil +} + +func (x *BatchDeleteSensitiveWordsReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *AddSensitiveWordGroupReq) Check() error { + if x.Name == "" { + return errs.ErrArgs.WrapMsg("name is empty") + } + return nil +} + +func (x *UpdateSensitiveWordGroupReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *DeleteSensitiveWordGroupReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordGroupReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *GetAllSensitiveWordGroupsReq) Check() error { + return nil +} + +func (x *GetSensitiveWordConfigReq) Check() error { + return nil +} + +func (x *UpdateSensitiveWordConfigReq) Check() error { + if x.Config == nil { + return errs.ErrArgs.WrapMsg("config is empty") + } + return nil +} + +func (x *GetSensitiveWordLogsReq) Check() error { + if x.Pagination.ShowNumber == 0 { + return errs.ErrArgs.WrapMsg("showNumber is empty") + } + if x.Pagination.PageNumber == 0 { + return errs.ErrArgs.WrapMsg("pageNumber is empty") + } + return nil +} + +func (x *DeleteSensitiveWordLogsReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordStatsReq) Check() error { + return nil +} + +func (x *GetSensitiveWordLogStatsReq) Check() error { + return nil +} diff --git a/pkg/protocol/admin/admin.pb.go b/pkg/protocol/admin/admin.pb.go new file mode 100644 index 0000000..e6f8cc5 --- /dev/null +++ b/pkg/protocol/admin/admin.pb.go @@ -0,0 +1,18377 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v6.33.0 +// source: admin/admin.proto + +package admin + +import ( + common "git.imall.cloud/openim/chat/pkg/protocol/common" + sdkws "git.imall.cloud/openim/protocol/sdkws" + wrapperspb "git.imall.cloud/openim/protocol/wrapperspb" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// login +type LoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + GoogleAuthCode string `protobuf:"bytes,4,opt,name=googleAuthCode,proto3" json:"googleAuthCode"` // Google Authenticator 验证码(如果设置了 googleAuthKey 则必填) +} + +func (x *LoginReq) Reset() { + *x = LoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginReq) ProtoMessage() {} + +func (x *LoginReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginReq.ProtoReflect.Descriptor instead. +func (*LoginReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{0} +} + +func (x *LoginReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *LoginReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *LoginReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *LoginReq) GetGoogleAuthCode() string { + if x != nil { + return x.GoogleAuthCode + } + return "" +} + +type LoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AdminAccount string `protobuf:"bytes,1,opt,name=adminAccount,proto3" json:"adminAccount"` + AdminToken string `protobuf:"bytes,2,opt,name=adminToken,proto3" json:"adminToken"` + Nickname string `protobuf:"bytes,3,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,4,opt,name=faceURL,proto3" json:"faceURL"` + Level int32 `protobuf:"varint,5,opt,name=level,proto3" json:"level"` + AdminUserID string `protobuf:"bytes,6,opt,name=adminUserID,proto3" json:"adminUserID"` +} + +func (x *LoginResp) Reset() { + *x = LoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginResp) ProtoMessage() {} + +func (x *LoginResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginResp.ProtoReflect.Descriptor instead. +func (*LoginResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{1} +} + +func (x *LoginResp) GetAdminAccount() string { + if x != nil { + return x.AdminAccount + } + return "" +} + +func (x *LoginResp) GetAdminToken() string { + if x != nil { + return x.AdminToken + } + return "" +} + +func (x *LoginResp) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *LoginResp) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *LoginResp) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *LoginResp) GetAdminUserID() string { + if x != nil { + return x.AdminUserID + } + return "" +} + +type AddAdminAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` + Nickname string `protobuf:"bytes,4,opt,name=nickname,proto3" json:"nickname"` +} + +func (x *AddAdminAccountReq) Reset() { + *x = AddAdminAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddAdminAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddAdminAccountReq) ProtoMessage() {} + +func (x *AddAdminAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddAdminAccountReq.ProtoReflect.Descriptor instead. +func (*AddAdminAccountReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{2} +} + +func (x *AddAdminAccountReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *AddAdminAccountReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *AddAdminAccountReq) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *AddAdminAccountReq) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +type AddAdminAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddAdminAccountResp) Reset() { + *x = AddAdminAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddAdminAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddAdminAccountResp) ProtoMessage() {} + +func (x *AddAdminAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddAdminAccountResp.ProtoReflect.Descriptor instead. +func (*AddAdminAccountResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{3} +} + +type AdminUpdateInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Account *wrapperspb.StringValue `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` + Password *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=password,proto3" json:"password"` + FaceURL *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` + Nickname *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=nickname,proto3" json:"nickname"` + Level *wrapperspb.Int32Value `protobuf:"bytes,6,opt,name=level,proto3" json:"level"` + GoogleAuthKey *wrapperspb.StringValue `protobuf:"bytes,7,opt,name=googleAuthKey,proto3" json:"googleAuthKey"` + OperationPassword *wrapperspb.StringValue `protobuf:"bytes,9,opt,name=operationPassword,proto3" json:"operationPassword"` +} + +func (x *AdminUpdateInfoReq) Reset() { + *x = AdminUpdateInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AdminUpdateInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminUpdateInfoReq) ProtoMessage() {} + +func (x *AdminUpdateInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdminUpdateInfoReq.ProtoReflect.Descriptor instead. +func (*AdminUpdateInfoReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{4} +} + +func (x *AdminUpdateInfoReq) GetAccount() *wrapperspb.StringValue { + if x != nil { + return x.Account + } + return nil +} + +func (x *AdminUpdateInfoReq) GetPassword() *wrapperspb.StringValue { + if x != nil { + return x.Password + } + return nil +} + +func (x *AdminUpdateInfoReq) GetFaceURL() *wrapperspb.StringValue { + if x != nil { + return x.FaceURL + } + return nil +} + +func (x *AdminUpdateInfoReq) GetNickname() *wrapperspb.StringValue { + if x != nil { + return x.Nickname + } + return nil +} + +func (x *AdminUpdateInfoReq) GetLevel() *wrapperspb.Int32Value { + if x != nil { + return x.Level + } + return nil +} + +func (x *AdminUpdateInfoReq) GetGoogleAuthKey() *wrapperspb.StringValue { + if x != nil { + return x.GoogleAuthKey + } + return nil +} + +func (x *AdminUpdateInfoReq) GetOperationPassword() *wrapperspb.StringValue { + if x != nil { + return x.OperationPassword + } + return nil +} + +type AdminUpdateInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` +} + +func (x *AdminUpdateInfoResp) Reset() { + *x = AdminUpdateInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AdminUpdateInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminUpdateInfoResp) ProtoMessage() {} + +func (x *AdminUpdateInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdminUpdateInfoResp.ProtoReflect.Descriptor instead. +func (*AdminUpdateInfoResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{5} +} + +func (x *AdminUpdateInfoResp) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *AdminUpdateInfoResp) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *AdminUpdateInfoResp) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +type ChangePasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password"` + CurrentOperationPassword string `protobuf:"bytes,2,opt,name=currentOperationPassword,proto3" json:"currentOperationPassword"` // 当前操作密码(修改操作密码时需要) + NewOperationPassword string `protobuf:"bytes,3,opt,name=newOperationPassword,proto3" json:"newOperationPassword"` // 新操作密码(可选,如果提供则修改操作密码) +} + +func (x *ChangePasswordReq) Reset() { + *x = ChangePasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordReq) ProtoMessage() {} + +func (x *ChangePasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordReq.ProtoReflect.Descriptor instead. +func (*ChangePasswordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{6} +} + +func (x *ChangePasswordReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *ChangePasswordReq) GetCurrentOperationPassword() string { + if x != nil { + return x.CurrentOperationPassword + } + return "" +} + +func (x *ChangePasswordReq) GetNewOperationPassword() string { + if x != nil { + return x.NewOperationPassword + } + return "" +} + +type ChangePasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChangePasswordResp) Reset() { + *x = ChangePasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordResp) ProtoMessage() {} + +func (x *ChangePasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordResp.ProtoReflect.Descriptor instead. +func (*ChangePasswordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{7} +} + +type GetAdminInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAdminInfoReq) Reset() { + *x = GetAdminInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAdminInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdminInfoReq) ProtoMessage() {} + +func (x *GetAdminInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdminInfoReq.ProtoReflect.Descriptor instead. +func (*GetAdminInfoReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{8} +} + +type ChangeAdminPasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + CurrentPassword string `protobuf:"bytes,2,opt,name=currentPassword,proto3" json:"currentPassword"` + NewPassword string `protobuf:"bytes,3,opt,name=newPassword,proto3" json:"newPassword"` +} + +func (x *ChangeAdminPasswordReq) Reset() { + *x = ChangeAdminPasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangeAdminPasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangeAdminPasswordReq) ProtoMessage() {} + +func (x *ChangeAdminPasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangeAdminPasswordReq.ProtoReflect.Descriptor instead. +func (*ChangeAdminPasswordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{9} +} + +func (x *ChangeAdminPasswordReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *ChangeAdminPasswordReq) GetCurrentPassword() string { + if x != nil { + return x.CurrentPassword + } + return "" +} + +func (x *ChangeAdminPasswordReq) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +type ChangeAdminPasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChangeAdminPasswordResp) Reset() { + *x = ChangeAdminPasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangeAdminPasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangeAdminPasswordResp) ProtoMessage() {} + +func (x *ChangeAdminPasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangeAdminPasswordResp.ProtoReflect.Descriptor instead. +func (*ChangeAdminPasswordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{10} +} + +type ChangeOperationPasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CurrentPassword string `protobuf:"bytes,1,opt,name=currentPassword,proto3" json:"currentPassword"` // 当前操作密码(如果已设置) + NewPassword string `protobuf:"bytes,2,opt,name=newPassword,proto3" json:"newPassword"` // 新操作密码 +} + +func (x *ChangeOperationPasswordReq) Reset() { + *x = ChangeOperationPasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangeOperationPasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangeOperationPasswordReq) ProtoMessage() {} + +func (x *ChangeOperationPasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangeOperationPasswordReq.ProtoReflect.Descriptor instead. +func (*ChangeOperationPasswordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{11} +} + +func (x *ChangeOperationPasswordReq) GetCurrentPassword() string { + if x != nil { + return x.CurrentPassword + } + return "" +} + +func (x *ChangeOperationPasswordReq) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +type ChangeOperationPasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChangeOperationPasswordResp) Reset() { + *x = ChangeOperationPasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangeOperationPasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangeOperationPasswordResp) ProtoMessage() {} + +func (x *ChangeOperationPasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangeOperationPasswordResp.ProtoReflect.Descriptor instead. +func (*ChangeOperationPasswordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{12} +} + +type DelAdminAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *DelAdminAccountReq) Reset() { + *x = DelAdminAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelAdminAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelAdminAccountReq) ProtoMessage() {} + +func (x *DelAdminAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelAdminAccountReq.ProtoReflect.Descriptor instead. +func (*DelAdminAccountReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{13} +} + +func (x *DelAdminAccountReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type DelAdminAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelAdminAccountResp) Reset() { + *x = DelAdminAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelAdminAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelAdminAccountResp) ProtoMessage() {} + +func (x *DelAdminAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelAdminAccountResp.ProtoReflect.Descriptor instead. +func (*DelAdminAccountResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{14} +} + +type SearchAdminAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` // 搜索关键词(可选),支持账号、昵称、用户ID的模糊搜索 + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchAdminAccountReq) Reset() { + *x = SearchAdminAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchAdminAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchAdminAccountReq) ProtoMessage() {} + +func (x *SearchAdminAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchAdminAccountReq.ProtoReflect.Descriptor instead. +func (*SearchAdminAccountReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{15} +} + +func (x *SearchAdminAccountReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchAdminAccountReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchAdminAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + AdminAccounts []*GetAdminInfoResp `protobuf:"bytes,2,rep,name=adminAccounts,proto3" json:"adminAccounts"` +} + +func (x *SearchAdminAccountResp) Reset() { + *x = SearchAdminAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchAdminAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchAdminAccountResp) ProtoMessage() {} + +func (x *SearchAdminAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchAdminAccountResp.ProtoReflect.Descriptor instead. +func (*SearchAdminAccountResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{16} +} + +func (x *SearchAdminAccountResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchAdminAccountResp) GetAdminAccounts() []*GetAdminInfoResp { + if x != nil { + return x.AdminAccounts + } + return nil +} + +type GetAdminInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password"` + FaceURL string `protobuf:"bytes,4,opt,name=faceURL,proto3" json:"faceURL"` + Nickname string `protobuf:"bytes,5,opt,name=nickname,proto3" json:"nickname"` + UserID string `protobuf:"bytes,6,opt,name=userID,proto3" json:"userID"` + Level int32 `protobuf:"varint,7,opt,name=level,proto3" json:"level"` + CreateTime int64 `protobuf:"varint,8,opt,name=createTime,proto3" json:"createTime"` + GoogleAuthKey string `protobuf:"bytes,9,opt,name=googleAuthKey,proto3" json:"googleAuthKey"` + OperationPassword string `protobuf:"bytes,11,opt,name=operationPassword,proto3" json:"operationPassword"` +} + +func (x *GetAdminInfoResp) Reset() { + *x = GetAdminInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAdminInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdminInfoResp) ProtoMessage() {} + +func (x *GetAdminInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdminInfoResp.ProtoReflect.Descriptor instead. +func (*GetAdminInfoResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{17} +} + +func (x *GetAdminInfoResp) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *GetAdminInfoResp) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetAdminInfoResp) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *GetAdminInfoResp) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *GetAdminInfoResp) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GetAdminInfoResp) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *GetAdminInfoResp) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *GetAdminInfoResp) GetGoogleAuthKey() string { + if x != nil { + return x.GoogleAuthKey + } + return "" +} + +func (x *GetAdminInfoResp) GetOperationPassword() string { + if x != nil { + return x.OperationPassword + } + return "" +} + +// 设置谷歌身份验证密钥请求 +type SetGoogleAuthKeyReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OperationType int32 `protobuf:"varint,1,opt,name=operationType,proto3" json:"operationType"` // 操作类型:1-新设置(如果为空则设置,如果已存在则返回错误),2-强制覆盖旧的(即使存在也生成新的),3-清空(删除现有的密钥) + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 目标管理员ID,可选;为空时默认当前登录管理员,非空时仅超级管理员可操作 +} + +func (x *SetGoogleAuthKeyReq) Reset() { + *x = SetGoogleAuthKeyReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetGoogleAuthKeyReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetGoogleAuthKeyReq) ProtoMessage() {} + +func (x *SetGoogleAuthKeyReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetGoogleAuthKeyReq.ProtoReflect.Descriptor instead. +func (*SetGoogleAuthKeyReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{18} +} + +func (x *SetGoogleAuthKeyReq) GetOperationType() int32 { + if x != nil { + return x.OperationType + } + return 0 +} + +func (x *SetGoogleAuthKeyReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +// 设置谷歌身份验证密钥响应 +type SetGoogleAuthKeyResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GoogleAuthKey string `protobuf:"bytes,1,opt,name=googleAuthKey,proto3" json:"googleAuthKey"` // 生成的谷歌身份验证密钥(Base32编码),操作类型为3(清空)时为空字符串 + QrCodeURL string `protobuf:"bytes,2,opt,name=qrCodeURL,proto3" json:"qrCodeURL"` // 二维码URL(otpauth格式),用于扫码绑定到Google Authenticator,操作类型为3(清空)时为空字符串 + OperationType int32 `protobuf:"varint,3,opt,name=operationType,proto3" json:"operationType"` // 实际执行的操作类型:1-新设置,2-强制覆盖,3-清空 +} + +func (x *SetGoogleAuthKeyResp) Reset() { + *x = SetGoogleAuthKeyResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetGoogleAuthKeyResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetGoogleAuthKeyResp) ProtoMessage() {} + +func (x *SetGoogleAuthKeyResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetGoogleAuthKeyResp.ProtoReflect.Descriptor instead. +func (*SetGoogleAuthKeyResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{19} +} + +func (x *SetGoogleAuthKeyResp) GetGoogleAuthKey() string { + if x != nil { + return x.GoogleAuthKey + } + return "" +} + +func (x *SetGoogleAuthKeyResp) GetQrCodeURL() string { + if x != nil { + return x.QrCodeURL + } + return "" +} + +func (x *SetGoogleAuthKeyResp) GetOperationType() int32 { + if x != nil { + return x.OperationType + } + return 0 +} + +type AddDefaultFriendReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *AddDefaultFriendReq) Reset() { + *x = AddDefaultFriendReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddDefaultFriendReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddDefaultFriendReq) ProtoMessage() {} + +func (x *AddDefaultFriendReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddDefaultFriendReq.ProtoReflect.Descriptor instead. +func (*AddDefaultFriendReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{20} +} + +func (x *AddDefaultFriendReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type AddDefaultFriendResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddDefaultFriendResp) Reset() { + *x = AddDefaultFriendResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddDefaultFriendResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddDefaultFriendResp) ProtoMessage() {} + +func (x *AddDefaultFriendResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddDefaultFriendResp.ProtoReflect.Descriptor instead. +func (*AddDefaultFriendResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{21} +} + +type DelDefaultFriendReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *DelDefaultFriendReq) Reset() { + *x = DelDefaultFriendReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelDefaultFriendReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelDefaultFriendReq) ProtoMessage() {} + +func (x *DelDefaultFriendReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelDefaultFriendReq.ProtoReflect.Descriptor instead. +func (*DelDefaultFriendReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{22} +} + +func (x *DelDefaultFriendReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type DelDefaultFriendResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelDefaultFriendResp) Reset() { + *x = DelDefaultFriendResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelDefaultFriendResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelDefaultFriendResp) ProtoMessage() {} + +func (x *DelDefaultFriendResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelDefaultFriendResp.ProtoReflect.Descriptor instead. +func (*DelDefaultFriendResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{23} +} + +type FindDefaultFriendReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *FindDefaultFriendReq) Reset() { + *x = FindDefaultFriendReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindDefaultFriendReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindDefaultFriendReq) ProtoMessage() {} + +func (x *FindDefaultFriendReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindDefaultFriendReq.ProtoReflect.Descriptor instead. +func (*FindDefaultFriendReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{24} +} + +type FindDefaultFriendResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *FindDefaultFriendResp) Reset() { + *x = FindDefaultFriendResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindDefaultFriendResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindDefaultFriendResp) ProtoMessage() {} + +func (x *FindDefaultFriendResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindDefaultFriendResp.ProtoReflect.Descriptor instead. +func (*FindDefaultFriendResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{25} +} + +func (x *FindDefaultFriendResp) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type SearchDefaultFriendReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchDefaultFriendReq) Reset() { + *x = SearchDefaultFriendReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchDefaultFriendReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchDefaultFriendReq) ProtoMessage() {} + +func (x *SearchDefaultFriendReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchDefaultFriendReq.ProtoReflect.Descriptor instead. +func (*SearchDefaultFriendReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{26} +} + +func (x *SearchDefaultFriendReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchDefaultFriendReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type DefaultFriendAttribute struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + CreateTime int64 `protobuf:"varint,2,opt,name=createTime,proto3" json:"createTime"` + User *common.UserPublicInfo `protobuf:"bytes,3,opt,name=user,proto3" json:"user"` +} + +func (x *DefaultFriendAttribute) Reset() { + *x = DefaultFriendAttribute{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DefaultFriendAttribute) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DefaultFriendAttribute) ProtoMessage() {} + +func (x *DefaultFriendAttribute) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DefaultFriendAttribute.ProtoReflect.Descriptor instead. +func (*DefaultFriendAttribute) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{27} +} + +func (x *DefaultFriendAttribute) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *DefaultFriendAttribute) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *DefaultFriendAttribute) GetUser() *common.UserPublicInfo { + if x != nil { + return x.User + } + return nil +} + +type SearchDefaultFriendResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Users []*DefaultFriendAttribute `protobuf:"bytes,2,rep,name=users,proto3" json:"users"` +} + +func (x *SearchDefaultFriendResp) Reset() { + *x = SearchDefaultFriendResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchDefaultFriendResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchDefaultFriendResp) ProtoMessage() {} + +func (x *SearchDefaultFriendResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchDefaultFriendResp.ProtoReflect.Descriptor instead. +func (*SearchDefaultFriendResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{28} +} + +func (x *SearchDefaultFriendResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchDefaultFriendResp) GetUsers() []*DefaultFriendAttribute { + if x != nil { + return x.Users + } + return nil +} + +type AddDefaultGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupIDs []string `protobuf:"bytes,1,rep,name=groupIDs,proto3" json:"groupIDs"` +} + +func (x *AddDefaultGroupReq) Reset() { + *x = AddDefaultGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddDefaultGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddDefaultGroupReq) ProtoMessage() {} + +func (x *AddDefaultGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddDefaultGroupReq.ProtoReflect.Descriptor instead. +func (*AddDefaultGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{29} +} + +func (x *AddDefaultGroupReq) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +type AddDefaultGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddDefaultGroupResp) Reset() { + *x = AddDefaultGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddDefaultGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddDefaultGroupResp) ProtoMessage() {} + +func (x *AddDefaultGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddDefaultGroupResp.ProtoReflect.Descriptor instead. +func (*AddDefaultGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{30} +} + +type DelDefaultGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupIDs []string `protobuf:"bytes,1,rep,name=groupIDs,proto3" json:"groupIDs"` +} + +func (x *DelDefaultGroupReq) Reset() { + *x = DelDefaultGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelDefaultGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelDefaultGroupReq) ProtoMessage() {} + +func (x *DelDefaultGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelDefaultGroupReq.ProtoReflect.Descriptor instead. +func (*DelDefaultGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{31} +} + +func (x *DelDefaultGroupReq) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +type DelDefaultGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelDefaultGroupResp) Reset() { + *x = DelDefaultGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelDefaultGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelDefaultGroupResp) ProtoMessage() {} + +func (x *DelDefaultGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelDefaultGroupResp.ProtoReflect.Descriptor instead. +func (*DelDefaultGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{32} +} + +type FindDefaultGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *FindDefaultGroupReq) Reset() { + *x = FindDefaultGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindDefaultGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindDefaultGroupReq) ProtoMessage() {} + +func (x *FindDefaultGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindDefaultGroupReq.ProtoReflect.Descriptor instead. +func (*FindDefaultGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{33} +} + +type FindDefaultGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupIDs []string `protobuf:"bytes,1,rep,name=groupIDs,proto3" json:"groupIDs"` +} + +func (x *FindDefaultGroupResp) Reset() { + *x = FindDefaultGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindDefaultGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindDefaultGroupResp) ProtoMessage() {} + +func (x *FindDefaultGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindDefaultGroupResp.ProtoReflect.Descriptor instead. +func (*FindDefaultGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{34} +} + +func (x *FindDefaultGroupResp) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +type SearchDefaultGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchDefaultGroupReq) Reset() { + *x = SearchDefaultGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchDefaultGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchDefaultGroupReq) ProtoMessage() {} + +func (x *SearchDefaultGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchDefaultGroupReq.ProtoReflect.Descriptor instead. +func (*SearchDefaultGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{35} +} + +func (x *SearchDefaultGroupReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchDefaultGroupReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GroupAttribute struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupID string `protobuf:"bytes,1,opt,name=groupID,proto3" json:"groupID"` + CreateTime int64 `protobuf:"varint,2,opt,name=createTime,proto3" json:"createTime"` + Group *sdkws.GroupInfo `protobuf:"bytes,3,opt,name=group,proto3" json:"group"` +} + +func (x *GroupAttribute) Reset() { + *x = GroupAttribute{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupAttribute) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupAttribute) ProtoMessage() {} + +func (x *GroupAttribute) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupAttribute.ProtoReflect.Descriptor instead. +func (*GroupAttribute) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{36} +} + +func (x *GroupAttribute) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *GroupAttribute) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *GroupAttribute) GetGroup() *sdkws.GroupInfo { + if x != nil { + return x.Group + } + return nil +} + +type SearchDefaultGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + GroupIDs []string `protobuf:"bytes,2,rep,name=groupIDs,proto3" json:"groupIDs"` +} + +func (x *SearchDefaultGroupResp) Reset() { + *x = SearchDefaultGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchDefaultGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchDefaultGroupResp) ProtoMessage() {} + +func (x *SearchDefaultGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchDefaultGroupResp.ProtoReflect.Descriptor instead. +func (*SearchDefaultGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{37} +} + +func (x *SearchDefaultGroupResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchDefaultGroupResp) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +type AddInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Codes []string `protobuf:"bytes,1,rep,name=codes,proto3" json:"codes"` +} + +func (x *AddInvitationCodeReq) Reset() { + *x = AddInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddInvitationCodeReq) ProtoMessage() {} + +func (x *AddInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*AddInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{38} +} + +func (x *AddInvitationCodeReq) GetCodes() []string { + if x != nil { + return x.Codes + } + return nil +} + +type AddInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddInvitationCodeResp) Reset() { + *x = AddInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddInvitationCodeResp) ProtoMessage() {} + +func (x *AddInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*AddInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{39} +} + +type GenInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Len int32 `protobuf:"varint,1,opt,name=len,proto3" json:"len"` + Num int32 `protobuf:"varint,2,opt,name=num,proto3" json:"num"` + Chars string `protobuf:"bytes,3,opt,name=chars,proto3" json:"chars"` +} + +func (x *GenInvitationCodeReq) Reset() { + *x = GenInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenInvitationCodeReq) ProtoMessage() {} + +func (x *GenInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*GenInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{40} +} + +func (x *GenInvitationCodeReq) GetLen() int32 { + if x != nil { + return x.Len + } + return 0 +} + +func (x *GenInvitationCodeReq) GetNum() int32 { + if x != nil { + return x.Num + } + return 0 +} + +func (x *GenInvitationCodeReq) GetChars() string { + if x != nil { + return x.Chars + } + return "" +} + +type GenInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GenInvitationCodeResp) Reset() { + *x = GenInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenInvitationCodeResp) ProtoMessage() {} + +func (x *GenInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*GenInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{41} +} + +type FindInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Codes []string `protobuf:"bytes,1,rep,name=codes,proto3" json:"codes"` +} + +func (x *FindInvitationCodeReq) Reset() { + *x = FindInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindInvitationCodeReq) ProtoMessage() {} + +func (x *FindInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*FindInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{42} +} + +func (x *FindInvitationCodeReq) GetCodes() []string { + if x != nil { + return x.Codes + } + return nil +} + +type FindInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Codes []*InvitationRegister `protobuf:"bytes,1,rep,name=codes,proto3" json:"codes"` +} + +func (x *FindInvitationCodeResp) Reset() { + *x = FindInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindInvitationCodeResp) ProtoMessage() {} + +func (x *FindInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*FindInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{43} +} + +func (x *FindInvitationCodeResp) GetCodes() []*InvitationRegister { + if x != nil { + return x.Codes + } + return nil +} + +type UseInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code"` + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` +} + +func (x *UseInvitationCodeReq) Reset() { + *x = UseInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UseInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UseInvitationCodeReq) ProtoMessage() {} + +func (x *UseInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UseInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*UseInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{44} +} + +func (x *UseInvitationCodeReq) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *UseInvitationCodeReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type UseInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UseInvitationCodeResp) Reset() { + *x = UseInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UseInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UseInvitationCodeResp) ProtoMessage() {} + +func (x *UseInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UseInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*UseInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{45} +} + +type DelInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Codes []string `protobuf:"bytes,1,rep,name=codes,proto3" json:"codes"` +} + +func (x *DelInvitationCodeReq) Reset() { + *x = DelInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelInvitationCodeReq) ProtoMessage() {} + +func (x *DelInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*DelInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{46} +} + +func (x *DelInvitationCodeReq) GetCodes() []string { + if x != nil { + return x.Codes + } + return nil +} + +type DelInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelInvitationCodeResp) Reset() { + *x = DelInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelInvitationCodeResp) ProtoMessage() {} + +func (x *DelInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*DelInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{47} +} + +type InvitationRegister struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InvitationCode string `protobuf:"bytes,1,opt,name=invitationCode,proto3" json:"invitationCode"` + CreateTime int64 `protobuf:"varint,2,opt,name=createTime,proto3" json:"createTime"` + UsedUserID string `protobuf:"bytes,3,opt,name=usedUserID,proto3" json:"usedUserID"` + UsedUser *common.UserPublicInfo `protobuf:"bytes,4,opt,name=usedUser,proto3" json:"usedUser"` +} + +func (x *InvitationRegister) Reset() { + *x = InvitationRegister{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvitationRegister) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvitationRegister) ProtoMessage() {} + +func (x *InvitationRegister) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvitationRegister.ProtoReflect.Descriptor instead. +func (*InvitationRegister) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{48} +} + +func (x *InvitationRegister) GetInvitationCode() string { + if x != nil { + return x.InvitationCode + } + return "" +} + +func (x *InvitationRegister) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *InvitationRegister) GetUsedUserID() string { + if x != nil { + return x.UsedUserID + } + return "" +} + +func (x *InvitationRegister) GetUsedUser() *common.UserPublicInfo { + if x != nil { + return x.UsedUser + } + return nil +} + +type SearchInvitationCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status"` + UserIDs []string `protobuf:"bytes,2,rep,name=userIDs,proto3" json:"userIDs"` + Codes []string `protobuf:"bytes,3,rep,name=codes,proto3" json:"codes"` + Keyword string `protobuf:"bytes,4,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,5,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchInvitationCodeReq) Reset() { + *x = SearchInvitationCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchInvitationCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchInvitationCodeReq) ProtoMessage() {} + +func (x *SearchInvitationCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchInvitationCodeReq.ProtoReflect.Descriptor instead. +func (*SearchInvitationCodeReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{49} +} + +func (x *SearchInvitationCodeReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SearchInvitationCodeReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +func (x *SearchInvitationCodeReq) GetCodes() []string { + if x != nil { + return x.Codes + } + return nil +} + +func (x *SearchInvitationCodeReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchInvitationCodeReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchInvitationCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + List []*InvitationRegister `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` +} + +func (x *SearchInvitationCodeResp) Reset() { + *x = SearchInvitationCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchInvitationCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchInvitationCodeResp) ProtoMessage() {} + +func (x *SearchInvitationCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[50] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchInvitationCodeResp.ProtoReflect.Descriptor instead. +func (*SearchInvitationCodeResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{50} +} + +func (x *SearchInvitationCodeResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchInvitationCodeResp) GetList() []*InvitationRegister { + if x != nil { + return x.List + } + return nil +} + +type SearchUserIPLimitLoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchUserIPLimitLoginReq) Reset() { + *x = SearchUserIPLimitLoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserIPLimitLoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserIPLimitLoginReq) ProtoMessage() {} + +func (x *SearchUserIPLimitLoginReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[51] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserIPLimitLoginReq.ProtoReflect.Descriptor instead. +func (*SearchUserIPLimitLoginReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{51} +} + +func (x *SearchUserIPLimitLoginReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchUserIPLimitLoginReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type LimitUserLoginIP struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip"` + CreateTime int64 `protobuf:"varint,3,opt,name=createTime,proto3" json:"createTime"` + User *common.UserPublicInfo `protobuf:"bytes,4,opt,name=user,proto3" json:"user"` +} + +func (x *LimitUserLoginIP) Reset() { + *x = LimitUserLoginIP{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LimitUserLoginIP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LimitUserLoginIP) ProtoMessage() {} + +func (x *LimitUserLoginIP) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[52] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LimitUserLoginIP.ProtoReflect.Descriptor instead. +func (*LimitUserLoginIP) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{52} +} + +func (x *LimitUserLoginIP) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *LimitUserLoginIP) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *LimitUserLoginIP) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *LimitUserLoginIP) GetUser() *common.UserPublicInfo { + if x != nil { + return x.User + } + return nil +} + +type SearchUserIPLimitLoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Limits []*LimitUserLoginIP `protobuf:"bytes,2,rep,name=limits,proto3" json:"limits"` +} + +func (x *SearchUserIPLimitLoginResp) Reset() { + *x = SearchUserIPLimitLoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserIPLimitLoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserIPLimitLoginResp) ProtoMessage() {} + +func (x *SearchUserIPLimitLoginResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[53] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserIPLimitLoginResp.ProtoReflect.Descriptor instead. +func (*SearchUserIPLimitLoginResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{53} +} + +func (x *SearchUserIPLimitLoginResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchUserIPLimitLoginResp) GetLimits() []*LimitUserLoginIP { + if x != nil { + return x.Limits + } + return nil +} + +type UserIPLimitLogin struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip"` +} + +func (x *UserIPLimitLogin) Reset() { + *x = UserIPLimitLogin{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserIPLimitLogin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserIPLimitLogin) ProtoMessage() {} + +func (x *UserIPLimitLogin) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserIPLimitLogin.ProtoReflect.Descriptor instead. +func (*UserIPLimitLogin) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{54} +} + +func (x *UserIPLimitLogin) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UserIPLimitLogin) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +type AddUserIPLimitLoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Limits []*UserIPLimitLogin `protobuf:"bytes,1,rep,name=limits,proto3" json:"limits"` +} + +func (x *AddUserIPLimitLoginReq) Reset() { + *x = AddUserIPLimitLoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUserIPLimitLoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUserIPLimitLoginReq) ProtoMessage() {} + +func (x *AddUserIPLimitLoginReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddUserIPLimitLoginReq.ProtoReflect.Descriptor instead. +func (*AddUserIPLimitLoginReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{55} +} + +func (x *AddUserIPLimitLoginReq) GetLimits() []*UserIPLimitLogin { + if x != nil { + return x.Limits + } + return nil +} + +type AddUserIPLimitLoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddUserIPLimitLoginResp) Reset() { + *x = AddUserIPLimitLoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUserIPLimitLoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUserIPLimitLoginResp) ProtoMessage() {} + +func (x *AddUserIPLimitLoginResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[56] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddUserIPLimitLoginResp.ProtoReflect.Descriptor instead. +func (*AddUserIPLimitLoginResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{56} +} + +type DelUserIPLimitLoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Limits []*UserIPLimitLogin `protobuf:"bytes,1,rep,name=limits,proto3" json:"limits"` +} + +func (x *DelUserIPLimitLoginReq) Reset() { + *x = DelUserIPLimitLoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelUserIPLimitLoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelUserIPLimitLoginReq) ProtoMessage() {} + +func (x *DelUserIPLimitLoginReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[57] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelUserIPLimitLoginReq.ProtoReflect.Descriptor instead. +func (*DelUserIPLimitLoginReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{57} +} + +func (x *DelUserIPLimitLoginReq) GetLimits() []*UserIPLimitLogin { + if x != nil { + return x.Limits + } + return nil +} + +type DelUserIPLimitLoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelUserIPLimitLoginResp) Reset() { + *x = DelUserIPLimitLoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelUserIPLimitLoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelUserIPLimitLoginResp) ProtoMessage() {} + +func (x *DelUserIPLimitLoginResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[58] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelUserIPLimitLoginResp.ProtoReflect.Descriptor instead. +func (*DelUserIPLimitLoginResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{58} +} + +type IPForbidden struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip"` + LimitRegister bool `protobuf:"varint,2,opt,name=limitRegister,proto3" json:"limitRegister"` + LimitLogin bool `protobuf:"varint,3,opt,name=limitLogin,proto3" json:"limitLogin"` + CreateTime int64 `protobuf:"varint,4,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *IPForbidden) Reset() { + *x = IPForbidden{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IPForbidden) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IPForbidden) ProtoMessage() {} + +func (x *IPForbidden) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[59] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IPForbidden.ProtoReflect.Descriptor instead. +func (*IPForbidden) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{59} +} + +func (x *IPForbidden) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *IPForbidden) GetLimitRegister() bool { + if x != nil { + return x.LimitRegister + } + return false +} + +func (x *IPForbidden) GetLimitLogin() bool { + if x != nil { + return x.LimitLogin + } + return false +} + +func (x *IPForbidden) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type IPForbiddenAdd struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip"` + LimitRegister bool `protobuf:"varint,2,opt,name=limitRegister,proto3" json:"limitRegister"` + LimitLogin bool `protobuf:"varint,3,opt,name=limitLogin,proto3" json:"limitLogin"` +} + +func (x *IPForbiddenAdd) Reset() { + *x = IPForbiddenAdd{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IPForbiddenAdd) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IPForbiddenAdd) ProtoMessage() {} + +func (x *IPForbiddenAdd) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[60] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IPForbiddenAdd.ProtoReflect.Descriptor instead. +func (*IPForbiddenAdd) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{60} +} + +func (x *IPForbiddenAdd) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *IPForbiddenAdd) GetLimitRegister() bool { + if x != nil { + return x.LimitRegister + } + return false +} + +func (x *IPForbiddenAdd) GetLimitLogin() bool { + if x != nil { + return x.LimitLogin + } + return false +} + +type SearchIPForbiddenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchIPForbiddenReq) Reset() { + *x = SearchIPForbiddenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchIPForbiddenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchIPForbiddenReq) ProtoMessage() {} + +func (x *SearchIPForbiddenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[61] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchIPForbiddenReq.ProtoReflect.Descriptor instead. +func (*SearchIPForbiddenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{61} +} + +func (x *SearchIPForbiddenReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchIPForbiddenReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SearchIPForbiddenReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchIPForbiddenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Forbiddens []*IPForbidden `protobuf:"bytes,2,rep,name=forbiddens,proto3" json:"forbiddens"` +} + +func (x *SearchIPForbiddenResp) Reset() { + *x = SearchIPForbiddenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchIPForbiddenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchIPForbiddenResp) ProtoMessage() {} + +func (x *SearchIPForbiddenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[62] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchIPForbiddenResp.ProtoReflect.Descriptor instead. +func (*SearchIPForbiddenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{62} +} + +func (x *SearchIPForbiddenResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchIPForbiddenResp) GetForbiddens() []*IPForbidden { + if x != nil { + return x.Forbiddens + } + return nil +} + +type AddIPForbiddenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Forbiddens []*IPForbiddenAdd `protobuf:"bytes,1,rep,name=forbiddens,proto3" json:"forbiddens"` +} + +func (x *AddIPForbiddenReq) Reset() { + *x = AddIPForbiddenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddIPForbiddenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddIPForbiddenReq) ProtoMessage() {} + +func (x *AddIPForbiddenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[63] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddIPForbiddenReq.ProtoReflect.Descriptor instead. +func (*AddIPForbiddenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{63} +} + +func (x *AddIPForbiddenReq) GetForbiddens() []*IPForbiddenAdd { + if x != nil { + return x.Forbiddens + } + return nil +} + +type AddIPForbiddenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddIPForbiddenResp) Reset() { + *x = AddIPForbiddenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddIPForbiddenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddIPForbiddenResp) ProtoMessage() {} + +func (x *AddIPForbiddenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddIPForbiddenResp.ProtoReflect.Descriptor instead. +func (*AddIPForbiddenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{64} +} + +type DelIPForbiddenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ips []string `protobuf:"bytes,1,rep,name=ips,proto3" json:"ips"` +} + +func (x *DelIPForbiddenReq) Reset() { + *x = DelIPForbiddenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelIPForbiddenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelIPForbiddenReq) ProtoMessage() {} + +func (x *DelIPForbiddenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelIPForbiddenReq.ProtoReflect.Descriptor instead. +func (*DelIPForbiddenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{65} +} + +func (x *DelIPForbiddenReq) GetIps() []string { + if x != nil { + return x.Ips + } + return nil +} + +type DelIPForbiddenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelIPForbiddenResp) Reset() { + *x = DelIPForbiddenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelIPForbiddenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelIPForbiddenResp) ProtoMessage() {} + +func (x *DelIPForbiddenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelIPForbiddenResp.ProtoReflect.Descriptor instead. +func (*DelIPForbiddenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{66} +} + +// ################### User Limit ################### +type CheckRegisterForbiddenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip"` +} + +func (x *CheckRegisterForbiddenReq) Reset() { + *x = CheckRegisterForbiddenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckRegisterForbiddenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckRegisterForbiddenReq) ProtoMessage() {} + +func (x *CheckRegisterForbiddenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[67] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckRegisterForbiddenReq.ProtoReflect.Descriptor instead. +func (*CheckRegisterForbiddenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{67} +} + +func (x *CheckRegisterForbiddenReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +type CheckRegisterForbiddenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CheckRegisterForbiddenResp) Reset() { + *x = CheckRegisterForbiddenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckRegisterForbiddenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckRegisterForbiddenResp) ProtoMessage() {} + +func (x *CheckRegisterForbiddenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[68] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckRegisterForbiddenResp.ProtoReflect.Descriptor instead. +func (*CheckRegisterForbiddenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{68} +} + +type CheckLoginForbiddenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip"` + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` +} + +func (x *CheckLoginForbiddenReq) Reset() { + *x = CheckLoginForbiddenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckLoginForbiddenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckLoginForbiddenReq) ProtoMessage() {} + +func (x *CheckLoginForbiddenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[69] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckLoginForbiddenReq.ProtoReflect.Descriptor instead. +func (*CheckLoginForbiddenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{69} +} + +func (x *CheckLoginForbiddenReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *CheckLoginForbiddenReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type CheckLoginForbiddenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CheckLoginForbiddenResp) Reset() { + *x = CheckLoginForbiddenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckLoginForbiddenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckLoginForbiddenResp) ProtoMessage() {} + +func (x *CheckLoginForbiddenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckLoginForbiddenResp.ProtoReflect.Descriptor instead. +func (*CheckLoginForbiddenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{70} +} + +// ################### login out ################### +type CancellationUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason"` +} + +func (x *CancellationUserReq) Reset() { + *x = CancellationUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancellationUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancellationUserReq) ProtoMessage() {} + +func (x *CancellationUserReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[71] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancellationUserReq.ProtoReflect.Descriptor instead. +func (*CancellationUserReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{71} +} + +func (x *CancellationUserReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *CancellationUserReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type CancellationUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CancellationUserResp) Reset() { + *x = CancellationUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancellationUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancellationUserResp) ProtoMessage() {} + +func (x *CancellationUserResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[72] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancellationUserResp.ProtoReflect.Descriptor instead. +func (*CancellationUserResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{72} +} + +// ################### Block User, Unblock User ################### +type BlockUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason"` +} + +func (x *BlockUserReq) Reset() { + *x = BlockUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockUserReq) ProtoMessage() {} + +func (x *BlockUserReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockUserReq.ProtoReflect.Descriptor instead. +func (*BlockUserReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{73} +} + +func (x *BlockUserReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *BlockUserReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type BlockUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BlockUserResp) Reset() { + *x = BlockUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockUserResp) ProtoMessage() {} + +func (x *BlockUserResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[74] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockUserResp.ProtoReflect.Descriptor instead. +func (*BlockUserResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{74} +} + +type UnblockUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *UnblockUserReq) Reset() { + *x = UnblockUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnblockUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnblockUserReq) ProtoMessage() {} + +func (x *UnblockUserReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[75] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnblockUserReq.ProtoReflect.Descriptor instead. +func (*UnblockUserReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{75} +} + +func (x *UnblockUserReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type UnblockUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UnblockUserResp) Reset() { + *x = UnblockUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnblockUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnblockUserResp) ProtoMessage() {} + +func (x *UnblockUserResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[76] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnblockUserResp.ProtoReflect.Descriptor instead. +func (*UnblockUserResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{76} +} + +type SearchBlockUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchBlockUserReq) Reset() { + *x = SearchBlockUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchBlockUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchBlockUserReq) ProtoMessage() {} + +func (x *SearchBlockUserReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[77] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchBlockUserReq.ProtoReflect.Descriptor instead. +func (*SearchBlockUserReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{77} +} + +func (x *SearchBlockUserReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchBlockUserReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type BlockUserInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account"` + PhoneNumber string `protobuf:"bytes,3,opt,name=phoneNumber,proto3" json:"phoneNumber"` + AreaCode string `protobuf:"bytes,4,opt,name=areaCode,proto3" json:"areaCode"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email"` + Nickname string `protobuf:"bytes,6,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,7,opt,name=faceURL,proto3" json:"faceURL"` + Gender int32 `protobuf:"varint,8,opt,name=gender,proto3" json:"gender"` + Reason string `protobuf:"bytes,9,opt,name=reason,proto3" json:"reason"` + OpUserID string `protobuf:"bytes,10,opt,name=opUserID,proto3" json:"opUserID"` + CreateTime int64 `protobuf:"varint,11,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *BlockUserInfo) Reset() { + *x = BlockUserInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockUserInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockUserInfo) ProtoMessage() {} + +func (x *BlockUserInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[78] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockUserInfo.ProtoReflect.Descriptor instead. +func (*BlockUserInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{78} +} + +func (x *BlockUserInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *BlockUserInfo) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *BlockUserInfo) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *BlockUserInfo) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *BlockUserInfo) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *BlockUserInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *BlockUserInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *BlockUserInfo) GetGender() int32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *BlockUserInfo) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *BlockUserInfo) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *BlockUserInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type SearchBlockUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Users []*BlockUserInfo `protobuf:"bytes,2,rep,name=users,proto3" json:"users"` +} + +func (x *SearchBlockUserResp) Reset() { + *x = SearchBlockUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchBlockUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchBlockUserResp) ProtoMessage() {} + +func (x *SearchBlockUserResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[79] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchBlockUserResp.ProtoReflect.Descriptor instead. +func (*SearchBlockUserResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{79} +} + +func (x *SearchBlockUserResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchBlockUserResp) GetUsers() []*BlockUserInfo { + if x != nil { + return x.Users + } + return nil +} + +type FindUserBlockInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *FindUserBlockInfoReq) Reset() { + *x = FindUserBlockInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserBlockInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserBlockInfoReq) ProtoMessage() {} + +func (x *FindUserBlockInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[80] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserBlockInfoReq.ProtoReflect.Descriptor instead. +func (*FindUserBlockInfoReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{80} +} + +func (x *FindUserBlockInfoReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type BlockInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID,proto3" json:"opUserID"` + CreateTime int64 `protobuf:"varint,4,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *BlockInfo) Reset() { + *x = BlockInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[81] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockInfo) ProtoMessage() {} + +func (x *BlockInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[81] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockInfo.ProtoReflect.Descriptor instead. +func (*BlockInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{81} +} + +func (x *BlockInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *BlockInfo) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *BlockInfo) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *BlockInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type FindUserBlockInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Blocks []*BlockInfo `protobuf:"bytes,2,rep,name=blocks,proto3" json:"blocks"` +} + +func (x *FindUserBlockInfoResp) Reset() { + *x = FindUserBlockInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[82] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserBlockInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserBlockInfoResp) ProtoMessage() {} + +func (x *FindUserBlockInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[82] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserBlockInfoResp.ProtoReflect.Descriptor instead. +func (*FindUserBlockInfoResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{82} +} + +func (x *FindUserBlockInfoResp) GetBlocks() []*BlockInfo { + if x != nil { + return x.Blocks + } + return nil +} + +type CreateTokenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + UserType int32 `protobuf:"varint,32,opt,name=userType,proto3" json:"userType"` +} + +func (x *CreateTokenReq) Reset() { + *x = CreateTokenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[83] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTokenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTokenReq) ProtoMessage() {} + +func (x *CreateTokenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[83] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTokenReq.ProtoReflect.Descriptor instead. +func (*CreateTokenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{83} +} + +func (x *CreateTokenReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *CreateTokenReq) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +type CreateTokenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token"` +} + +func (x *CreateTokenResp) Reset() { + *x = CreateTokenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[84] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTokenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTokenResp) ProtoMessage() {} + +func (x *CreateTokenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[84] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTokenResp.ProtoReflect.Descriptor instead. +func (*CreateTokenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{84} +} + +func (x *CreateTokenResp) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type ParseTokenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token"` +} + +func (x *ParseTokenReq) Reset() { + *x = ParseTokenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[85] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ParseTokenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParseTokenReq) ProtoMessage() {} + +func (x *ParseTokenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[85] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParseTokenReq.ProtoReflect.Descriptor instead. +func (*ParseTokenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{85} +} + +func (x *ParseTokenReq) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type ParseTokenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + UserType int32 `protobuf:"varint,2,opt,name=userType,proto3" json:"userType"` + ExpireTimeSeconds int64 `protobuf:"varint,3,opt,name=expireTimeSeconds,proto3" json:"expireTimeSeconds"` +} + +func (x *ParseTokenResp) Reset() { + *x = ParseTokenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[86] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ParseTokenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParseTokenResp) ProtoMessage() {} + +func (x *ParseTokenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[86] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParseTokenResp.ProtoReflect.Descriptor instead. +func (*ParseTokenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{86} +} + +func (x *ParseTokenResp) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *ParseTokenResp) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +func (x *ParseTokenResp) GetExpireTimeSeconds() int64 { + if x != nil { + return x.ExpireTimeSeconds + } + return 0 +} + +type InvalidateTokenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` +} + +func (x *InvalidateTokenReq) Reset() { + *x = InvalidateTokenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[87] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvalidateTokenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvalidateTokenReq) ProtoMessage() {} + +func (x *InvalidateTokenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[87] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvalidateTokenReq.ProtoReflect.Descriptor instead. +func (*InvalidateTokenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{87} +} + +func (x *InvalidateTokenReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type InvalidateTokenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *InvalidateTokenResp) Reset() { + *x = InvalidateTokenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[88] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvalidateTokenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvalidateTokenResp) ProtoMessage() {} + +func (x *InvalidateTokenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[88] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvalidateTokenResp.ProtoReflect.Descriptor instead. +func (*InvalidateTokenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{88} +} + +type AddAppletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + AppID string `protobuf:"bytes,3,opt,name=appID,proto3" json:"appID"` + Icon string `protobuf:"bytes,4,opt,name=icon,proto3" json:"icon"` + Url string `protobuf:"bytes,5,opt,name=url,proto3" json:"url"` + Md5 string `protobuf:"bytes,6,opt,name=md5,proto3" json:"md5"` + Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size"` + Version string `protobuf:"bytes,8,opt,name=version,proto3" json:"version"` + Priority uint32 `protobuf:"varint,9,opt,name=priority,proto3" json:"priority"` + Status uint32 `protobuf:"varint,10,opt,name=status,proto3" json:"status"` + CreateTime int64 `protobuf:"varint,11,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *AddAppletReq) Reset() { + *x = AddAppletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[89] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddAppletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddAppletReq) ProtoMessage() {} + +func (x *AddAppletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[89] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddAppletReq.ProtoReflect.Descriptor instead. +func (*AddAppletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{89} +} + +func (x *AddAppletReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AddAppletReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddAppletReq) GetAppID() string { + if x != nil { + return x.AppID + } + return "" +} + +func (x *AddAppletReq) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *AddAppletReq) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *AddAppletReq) GetMd5() string { + if x != nil { + return x.Md5 + } + return "" +} + +func (x *AddAppletReq) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *AddAppletReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *AddAppletReq) GetPriority() uint32 { + if x != nil { + return x.Priority + } + return 0 +} + +func (x *AddAppletReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *AddAppletReq) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type AddAppletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddAppletResp) Reset() { + *x = AddAppletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[90] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddAppletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddAppletResp) ProtoMessage() {} + +func (x *AddAppletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[90] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddAppletResp.ProtoReflect.Descriptor instead. +func (*AddAppletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{90} +} + +type DelAppletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AppletIds []string `protobuf:"bytes,1,rep,name=appletIds,proto3" json:"appletIds"` +} + +func (x *DelAppletReq) Reset() { + *x = DelAppletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[91] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelAppletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelAppletReq) ProtoMessage() {} + +func (x *DelAppletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[91] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelAppletReq.ProtoReflect.Descriptor instead. +func (*DelAppletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{91} +} + +func (x *DelAppletReq) GetAppletIds() []string { + if x != nil { + return x.AppletIds + } + return nil +} + +type DelAppletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelAppletResp) Reset() { + *x = DelAppletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[92] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelAppletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelAppletResp) ProtoMessage() {} + +func (x *DelAppletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[92] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelAppletResp.ProtoReflect.Descriptor instead. +func (*DelAppletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{92} +} + +type UpdateAppletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + AppID *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=appID,proto3" json:"appID"` + Icon *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=icon,proto3" json:"icon"` + Url *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=url,proto3" json:"url"` + Md5 *wrapperspb.StringValue `protobuf:"bytes,6,opt,name=md5,proto3" json:"md5"` + Size *wrapperspb.Int64Value `protobuf:"bytes,7,opt,name=size,proto3" json:"size"` + Version *wrapperspb.StringValue `protobuf:"bytes,8,opt,name=version,proto3" json:"version"` + Priority *wrapperspb.UInt32Value `protobuf:"bytes,9,opt,name=priority,proto3" json:"priority"` + Status *wrapperspb.UInt32Value `protobuf:"bytes,10,opt,name=status,proto3" json:"status"` + CreateTime *wrapperspb.Int64Value `protobuf:"bytes,11,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *UpdateAppletReq) Reset() { + *x = UpdateAppletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[93] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateAppletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAppletReq) ProtoMessage() {} + +func (x *UpdateAppletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[93] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAppletReq.ProtoReflect.Descriptor instead. +func (*UpdateAppletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{93} +} + +func (x *UpdateAppletReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateAppletReq) GetName() *wrapperspb.StringValue { + if x != nil { + return x.Name + } + return nil +} + +func (x *UpdateAppletReq) GetAppID() *wrapperspb.StringValue { + if x != nil { + return x.AppID + } + return nil +} + +func (x *UpdateAppletReq) GetIcon() *wrapperspb.StringValue { + if x != nil { + return x.Icon + } + return nil +} + +func (x *UpdateAppletReq) GetUrl() *wrapperspb.StringValue { + if x != nil { + return x.Url + } + return nil +} + +func (x *UpdateAppletReq) GetMd5() *wrapperspb.StringValue { + if x != nil { + return x.Md5 + } + return nil +} + +func (x *UpdateAppletReq) GetSize() *wrapperspb.Int64Value { + if x != nil { + return x.Size + } + return nil +} + +func (x *UpdateAppletReq) GetVersion() *wrapperspb.StringValue { + if x != nil { + return x.Version + } + return nil +} + +func (x *UpdateAppletReq) GetPriority() *wrapperspb.UInt32Value { + if x != nil { + return x.Priority + } + return nil +} + +func (x *UpdateAppletReq) GetStatus() *wrapperspb.UInt32Value { + if x != nil { + return x.Status + } + return nil +} + +func (x *UpdateAppletReq) GetCreateTime() *wrapperspb.Int64Value { + if x != nil { + return x.CreateTime + } + return nil +} + +type UpdateAppletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateAppletResp) Reset() { + *x = UpdateAppletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[94] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateAppletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAppletResp) ProtoMessage() {} + +func (x *UpdateAppletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[94] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAppletResp.ProtoReflect.Descriptor instead. +func (*UpdateAppletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{94} +} + +type FindAppletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *FindAppletReq) Reset() { + *x = FindAppletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[95] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindAppletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindAppletReq) ProtoMessage() {} + +func (x *FindAppletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[95] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindAppletReq.ProtoReflect.Descriptor instead. +func (*FindAppletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{95} +} + +type FindAppletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Applets []*common.AppletInfo `protobuf:"bytes,1,rep,name=applets,proto3" json:"applets"` +} + +func (x *FindAppletResp) Reset() { + *x = FindAppletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[96] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindAppletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindAppletResp) ProtoMessage() {} + +func (x *FindAppletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[96] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindAppletResp.ProtoReflect.Descriptor instead. +func (*FindAppletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{96} +} + +func (x *FindAppletResp) GetApplets() []*common.AppletInfo { + if x != nil { + return x.Applets + } + return nil +} + +type SearchAppletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchAppletReq) Reset() { + *x = SearchAppletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[97] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchAppletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchAppletReq) ProtoMessage() {} + +func (x *SearchAppletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[97] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchAppletReq.ProtoReflect.Descriptor instead. +func (*SearchAppletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{97} +} + +func (x *SearchAppletReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchAppletReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchAppletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Applets []*common.AppletInfo `protobuf:"bytes,2,rep,name=applets,proto3" json:"applets"` +} + +func (x *SearchAppletResp) Reset() { + *x = SearchAppletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[98] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchAppletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchAppletResp) ProtoMessage() {} + +func (x *SearchAppletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[98] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchAppletResp.ProtoReflect.Descriptor instead. +func (*SearchAppletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{98} +} + +func (x *SearchAppletResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchAppletResp) GetApplets() []*common.AppletInfo { + if x != nil { + return x.Applets + } + return nil +} + +type SetClientConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config map[string]string `protobuf:"bytes,1,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SetClientConfigReq) Reset() { + *x = SetClientConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[99] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetClientConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetClientConfigReq) ProtoMessage() {} + +func (x *SetClientConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[99] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetClientConfigReq.ProtoReflect.Descriptor instead. +func (*SetClientConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{99} +} + +func (x *SetClientConfigReq) GetConfig() map[string]string { + if x != nil { + return x.Config + } + return nil +} + +type SetClientConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetClientConfigResp) Reset() { + *x = SetClientConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[100] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetClientConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetClientConfigResp) ProtoMessage() {} + +func (x *SetClientConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[100] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetClientConfigResp.ProtoReflect.Descriptor instead. +func (*SetClientConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{100} +} + +type DelClientConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys"` +} + +func (x *DelClientConfigReq) Reset() { + *x = DelClientConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[101] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelClientConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelClientConfigReq) ProtoMessage() {} + +func (x *DelClientConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[101] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelClientConfigReq.ProtoReflect.Descriptor instead. +func (*DelClientConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{101} +} + +func (x *DelClientConfigReq) GetKeys() []string { + if x != nil { + return x.Keys + } + return nil +} + +type DelClientConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelClientConfigResp) Reset() { + *x = DelClientConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[102] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelClientConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelClientConfigResp) ProtoMessage() {} + +func (x *DelClientConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[102] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelClientConfigResp.ProtoReflect.Descriptor instead. +func (*DelClientConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{102} +} + +type GetClientConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetClientConfigReq) Reset() { + *x = GetClientConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetClientConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetClientConfigReq) ProtoMessage() {} + +func (x *GetClientConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[103] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetClientConfigReq.ProtoReflect.Descriptor instead. +func (*GetClientConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{103} +} + +type GetClientConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config map[string]string `protobuf:"bytes,1,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *GetClientConfigResp) Reset() { + *x = GetClientConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetClientConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetClientConfigResp) ProtoMessage() {} + +func (x *GetClientConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[104] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetClientConfigResp.ProtoReflect.Descriptor instead. +func (*GetClientConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{104} +} + +func (x *GetClientConfigResp) GetConfig() map[string]string { + if x != nil { + return x.Config + } + return nil +} + +type GetUserTokenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` +} + +func (x *GetUserTokenReq) Reset() { + *x = GetUserTokenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserTokenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserTokenReq) ProtoMessage() {} + +func (x *GetUserTokenReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[105] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserTokenReq.ProtoReflect.Descriptor instead. +func (*GetUserTokenReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{105} +} + +func (x *GetUserTokenReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type GetUserTokenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TokensMap map[string]int32 `protobuf:"bytes,1,rep,name=tokensMap,proto3" json:"tokensMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` +} + +func (x *GetUserTokenResp) Reset() { + *x = GetUserTokenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserTokenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserTokenResp) ProtoMessage() {} + +func (x *GetUserTokenResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[106] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserTokenResp.ProtoReflect.Descriptor instead. +func (*GetUserTokenResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{106} +} + +func (x *GetUserTokenResp) GetTokensMap() map[string]int32 { + if x != nil { + return x.TokensMap + } + return nil +} + +type ApplicationVersion struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Platform string `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Text string `protobuf:"bytes,5,opt,name=text,proto3" json:"text"` + Force bool `protobuf:"varint,6,opt,name=force,proto3" json:"force"` + Latest bool `protobuf:"varint,7,opt,name=latest,proto3" json:"latest"` + Hot bool `protobuf:"varint,8,opt,name=hot,proto3" json:"hot"` + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *ApplicationVersion) Reset() { + *x = ApplicationVersion{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplicationVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplicationVersion) ProtoMessage() {} + +func (x *ApplicationVersion) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[107] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplicationVersion.ProtoReflect.Descriptor instead. +func (*ApplicationVersion) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{107} +} + +func (x *ApplicationVersion) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ApplicationVersion) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *ApplicationVersion) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ApplicationVersion) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *ApplicationVersion) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *ApplicationVersion) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +func (x *ApplicationVersion) GetLatest() bool { + if x != nil { + return x.Latest + } + return false +} + +func (x *ApplicationVersion) GetHot() bool { + if x != nil { + return x.Hot + } + return false +} + +func (x *ApplicationVersion) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type LatestApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform string `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` +} + +func (x *LatestApplicationVersionReq) Reset() { + *x = LatestApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LatestApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LatestApplicationVersionReq) ProtoMessage() {} + +func (x *LatestApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[108] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LatestApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*LatestApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{108} +} + +func (x *LatestApplicationVersionReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *LatestApplicationVersionReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +type LatestApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version *ApplicationVersion `protobuf:"bytes,1,opt,name=version,proto3" json:"version"` +} + +func (x *LatestApplicationVersionResp) Reset() { + *x = LatestApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[109] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LatestApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LatestApplicationVersionResp) ProtoMessage() {} + +func (x *LatestApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[109] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LatestApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*LatestApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{109} +} + +func (x *LatestApplicationVersionResp) GetVersion() *ApplicationVersion { + if x != nil { + return x.Version + } + return nil +} + +type AddApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version"` + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url"` + Text string `protobuf:"bytes,4,opt,name=text,proto3" json:"text"` + Force bool `protobuf:"varint,5,opt,name=force,proto3" json:"force"` + Latest bool `protobuf:"varint,6,opt,name=latest,proto3" json:"latest"` + Hot bool `protobuf:"varint,7,opt,name=hot,proto3" json:"hot"` +} + +func (x *AddApplicationVersionReq) Reset() { + *x = AddApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[110] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddApplicationVersionReq) ProtoMessage() {} + +func (x *AddApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[110] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*AddApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{110} +} + +func (x *AddApplicationVersionReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *AddApplicationVersionReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *AddApplicationVersionReq) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *AddApplicationVersionReq) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *AddApplicationVersionReq) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +func (x *AddApplicationVersionReq) GetLatest() bool { + if x != nil { + return x.Latest + } + return false +} + +func (x *AddApplicationVersionReq) GetHot() bool { + if x != nil { + return x.Hot + } + return false +} + +type AddApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddApplicationVersionResp) Reset() { + *x = AddApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[111] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddApplicationVersionResp) ProtoMessage() {} + +func (x *AddApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[111] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*AddApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{111} +} + +type UpdateApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Platform *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + Url *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Text *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=text,proto3" json:"text"` + Force *wrapperspb.BoolValue `protobuf:"bytes,6,opt,name=force,proto3" json:"force"` + Latest *wrapperspb.BoolValue `protobuf:"bytes,7,opt,name=latest,proto3" json:"latest"` + Hot *wrapperspb.BoolValue `protobuf:"bytes,8,opt,name=hot,proto3" json:"hot"` +} + +func (x *UpdateApplicationVersionReq) Reset() { + *x = UpdateApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[112] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateApplicationVersionReq) ProtoMessage() {} + +func (x *UpdateApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[112] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*UpdateApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{112} +} + +func (x *UpdateApplicationVersionReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateApplicationVersionReq) GetPlatform() *wrapperspb.StringValue { + if x != nil { + return x.Platform + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetVersion() *wrapperspb.StringValue { + if x != nil { + return x.Version + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetUrl() *wrapperspb.StringValue { + if x != nil { + return x.Url + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetText() *wrapperspb.StringValue { + if x != nil { + return x.Text + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetForce() *wrapperspb.BoolValue { + if x != nil { + return x.Force + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetLatest() *wrapperspb.BoolValue { + if x != nil { + return x.Latest + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetHot() *wrapperspb.BoolValue { + if x != nil { + return x.Hot + } + return nil +} + +type UpdateApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateApplicationVersionResp) Reset() { + *x = UpdateApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[113] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateApplicationVersionResp) ProtoMessage() {} + +func (x *UpdateApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[113] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*UpdateApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{113} +} + +type DeleteApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id []string `protobuf:"bytes,1,rep,name=id,proto3" json:"id"` +} + +func (x *DeleteApplicationVersionReq) Reset() { + *x = DeleteApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[114] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteApplicationVersionReq) ProtoMessage() {} + +func (x *DeleteApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[114] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*DeleteApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{114} +} + +func (x *DeleteApplicationVersionReq) GetId() []string { + if x != nil { + return x.Id + } + return nil +} + +type DeleteApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteApplicationVersionResp) Reset() { + *x = DeleteApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[115] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteApplicationVersionResp) ProtoMessage() {} + +func (x *DeleteApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[115] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*DeleteApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{115} +} + +type PageApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform []string `protobuf:"bytes,1,rep,name=platform,proto3" json:"platform"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *PageApplicationVersionReq) Reset() { + *x = PageApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[116] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PageApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageApplicationVersionReq) ProtoMessage() {} + +func (x *PageApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[116] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*PageApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{116} +} + +func (x *PageApplicationVersionReq) GetPlatform() []string { + if x != nil { + return x.Platform + } + return nil +} + +func (x *PageApplicationVersionReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type PageApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Versions []*ApplicationVersion `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions"` +} + +func (x *PageApplicationVersionResp) Reset() { + *x = PageApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PageApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageApplicationVersionResp) ProtoMessage() {} + +func (x *PageApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[117] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*PageApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{117} +} + +func (x *PageApplicationVersionResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *PageApplicationVersionResp) GetVersions() []*ApplicationVersion { + if x != nil { + return x.Versions + } + return nil +} + +// 敏感词信息 +type SensitiveWordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Word string `protobuf:"bytes,2,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,5,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` + Creator string `protobuf:"bytes,7,opt,name=creator,proto3" json:"creator"` + Updater string `protobuf:"bytes,8,opt,name=updater,proto3" json:"updater"` + CreateTime int64 `protobuf:"varint,9,opt,name=create_time,json=createTime,proto3" json:"create_time"` + UpdateTime int64 `protobuf:"varint,10,opt,name=update_time,json=updateTime,proto3" json:"update_time"` + Remark string `protobuf:"bytes,11,opt,name=remark,proto3" json:"remark"` +} + +func (x *SensitiveWordInfo) Reset() { + *x = SensitiveWordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[118] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordInfo) ProtoMessage() {} + +func (x *SensitiveWordInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[118] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{118} +} + +func (x *SensitiveWordInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordInfo) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *SensitiveWordInfo) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *SensitiveWordInfo) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *SensitiveWordInfo) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SensitiveWordInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SensitiveWordInfo) GetCreator() string { + if x != nil { + return x.Creator + } + return "" +} + +func (x *SensitiveWordInfo) GetUpdater() string { + if x != nil { + return x.Updater + } + return "" +} + +func (x *SensitiveWordInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SensitiveWordInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +func (x *SensitiveWordInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +// 敏感词分组信息 +type SensitiveWordGroupInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark"` + CreateTime int64 `protobuf:"varint,4,opt,name=create_time,json=createTime,proto3" json:"create_time"` + UpdateTime int64 `protobuf:"varint,5,opt,name=update_time,json=updateTime,proto3" json:"update_time"` +} + +func (x *SensitiveWordGroupInfo) Reset() { + *x = SensitiveWordGroupInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[119] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordGroupInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordGroupInfo) ProtoMessage() {} + +func (x *SensitiveWordGroupInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[119] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordGroupInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordGroupInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{119} +} + +func (x *SensitiveWordGroupInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SensitiveWordGroupInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 敏感词配置信息 +type SensitiveWordConfigInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + EnableFilter bool `protobuf:"varint,2,opt,name=enable_filter,json=enableFilter,proto3" json:"enable_filter"` + FilterMode int32 `protobuf:"varint,3,opt,name=filter_mode,json=filterMode,proto3" json:"filter_mode"` + ReplaceChar string `protobuf:"bytes,4,opt,name=replace_char,json=replaceChar,proto3" json:"replace_char"` + WhitelistUsers []string `protobuf:"bytes,5,rep,name=whitelist_users,json=whitelistUsers,proto3" json:"whitelist_users"` + WhitelistGroups []string `protobuf:"bytes,6,rep,name=whitelist_groups,json=whitelistGroups,proto3" json:"whitelist_groups"` + LogEnabled bool `protobuf:"varint,7,opt,name=log_enabled,json=logEnabled,proto3" json:"log_enabled"` + AutoApprove bool `protobuf:"varint,8,opt,name=auto_approve,json=autoApprove,proto3" json:"auto_approve"` + UpdateTime int64 `protobuf:"varint,9,opt,name=update_time,json=updateTime,proto3" json:"update_time"` +} + +func (x *SensitiveWordConfigInfo) Reset() { + *x = SensitiveWordConfigInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[120] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordConfigInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordConfigInfo) ProtoMessage() {} + +func (x *SensitiveWordConfigInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[120] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordConfigInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordConfigInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{120} +} + +func (x *SensitiveWordConfigInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordConfigInfo) GetEnableFilter() bool { + if x != nil { + return x.EnableFilter + } + return false +} + +func (x *SensitiveWordConfigInfo) GetFilterMode() int32 { + if x != nil { + return x.FilterMode + } + return 0 +} + +func (x *SensitiveWordConfigInfo) GetReplaceChar() string { + if x != nil { + return x.ReplaceChar + } + return "" +} + +func (x *SensitiveWordConfigInfo) GetWhitelistUsers() []string { + if x != nil { + return x.WhitelistUsers + } + return nil +} + +func (x *SensitiveWordConfigInfo) GetWhitelistGroups() []string { + if x != nil { + return x.WhitelistGroups + } + return nil +} + +func (x *SensitiveWordConfigInfo) GetLogEnabled() bool { + if x != nil { + return x.LogEnabled + } + return false +} + +func (x *SensitiveWordConfigInfo) GetAutoApprove() bool { + if x != nil { + return x.AutoApprove + } + return false +} + +func (x *SensitiveWordConfigInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 敏感词日志信息 +type SensitiveWordLogInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id"` + GroupId string `protobuf:"bytes,3,opt,name=group_id,json=groupId,proto3" json:"group_id"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content"` + MatchedWords []string `protobuf:"bytes,5,rep,name=matched_words,json=matchedWords,proto3" json:"matched_words"` + Action int32 `protobuf:"varint,6,opt,name=action,proto3" json:"action"` + ProcessedText string `protobuf:"bytes,7,opt,name=processed_text,json=processedText,proto3" json:"processed_text"` + CreateTime int64 `protobuf:"varint,8,opt,name=create_time,json=createTime,proto3" json:"create_time"` +} + +func (x *SensitiveWordLogInfo) Reset() { + *x = SensitiveWordLogInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[121] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordLogInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordLogInfo) ProtoMessage() {} + +func (x *SensitiveWordLogInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[121] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordLogInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordLogInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{121} +} + +func (x *SensitiveWordLogInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordLogInfo) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *SensitiveWordLogInfo) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *SensitiveWordLogInfo) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *SensitiveWordLogInfo) GetMatchedWords() []string { + if x != nil { + return x.MatchedWords + } + return nil +} + +func (x *SensitiveWordLogInfo) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SensitiveWordLogInfo) GetProcessedText() string { + if x != nil { + return x.ProcessedText + } + return "" +} + +func (x *SensitiveWordLogInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +// 敏感词统计信息 +type SensitiveWordStatsInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Enabled int64 `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled"` + Disabled int64 `protobuf:"varint,3,opt,name=disabled,proto3" json:"disabled"` + Replace int64 `protobuf:"varint,4,opt,name=replace,proto3" json:"replace"` + Block int64 `protobuf:"varint,5,opt,name=block,proto3" json:"block"` +} + +func (x *SensitiveWordStatsInfo) Reset() { + *x = SensitiveWordStatsInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[122] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordStatsInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordStatsInfo) ProtoMessage() {} + +func (x *SensitiveWordStatsInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[122] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordStatsInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordStatsInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{122} +} + +func (x *SensitiveWordStatsInfo) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetEnabled() int64 { + if x != nil { + return x.Enabled + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetDisabled() int64 { + if x != nil { + return x.Disabled + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetReplace() int64 { + if x != nil { + return x.Replace + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetBlock() int64 { + if x != nil { + return x.Block + } + return 0 +} + +// 敏感词日志统计信息 +type SensitiveWordLogStatsInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Replace int64 `protobuf:"varint,2,opt,name=replace,proto3" json:"replace"` + Block int64 `protobuf:"varint,3,opt,name=block,proto3" json:"block"` +} + +func (x *SensitiveWordLogStatsInfo) Reset() { + *x = SensitiveWordLogStatsInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[123] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordLogStatsInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordLogStatsInfo) ProtoMessage() {} + +func (x *SensitiveWordLogStatsInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[123] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordLogStatsInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordLogStatsInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{123} +} + +func (x *SensitiveWordLogStatsInfo) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SensitiveWordLogStatsInfo) GetReplace() int64 { + if x != nil { + return x.Replace + } + return 0 +} + +func (x *SensitiveWordLogStatsInfo) GetBlock() int64 { + if x != nil { + return x.Block + } + return 0 +} + +// 添加敏感词 +type AddSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word string `protobuf:"bytes,1,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,2,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,3,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,4,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,5,opt,name=status,proto3" json:"status"` + Remark string `protobuf:"bytes,6,opt,name=remark,proto3" json:"remark"` +} + +func (x *AddSensitiveWordReq) Reset() { + *x = AddSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[124] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordReq) ProtoMessage() {} + +func (x *AddSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[124] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{124} +} + +func (x *AddSensitiveWordReq) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *AddSensitiveWordReq) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *AddSensitiveWordReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *AddSensitiveWordReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *AddSensitiveWordReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *AddSensitiveWordReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type AddSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddSensitiveWordResp) Reset() { + *x = AddSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[125] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordResp) ProtoMessage() {} + +func (x *AddSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[125] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{125} +} + +// 更新敏感词 +type UpdateSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Word string `protobuf:"bytes,2,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,5,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` + Remark string `protobuf:"bytes,7,opt,name=remark,proto3" json:"remark"` +} + +func (x *UpdateSensitiveWordReq) Reset() { + *x = UpdateSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[126] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[126] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{126} +} + +func (x *UpdateSensitiveWordReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateSensitiveWordReq) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *UpdateSensitiveWordReq) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type UpdateSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordResp) Reset() { + *x = UpdateSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[127] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[127] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{127} +} + +// 删除敏感词 +type DeleteSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordReq) Reset() { + *x = DeleteSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[128] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[128] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{128} +} + +func (x *DeleteSensitiveWordReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordResp) Reset() { + *x = DeleteSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[129] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[129] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{129} +} + +// 获取敏感词 +type GetSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` +} + +func (x *GetSensitiveWordReq) Reset() { + *x = GetSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[130] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordReq) ProtoMessage() {} + +func (x *GetSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[130] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{130} +} + +func (x *GetSensitiveWordReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word *SensitiveWordInfo `protobuf:"bytes,1,opt,name=word,proto3" json:"word"` +} + +func (x *GetSensitiveWordResp) Reset() { + *x = GetSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[131] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordResp) ProtoMessage() {} + +func (x *GetSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[131] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{131} +} + +func (x *GetSensitiveWordResp) GetWord() *SensitiveWordInfo { + if x != nil { + return x.Word + } + return nil +} + +// 搜索敏感词 +type SearchSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Action int32 `protobuf:"varint,2,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchSensitiveWordsReq) Reset() { + *x = SearchSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[132] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchSensitiveWordsReq) ProtoMessage() {} + +func (x *SearchSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[132] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*SearchSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{132} +} + +func (x *SearchSensitiveWordsReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchSensitiveWordsReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SearchSensitiveWordsReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SearchSensitiveWordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Words []*SensitiveWordInfo `protobuf:"bytes,2,rep,name=words,proto3" json:"words"` +} + +func (x *SearchSensitiveWordsResp) Reset() { + *x = SearchSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[133] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchSensitiveWordsResp) ProtoMessage() {} + +func (x *SearchSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[133] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*SearchSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{133} +} + +func (x *SearchSensitiveWordsResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchSensitiveWordsResp) GetWords() []*SensitiveWordInfo { + if x != nil { + return x.Words + } + return nil +} + +// 批量添加敏感词 +type BatchAddSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Words []*SensitiveWordInfo `protobuf:"bytes,1,rep,name=words,proto3" json:"words"` +} + +func (x *BatchAddSensitiveWordsReq) Reset() { + *x = BatchAddSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[134] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchAddSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchAddSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchAddSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[134] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchAddSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchAddSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{134} +} + +func (x *BatchAddSensitiveWordsReq) GetWords() []*SensitiveWordInfo { + if x != nil { + return x.Words + } + return nil +} + +type BatchAddSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *BatchAddSensitiveWordsResp) Reset() { + *x = BatchAddSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[135] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchAddSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchAddSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchAddSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[135] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchAddSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchAddSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{135} +} + +func (x *BatchAddSensitiveWordsResp) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +// 批量更新敏感词 +type BatchUpdateSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Updates map[string]*SensitiveWordInfo `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *BatchUpdateSensitiveWordsReq) Reset() { + *x = BatchUpdateSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[136] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchUpdateSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[136] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchUpdateSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{136} +} + +func (x *BatchUpdateSensitiveWordsReq) GetUpdates() map[string]*SensitiveWordInfo { + if x != nil { + return x.Updates + } + return nil +} + +type BatchUpdateSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchUpdateSensitiveWordsResp) Reset() { + *x = BatchUpdateSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[137] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchUpdateSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[137] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchUpdateSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{137} +} + +// 批量删除敏感词 +type BatchDeleteSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *BatchDeleteSensitiveWordsReq) Reset() { + *x = BatchDeleteSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[138] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchDeleteSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchDeleteSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchDeleteSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[138] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchDeleteSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchDeleteSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{138} +} + +func (x *BatchDeleteSensitiveWordsReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type BatchDeleteSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchDeleteSensitiveWordsResp) Reset() { + *x = BatchDeleteSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[139] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchDeleteSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchDeleteSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchDeleteSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[139] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchDeleteSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchDeleteSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{139} +} + +// 添加敏感词分组 +type AddSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,2,opt,name=remark,proto3" json:"remark"` +} + +func (x *AddSensitiveWordGroupReq) Reset() { + *x = AddSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[140] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordGroupReq) ProtoMessage() {} + +func (x *AddSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[140] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{140} +} + +func (x *AddSensitiveWordGroupReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddSensitiveWordGroupReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type AddSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddSensitiveWordGroupResp) Reset() { + *x = AddSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[141] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordGroupResp) ProtoMessage() {} + +func (x *AddSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[141] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{141} +} + +// 更新敏感词分组 +type UpdateSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark"` +} + +func (x *UpdateSensitiveWordGroupReq) Reset() { + *x = UpdateSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[142] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordGroupReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[142] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{142} +} + +func (x *UpdateSensitiveWordGroupReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateSensitiveWordGroupReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateSensitiveWordGroupReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type UpdateSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordGroupResp) Reset() { + *x = UpdateSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[143] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordGroupResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[143] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{143} +} + +// 删除敏感词分组 +type DeleteSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordGroupReq) Reset() { + *x = DeleteSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[144] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordGroupReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[144] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{144} +} + +func (x *DeleteSensitiveWordGroupReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordGroupResp) Reset() { + *x = DeleteSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[145] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordGroupResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[145] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{145} +} + +// 获取敏感词分组 +type GetSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` +} + +func (x *GetSensitiveWordGroupReq) Reset() { + *x = GetSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[146] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordGroupReq) ProtoMessage() {} + +func (x *GetSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[146] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{146} +} + +func (x *GetSensitiveWordGroupReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group *SensitiveWordGroupInfo `protobuf:"bytes,1,opt,name=group,proto3" json:"group"` +} + +func (x *GetSensitiveWordGroupResp) Reset() { + *x = GetSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[147] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordGroupResp) ProtoMessage() {} + +func (x *GetSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[147] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{147} +} + +func (x *GetSensitiveWordGroupResp) GetGroup() *SensitiveWordGroupInfo { + if x != nil { + return x.Group + } + return nil +} + +// 获取所有敏感词分组 +type GetAllSensitiveWordGroupsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAllSensitiveWordGroupsReq) Reset() { + *x = GetAllSensitiveWordGroupsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[148] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSensitiveWordGroupsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSensitiveWordGroupsReq) ProtoMessage() {} + +func (x *GetAllSensitiveWordGroupsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[148] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSensitiveWordGroupsReq.ProtoReflect.Descriptor instead. +func (*GetAllSensitiveWordGroupsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{148} +} + +type GetAllSensitiveWordGroupsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Groups []*SensitiveWordGroupInfo `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups"` +} + +func (x *GetAllSensitiveWordGroupsResp) Reset() { + *x = GetAllSensitiveWordGroupsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[149] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSensitiveWordGroupsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSensitiveWordGroupsResp) ProtoMessage() {} + +func (x *GetAllSensitiveWordGroupsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[149] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSensitiveWordGroupsResp.ProtoReflect.Descriptor instead. +func (*GetAllSensitiveWordGroupsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{149} +} + +func (x *GetAllSensitiveWordGroupsResp) GetGroups() []*SensitiveWordGroupInfo { + if x != nil { + return x.Groups + } + return nil +} + +// 获取敏感词配置 +type GetSensitiveWordConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSensitiveWordConfigReq) Reset() { + *x = GetSensitiveWordConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[150] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordConfigReq) ProtoMessage() {} + +func (x *GetSensitiveWordConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[150] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordConfigReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{150} +} + +type GetSensitiveWordConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *SensitiveWordConfigInfo `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` +} + +func (x *GetSensitiveWordConfigResp) Reset() { + *x = GetSensitiveWordConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[151] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordConfigResp) ProtoMessage() {} + +func (x *GetSensitiveWordConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[151] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordConfigResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{151} +} + +func (x *GetSensitiveWordConfigResp) GetConfig() *SensitiveWordConfigInfo { + if x != nil { + return x.Config + } + return nil +} + +// 更新敏感词配置 +type UpdateSensitiveWordConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *SensitiveWordConfigInfo `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` +} + +func (x *UpdateSensitiveWordConfigReq) Reset() { + *x = UpdateSensitiveWordConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[152] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordConfigReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[152] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordConfigReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{152} +} + +func (x *UpdateSensitiveWordConfigReq) GetConfig() *SensitiveWordConfigInfo { + if x != nil { + return x.Config + } + return nil +} + +type UpdateSensitiveWordConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordConfigResp) Reset() { + *x = UpdateSensitiveWordConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[153] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordConfigResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[153] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordConfigResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{153} +} + +// 获取敏感词日志 +type GetSensitiveWordLogsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` + GroupId string `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *GetSensitiveWordLogsReq) Reset() { + *x = GetSensitiveWordLogsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[154] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogsReq) ProtoMessage() {} + +func (x *GetSensitiveWordLogsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[154] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{154} +} + +func (x *GetSensitiveWordLogsReq) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetSensitiveWordLogsReq) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *GetSensitiveWordLogsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetSensitiveWordLogsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Logs []*SensitiveWordLogInfo `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs"` +} + +func (x *GetSensitiveWordLogsResp) Reset() { + *x = GetSensitiveWordLogsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[155] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogsResp) ProtoMessage() {} + +func (x *GetSensitiveWordLogsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[155] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{155} +} + +func (x *GetSensitiveWordLogsResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetSensitiveWordLogsResp) GetLogs() []*SensitiveWordLogInfo { + if x != nil { + return x.Logs + } + return nil +} + +// 用户登录记录信息 +type UserLoginRecordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` // 用户ID + LoginTime int64 `protobuf:"varint,2,opt,name=login_time,json=loginTime,proto3" json:"login_time"` // 登录时间(毫秒时间戳) + Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip"` // 登录IP + DeviceId string `protobuf:"bytes,4,opt,name=device_id,json=deviceId,proto3" json:"device_id"` // 设备ID + Platform string `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform"` // 平台 + FaceUrl string `protobuf:"bytes,6,opt,name=face_url,json=faceUrl,proto3" json:"face_url"` // 用户头像 + Nickname string `protobuf:"bytes,7,opt,name=nickname,proto3" json:"nickname"` // 用户昵称 +} + +func (x *UserLoginRecordInfo) Reset() { + *x = UserLoginRecordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[156] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserLoginRecordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserLoginRecordInfo) ProtoMessage() {} + +func (x *UserLoginRecordInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[156] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserLoginRecordInfo.ProtoReflect.Descriptor instead. +func (*UserLoginRecordInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{156} +} + +func (x *UserLoginRecordInfo) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UserLoginRecordInfo) GetLoginTime() int64 { + if x != nil { + return x.LoginTime + } + return 0 +} + +func (x *UserLoginRecordInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *UserLoginRecordInfo) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *UserLoginRecordInfo) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *UserLoginRecordInfo) GetFaceUrl() string { + if x != nil { + return x.FaceUrl + } + return "" +} + +func (x *UserLoginRecordInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +// 查询用户登录记录请求 +type GetUserLoginRecordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` // 用户ID(可选,如果提供则查询该用户的登录记录) + Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip"` // IP地址(可选,如果提供则查询使用该IP的所有登录记录) + Pagination *sdkws.RequestPagination `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetUserLoginRecordsReq) Reset() { + *x = GetUserLoginRecordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[157] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserLoginRecordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserLoginRecordsReq) ProtoMessage() {} + +func (x *GetUserLoginRecordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[157] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserLoginRecordsReq.ProtoReflect.Descriptor instead. +func (*GetUserLoginRecordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{157} +} + +func (x *GetUserLoginRecordsReq) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetUserLoginRecordsReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *GetUserLoginRecordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 查询用户登录记录响应 +type GetUserLoginRecordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Records []*UserLoginRecordInfo `protobuf:"bytes,2,rep,name=records,proto3" json:"records"` // 登录记录列表 +} + +func (x *GetUserLoginRecordsResp) Reset() { + *x = GetUserLoginRecordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[158] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserLoginRecordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserLoginRecordsResp) ProtoMessage() {} + +func (x *GetUserLoginRecordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[158] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserLoginRecordsResp.ProtoReflect.Descriptor instead. +func (*GetUserLoginRecordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{158} +} + +func (x *GetUserLoginRecordsResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetUserLoginRecordsResp) GetRecords() []*UserLoginRecordInfo { + if x != nil { + return x.Records + } + return nil +} + +// 删除敏感词日志 +type DeleteSensitiveWordLogsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordLogsReq) Reset() { + *x = DeleteSensitiveWordLogsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[159] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordLogsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordLogsReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordLogsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[159] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordLogsReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordLogsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{159} +} + +func (x *DeleteSensitiveWordLogsReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordLogsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordLogsResp) Reset() { + *x = DeleteSensitiveWordLogsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[160] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordLogsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordLogsResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordLogsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[160] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordLogsResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordLogsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{160} +} + +// 获取敏感词统计 +type GetSensitiveWordStatsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSensitiveWordStatsReq) Reset() { + *x = GetSensitiveWordStatsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[161] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordStatsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordStatsReq) ProtoMessage() {} + +func (x *GetSensitiveWordStatsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[161] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordStatsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordStatsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{161} +} + +type GetSensitiveWordStatsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *SensitiveWordStatsInfo `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats"` +} + +func (x *GetSensitiveWordStatsResp) Reset() { + *x = GetSensitiveWordStatsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[162] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordStatsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordStatsResp) ProtoMessage() {} + +func (x *GetSensitiveWordStatsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[162] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordStatsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordStatsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{162} +} + +func (x *GetSensitiveWordStatsResp) GetStats() *SensitiveWordStatsInfo { + if x != nil { + return x.Stats + } + return nil +} + +// 获取敏感词日志统计 +type GetSensitiveWordLogStatsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartTime int64 `protobuf:"varint,1,opt,name=start_time,json=startTime,proto3" json:"start_time"` + EndTime int64 `protobuf:"varint,2,opt,name=end_time,json=endTime,proto3" json:"end_time"` +} + +func (x *GetSensitiveWordLogStatsReq) Reset() { + *x = GetSensitiveWordLogStatsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[163] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogStatsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogStatsReq) ProtoMessage() {} + +func (x *GetSensitiveWordLogStatsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[163] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogStatsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogStatsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{163} +} + +func (x *GetSensitiveWordLogStatsReq) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *GetSensitiveWordLogStatsReq) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +type GetSensitiveWordLogStatsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *SensitiveWordLogStatsInfo `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats"` +} + +func (x *GetSensitiveWordLogStatsResp) Reset() { + *x = GetSensitiveWordLogStatsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[164] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogStatsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogStatsResp) ProtoMessage() {} + +func (x *GetSensitiveWordLogStatsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[164] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogStatsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogStatsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{164} +} + +func (x *GetSensitiveWordLogStatsResp) GetStats() *SensitiveWordLogStatsInfo { + if x != nil { + return x.Stats + } + return nil +} + +// 获取定时任务列表请求 +type GetScheduledTasksReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetScheduledTasksReq) Reset() { + *x = GetScheduledTasksReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[165] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTasksReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTasksReq) ProtoMessage() {} + +func (x *GetScheduledTasksReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[165] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTasksReq.ProtoReflect.Descriptor instead. +func (*GetScheduledTasksReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{165} +} + +func (x *GetScheduledTasksReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 定时任务消息内容 +type ScheduledTaskMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type"` // 消息类型:1-文本,2-图片,3-视频 + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` // 消息内容(文本内容、图片URL、视频URL等) + Thumbnail string `protobuf:"bytes,3,opt,name=thumbnail,proto3" json:"thumbnail"` // 缩略图URL(用于图片和视频) + Duration int32 `protobuf:"varint,4,opt,name=duration,proto3" json:"duration"` // 时长(秒,用于视频) + FileSize int64 `protobuf:"varint,5,opt,name=fileSize,proto3" json:"fileSize"` // 文件大小(字节,用于图片和视频) + Width int32 `protobuf:"varint,6,opt,name=width,proto3" json:"width"` // 宽度(像素,用于图片和视频) + Height int32 `protobuf:"varint,7,opt,name=height,proto3" json:"height"` // 高度(像素,用于图片和视频) +} + +func (x *ScheduledTaskMessage) Reset() { + *x = ScheduledTaskMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[166] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScheduledTaskMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduledTaskMessage) ProtoMessage() {} + +func (x *ScheduledTaskMessage) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[166] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduledTaskMessage.ProtoReflect.Descriptor instead. +func (*ScheduledTaskMessage) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{166} +} + +func (x *ScheduledTaskMessage) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *ScheduledTaskMessage) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *ScheduledTaskMessage) GetThumbnail() string { + if x != nil { + return x.Thumbnail + } + return "" +} + +func (x *ScheduledTaskMessage) GetDuration() int32 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *ScheduledTaskMessage) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *ScheduledTaskMessage) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *ScheduledTaskMessage) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +// 定时任务信息 +type ScheduledTaskInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 任务ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name"` // 任务名称 + CronExpression string `protobuf:"bytes,4,opt,name=cronExpression,proto3" json:"cronExpression"` // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + Messages []*ScheduledTaskMessage `protobuf:"bytes,5,rep,name=messages,proto3" json:"messages"` // 消息列表(支持多条消息一起发送) + RecvIDs []string `protobuf:"bytes,6,rep,name=recvIDs,proto3" json:"recvIDs"` // 接收者ID列表(单聊,可以多个) + GroupIDs []string `protobuf:"bytes,7,rep,name=groupIDs,proto3" json:"groupIDs"` // 群组ID列表(群聊,可以多个) + Status int32 `protobuf:"varint,8,opt,name=status,proto3" json:"status"` // 状态:0-已禁用,1-已启用 + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,10,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *ScheduledTaskInfo) Reset() { + *x = ScheduledTaskInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[167] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScheduledTaskInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduledTaskInfo) ProtoMessage() {} + +func (x *ScheduledTaskInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[167] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduledTaskInfo.ProtoReflect.Descriptor instead. +func (*ScheduledTaskInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{167} +} + +func (x *ScheduledTaskInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ScheduledTaskInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *ScheduledTaskInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ScheduledTaskInfo) GetCronExpression() string { + if x != nil { + return x.CronExpression + } + return "" +} + +func (x *ScheduledTaskInfo) GetMessages() []*ScheduledTaskMessage { + if x != nil { + return x.Messages + } + return nil +} + +func (x *ScheduledTaskInfo) GetRecvIDs() []string { + if x != nil { + return x.RecvIDs + } + return nil +} + +func (x *ScheduledTaskInfo) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +func (x *ScheduledTaskInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *ScheduledTaskInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *ScheduledTaskInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 获取定时任务列表响应 +type GetScheduledTasksResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Tasks []*ScheduledTaskInfo `protobuf:"bytes,2,rep,name=tasks,proto3" json:"tasks"` // 任务列表 +} + +func (x *GetScheduledTasksResp) Reset() { + *x = GetScheduledTasksResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[168] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTasksResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTasksResp) ProtoMessage() {} + +func (x *GetScheduledTasksResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[168] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTasksResp.ProtoReflect.Descriptor instead. +func (*GetScheduledTasksResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{168} +} + +func (x *GetScheduledTasksResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetScheduledTasksResp) GetTasks() []*ScheduledTaskInfo { + if x != nil { + return x.Tasks + } + return nil +} + +// 删除定时任务请求 +type DeleteScheduledTaskReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskIDs []string `protobuf:"bytes,1,rep,name=taskIDs,proto3" json:"taskIDs"` // 任务ID列表 +} + +func (x *DeleteScheduledTaskReq) Reset() { + *x = DeleteScheduledTaskReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[169] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteScheduledTaskReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteScheduledTaskReq) ProtoMessage() {} + +func (x *DeleteScheduledTaskReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[169] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteScheduledTaskReq.ProtoReflect.Descriptor instead. +func (*DeleteScheduledTaskReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{169} +} + +func (x *DeleteScheduledTaskReq) GetTaskIDs() []string { + if x != nil { + return x.TaskIDs + } + return nil +} + +// 删除定时任务响应 +type DeleteScheduledTaskResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteScheduledTaskResp) Reset() { + *x = DeleteScheduledTaskResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[170] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteScheduledTaskResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteScheduledTaskResp) ProtoMessage() {} + +func (x *DeleteScheduledTaskResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[170] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteScheduledTaskResp.ProtoReflect.Descriptor instead. +func (*DeleteScheduledTaskResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{170} +} + +// 系统配置信息 +type SystemConfigInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键(唯一标识) + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 配置标题 + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value"` // 配置值(字符串形式存储,根据ValueType解析) + ValueType int32 `protobuf:"varint,4,opt,name=valueType,proto3" json:"valueType"` // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description"` // 配置描述 + Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled"` // 是否启用(用于开关类配置) + ShowInApp bool `protobuf:"varint,7,opt,name=showInApp,proto3" json:"showInApp"` // 是否在APP端展示 + CreateTime int64 `protobuf:"varint,8,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,9,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *SystemConfigInfo) Reset() { + *x = SystemConfigInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[171] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SystemConfigInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemConfigInfo) ProtoMessage() {} + +func (x *SystemConfigInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[171] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SystemConfigInfo.ProtoReflect.Descriptor instead. +func (*SystemConfigInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{171} +} + +func (x *SystemConfigInfo) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *SystemConfigInfo) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *SystemConfigInfo) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *SystemConfigInfo) GetValueType() int32 { + if x != nil { + return x.ValueType + } + return 0 +} + +func (x *SystemConfigInfo) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *SystemConfigInfo) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *SystemConfigInfo) GetShowInApp() bool { + if x != nil { + return x.ShowInApp + } + return false +} + +func (x *SystemConfigInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SystemConfigInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 创建系统配置 +type CreateSystemConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键(唯一标识) + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 配置标题 + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value"` // 配置值 + ValueType int32 `protobuf:"varint,4,opt,name=valueType,proto3" json:"valueType"` // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description"` // 配置描述 + Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled"` // 是否启用 + ShowInApp bool `protobuf:"varint,7,opt,name=showInApp,proto3" json:"showInApp"` // 是否在APP端展示(默认为false) +} + +func (x *CreateSystemConfigReq) Reset() { + *x = CreateSystemConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[172] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSystemConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSystemConfigReq) ProtoMessage() {} + +func (x *CreateSystemConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[172] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateSystemConfigReq.ProtoReflect.Descriptor instead. +func (*CreateSystemConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{172} +} + +func (x *CreateSystemConfigReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *CreateSystemConfigReq) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreateSystemConfigReq) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *CreateSystemConfigReq) GetValueType() int32 { + if x != nil { + return x.ValueType + } + return 0 +} + +func (x *CreateSystemConfigReq) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CreateSystemConfigReq) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *CreateSystemConfigReq) GetShowInApp() bool { + if x != nil { + return x.ShowInApp + } + return false +} + +type CreateSystemConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CreateSystemConfigResp) Reset() { + *x = CreateSystemConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[173] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSystemConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSystemConfigResp) ProtoMessage() {} + +func (x *CreateSystemConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[173] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateSystemConfigResp.ProtoReflect.Descriptor instead. +func (*CreateSystemConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{173} +} + +// 获取系统配置 +type GetSystemConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键 +} + +func (x *GetSystemConfigReq) Reset() { + *x = GetSystemConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[174] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSystemConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSystemConfigReq) ProtoMessage() {} + +func (x *GetSystemConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[174] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSystemConfigReq.ProtoReflect.Descriptor instead. +func (*GetSystemConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{174} +} + +func (x *GetSystemConfigReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +type GetSystemConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *SystemConfigInfo `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` // 配置信息 +} + +func (x *GetSystemConfigResp) Reset() { + *x = GetSystemConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[175] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSystemConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSystemConfigResp) ProtoMessage() {} + +func (x *GetSystemConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[175] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSystemConfigResp.ProtoReflect.Descriptor instead. +func (*GetSystemConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{175} +} + +func (x *GetSystemConfigResp) GetConfig() *SystemConfigInfo { + if x != nil { + return x.Config + } + return nil +} + +// 获取所有系统配置(分页) +type GetAllSystemConfigsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetAllSystemConfigsReq) Reset() { + *x = GetAllSystemConfigsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[176] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSystemConfigsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSystemConfigsReq) ProtoMessage() {} + +func (x *GetAllSystemConfigsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[176] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSystemConfigsReq.ProtoReflect.Descriptor instead. +func (*GetAllSystemConfigsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{176} +} + +func (x *GetAllSystemConfigsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetAllSystemConfigsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + List []*SystemConfigInfo `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` // 配置列表 +} + +func (x *GetAllSystemConfigsResp) Reset() { + *x = GetAllSystemConfigsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[177] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSystemConfigsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSystemConfigsResp) ProtoMessage() {} + +func (x *GetAllSystemConfigsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[177] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSystemConfigsResp.ProtoReflect.Descriptor instead. +func (*GetAllSystemConfigsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{177} +} + +func (x *GetAllSystemConfigsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetAllSystemConfigsResp) GetList() []*SystemConfigInfo { + if x != nil { + return x.List + } + return nil +} + +// 更新系统配置 +type UpdateSystemConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键 + Title *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 配置标题(可选) + Value *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=value,proto3" json:"value"` // 配置值(可选) + ValueType *wrapperspb.Int32Value `protobuf:"bytes,4,opt,name=valueType,proto3" json:"valueType"` // 配置值类型(可选) + Description *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=description,proto3" json:"description"` // 配置描述(可选) + Enabled *wrapperspb.BoolValue `protobuf:"bytes,6,opt,name=enabled,proto3" json:"enabled"` // 是否启用(可选) + ShowInApp *wrapperspb.BoolValue `protobuf:"bytes,7,opt,name=showInApp,proto3" json:"showInApp"` // 是否在APP端展示(可选) +} + +func (x *UpdateSystemConfigReq) Reset() { + *x = UpdateSystemConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[178] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigReq) ProtoMessage() {} + +func (x *UpdateSystemConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[178] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigReq.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{178} +} + +func (x *UpdateSystemConfigReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *UpdateSystemConfigReq) GetTitle() *wrapperspb.StringValue { + if x != nil { + return x.Title + } + return nil +} + +func (x *UpdateSystemConfigReq) GetValue() *wrapperspb.StringValue { + if x != nil { + return x.Value + } + return nil +} + +func (x *UpdateSystemConfigReq) GetValueType() *wrapperspb.Int32Value { + if x != nil { + return x.ValueType + } + return nil +} + +func (x *UpdateSystemConfigReq) GetDescription() *wrapperspb.StringValue { + if x != nil { + return x.Description + } + return nil +} + +func (x *UpdateSystemConfigReq) GetEnabled() *wrapperspb.BoolValue { + if x != nil { + return x.Enabled + } + return nil +} + +func (x *UpdateSystemConfigReq) GetShowInApp() *wrapperspb.BoolValue { + if x != nil { + return x.ShowInApp + } + return nil +} + +type UpdateSystemConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSystemConfigResp) Reset() { + *x = UpdateSystemConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[179] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigResp) ProtoMessage() {} + +func (x *UpdateSystemConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[179] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigResp.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{179} +} + +// 更新系统配置值 +type UpdateSystemConfigValueReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键 + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value"` // 配置值 +} + +func (x *UpdateSystemConfigValueReq) Reset() { + *x = UpdateSystemConfigValueReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[180] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigValueReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigValueReq) ProtoMessage() {} + +func (x *UpdateSystemConfigValueReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[180] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigValueReq.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigValueReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{180} +} + +func (x *UpdateSystemConfigValueReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *UpdateSystemConfigValueReq) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +type UpdateSystemConfigValueResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSystemConfigValueResp) Reset() { + *x = UpdateSystemConfigValueResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[181] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigValueResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigValueResp) ProtoMessage() {} + +func (x *UpdateSystemConfigValueResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[181] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigValueResp.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigValueResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{181} +} + +// 更新系统配置启用状态 +type UpdateSystemConfigEnabledReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键 + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled"` // 是否启用 +} + +func (x *UpdateSystemConfigEnabledReq) Reset() { + *x = UpdateSystemConfigEnabledReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[182] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigEnabledReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigEnabledReq) ProtoMessage() {} + +func (x *UpdateSystemConfigEnabledReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[182] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigEnabledReq.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigEnabledReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{182} +} + +func (x *UpdateSystemConfigEnabledReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *UpdateSystemConfigEnabledReq) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +type UpdateSystemConfigEnabledResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSystemConfigEnabledResp) Reset() { + *x = UpdateSystemConfigEnabledResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[183] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSystemConfigEnabledResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSystemConfigEnabledResp) ProtoMessage() {} + +func (x *UpdateSystemConfigEnabledResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[183] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSystemConfigEnabledResp.ProtoReflect.Descriptor instead. +func (*UpdateSystemConfigEnabledResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{183} +} + +// 删除系统配置 +type DeleteSystemConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys"` // 配置键列表 +} + +func (x *DeleteSystemConfigReq) Reset() { + *x = DeleteSystemConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[184] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSystemConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSystemConfigReq) ProtoMessage() {} + +func (x *DeleteSystemConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[184] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSystemConfigReq.ProtoReflect.Descriptor instead. +func (*DeleteSystemConfigReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{184} +} + +func (x *DeleteSystemConfigReq) GetKeys() []string { + if x != nil { + return x.Keys + } + return nil +} + +type DeleteSystemConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSystemConfigResp) Reset() { + *x = DeleteSystemConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[185] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSystemConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSystemConfigResp) ProtoMessage() {} + +func (x *DeleteSystemConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[185] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSystemConfigResp.ProtoReflect.Descriptor instead. +func (*DeleteSystemConfigResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{185} +} + +// 获取所有已启用的配置 +type GetEnabledSystemConfigsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetEnabledSystemConfigsReq) Reset() { + *x = GetEnabledSystemConfigsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[186] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetEnabledSystemConfigsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEnabledSystemConfigsReq) ProtoMessage() {} + +func (x *GetEnabledSystemConfigsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[186] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEnabledSystemConfigsReq.ProtoReflect.Descriptor instead. +func (*GetEnabledSystemConfigsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{186} +} + +type GetEnabledSystemConfigsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + List []*SystemConfigInfo `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` // 配置列表 +} + +func (x *GetEnabledSystemConfigsResp) Reset() { + *x = GetEnabledSystemConfigsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[187] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetEnabledSystemConfigsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEnabledSystemConfigsResp) ProtoMessage() {} + +func (x *GetEnabledSystemConfigsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[187] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEnabledSystemConfigsResp.ProtoReflect.Descriptor instead. +func (*GetEnabledSystemConfigsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{187} +} + +func (x *GetEnabledSystemConfigsResp) GetList() []*SystemConfigInfo { + if x != nil { + return x.List + } + return nil +} + +// 实名认证信息 +type RealNameAuthInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IdCard string `protobuf:"bytes,1,opt,name=idCard,proto3" json:"idCard"` // 身份证号 + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` // 真实姓名 + IdCardPhotoFront string `protobuf:"bytes,3,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL + IdCardPhotoBack string `protobuf:"bytes,4,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL + AuditStatus int32 `protobuf:"varint,5,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +func (x *RealNameAuthInfo) Reset() { + *x = RealNameAuthInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[188] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RealNameAuthInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RealNameAuthInfo) ProtoMessage() {} + +func (x *RealNameAuthInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[188] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RealNameAuthInfo.ProtoReflect.Descriptor instead. +func (*RealNameAuthInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{188} +} + +func (x *RealNameAuthInfo) GetIdCard() string { + if x != nil { + return x.IdCard + } + return "" +} + +func (x *RealNameAuthInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RealNameAuthInfo) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *RealNameAuthInfo) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +func (x *RealNameAuthInfo) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +// 钱包信息 +type WalletInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Balance int64 `protobuf:"varint,2,opt,name=balance,proto3" json:"balance"` // 余额(单位:分) + WithdrawAccount string `protobuf:"bytes,3,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提现账号 + RealNameAuth *RealNameAuthInfo `protobuf:"bytes,4,opt,name=realNameAuth,proto3" json:"realNameAuth"` // 实名认证信息 + WithdrawReceiveAccount string `protobuf:"bytes,5,opt,name=withdrawReceiveAccount,proto3" json:"withdrawReceiveAccount"` // 提现收款账号 + HasPaymentPassword bool `protobuf:"varint,6,opt,name=hasPaymentPassword,proto3" json:"hasPaymentPassword"` // 是否已设置支付密码 + CreateTime int64 `protobuf:"varint,7,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,8,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *WalletInfo) Reset() { + *x = WalletInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[189] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WalletInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WalletInfo) ProtoMessage() {} + +func (x *WalletInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[189] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WalletInfo.ProtoReflect.Descriptor instead. +func (*WalletInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{189} +} + +func (x *WalletInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WalletInfo) GetBalance() int64 { + if x != nil { + return x.Balance + } + return 0 +} + +func (x *WalletInfo) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +func (x *WalletInfo) GetRealNameAuth() *RealNameAuthInfo { + if x != nil { + return x.RealNameAuth + } + return nil +} + +func (x *WalletInfo) GetWithdrawReceiveAccount() string { + if x != nil { + return x.WithdrawReceiveAccount + } + return "" +} + +func (x *WalletInfo) GetHasPaymentPassword() bool { + if x != nil { + return x.HasPaymentPassword + } + return false +} + +func (x *WalletInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *WalletInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 余额变动记录信息 +type WalletBalanceRecordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 记录ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount"` // 变动金额(单位:分,正数表示增加,负数表示减少) + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` // 变动类型:1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 + BeforeBalance int64 `protobuf:"varint,5,opt,name=beforeBalance,proto3" json:"beforeBalance"` // 变动前余额(单位:分) + AfterBalance int64 `protobuf:"varint,6,opt,name=afterBalance,proto3" json:"afterBalance"` // 变动后余额(单位:分) + OrderID string `protobuf:"bytes,7,opt,name=orderID,proto3" json:"orderID"` // 关联订单ID(可选) + TransactionID string `protobuf:"bytes,8,opt,name=transactionID,proto3" json:"transactionID"` // 交易ID(可选) + RedPacketID string `protobuf:"bytes,9,opt,name=redPacketID,proto3" json:"redPacketID"` // 红包ID(可选) + Remark string `protobuf:"bytes,10,opt,name=remark,proto3" json:"remark"` // 备注 + CreateTime int64 `protobuf:"varint,11,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) +} + +func (x *WalletBalanceRecordInfo) Reset() { + *x = WalletBalanceRecordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[190] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WalletBalanceRecordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WalletBalanceRecordInfo) ProtoMessage() {} + +func (x *WalletBalanceRecordInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[190] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WalletBalanceRecordInfo.ProtoReflect.Descriptor instead. +func (*WalletBalanceRecordInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{190} +} + +func (x *WalletBalanceRecordInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetBeforeBalance() int64 { + if x != nil { + return x.BeforeBalance + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetAfterBalance() int64 { + if x != nil { + return x.AfterBalance + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetOrderID() string { + if x != nil { + return x.OrderID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetTransactionID() string { + if x != nil { + return x.TransactionID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetRedPacketID() string { + if x != nil { + return x.RedPacketID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +// 获取用户钱包信息请求 +type GetUserWalletReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID +} + +func (x *GetUserWalletReq) Reset() { + *x = GetUserWalletReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[191] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWalletReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWalletReq) ProtoMessage() {} + +func (x *GetUserWalletReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[191] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWalletReq.ProtoReflect.Descriptor instead. +func (*GetUserWalletReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{191} +} + +func (x *GetUserWalletReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +// 获取用户钱包信息响应 +type GetUserWalletResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Wallet *WalletInfo `protobuf:"bytes,1,opt,name=wallet,proto3" json:"wallet"` // 钱包信息 +} + +func (x *GetUserWalletResp) Reset() { + *x = GetUserWalletResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[192] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWalletResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWalletResp) ProtoMessage() {} + +func (x *GetUserWalletResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[192] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWalletResp.ProtoReflect.Descriptor instead. +func (*GetUserWalletResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{192} +} + +func (x *GetUserWalletResp) GetWallet() *WalletInfo { + if x != nil { + return x.Wallet + } + return nil +} + +// 更新用户余额请求 +type UpdateUserWalletBalanceReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount"` // 变动金额(单位:分,正数表示增加,负数表示减少) + Type int32 `protobuf:"varint,3,opt,name=type,proto3" json:"type"` // 变动类型:6-后台充值,99-其他(后台操作) + Remark string `protobuf:"bytes,4,opt,name=remark,proto3" json:"remark"` // 备注 + OperationPassword string `protobuf:"bytes,5,opt,name=operationPassword,proto3" json:"operationPassword"` // 操作密码(超级管理员必须提供并验证) +} + +func (x *UpdateUserWalletBalanceReq) Reset() { + *x = UpdateUserWalletBalanceReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[193] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserWalletBalanceReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserWalletBalanceReq) ProtoMessage() {} + +func (x *UpdateUserWalletBalanceReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[193] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserWalletBalanceReq.ProtoReflect.Descriptor instead. +func (*UpdateUserWalletBalanceReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{193} +} + +func (x *UpdateUserWalletBalanceReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UpdateUserWalletBalanceReq) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *UpdateUserWalletBalanceReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *UpdateUserWalletBalanceReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *UpdateUserWalletBalanceReq) GetOperationPassword() string { + if x != nil { + return x.OperationPassword + } + return "" +} + +// 更新用户余额响应 +type UpdateUserWalletBalanceResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Balance int64 `protobuf:"varint,1,opt,name=balance,proto3" json:"balance"` // 更新后的余额(单位:分) +} + +func (x *UpdateUserWalletBalanceResp) Reset() { + *x = UpdateUserWalletBalanceResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[194] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserWalletBalanceResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserWalletBalanceResp) ProtoMessage() {} + +func (x *UpdateUserWalletBalanceResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[194] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserWalletBalanceResp.ProtoReflect.Descriptor instead. +func (*UpdateUserWalletBalanceResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{194} +} + +func (x *UpdateUserWalletBalanceResp) GetBalance() int64 { + if x != nil { + return x.Balance + } + return 0 +} + +// 获取用户余额变动记录列表请求 +type GetUserWalletBalanceRecordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetUserWalletBalanceRecordsReq) Reset() { + *x = GetUserWalletBalanceRecordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[195] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWalletBalanceRecordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWalletBalanceRecordsReq) ProtoMessage() {} + +func (x *GetUserWalletBalanceRecordsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[195] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWalletBalanceRecordsReq.ProtoReflect.Descriptor instead. +func (*GetUserWalletBalanceRecordsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{195} +} + +func (x *GetUserWalletBalanceRecordsReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GetUserWalletBalanceRecordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 获取用户余额变动记录列表响应 +type GetUserWalletBalanceRecordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + List []*WalletBalanceRecordInfo `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` // 记录列表 +} + +func (x *GetUserWalletBalanceRecordsResp) Reset() { + *x = GetUserWalletBalanceRecordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[196] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWalletBalanceRecordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWalletBalanceRecordsResp) ProtoMessage() {} + +func (x *GetUserWalletBalanceRecordsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[196] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWalletBalanceRecordsResp.ProtoReflect.Descriptor instead. +func (*GetUserWalletBalanceRecordsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{196} +} + +func (x *GetUserWalletBalanceRecordsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetUserWalletBalanceRecordsResp) GetList() []*WalletBalanceRecordInfo { + if x != nil { + return x.List + } + return nil +} + +// 修改用户支付密码请求 +type UpdateUserPaymentPasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + PaymentPassword string `protobuf:"bytes,2,opt,name=paymentPassword,proto3" json:"paymentPassword"` // 新的支付密码(需要加密后存储) +} + +func (x *UpdateUserPaymentPasswordReq) Reset() { + *x = UpdateUserPaymentPasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[197] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserPaymentPasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserPaymentPasswordReq) ProtoMessage() {} + +func (x *UpdateUserPaymentPasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[197] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserPaymentPasswordReq.ProtoReflect.Descriptor instead. +func (*UpdateUserPaymentPasswordReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{197} +} + +func (x *UpdateUserPaymentPasswordReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UpdateUserPaymentPasswordReq) GetPaymentPassword() string { + if x != nil { + return x.PaymentPassword + } + return "" +} + +// 修改用户支付密码响应 +type UpdateUserPaymentPasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateUserPaymentPasswordResp) Reset() { + *x = UpdateUserPaymentPasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[198] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserPaymentPasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserPaymentPasswordResp) ProtoMessage() {} + +func (x *UpdateUserPaymentPasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[198] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserPaymentPasswordResp.ProtoReflect.Descriptor instead. +func (*UpdateUserPaymentPasswordResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{198} +} + +// 设置用户提款账号请求 +type SetUserWithdrawAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + WithdrawAccount string `protobuf:"bytes,2,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提款账号 +} + +func (x *SetUserWithdrawAccountReq) Reset() { + *x = SetUserWithdrawAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[199] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetUserWithdrawAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUserWithdrawAccountReq) ProtoMessage() {} + +func (x *SetUserWithdrawAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[199] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetUserWithdrawAccountReq.ProtoReflect.Descriptor instead. +func (*SetUserWithdrawAccountReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{199} +} + +func (x *SetUserWithdrawAccountReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *SetUserWithdrawAccountReq) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +// 设置用户提款账号响应 +type SetUserWithdrawAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetUserWithdrawAccountResp) Reset() { + *x = SetUserWithdrawAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[200] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetUserWithdrawAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUserWithdrawAccountResp) ProtoMessage() {} + +func (x *SetUserWithdrawAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[200] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetUserWithdrawAccountResp.ProtoReflect.Descriptor instead. +func (*SetUserWithdrawAccountResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{200} +} + +// 批量更新用户余额请求 - 单个用户的操作项 +type BatchUpdateUserItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID(选填,与 phoneNumber/account 至少提供一个) + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` // 手机号(选填) + Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` // 账号(选填) + Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount"` // 金额(分)(选填,如果不填则使用默认金额) + Operation string `protobuf:"bytes,5,opt,name=operation,proto3" json:"operation"` // 操作类型(选填,如果不填则使用默认操作):set/add/subtract + Remark string `protobuf:"bytes,6,opt,name=remark,proto3" json:"remark"` // 备注信息(选填) +} + +func (x *BatchUpdateUserItem) Reset() { + *x = BatchUpdateUserItem{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[201] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateUserItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateUserItem) ProtoMessage() {} + +func (x *BatchUpdateUserItem) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[201] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateUserItem.ProtoReflect.Descriptor instead. +func (*BatchUpdateUserItem) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{201} +} + +func (x *BatchUpdateUserItem) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *BatchUpdateUserItem) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *BatchUpdateUserItem) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *BatchUpdateUserItem) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *BatchUpdateUserItem) GetOperation() string { + if x != nil { + return x.Operation + } + return "" +} + +func (x *BatchUpdateUserItem) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +// 批量更新用户余额请求 +type BatchUpdateWalletBalanceReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*BatchUpdateUserItem `protobuf:"bytes,1,rep,name=users,proto3" json:"users"` // 用户列表(必填) + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount"` // 默认金额(分),用户未指定时使用此值 + Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation"` // 默认操作类型:set/add/subtract,默认为add + OperationPassword string `protobuf:"bytes,4,opt,name=operationPassword,proto3" json:"operationPassword"` // 操作密码(超级管理员必须提供并验证) +} + +func (x *BatchUpdateWalletBalanceReq) Reset() { + *x = BatchUpdateWalletBalanceReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[202] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateWalletBalanceReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateWalletBalanceReq) ProtoMessage() {} + +func (x *BatchUpdateWalletBalanceReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[202] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateWalletBalanceReq.ProtoReflect.Descriptor instead. +func (*BatchUpdateWalletBalanceReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{202} +} + +func (x *BatchUpdateWalletBalanceReq) GetUsers() []*BatchUpdateUserItem { + if x != nil { + return x.Users + } + return nil +} + +func (x *BatchUpdateWalletBalanceReq) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *BatchUpdateWalletBalanceReq) GetOperation() string { + if x != nil { + return x.Operation + } + return "" +} + +func (x *BatchUpdateWalletBalanceReq) GetOperationPassword() string { + if x != nil { + return x.OperationPassword + } + return "" +} + +// 批量更新用户余额响应 - 单个用户的结果 +type BatchUpdateResultItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` // 手机号 + Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` // 账号 + Success bool `protobuf:"varint,4,opt,name=success,proto3" json:"success"` // 是否成功 + Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message"` // 结果消息 + OldBalance int64 `protobuf:"varint,6,opt,name=oldBalance,proto3" json:"oldBalance"` // 修改前余额(分) + NewBalance int64 `protobuf:"varint,7,opt,name=newBalance,proto3" json:"newBalance"` // 修改后余额(分) + Remark string `protobuf:"bytes,8,opt,name=remark,proto3" json:"remark"` // 备注信息 +} + +func (x *BatchUpdateResultItem) Reset() { + *x = BatchUpdateResultItem{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[203] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateResultItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateResultItem) ProtoMessage() {} + +func (x *BatchUpdateResultItem) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[203] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateResultItem.ProtoReflect.Descriptor instead. +func (*BatchUpdateResultItem) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{203} +} + +func (x *BatchUpdateResultItem) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *BatchUpdateResultItem) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *BatchUpdateResultItem) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *BatchUpdateResultItem) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *BatchUpdateResultItem) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *BatchUpdateResultItem) GetOldBalance() int64 { + if x != nil { + return x.OldBalance + } + return 0 +} + +func (x *BatchUpdateResultItem) GetNewBalance() int64 { + if x != nil { + return x.NewBalance + } + return 0 +} + +func (x *BatchUpdateResultItem) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +// 批量更新用户余额响应 +type BatchUpdateWalletBalanceResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总处理数量 + Success uint32 `protobuf:"varint,2,opt,name=success,proto3" json:"success"` // 成功数量 + Failed uint32 `protobuf:"varint,3,opt,name=failed,proto3" json:"failed"` // 失败数量 + Results []*BatchUpdateResultItem `protobuf:"bytes,4,rep,name=results,proto3" json:"results"` // 结果列表 +} + +func (x *BatchUpdateWalletBalanceResp) Reset() { + *x = BatchUpdateWalletBalanceResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[204] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateWalletBalanceResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateWalletBalanceResp) ProtoMessage() {} + +func (x *BatchUpdateWalletBalanceResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[204] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateWalletBalanceResp.ProtoReflect.Descriptor instead. +func (*BatchUpdateWalletBalanceResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{204} +} + +func (x *BatchUpdateWalletBalanceResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *BatchUpdateWalletBalanceResp) GetSuccess() uint32 { + if x != nil { + return x.Success + } + return 0 +} + +func (x *BatchUpdateWalletBalanceResp) GetFailed() uint32 { + if x != nil { + return x.Failed + } + return 0 +} + +func (x *BatchUpdateWalletBalanceResp) GetResults() []*BatchUpdateResultItem { + if x != nil { + return x.Results + } + return nil +} + +// 获取钱包列表请求 +type GetWalletsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID(选填,支持精确查询) + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` // 手机号(选填,支持模糊搜索) + Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` // 账号(选填,支持模糊搜索) + Pagination *sdkws.RequestPagination `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetWalletsReq) Reset() { + *x = GetWalletsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[205] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletsReq) ProtoMessage() {} + +func (x *GetWalletsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[205] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletsReq.ProtoReflect.Descriptor instead. +func (*GetWalletsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{205} +} + +func (x *GetWalletsReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GetWalletsReq) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *GetWalletsReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *GetWalletsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 钱包列表项信息 +type WalletListItemInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` // 用户昵称 + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` // 用户头像 + Balance int64 `protobuf:"varint,4,opt,name=balance,proto3" json:"balance"` // 余额(分) + CreateTime int64 `protobuf:"varint,5,opt,name=createTime,proto3" json:"createTime"` // 创建时间戳(毫秒) + UpdateTime int64 `protobuf:"varint,6,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间戳(毫秒) +} + +func (x *WalletListItemInfo) Reset() { + *x = WalletListItemInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[206] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WalletListItemInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WalletListItemInfo) ProtoMessage() {} + +func (x *WalletListItemInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[206] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WalletListItemInfo.ProtoReflect.Descriptor instead. +func (*WalletListItemInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{206} +} + +func (x *WalletListItemInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WalletListItemInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *WalletListItemInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *WalletListItemInfo) GetBalance() int64 { + if x != nil { + return x.Balance + } + return 0 +} + +func (x *WalletListItemInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *WalletListItemInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 获取钱包列表响应 +type GetWalletsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Wallets []*WalletListItemInfo `protobuf:"bytes,2,rep,name=wallets,proto3" json:"wallets"` // 钱包列表 +} + +func (x *GetWalletsResp) Reset() { + *x = GetWalletsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[207] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletsResp) ProtoMessage() {} + +func (x *GetWalletsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[207] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletsResp.ProtoReflect.Descriptor instead. +func (*GetWalletsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{207} +} + +func (x *GetWalletsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetWalletsResp) GetWallets() []*WalletListItemInfo { + if x != nil { + return x.Wallets + } + return nil +} + +// 提现记录信息 +type WithdrawInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 提现ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount"` // 提现金额(单位:分) + WithdrawAccount string `protobuf:"bytes,4,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提现账号 + Status int32 `protobuf:"varint,5,opt,name=status,proto3" json:"status"` // 审核状态:1-待审核,2-已通过,3-已拒绝 + AuditorID string `protobuf:"bytes,6,opt,name=auditorID,proto3" json:"auditorID"` // 审核人ID(管理员ID) + AuditTime int64 `protobuf:"varint,7,opt,name=auditTime,proto3" json:"auditTime"` // 审核时间(毫秒时间戳) + AuditRemark string `protobuf:"bytes,8,opt,name=auditRemark,proto3" json:"auditRemark"` // 审核备注 + Ip string `protobuf:"bytes,9,opt,name=ip,proto3" json:"ip"` // 提现IP + DeviceID string `protobuf:"bytes,10,opt,name=deviceID,proto3" json:"deviceID"` // 设备ID + Platform string `protobuf:"bytes,11,opt,name=platform,proto3" json:"platform"` // 平台(iOS、Android、Web等) + DeviceModel string `protobuf:"bytes,12,opt,name=deviceModel,proto3" json:"deviceModel"` // 设备型号 + DeviceBrand string `protobuf:"bytes,13,opt,name=deviceBrand,proto3" json:"deviceBrand"` // 设备品牌 + OsVersion string `protobuf:"bytes,14,opt,name=osVersion,proto3" json:"osVersion"` // 操作系统版本 + AppVersion string `protobuf:"bytes,15,opt,name=appVersion,proto3" json:"appVersion"` // 应用版本 + CreateTime int64 `protobuf:"varint,16,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,17,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) + RealNameAuth *RealNameAuthInfo `protobuf:"bytes,18,opt,name=realNameAuth,proto3" json:"realNameAuth"` // 用户实名认证信息 +} + +func (x *WithdrawInfo) Reset() { + *x = WithdrawInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[208] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawInfo) ProtoMessage() {} + +func (x *WithdrawInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[208] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawInfo.ProtoReflect.Descriptor instead. +func (*WithdrawInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{208} +} + +func (x *WithdrawInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WithdrawInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WithdrawInfo) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *WithdrawInfo) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +func (x *WithdrawInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *WithdrawInfo) GetAuditorID() string { + if x != nil { + return x.AuditorID + } + return "" +} + +func (x *WithdrawInfo) GetAuditTime() int64 { + if x != nil { + return x.AuditTime + } + return 0 +} + +func (x *WithdrawInfo) GetAuditRemark() string { + if x != nil { + return x.AuditRemark + } + return "" +} + +func (x *WithdrawInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *WithdrawInfo) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *WithdrawInfo) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *WithdrawInfo) GetDeviceModel() string { + if x != nil { + return x.DeviceModel + } + return "" +} + +func (x *WithdrawInfo) GetDeviceBrand() string { + if x != nil { + return x.DeviceBrand + } + return "" +} + +func (x *WithdrawInfo) GetOsVersion() string { + if x != nil { + return x.OsVersion + } + return "" +} + +func (x *WithdrawInfo) GetAppVersion() string { + if x != nil { + return x.AppVersion + } + return "" +} + +func (x *WithdrawInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *WithdrawInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +func (x *WithdrawInfo) GetRealNameAuth() *RealNameAuthInfo { + if x != nil { + return x.RealNameAuth + } + return nil +} + +// 创建提现记录请求 +type CreateWithdrawReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount"` // 提现金额(单位:分) + WithdrawAccount string `protobuf:"bytes,3,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提现账号 + Ip string `protobuf:"bytes,4,opt,name=ip,proto3" json:"ip"` // 提现IP + DeviceID string `protobuf:"bytes,5,opt,name=deviceID,proto3" json:"deviceID"` // 设备ID + Platform string `protobuf:"bytes,6,opt,name=platform,proto3" json:"platform"` // 平台 + DeviceModel string `protobuf:"bytes,7,opt,name=deviceModel,proto3" json:"deviceModel"` // 设备型号 + DeviceBrand string `protobuf:"bytes,8,opt,name=deviceBrand,proto3" json:"deviceBrand"` // 设备品牌 + OsVersion string `protobuf:"bytes,9,opt,name=osVersion,proto3" json:"osVersion"` // 操作系统版本 + AppVersion string `protobuf:"bytes,10,opt,name=appVersion,proto3" json:"appVersion"` // 应用版本 +} + +func (x *CreateWithdrawReq) Reset() { + *x = CreateWithdrawReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[209] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateWithdrawReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWithdrawReq) ProtoMessage() {} + +func (x *CreateWithdrawReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[209] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWithdrawReq.ProtoReflect.Descriptor instead. +func (*CreateWithdrawReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{209} +} + +func (x *CreateWithdrawReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *CreateWithdrawReq) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *CreateWithdrawReq) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +func (x *CreateWithdrawReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *CreateWithdrawReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *CreateWithdrawReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *CreateWithdrawReq) GetDeviceModel() string { + if x != nil { + return x.DeviceModel + } + return "" +} + +func (x *CreateWithdrawReq) GetDeviceBrand() string { + if x != nil { + return x.DeviceBrand + } + return "" +} + +func (x *CreateWithdrawReq) GetOsVersion() string { + if x != nil { + return x.OsVersion + } + return "" +} + +func (x *CreateWithdrawReq) GetAppVersion() string { + if x != nil { + return x.AppVersion + } + return "" +} + +// 创建提现记录响应 +type CreateWithdrawResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WithdrawID string `protobuf:"bytes,1,opt,name=withdrawID,proto3" json:"withdrawID"` // 提现ID +} + +func (x *CreateWithdrawResp) Reset() { + *x = CreateWithdrawResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[210] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateWithdrawResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWithdrawResp) ProtoMessage() {} + +func (x *CreateWithdrawResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[210] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWithdrawResp.ProtoReflect.Descriptor instead. +func (*CreateWithdrawResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{210} +} + +func (x *CreateWithdrawResp) GetWithdrawID() string { + if x != nil { + return x.WithdrawID + } + return "" +} + +// 获取提现记录详情请求 +type GetWithdrawReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WithdrawID string `protobuf:"bytes,1,opt,name=withdrawID,proto3" json:"withdrawID"` // 提现ID +} + +func (x *GetWithdrawReq) Reset() { + *x = GetWithdrawReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[211] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawReq) ProtoMessage() {} + +func (x *GetWithdrawReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[211] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawReq.ProtoReflect.Descriptor instead. +func (*GetWithdrawReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{211} +} + +func (x *GetWithdrawReq) GetWithdrawID() string { + if x != nil { + return x.WithdrawID + } + return "" +} + +// 获取提现记录详情响应 +type GetWithdrawResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Withdraw *WithdrawInfo `protobuf:"bytes,1,opt,name=withdraw,proto3" json:"withdraw"` // 提现记录信息 +} + +func (x *GetWithdrawResp) Reset() { + *x = GetWithdrawResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[212] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawResp) ProtoMessage() {} + +func (x *GetWithdrawResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[212] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawResp.ProtoReflect.Descriptor instead. +func (*GetWithdrawResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{212} +} + +func (x *GetWithdrawResp) GetWithdraw() *WithdrawInfo { + if x != nil { + return x.Withdraw + } + return nil +} + +// 获取用户的提现记录列表请求 +type GetUserWithdrawsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetUserWithdrawsReq) Reset() { + *x = GetUserWithdrawsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[213] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWithdrawsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWithdrawsReq) ProtoMessage() {} + +func (x *GetUserWithdrawsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[213] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWithdrawsReq.ProtoReflect.Descriptor instead. +func (*GetUserWithdrawsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{213} +} + +func (x *GetUserWithdrawsReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GetUserWithdrawsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 获取用户的提现记录列表响应 +type GetUserWithdrawsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + List []*WithdrawInfo `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` // 提现记录列表 +} + +func (x *GetUserWithdrawsResp) Reset() { + *x = GetUserWithdrawsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[214] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserWithdrawsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserWithdrawsResp) ProtoMessage() {} + +func (x *GetUserWithdrawsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[214] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserWithdrawsResp.ProtoReflect.Descriptor instead. +func (*GetUserWithdrawsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{214} +} + +func (x *GetUserWithdrawsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetUserWithdrawsResp) GetList() []*WithdrawInfo { + if x != nil { + return x.List + } + return nil +} + +// 获取提现记录列表请求(后台) +type GetWithdrawsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status"` // 状态筛选(0表示全部) + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetWithdrawsReq) Reset() { + *x = GetWithdrawsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[215] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawsReq) ProtoMessage() {} + +func (x *GetWithdrawsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[215] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawsReq.ProtoReflect.Descriptor instead. +func (*GetWithdrawsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{215} +} + +func (x *GetWithdrawsReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *GetWithdrawsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 获取提现记录列表响应(后台) +type GetWithdrawsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + List []*WithdrawInfo `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` // 提现记录列表 +} + +func (x *GetWithdrawsResp) Reset() { + *x = GetWithdrawsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[216] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawsResp) ProtoMessage() {} + +func (x *GetWithdrawsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[216] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawsResp.ProtoReflect.Descriptor instead. +func (*GetWithdrawsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{216} +} + +func (x *GetWithdrawsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetWithdrawsResp) GetList() []*WithdrawInfo { + if x != nil { + return x.List + } + return nil +} + +// 审核提现请求 +type AuditWithdrawReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WithdrawIDs []string `protobuf:"bytes,1,rep,name=withdrawIDs,proto3" json:"withdrawIDs"` // 提现申请ID列表(支持批量审核) + Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status"` // 审核状态:2-已通过,3-已拒绝 + AuditRemark string `protobuf:"bytes,3,opt,name=auditRemark,proto3" json:"auditRemark"` // 审核备注 +} + +func (x *AuditWithdrawReq) Reset() { + *x = AuditWithdrawReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[217] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditWithdrawReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditWithdrawReq) ProtoMessage() {} + +func (x *AuditWithdrawReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[217] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditWithdrawReq.ProtoReflect.Descriptor instead. +func (*AuditWithdrawReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{217} +} + +func (x *AuditWithdrawReq) GetWithdrawIDs() []string { + if x != nil { + return x.WithdrawIDs + } + return nil +} + +func (x *AuditWithdrawReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *AuditWithdrawReq) GetAuditRemark() string { + if x != nil { + return x.AuditRemark + } + return "" +} + +// 审核提现响应 +type AuditWithdrawResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SuccessCount uint32 `protobuf:"varint,1,opt,name=successCount,proto3" json:"successCount"` // 成功审核的数量 + FailCount uint32 `protobuf:"varint,2,opt,name=failCount,proto3" json:"failCount"` // 失败审核的数量 + FailedIDs []string `protobuf:"bytes,3,rep,name=failedIDs,proto3" json:"failedIDs"` // 失败的提现申请ID列表 +} + +func (x *AuditWithdrawResp) Reset() { + *x = AuditWithdrawResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[218] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditWithdrawResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditWithdrawResp) ProtoMessage() {} + +func (x *AuditWithdrawResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[218] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditWithdrawResp.ProtoReflect.Descriptor instead. +func (*AuditWithdrawResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{218} +} + +func (x *AuditWithdrawResp) GetSuccessCount() uint32 { + if x != nil { + return x.SuccessCount + } + return 0 +} + +func (x *AuditWithdrawResp) GetFailCount() uint32 { + if x != nil { + return x.FailCount + } + return 0 +} + +func (x *AuditWithdrawResp) GetFailedIDs() []string { + if x != nil { + return x.FailedIDs + } + return nil +} + +// 获取实名认证列表请求 +type GetRealNameAuthsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuditStatus int32 `protobuf:"varint,1,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态筛选(0-未审核,1-审核通过,2-审核拒绝,0表示全部) + UserID string `protobuf:"bytes,3,opt,name=userID,proto3" json:"userID"` // 用户ID搜索(可选,为空时不过滤) + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetRealNameAuthsReq) Reset() { + *x = GetRealNameAuthsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[219] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRealNameAuthsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRealNameAuthsReq) ProtoMessage() {} + +func (x *GetRealNameAuthsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[219] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRealNameAuthsReq.ProtoReflect.Descriptor instead. +func (*GetRealNameAuthsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{219} +} + +func (x *GetRealNameAuthsReq) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +func (x *GetRealNameAuthsReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GetRealNameAuthsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 实名认证列表项信息 +type RealNameAuthListItemInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` // 用户昵称 + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` // 用户头像 + IdCard string `protobuf:"bytes,4,opt,name=idCard,proto3" json:"idCard"` // 身份证号 + Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name"` // 真实姓名 + IdCardPhotoFront string `protobuf:"bytes,6,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL + IdCardPhotoBack string `protobuf:"bytes,7,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL + AuditStatus int32 `protobuf:"varint,8,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态:0-未审核,1-审核通过,2-审核拒绝 + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` // 创建时间戳(毫秒) + UpdateTime int64 `protobuf:"varint,10,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间戳(毫秒) +} + +func (x *RealNameAuthListItemInfo) Reset() { + *x = RealNameAuthListItemInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[220] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RealNameAuthListItemInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RealNameAuthListItemInfo) ProtoMessage() {} + +func (x *RealNameAuthListItemInfo) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[220] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RealNameAuthListItemInfo.ProtoReflect.Descriptor instead. +func (*RealNameAuthListItemInfo) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{220} +} + +func (x *RealNameAuthListItemInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetIdCard() string { + if x != nil { + return x.IdCard + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +func (x *RealNameAuthListItemInfo) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +func (x *RealNameAuthListItemInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *RealNameAuthListItemInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 获取实名认证列表响应 +type GetRealNameAuthsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + List []*RealNameAuthListItemInfo `protobuf:"bytes,2,rep,name=list,proto3" json:"list"` // 实名认证列表 +} + +func (x *GetRealNameAuthsResp) Reset() { + *x = GetRealNameAuthsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[221] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRealNameAuthsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRealNameAuthsResp) ProtoMessage() {} + +func (x *GetRealNameAuthsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[221] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRealNameAuthsResp.ProtoReflect.Descriptor instead. +func (*GetRealNameAuthsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{221} +} + +func (x *GetRealNameAuthsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetRealNameAuthsResp) GetList() []*RealNameAuthListItemInfo { + if x != nil { + return x.List + } + return nil +} + +// 审核实名认证请求 +type AuditRealNameAuthReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` // 用户ID + AuditStatus int32 `protobuf:"varint,2,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态:1-审核通过,2-审核拒绝 + AuditRemark string `protobuf:"bytes,3,opt,name=auditRemark,proto3" json:"auditRemark"` // 审核备注(可选) +} + +func (x *AuditRealNameAuthReq) Reset() { + *x = AuditRealNameAuthReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[222] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditRealNameAuthReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditRealNameAuthReq) ProtoMessage() {} + +func (x *AuditRealNameAuthReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[222] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditRealNameAuthReq.ProtoReflect.Descriptor instead. +func (*AuditRealNameAuthReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{222} +} + +func (x *AuditRealNameAuthReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *AuditRealNameAuthReq) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +func (x *AuditRealNameAuthReq) GetAuditRemark() string { + if x != nil { + return x.AuditRemark + } + return "" +} + +// 审核实名认证响应 +type AuditRealNameAuthResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AuditRealNameAuthResp) Reset() { + *x = AuditRealNameAuthResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[223] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditRealNameAuthResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditRealNameAuthResp) ProtoMessage() {} + +func (x *AuditRealNameAuthResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[223] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditRealNameAuthResp.ProtoReflect.Descriptor instead. +func (*AuditRealNameAuthResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{223} +} + +// 获取系统统计数据 +type GetStatisticsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetStatisticsReq) Reset() { + *x = GetStatisticsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[224] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetStatisticsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStatisticsReq) ProtoMessage() {} + +func (x *GetStatisticsReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[224] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStatisticsReq.ProtoReflect.Descriptor instead. +func (*GetStatisticsReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{224} +} + +type GetStatisticsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TotalUsers int64 `protobuf:"varint,1,opt,name=totalUsers,proto3" json:"totalUsers"` // 用户总数 + TodayRegisteredUsers int64 `protobuf:"varint,2,opt,name=todayRegisteredUsers,proto3" json:"todayRegisteredUsers"` // 今天注册的用户数 + TodayActiveUsers int64 `protobuf:"varint,3,opt,name=todayActiveUsers,proto3" json:"todayActiveUsers"` // 今天活跃用户数(今天登录的用户数) + TodayMessages int64 `protobuf:"varint,4,opt,name=todayMessages,proto3" json:"todayMessages"` // 今天发送消息总数 + TotalMessages int64 `protobuf:"varint,5,opt,name=totalMessages,proto3" json:"totalMessages"` // 历史发送的消息总数 + TotalGroups int64 `protobuf:"varint,6,opt,name=totalGroups,proto3" json:"totalGroups"` // 群聊总数 + TotalFriends int64 `protobuf:"varint,7,opt,name=totalFriends,proto3" json:"totalFriends"` // 好友关系总数 + OnlineUsers int64 `protobuf:"varint,8,opt,name=onlineUsers,proto3" json:"onlineUsers"` // 当前在线用户数 + TodayNewGroups int64 `protobuf:"varint,9,opt,name=todayNewGroups,proto3" json:"todayNewGroups"` // 今天新建群聊数 +} + +func (x *GetStatisticsResp) Reset() { + *x = GetStatisticsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[225] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetStatisticsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStatisticsResp) ProtoMessage() {} + +func (x *GetStatisticsResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[225] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStatisticsResp.ProtoReflect.Descriptor instead. +func (*GetStatisticsResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{225} +} + +func (x *GetStatisticsResp) GetTotalUsers() int64 { + if x != nil { + return x.TotalUsers + } + return 0 +} + +func (x *GetStatisticsResp) GetTodayRegisteredUsers() int64 { + if x != nil { + return x.TodayRegisteredUsers + } + return 0 +} + +func (x *GetStatisticsResp) GetTodayActiveUsers() int64 { + if x != nil { + return x.TodayActiveUsers + } + return 0 +} + +func (x *GetStatisticsResp) GetTodayMessages() int64 { + if x != nil { + return x.TodayMessages + } + return 0 +} + +func (x *GetStatisticsResp) GetTotalMessages() int64 { + if x != nil { + return x.TotalMessages + } + return 0 +} + +func (x *GetStatisticsResp) GetTotalGroups() int64 { + if x != nil { + return x.TotalGroups + } + return 0 +} + +func (x *GetStatisticsResp) GetTotalFriends() int64 { + if x != nil { + return x.TotalFriends + } + return 0 +} + +func (x *GetStatisticsResp) GetOnlineUsers() int64 { + if x != nil { + return x.OnlineUsers + } + return 0 +} + +func (x *GetStatisticsResp) GetTodayNewGroups() int64 { + if x != nil { + return x.TodayNewGroups + } + return 0 +} + +var File_admin_admin_proto protoreflect.FileDescriptor + +var file_admin_admin_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2f, 0x73, 0x64, + 0x6b, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x77, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x73, 0x70, 0x62, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x70, 0x62, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, + 0x68, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x22, 0xbd, 0x01, 0x0a, 0x09, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x0a, + 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, + 0x65, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x80, 0x01, 0x0a, 0x12, + 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, + 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x15, + 0x0a, 0x13, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xbb, 0x03, 0x0a, 0x12, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x07, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x36, + 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x66, + 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x38, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x31, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x12, 0x42, 0x0a, 0x0d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, + 0x68, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x4a, 0x0a, 0x11, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x11, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x22, 0x63, 0x0a, 0x13, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x22, 0x9f, 0x01, 0x0a, 0x11, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3a, 0x0a, 0x18, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x6e, 0x65, 0x77, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6e, 0x65, 0x77, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x22, 0x7c, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, + 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x68, 0x0a, 0x1a, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x72, 0x0a, 0x15, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, + 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, + 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x74, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x44, 0x0a, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x52, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x02, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, + 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x53, 0x0a, 0x13, 0x53, 0x65, 0x74, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, + 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x80, + 0x01, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, + 0x09, 0x71, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x71, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x24, 0x0a, 0x0d, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x2f, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, + 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x44, + 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x16, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x22, 0x31, 0x0a, 0x15, 0x46, + 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x73, + 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x88, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x6b, + 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x3a, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x12, 0x41, + 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, + 0x13, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x30, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x15, 0x0a, + 0x13, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x22, 0x32, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x72, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x79, 0x0a, 0x0e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x4a, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x44, 0x73, 0x22, 0x2c, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, + 0x73, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x65, + 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x6c, 0x65, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x72, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x72, 0x73, 0x22, 0x17, 0x0a, 0x15, + 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, + 0x6f, 0x64, 0x65, 0x73, 0x22, 0x50, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, + 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, + 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x17, 0x0a, 0x15, 0x55, 0x73, + 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, + 0x73, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0xbc, 0x01, 0x0a, 0x12, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x73, 0x65, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, + 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x3e, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x08, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x22, 0xbc, 0x01, 0x0a, 0x17, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x04, 0x6c, 0x69, + 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, + 0x22, 0x76, 0x0a, 0x19, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, + 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, 0x50, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x6a, 0x0a, + 0x1a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x12, 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, + 0x50, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x10, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x50, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, + 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x41, 0x64, 0x64, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x50, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x06, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x83, 0x01, 0x0a, 0x0b, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, + 0x24, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x66, 0x0a, 0x0e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, + 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x22, 0x89, 0x01, + 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x15, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, + 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x3c, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, + 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, + 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x25, 0x0a, 0x11, + 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, + 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, + 0x69, 0x70, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2b, 0x0a, 0x19, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x1c, 0x0a, 0x1a, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x40, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, + 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x22, 0x45, 0x0a, 0x13, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x3e, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x22, 0x0f, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x22, 0x2a, 0x0a, 0x0e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, + 0x0f, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, + 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0xb7, 0x02, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, + 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x5e, 0x0a, 0x13, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x14, 0x46, + 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x77, 0x0a, + 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, + 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x2f, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x22, 0x44, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x27, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, + 0x25, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x72, 0x0a, 0x0e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x11, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x2c, 0x0a, 0x12, 0x49, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, + 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x82, 0x02, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, + 0x64, 0x35, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, + 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x49, 0x64, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x22, 0xaf, 0x04, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x30, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, + 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x30, + 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, + 0x12, 0x2e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x2e, 0x0a, 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x6d, 0x64, 0x35, + 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x73, 0x69, 0x7a, + 0x65, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, + 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x46, 0x69, + 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x22, 0x4a, 0x0a, 0x0e, 0x46, + 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x38, 0x0a, + 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x22, 0x6c, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, + 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x38, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x12, 0x53, 0x65, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x12, 0x44, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x71, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x15, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x28, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, + 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, + 0x79, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x22, + 0x97, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, + 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x3c, 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe0, 0x01, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x1b, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x1c, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3a, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, + 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x95, + 0x03, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, + 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x2e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x30, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x74, 0x65, + 0x78, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x78, 0x0a, 0x19, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3f, + 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, + 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x70, 0x0a, 0x1a, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x12, 0x3c, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, + 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x12, + 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, + 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x22, 0x96, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xcb, 0x02, 0x0a, + 0x17, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, + 0x0b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, + 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x68, 0x69, 0x74, + 0x65, 0x6c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x61, + 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x75, + 0x74, 0x6f, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf9, 0x01, 0x0a, 0x14, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, + 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x64, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, + 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x65, 0x78, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x54, 0x65, 0x78, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x61, 0x0a, + 0x19, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x22, 0x9b, 0x01, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x16, + 0x0a, 0x14, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0xae, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x2a, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, + 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x19, + 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x4b, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x33, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x22, 0xa4, 0x01, + 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x67, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x05, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x52, 0x0a, + 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x35, 0x0a, 0x05, 0x77, 0x6f, + 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x77, 0x6f, 0x72, 0x64, + 0x73, 0x22, 0x2e, 0x0a, 0x1a, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, + 0x73, 0x22, 0xce, 0x01, 0x0a, 0x1c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x12, 0x51, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x5b, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x1f, 0x0a, 0x1d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x30, 0x0a, 0x1c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x1f, 0x0a, 0x1d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x46, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x1b, + 0x0a, 0x19, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x59, 0x0a, 0x1b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x57, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x3a, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x1e, 0x0a, 0x1c, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x22, 0x5d, 0x0a, 0x1d, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3c, 0x0a, + 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x22, 0x5b, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x5d, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x3d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1f, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x8e, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, + 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, + 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x61, 0x63, + 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, + 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x22, 0x82, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3b, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x22, 0x2e, 0x0a, 0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, + 0x69, 0x64, 0x73, 0x22, 0x1d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x22, 0x57, + 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3a, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, + 0x22, 0x5d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x3d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, + 0x57, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, + 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc8, 0x01, 0x0a, 0x14, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x22, 0xc5, 0x02, 0x0a, 0x11, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x64, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, + 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x44, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x44, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x64, 0x0a, 0x15, 0x47, + 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x05, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x22, 0x32, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x74, + 0x61, 0x73, 0x6b, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, + 0x73, 0x6b, 0x49, 0x44, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x88, 0x02, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x15, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x22, 0x18, 0x0a, 0x16, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x26, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4d, 0x0a, + 0x13, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x59, 0x0a, 0x16, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x63, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x41, 0x6c, + 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0xfc, 0x02, 0x0a, + 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x32, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x39, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, + 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x09, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x70, 0x70, 0x22, 0x18, 0x0a, 0x16, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x44, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1d, 0x0a, 0x1b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x4a, 0x0a, 0x1c, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, + 0x6b, 0x65, 0x79, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1c, + 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x22, 0x51, 0x0a, 0x1b, + 0x47, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x32, 0x0a, 0x04, 0x6c, + 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, + 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, 0x61, + 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, + 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, + 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x75, 0x64, + 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xd4, 0x02, 0x0a, 0x0a, 0x57, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x18, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x77, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x12, 0x36, 0x0a, 0x16, 0x77, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x2e, 0x0a, 0x12, 0x68, 0x61, 0x73, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x68, 0x61, 0x73, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, + 0xd1, 0x02, 0x0a, 0x17, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x24, 0x0a, 0x0d, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x66, 0x74, 0x65, 0x72, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x64, + 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, + 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, + 0x45, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x30, 0x0a, 0x06, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, + 0x6b, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, + 0x37, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, + 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x79, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x72, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x39, 0x0a, 0x04, + 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x60, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x5d, 0x0a, 0x19, 0x53, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x28, 0x0a, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1c, 0x0a, 0x1a, 0x53, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xb7, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x74, 0x65, 0x6d, 0x12, + 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, + 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, + 0x6b, 0x22, 0xba, 0x01, 0x0a, 0x1b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x12, 0x37, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0xf7, + 0x01, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x6f, 0x6c, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6f, 0x6c, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa5, 0x01, 0x0a, 0x1c, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x66, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x12, 0x3d, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x22, 0xa4, 0x01, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, + 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xbc, 0x01, 0x0a, 0x12, 0x57, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, + 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x18, 0x0a, 0x07, + 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x62, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3a, + 0x0a, 0x07, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x07, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x22, 0xbc, 0x04, 0x0a, 0x0c, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x77, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, + 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, + 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, + 0x72, 0x61, 0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x41, 0x75, 0x74, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x72, 0x65, 0x61, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x22, 0xb7, 0x02, 0x0a, 0x11, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x12, + 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x28, 0x0a, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x72, 0x61, + 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x42, 0x72, 0x61, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x34, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x22, 0x30, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x77, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x22, 0x49, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, + 0x0a, 0x08, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x69, + 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x22, 0x6e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5c, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x2e, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, + 0x6c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, + 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x58, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x2e, 0x0a, 0x04, 0x6c, 0x69, + 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x6e, 0x0a, 0x10, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x12, 0x20, + 0x0a, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x49, 0x44, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, + 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x73, 0x0a, 0x11, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x61, 0x69, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x66, 0x61, 0x69, 0x6c, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x49, 0x44, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x49, 0x44, 0x73, 0x22, + 0x90, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x75, + 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, + 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0xcc, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, + 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, + 0x64, 0x43, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x64, 0x43, + 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, + 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, + 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x12, + 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x22, 0x68, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, + 0x41, 0x75, 0x74, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x3a, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x61, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, + 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x72, 0x0a, 0x14, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, + 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, + 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, + 0x17, 0x0a, 0x15, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, + 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x22, 0xef, 0x02, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x14, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x10, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x6f, 0x64, 0x61, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x72, 0x69, + 0x65, 0x6e, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x4e, + 0x65, 0x77, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, + 0x74, 0x6f, 0x64, 0x61, 0x79, 0x4e, 0x65, 0x77, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x32, 0x9e, + 0x4a, 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x12, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1e, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, + 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6e, 0x0a, 0x17, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, + 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x53, 0x65, + 0x74, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x21, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, + 0x74, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x65, 0x74, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, + 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, + 0x0a, 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x44, 0x65, 0x6c, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, + 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, + 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, + 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, + 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, + 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, + 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x5c, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, + 0x11, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x65, 0x0a, 0x14, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x62, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x22, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, + 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x44, 0x65, + 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, + 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, + 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x59, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x4a, 0x0a, 0x0b, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, + 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, + 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x27, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x62, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x47, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, + 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, + 0x74, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1c, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, + 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, + 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x68, 0x0a, + 0x15, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x27, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, + 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, + 0x16, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x41, 0x64, + 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x21, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, + 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x24, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x65, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x6b, 0x0a, 0x16, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, + 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, + 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2b, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x29, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, + 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2b, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, + 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x2b, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x65, 0x0a, 0x14, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, + 0x6f, 0x67, 0x73, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6e, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x28, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, + 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x71, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x29, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x25, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, + 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, + 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x6e, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x28, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x2b, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6e, 0x0a, 0x17, 0x47, 0x65, + 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0d, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6e, 0x0a, 0x17, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x1a, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x7a, 0x0a, 0x1b, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2c, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x47, + 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x74, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x2b, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x22, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x61, 0x6c, + 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, + 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, + 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, + 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x59, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, + 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x12, 0x1d, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, + 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0d, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x12, 0x1e, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x75, 0x64, 0x69, + 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x75, 0x64, 0x69, + 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, + 0x0d, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x1e, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1f, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x42, + 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x2e, 0x69, 0x6d, 0x61, 0x6c, 0x6c, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_admin_admin_proto_rawDescOnce sync.Once + file_admin_admin_proto_rawDescData = file_admin_admin_proto_rawDesc +) + +func file_admin_admin_proto_rawDescGZIP() []byte { + file_admin_admin_proto_rawDescOnce.Do(func() { + file_admin_admin_proto_rawDescData = protoimpl.X.CompressGZIP(file_admin_admin_proto_rawDescData) + }) + return file_admin_admin_proto_rawDescData +} + +var file_admin_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 230) +var file_admin_admin_proto_goTypes = []interface{}{ + (*LoginReq)(nil), // 0: openim.admin.LoginReq + (*LoginResp)(nil), // 1: openim.admin.LoginResp + (*AddAdminAccountReq)(nil), // 2: openim.admin.AddAdminAccountReq + (*AddAdminAccountResp)(nil), // 3: openim.admin.AddAdminAccountResp + (*AdminUpdateInfoReq)(nil), // 4: openim.admin.AdminUpdateInfoReq + (*AdminUpdateInfoResp)(nil), // 5: openim.admin.AdminUpdateInfoResp + (*ChangePasswordReq)(nil), // 6: openim.admin.ChangePasswordReq + (*ChangePasswordResp)(nil), // 7: openim.admin.ChangePasswordResp + (*GetAdminInfoReq)(nil), // 8: openim.admin.GetAdminInfoReq + (*ChangeAdminPasswordReq)(nil), // 9: openim.admin.ChangeAdminPasswordReq + (*ChangeAdminPasswordResp)(nil), // 10: openim.admin.ChangeAdminPasswordResp + (*ChangeOperationPasswordReq)(nil), // 11: openim.admin.ChangeOperationPasswordReq + (*ChangeOperationPasswordResp)(nil), // 12: openim.admin.ChangeOperationPasswordResp + (*DelAdminAccountReq)(nil), // 13: openim.admin.DelAdminAccountReq + (*DelAdminAccountResp)(nil), // 14: openim.admin.DelAdminAccountResp + (*SearchAdminAccountReq)(nil), // 15: openim.admin.SearchAdminAccountReq + (*SearchAdminAccountResp)(nil), // 16: openim.admin.SearchAdminAccountResp + (*GetAdminInfoResp)(nil), // 17: openim.admin.GetAdminInfoResp + (*SetGoogleAuthKeyReq)(nil), // 18: openim.admin.SetGoogleAuthKeyReq + (*SetGoogleAuthKeyResp)(nil), // 19: openim.admin.SetGoogleAuthKeyResp + (*AddDefaultFriendReq)(nil), // 20: openim.admin.AddDefaultFriendReq + (*AddDefaultFriendResp)(nil), // 21: openim.admin.AddDefaultFriendResp + (*DelDefaultFriendReq)(nil), // 22: openim.admin.DelDefaultFriendReq + (*DelDefaultFriendResp)(nil), // 23: openim.admin.DelDefaultFriendResp + (*FindDefaultFriendReq)(nil), // 24: openim.admin.FindDefaultFriendReq + (*FindDefaultFriendResp)(nil), // 25: openim.admin.FindDefaultFriendResp + (*SearchDefaultFriendReq)(nil), // 26: openim.admin.SearchDefaultFriendReq + (*DefaultFriendAttribute)(nil), // 27: openim.admin.DefaultFriendAttribute + (*SearchDefaultFriendResp)(nil), // 28: openim.admin.SearchDefaultFriendResp + (*AddDefaultGroupReq)(nil), // 29: openim.admin.AddDefaultGroupReq + (*AddDefaultGroupResp)(nil), // 30: openim.admin.AddDefaultGroupResp + (*DelDefaultGroupReq)(nil), // 31: openim.admin.DelDefaultGroupReq + (*DelDefaultGroupResp)(nil), // 32: openim.admin.DelDefaultGroupResp + (*FindDefaultGroupReq)(nil), // 33: openim.admin.FindDefaultGroupReq + (*FindDefaultGroupResp)(nil), // 34: openim.admin.FindDefaultGroupResp + (*SearchDefaultGroupReq)(nil), // 35: openim.admin.SearchDefaultGroupReq + (*GroupAttribute)(nil), // 36: openim.admin.GroupAttribute + (*SearchDefaultGroupResp)(nil), // 37: openim.admin.SearchDefaultGroupResp + (*AddInvitationCodeReq)(nil), // 38: openim.admin.AddInvitationCodeReq + (*AddInvitationCodeResp)(nil), // 39: openim.admin.AddInvitationCodeResp + (*GenInvitationCodeReq)(nil), // 40: openim.admin.GenInvitationCodeReq + (*GenInvitationCodeResp)(nil), // 41: openim.admin.GenInvitationCodeResp + (*FindInvitationCodeReq)(nil), // 42: openim.admin.FindInvitationCodeReq + (*FindInvitationCodeResp)(nil), // 43: openim.admin.FindInvitationCodeResp + (*UseInvitationCodeReq)(nil), // 44: openim.admin.UseInvitationCodeReq + (*UseInvitationCodeResp)(nil), // 45: openim.admin.UseInvitationCodeResp + (*DelInvitationCodeReq)(nil), // 46: openim.admin.DelInvitationCodeReq + (*DelInvitationCodeResp)(nil), // 47: openim.admin.DelInvitationCodeResp + (*InvitationRegister)(nil), // 48: openim.admin.InvitationRegister + (*SearchInvitationCodeReq)(nil), // 49: openim.admin.SearchInvitationCodeReq + (*SearchInvitationCodeResp)(nil), // 50: openim.admin.SearchInvitationCodeResp + (*SearchUserIPLimitLoginReq)(nil), // 51: openim.admin.SearchUserIPLimitLoginReq + (*LimitUserLoginIP)(nil), // 52: openim.admin.LimitUserLoginIP + (*SearchUserIPLimitLoginResp)(nil), // 53: openim.admin.SearchUserIPLimitLoginResp + (*UserIPLimitLogin)(nil), // 54: openim.admin.UserIPLimitLogin + (*AddUserIPLimitLoginReq)(nil), // 55: openim.admin.AddUserIPLimitLoginReq + (*AddUserIPLimitLoginResp)(nil), // 56: openim.admin.AddUserIPLimitLoginResp + (*DelUserIPLimitLoginReq)(nil), // 57: openim.admin.DelUserIPLimitLoginReq + (*DelUserIPLimitLoginResp)(nil), // 58: openim.admin.DelUserIPLimitLoginResp + (*IPForbidden)(nil), // 59: openim.admin.IPForbidden + (*IPForbiddenAdd)(nil), // 60: openim.admin.IPForbiddenAdd + (*SearchIPForbiddenReq)(nil), // 61: openim.admin.SearchIPForbiddenReq + (*SearchIPForbiddenResp)(nil), // 62: openim.admin.SearchIPForbiddenResp + (*AddIPForbiddenReq)(nil), // 63: openim.admin.AddIPForbiddenReq + (*AddIPForbiddenResp)(nil), // 64: openim.admin.AddIPForbiddenResp + (*DelIPForbiddenReq)(nil), // 65: openim.admin.DelIPForbiddenReq + (*DelIPForbiddenResp)(nil), // 66: openim.admin.DelIPForbiddenResp + (*CheckRegisterForbiddenReq)(nil), // 67: openim.admin.CheckRegisterForbiddenReq + (*CheckRegisterForbiddenResp)(nil), // 68: openim.admin.CheckRegisterForbiddenResp + (*CheckLoginForbiddenReq)(nil), // 69: openim.admin.CheckLoginForbiddenReq + (*CheckLoginForbiddenResp)(nil), // 70: openim.admin.CheckLoginForbiddenResp + (*CancellationUserReq)(nil), // 71: openim.admin.CancellationUserReq + (*CancellationUserResp)(nil), // 72: openim.admin.CancellationUserResp + (*BlockUserReq)(nil), // 73: openim.admin.BlockUserReq + (*BlockUserResp)(nil), // 74: openim.admin.BlockUserResp + (*UnblockUserReq)(nil), // 75: openim.admin.UnblockUserReq + (*UnblockUserResp)(nil), // 76: openim.admin.UnblockUserResp + (*SearchBlockUserReq)(nil), // 77: openim.admin.SearchBlockUserReq + (*BlockUserInfo)(nil), // 78: openim.admin.BlockUserInfo + (*SearchBlockUserResp)(nil), // 79: openim.admin.SearchBlockUserResp + (*FindUserBlockInfoReq)(nil), // 80: openim.admin.FindUserBlockInfoReq + (*BlockInfo)(nil), // 81: openim.admin.BlockInfo + (*FindUserBlockInfoResp)(nil), // 82: openim.admin.FindUserBlockInfoResp + (*CreateTokenReq)(nil), // 83: openim.admin.CreateTokenReq + (*CreateTokenResp)(nil), // 84: openim.admin.CreateTokenResp + (*ParseTokenReq)(nil), // 85: openim.admin.ParseTokenReq + (*ParseTokenResp)(nil), // 86: openim.admin.ParseTokenResp + (*InvalidateTokenReq)(nil), // 87: openim.admin.InvalidateTokenReq + (*InvalidateTokenResp)(nil), // 88: openim.admin.InvalidateTokenResp + (*AddAppletReq)(nil), // 89: openim.admin.AddAppletReq + (*AddAppletResp)(nil), // 90: openim.admin.AddAppletResp + (*DelAppletReq)(nil), // 91: openim.admin.DelAppletReq + (*DelAppletResp)(nil), // 92: openim.admin.DelAppletResp + (*UpdateAppletReq)(nil), // 93: openim.admin.UpdateAppletReq + (*UpdateAppletResp)(nil), // 94: openim.admin.UpdateAppletResp + (*FindAppletReq)(nil), // 95: openim.admin.FindAppletReq + (*FindAppletResp)(nil), // 96: openim.admin.FindAppletResp + (*SearchAppletReq)(nil), // 97: openim.admin.SearchAppletReq + (*SearchAppletResp)(nil), // 98: openim.admin.SearchAppletResp + (*SetClientConfigReq)(nil), // 99: openim.admin.SetClientConfigReq + (*SetClientConfigResp)(nil), // 100: openim.admin.SetClientConfigResp + (*DelClientConfigReq)(nil), // 101: openim.admin.DelClientConfigReq + (*DelClientConfigResp)(nil), // 102: openim.admin.DelClientConfigResp + (*GetClientConfigReq)(nil), // 103: openim.admin.GetClientConfigReq + (*GetClientConfigResp)(nil), // 104: openim.admin.GetClientConfigResp + (*GetUserTokenReq)(nil), // 105: openim.admin.GetUserTokenReq + (*GetUserTokenResp)(nil), // 106: openim.admin.GetUserTokenResp + (*ApplicationVersion)(nil), // 107: openim.admin.ApplicationVersion + (*LatestApplicationVersionReq)(nil), // 108: openim.admin.LatestApplicationVersionReq + (*LatestApplicationVersionResp)(nil), // 109: openim.admin.LatestApplicationVersionResp + (*AddApplicationVersionReq)(nil), // 110: openim.admin.AddApplicationVersionReq + (*AddApplicationVersionResp)(nil), // 111: openim.admin.AddApplicationVersionResp + (*UpdateApplicationVersionReq)(nil), // 112: openim.admin.UpdateApplicationVersionReq + (*UpdateApplicationVersionResp)(nil), // 113: openim.admin.UpdateApplicationVersionResp + (*DeleteApplicationVersionReq)(nil), // 114: openim.admin.DeleteApplicationVersionReq + (*DeleteApplicationVersionResp)(nil), // 115: openim.admin.DeleteApplicationVersionResp + (*PageApplicationVersionReq)(nil), // 116: openim.admin.PageApplicationVersionReq + (*PageApplicationVersionResp)(nil), // 117: openim.admin.PageApplicationVersionResp + (*SensitiveWordInfo)(nil), // 118: openim.admin.SensitiveWordInfo + (*SensitiveWordGroupInfo)(nil), // 119: openim.admin.SensitiveWordGroupInfo + (*SensitiveWordConfigInfo)(nil), // 120: openim.admin.SensitiveWordConfigInfo + (*SensitiveWordLogInfo)(nil), // 121: openim.admin.SensitiveWordLogInfo + (*SensitiveWordStatsInfo)(nil), // 122: openim.admin.SensitiveWordStatsInfo + (*SensitiveWordLogStatsInfo)(nil), // 123: openim.admin.SensitiveWordLogStatsInfo + (*AddSensitiveWordReq)(nil), // 124: openim.admin.AddSensitiveWordReq + (*AddSensitiveWordResp)(nil), // 125: openim.admin.AddSensitiveWordResp + (*UpdateSensitiveWordReq)(nil), // 126: openim.admin.UpdateSensitiveWordReq + (*UpdateSensitiveWordResp)(nil), // 127: openim.admin.UpdateSensitiveWordResp + (*DeleteSensitiveWordReq)(nil), // 128: openim.admin.DeleteSensitiveWordReq + (*DeleteSensitiveWordResp)(nil), // 129: openim.admin.DeleteSensitiveWordResp + (*GetSensitiveWordReq)(nil), // 130: openim.admin.GetSensitiveWordReq + (*GetSensitiveWordResp)(nil), // 131: openim.admin.GetSensitiveWordResp + (*SearchSensitiveWordsReq)(nil), // 132: openim.admin.SearchSensitiveWordsReq + (*SearchSensitiveWordsResp)(nil), // 133: openim.admin.SearchSensitiveWordsResp + (*BatchAddSensitiveWordsReq)(nil), // 134: openim.admin.BatchAddSensitiveWordsReq + (*BatchAddSensitiveWordsResp)(nil), // 135: openim.admin.BatchAddSensitiveWordsResp + (*BatchUpdateSensitiveWordsReq)(nil), // 136: openim.admin.BatchUpdateSensitiveWordsReq + (*BatchUpdateSensitiveWordsResp)(nil), // 137: openim.admin.BatchUpdateSensitiveWordsResp + (*BatchDeleteSensitiveWordsReq)(nil), // 138: openim.admin.BatchDeleteSensitiveWordsReq + (*BatchDeleteSensitiveWordsResp)(nil), // 139: openim.admin.BatchDeleteSensitiveWordsResp + (*AddSensitiveWordGroupReq)(nil), // 140: openim.admin.AddSensitiveWordGroupReq + (*AddSensitiveWordGroupResp)(nil), // 141: openim.admin.AddSensitiveWordGroupResp + (*UpdateSensitiveWordGroupReq)(nil), // 142: openim.admin.UpdateSensitiveWordGroupReq + (*UpdateSensitiveWordGroupResp)(nil), // 143: openim.admin.UpdateSensitiveWordGroupResp + (*DeleteSensitiveWordGroupReq)(nil), // 144: openim.admin.DeleteSensitiveWordGroupReq + (*DeleteSensitiveWordGroupResp)(nil), // 145: openim.admin.DeleteSensitiveWordGroupResp + (*GetSensitiveWordGroupReq)(nil), // 146: openim.admin.GetSensitiveWordGroupReq + (*GetSensitiveWordGroupResp)(nil), // 147: openim.admin.GetSensitiveWordGroupResp + (*GetAllSensitiveWordGroupsReq)(nil), // 148: openim.admin.GetAllSensitiveWordGroupsReq + (*GetAllSensitiveWordGroupsResp)(nil), // 149: openim.admin.GetAllSensitiveWordGroupsResp + (*GetSensitiveWordConfigReq)(nil), // 150: openim.admin.GetSensitiveWordConfigReq + (*GetSensitiveWordConfigResp)(nil), // 151: openim.admin.GetSensitiveWordConfigResp + (*UpdateSensitiveWordConfigReq)(nil), // 152: openim.admin.UpdateSensitiveWordConfigReq + (*UpdateSensitiveWordConfigResp)(nil), // 153: openim.admin.UpdateSensitiveWordConfigResp + (*GetSensitiveWordLogsReq)(nil), // 154: openim.admin.GetSensitiveWordLogsReq + (*GetSensitiveWordLogsResp)(nil), // 155: openim.admin.GetSensitiveWordLogsResp + (*UserLoginRecordInfo)(nil), // 156: openim.admin.UserLoginRecordInfo + (*GetUserLoginRecordsReq)(nil), // 157: openim.admin.GetUserLoginRecordsReq + (*GetUserLoginRecordsResp)(nil), // 158: openim.admin.GetUserLoginRecordsResp + (*DeleteSensitiveWordLogsReq)(nil), // 159: openim.admin.DeleteSensitiveWordLogsReq + (*DeleteSensitiveWordLogsResp)(nil), // 160: openim.admin.DeleteSensitiveWordLogsResp + (*GetSensitiveWordStatsReq)(nil), // 161: openim.admin.GetSensitiveWordStatsReq + (*GetSensitiveWordStatsResp)(nil), // 162: openim.admin.GetSensitiveWordStatsResp + (*GetSensitiveWordLogStatsReq)(nil), // 163: openim.admin.GetSensitiveWordLogStatsReq + (*GetSensitiveWordLogStatsResp)(nil), // 164: openim.admin.GetSensitiveWordLogStatsResp + (*GetScheduledTasksReq)(nil), // 165: openim.admin.GetScheduledTasksReq + (*ScheduledTaskMessage)(nil), // 166: openim.admin.ScheduledTaskMessage + (*ScheduledTaskInfo)(nil), // 167: openim.admin.ScheduledTaskInfo + (*GetScheduledTasksResp)(nil), // 168: openim.admin.GetScheduledTasksResp + (*DeleteScheduledTaskReq)(nil), // 169: openim.admin.DeleteScheduledTaskReq + (*DeleteScheduledTaskResp)(nil), // 170: openim.admin.DeleteScheduledTaskResp + (*SystemConfigInfo)(nil), // 171: openim.admin.SystemConfigInfo + (*CreateSystemConfigReq)(nil), // 172: openim.admin.CreateSystemConfigReq + (*CreateSystemConfigResp)(nil), // 173: openim.admin.CreateSystemConfigResp + (*GetSystemConfigReq)(nil), // 174: openim.admin.GetSystemConfigReq + (*GetSystemConfigResp)(nil), // 175: openim.admin.GetSystemConfigResp + (*GetAllSystemConfigsReq)(nil), // 176: openim.admin.GetAllSystemConfigsReq + (*GetAllSystemConfigsResp)(nil), // 177: openim.admin.GetAllSystemConfigsResp + (*UpdateSystemConfigReq)(nil), // 178: openim.admin.UpdateSystemConfigReq + (*UpdateSystemConfigResp)(nil), // 179: openim.admin.UpdateSystemConfigResp + (*UpdateSystemConfigValueReq)(nil), // 180: openim.admin.UpdateSystemConfigValueReq + (*UpdateSystemConfigValueResp)(nil), // 181: openim.admin.UpdateSystemConfigValueResp + (*UpdateSystemConfigEnabledReq)(nil), // 182: openim.admin.UpdateSystemConfigEnabledReq + (*UpdateSystemConfigEnabledResp)(nil), // 183: openim.admin.UpdateSystemConfigEnabledResp + (*DeleteSystemConfigReq)(nil), // 184: openim.admin.DeleteSystemConfigReq + (*DeleteSystemConfigResp)(nil), // 185: openim.admin.DeleteSystemConfigResp + (*GetEnabledSystemConfigsReq)(nil), // 186: openim.admin.GetEnabledSystemConfigsReq + (*GetEnabledSystemConfigsResp)(nil), // 187: openim.admin.GetEnabledSystemConfigsResp + (*RealNameAuthInfo)(nil), // 188: openim.admin.RealNameAuthInfo + (*WalletInfo)(nil), // 189: openim.admin.WalletInfo + (*WalletBalanceRecordInfo)(nil), // 190: openim.admin.WalletBalanceRecordInfo + (*GetUserWalletReq)(nil), // 191: openim.admin.GetUserWalletReq + (*GetUserWalletResp)(nil), // 192: openim.admin.GetUserWalletResp + (*UpdateUserWalletBalanceReq)(nil), // 193: openim.admin.UpdateUserWalletBalanceReq + (*UpdateUserWalletBalanceResp)(nil), // 194: openim.admin.UpdateUserWalletBalanceResp + (*GetUserWalletBalanceRecordsReq)(nil), // 195: openim.admin.GetUserWalletBalanceRecordsReq + (*GetUserWalletBalanceRecordsResp)(nil), // 196: openim.admin.GetUserWalletBalanceRecordsResp + (*UpdateUserPaymentPasswordReq)(nil), // 197: openim.admin.UpdateUserPaymentPasswordReq + (*UpdateUserPaymentPasswordResp)(nil), // 198: openim.admin.UpdateUserPaymentPasswordResp + (*SetUserWithdrawAccountReq)(nil), // 199: openim.admin.SetUserWithdrawAccountReq + (*SetUserWithdrawAccountResp)(nil), // 200: openim.admin.SetUserWithdrawAccountResp + (*BatchUpdateUserItem)(nil), // 201: openim.admin.BatchUpdateUserItem + (*BatchUpdateWalletBalanceReq)(nil), // 202: openim.admin.BatchUpdateWalletBalanceReq + (*BatchUpdateResultItem)(nil), // 203: openim.admin.BatchUpdateResultItem + (*BatchUpdateWalletBalanceResp)(nil), // 204: openim.admin.BatchUpdateWalletBalanceResp + (*GetWalletsReq)(nil), // 205: openim.admin.GetWalletsReq + (*WalletListItemInfo)(nil), // 206: openim.admin.WalletListItemInfo + (*GetWalletsResp)(nil), // 207: openim.admin.GetWalletsResp + (*WithdrawInfo)(nil), // 208: openim.admin.WithdrawInfo + (*CreateWithdrawReq)(nil), // 209: openim.admin.CreateWithdrawReq + (*CreateWithdrawResp)(nil), // 210: openim.admin.CreateWithdrawResp + (*GetWithdrawReq)(nil), // 211: openim.admin.GetWithdrawReq + (*GetWithdrawResp)(nil), // 212: openim.admin.GetWithdrawResp + (*GetUserWithdrawsReq)(nil), // 213: openim.admin.GetUserWithdrawsReq + (*GetUserWithdrawsResp)(nil), // 214: openim.admin.GetUserWithdrawsResp + (*GetWithdrawsReq)(nil), // 215: openim.admin.GetWithdrawsReq + (*GetWithdrawsResp)(nil), // 216: openim.admin.GetWithdrawsResp + (*AuditWithdrawReq)(nil), // 217: openim.admin.AuditWithdrawReq + (*AuditWithdrawResp)(nil), // 218: openim.admin.AuditWithdrawResp + (*GetRealNameAuthsReq)(nil), // 219: openim.admin.GetRealNameAuthsReq + (*RealNameAuthListItemInfo)(nil), // 220: openim.admin.RealNameAuthListItemInfo + (*GetRealNameAuthsResp)(nil), // 221: openim.admin.GetRealNameAuthsResp + (*AuditRealNameAuthReq)(nil), // 222: openim.admin.AuditRealNameAuthReq + (*AuditRealNameAuthResp)(nil), // 223: openim.admin.AuditRealNameAuthResp + (*GetStatisticsReq)(nil), // 224: openim.admin.GetStatisticsReq + (*GetStatisticsResp)(nil), // 225: openim.admin.GetStatisticsResp + nil, // 226: openim.admin.SetClientConfigReq.ConfigEntry + nil, // 227: openim.admin.GetClientConfigResp.ConfigEntry + nil, // 228: openim.admin.GetUserTokenResp.TokensMapEntry + nil, // 229: openim.admin.BatchUpdateSensitiveWordsReq.UpdatesEntry + (*wrapperspb.StringValue)(nil), // 230: openim.protobuf.StringValue + (*wrapperspb.Int32Value)(nil), // 231: openim.protobuf.Int32Value + (*sdkws.RequestPagination)(nil), // 232: openim.sdkws.RequestPagination + (*common.UserPublicInfo)(nil), // 233: openim.chat.common.UserPublicInfo + (*sdkws.GroupInfo)(nil), // 234: openim.sdkws.GroupInfo + (*wrapperspb.Int64Value)(nil), // 235: openim.protobuf.Int64Value + (*wrapperspb.UInt32Value)(nil), // 236: openim.protobuf.UInt32Value + (*common.AppletInfo)(nil), // 237: openim.chat.common.AppletInfo + (*wrapperspb.BoolValue)(nil), // 238: openim.protobuf.BoolValue +} +var file_admin_admin_proto_depIdxs = []int32{ + 230, // 0: openim.admin.AdminUpdateInfoReq.account:type_name -> openim.protobuf.StringValue + 230, // 1: openim.admin.AdminUpdateInfoReq.password:type_name -> openim.protobuf.StringValue + 230, // 2: openim.admin.AdminUpdateInfoReq.faceURL:type_name -> openim.protobuf.StringValue + 230, // 3: openim.admin.AdminUpdateInfoReq.nickname:type_name -> openim.protobuf.StringValue + 231, // 4: openim.admin.AdminUpdateInfoReq.level:type_name -> openim.protobuf.Int32Value + 230, // 5: openim.admin.AdminUpdateInfoReq.googleAuthKey:type_name -> openim.protobuf.StringValue + 230, // 6: openim.admin.AdminUpdateInfoReq.operationPassword:type_name -> openim.protobuf.StringValue + 232, // 7: openim.admin.SearchAdminAccountReq.pagination:type_name -> openim.sdkws.RequestPagination + 17, // 8: openim.admin.SearchAdminAccountResp.adminAccounts:type_name -> openim.admin.GetAdminInfoResp + 232, // 9: openim.admin.SearchDefaultFriendReq.pagination:type_name -> openim.sdkws.RequestPagination + 233, // 10: openim.admin.DefaultFriendAttribute.user:type_name -> openim.chat.common.UserPublicInfo + 27, // 11: openim.admin.SearchDefaultFriendResp.users:type_name -> openim.admin.DefaultFriendAttribute + 232, // 12: openim.admin.SearchDefaultGroupReq.pagination:type_name -> openim.sdkws.RequestPagination + 234, // 13: openim.admin.GroupAttribute.group:type_name -> openim.sdkws.GroupInfo + 48, // 14: openim.admin.FindInvitationCodeResp.codes:type_name -> openim.admin.InvitationRegister + 233, // 15: openim.admin.InvitationRegister.usedUser:type_name -> openim.chat.common.UserPublicInfo + 232, // 16: openim.admin.SearchInvitationCodeReq.pagination:type_name -> openim.sdkws.RequestPagination + 48, // 17: openim.admin.SearchInvitationCodeResp.list:type_name -> openim.admin.InvitationRegister + 232, // 18: openim.admin.SearchUserIPLimitLoginReq.pagination:type_name -> openim.sdkws.RequestPagination + 233, // 19: openim.admin.LimitUserLoginIP.user:type_name -> openim.chat.common.UserPublicInfo + 52, // 20: openim.admin.SearchUserIPLimitLoginResp.limits:type_name -> openim.admin.LimitUserLoginIP + 54, // 21: openim.admin.AddUserIPLimitLoginReq.limits:type_name -> openim.admin.UserIPLimitLogin + 54, // 22: openim.admin.DelUserIPLimitLoginReq.limits:type_name -> openim.admin.UserIPLimitLogin + 232, // 23: openim.admin.SearchIPForbiddenReq.pagination:type_name -> openim.sdkws.RequestPagination + 59, // 24: openim.admin.SearchIPForbiddenResp.forbiddens:type_name -> openim.admin.IPForbidden + 60, // 25: openim.admin.AddIPForbiddenReq.forbiddens:type_name -> openim.admin.IPForbiddenAdd + 232, // 26: openim.admin.SearchBlockUserReq.pagination:type_name -> openim.sdkws.RequestPagination + 78, // 27: openim.admin.SearchBlockUserResp.users:type_name -> openim.admin.BlockUserInfo + 81, // 28: openim.admin.FindUserBlockInfoResp.blocks:type_name -> openim.admin.BlockInfo + 230, // 29: openim.admin.UpdateAppletReq.name:type_name -> openim.protobuf.StringValue + 230, // 30: openim.admin.UpdateAppletReq.appID:type_name -> openim.protobuf.StringValue + 230, // 31: openim.admin.UpdateAppletReq.icon:type_name -> openim.protobuf.StringValue + 230, // 32: openim.admin.UpdateAppletReq.url:type_name -> openim.protobuf.StringValue + 230, // 33: openim.admin.UpdateAppletReq.md5:type_name -> openim.protobuf.StringValue + 235, // 34: openim.admin.UpdateAppletReq.size:type_name -> openim.protobuf.Int64Value + 230, // 35: openim.admin.UpdateAppletReq.version:type_name -> openim.protobuf.StringValue + 236, // 36: openim.admin.UpdateAppletReq.priority:type_name -> openim.protobuf.UInt32Value + 236, // 37: openim.admin.UpdateAppletReq.status:type_name -> openim.protobuf.UInt32Value + 235, // 38: openim.admin.UpdateAppletReq.createTime:type_name -> openim.protobuf.Int64Value + 237, // 39: openim.admin.FindAppletResp.applets:type_name -> openim.chat.common.AppletInfo + 232, // 40: openim.admin.SearchAppletReq.pagination:type_name -> openim.sdkws.RequestPagination + 237, // 41: openim.admin.SearchAppletResp.applets:type_name -> openim.chat.common.AppletInfo + 226, // 42: openim.admin.SetClientConfigReq.config:type_name -> openim.admin.SetClientConfigReq.ConfigEntry + 227, // 43: openim.admin.GetClientConfigResp.config:type_name -> openim.admin.GetClientConfigResp.ConfigEntry + 228, // 44: openim.admin.GetUserTokenResp.tokensMap:type_name -> openim.admin.GetUserTokenResp.TokensMapEntry + 107, // 45: openim.admin.LatestApplicationVersionResp.version:type_name -> openim.admin.ApplicationVersion + 230, // 46: openim.admin.UpdateApplicationVersionReq.platform:type_name -> openim.protobuf.StringValue + 230, // 47: openim.admin.UpdateApplicationVersionReq.version:type_name -> openim.protobuf.StringValue + 230, // 48: openim.admin.UpdateApplicationVersionReq.url:type_name -> openim.protobuf.StringValue + 230, // 49: openim.admin.UpdateApplicationVersionReq.text:type_name -> openim.protobuf.StringValue + 238, // 50: openim.admin.UpdateApplicationVersionReq.force:type_name -> openim.protobuf.BoolValue + 238, // 51: openim.admin.UpdateApplicationVersionReq.latest:type_name -> openim.protobuf.BoolValue + 238, // 52: openim.admin.UpdateApplicationVersionReq.hot:type_name -> openim.protobuf.BoolValue + 232, // 53: openim.admin.PageApplicationVersionReq.pagination:type_name -> openim.sdkws.RequestPagination + 107, // 54: openim.admin.PageApplicationVersionResp.versions:type_name -> openim.admin.ApplicationVersion + 118, // 55: openim.admin.GetSensitiveWordResp.word:type_name -> openim.admin.SensitiveWordInfo + 232, // 56: openim.admin.SearchSensitiveWordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 118, // 57: openim.admin.SearchSensitiveWordsResp.words:type_name -> openim.admin.SensitiveWordInfo + 118, // 58: openim.admin.BatchAddSensitiveWordsReq.words:type_name -> openim.admin.SensitiveWordInfo + 229, // 59: openim.admin.BatchUpdateSensitiveWordsReq.updates:type_name -> openim.admin.BatchUpdateSensitiveWordsReq.UpdatesEntry + 119, // 60: openim.admin.GetSensitiveWordGroupResp.group:type_name -> openim.admin.SensitiveWordGroupInfo + 119, // 61: openim.admin.GetAllSensitiveWordGroupsResp.groups:type_name -> openim.admin.SensitiveWordGroupInfo + 120, // 62: openim.admin.GetSensitiveWordConfigResp.config:type_name -> openim.admin.SensitiveWordConfigInfo + 120, // 63: openim.admin.UpdateSensitiveWordConfigReq.config:type_name -> openim.admin.SensitiveWordConfigInfo + 232, // 64: openim.admin.GetSensitiveWordLogsReq.pagination:type_name -> openim.sdkws.RequestPagination + 121, // 65: openim.admin.GetSensitiveWordLogsResp.logs:type_name -> openim.admin.SensitiveWordLogInfo + 232, // 66: openim.admin.GetUserLoginRecordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 156, // 67: openim.admin.GetUserLoginRecordsResp.records:type_name -> openim.admin.UserLoginRecordInfo + 122, // 68: openim.admin.GetSensitiveWordStatsResp.stats:type_name -> openim.admin.SensitiveWordStatsInfo + 123, // 69: openim.admin.GetSensitiveWordLogStatsResp.stats:type_name -> openim.admin.SensitiveWordLogStatsInfo + 232, // 70: openim.admin.GetScheduledTasksReq.pagination:type_name -> openim.sdkws.RequestPagination + 166, // 71: openim.admin.ScheduledTaskInfo.messages:type_name -> openim.admin.ScheduledTaskMessage + 167, // 72: openim.admin.GetScheduledTasksResp.tasks:type_name -> openim.admin.ScheduledTaskInfo + 171, // 73: openim.admin.GetSystemConfigResp.config:type_name -> openim.admin.SystemConfigInfo + 232, // 74: openim.admin.GetAllSystemConfigsReq.pagination:type_name -> openim.sdkws.RequestPagination + 171, // 75: openim.admin.GetAllSystemConfigsResp.list:type_name -> openim.admin.SystemConfigInfo + 230, // 76: openim.admin.UpdateSystemConfigReq.title:type_name -> openim.protobuf.StringValue + 230, // 77: openim.admin.UpdateSystemConfigReq.value:type_name -> openim.protobuf.StringValue + 231, // 78: openim.admin.UpdateSystemConfigReq.valueType:type_name -> openim.protobuf.Int32Value + 230, // 79: openim.admin.UpdateSystemConfigReq.description:type_name -> openim.protobuf.StringValue + 238, // 80: openim.admin.UpdateSystemConfigReq.enabled:type_name -> openim.protobuf.BoolValue + 238, // 81: openim.admin.UpdateSystemConfigReq.showInApp:type_name -> openim.protobuf.BoolValue + 171, // 82: openim.admin.GetEnabledSystemConfigsResp.list:type_name -> openim.admin.SystemConfigInfo + 188, // 83: openim.admin.WalletInfo.realNameAuth:type_name -> openim.admin.RealNameAuthInfo + 189, // 84: openim.admin.GetUserWalletResp.wallet:type_name -> openim.admin.WalletInfo + 232, // 85: openim.admin.GetUserWalletBalanceRecordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 190, // 86: openim.admin.GetUserWalletBalanceRecordsResp.list:type_name -> openim.admin.WalletBalanceRecordInfo + 201, // 87: openim.admin.BatchUpdateWalletBalanceReq.users:type_name -> openim.admin.BatchUpdateUserItem + 203, // 88: openim.admin.BatchUpdateWalletBalanceResp.results:type_name -> openim.admin.BatchUpdateResultItem + 232, // 89: openim.admin.GetWalletsReq.pagination:type_name -> openim.sdkws.RequestPagination + 206, // 90: openim.admin.GetWalletsResp.wallets:type_name -> openim.admin.WalletListItemInfo + 188, // 91: openim.admin.WithdrawInfo.realNameAuth:type_name -> openim.admin.RealNameAuthInfo + 208, // 92: openim.admin.GetWithdrawResp.withdraw:type_name -> openim.admin.WithdrawInfo + 232, // 93: openim.admin.GetUserWithdrawsReq.pagination:type_name -> openim.sdkws.RequestPagination + 208, // 94: openim.admin.GetUserWithdrawsResp.list:type_name -> openim.admin.WithdrawInfo + 232, // 95: openim.admin.GetWithdrawsReq.pagination:type_name -> openim.sdkws.RequestPagination + 208, // 96: openim.admin.GetWithdrawsResp.list:type_name -> openim.admin.WithdrawInfo + 232, // 97: openim.admin.GetRealNameAuthsReq.pagination:type_name -> openim.sdkws.RequestPagination + 220, // 98: openim.admin.GetRealNameAuthsResp.list:type_name -> openim.admin.RealNameAuthListItemInfo + 118, // 99: openim.admin.BatchUpdateSensitiveWordsReq.UpdatesEntry.value:type_name -> openim.admin.SensitiveWordInfo + 0, // 100: openim.admin.admin.Login:input_type -> openim.admin.LoginReq + 6, // 101: openim.admin.admin.ChangePassword:input_type -> openim.admin.ChangePasswordReq + 4, // 102: openim.admin.admin.AdminUpdateInfo:input_type -> openim.admin.AdminUpdateInfoReq + 8, // 103: openim.admin.admin.GetAdminInfo:input_type -> openim.admin.GetAdminInfoReq + 2, // 104: openim.admin.admin.AddAdminAccount:input_type -> openim.admin.AddAdminAccountReq + 9, // 105: openim.admin.admin.ChangeAdminPassword:input_type -> openim.admin.ChangeAdminPasswordReq + 11, // 106: openim.admin.admin.ChangeOperationPassword:input_type -> openim.admin.ChangeOperationPasswordReq + 18, // 107: openim.admin.admin.SetGoogleAuthKey:input_type -> openim.admin.SetGoogleAuthKeyReq + 13, // 108: openim.admin.admin.DelAdminAccount:input_type -> openim.admin.DelAdminAccountReq + 15, // 109: openim.admin.admin.SearchAdminAccount:input_type -> openim.admin.SearchAdminAccountReq + 20, // 110: openim.admin.admin.AddDefaultFriend:input_type -> openim.admin.AddDefaultFriendReq + 22, // 111: openim.admin.admin.DelDefaultFriend:input_type -> openim.admin.DelDefaultFriendReq + 24, // 112: openim.admin.admin.FindDefaultFriend:input_type -> openim.admin.FindDefaultFriendReq + 26, // 113: openim.admin.admin.SearchDefaultFriend:input_type -> openim.admin.SearchDefaultFriendReq + 29, // 114: openim.admin.admin.AddDefaultGroup:input_type -> openim.admin.AddDefaultGroupReq + 31, // 115: openim.admin.admin.DelDefaultGroup:input_type -> openim.admin.DelDefaultGroupReq + 33, // 116: openim.admin.admin.FindDefaultGroup:input_type -> openim.admin.FindDefaultGroupReq + 35, // 117: openim.admin.admin.SearchDefaultGroup:input_type -> openim.admin.SearchDefaultGroupReq + 38, // 118: openim.admin.admin.AddInvitationCode:input_type -> openim.admin.AddInvitationCodeReq + 40, // 119: openim.admin.admin.GenInvitationCode:input_type -> openim.admin.GenInvitationCodeReq + 42, // 120: openim.admin.admin.FindInvitationCode:input_type -> openim.admin.FindInvitationCodeReq + 44, // 121: openim.admin.admin.UseInvitationCode:input_type -> openim.admin.UseInvitationCodeReq + 46, // 122: openim.admin.admin.DelInvitationCode:input_type -> openim.admin.DelInvitationCodeReq + 49, // 123: openim.admin.admin.SearchInvitationCode:input_type -> openim.admin.SearchInvitationCodeReq + 51, // 124: openim.admin.admin.SearchUserIPLimitLogin:input_type -> openim.admin.SearchUserIPLimitLoginReq + 55, // 125: openim.admin.admin.AddUserIPLimitLogin:input_type -> openim.admin.AddUserIPLimitLoginReq + 57, // 126: openim.admin.admin.DelUserIPLimitLogin:input_type -> openim.admin.DelUserIPLimitLoginReq + 61, // 127: openim.admin.admin.SearchIPForbidden:input_type -> openim.admin.SearchIPForbiddenReq + 63, // 128: openim.admin.admin.AddIPForbidden:input_type -> openim.admin.AddIPForbiddenReq + 65, // 129: openim.admin.admin.DelIPForbidden:input_type -> openim.admin.DelIPForbiddenReq + 71, // 130: openim.admin.admin.CancellationUser:input_type -> openim.admin.CancellationUserReq + 73, // 131: openim.admin.admin.BlockUser:input_type -> openim.admin.BlockUserReq + 75, // 132: openim.admin.admin.UnblockUser:input_type -> openim.admin.UnblockUserReq + 77, // 133: openim.admin.admin.SearchBlockUser:input_type -> openim.admin.SearchBlockUserReq + 80, // 134: openim.admin.admin.FindUserBlockInfo:input_type -> openim.admin.FindUserBlockInfoReq + 67, // 135: openim.admin.admin.CheckRegisterForbidden:input_type -> openim.admin.CheckRegisterForbiddenReq + 69, // 136: openim.admin.admin.CheckLoginForbidden:input_type -> openim.admin.CheckLoginForbiddenReq + 83, // 137: openim.admin.admin.CreateToken:input_type -> openim.admin.CreateTokenReq + 85, // 138: openim.admin.admin.ParseToken:input_type -> openim.admin.ParseTokenReq + 89, // 139: openim.admin.admin.AddApplet:input_type -> openim.admin.AddAppletReq + 91, // 140: openim.admin.admin.DelApplet:input_type -> openim.admin.DelAppletReq + 93, // 141: openim.admin.admin.UpdateApplet:input_type -> openim.admin.UpdateAppletReq + 95, // 142: openim.admin.admin.FindApplet:input_type -> openim.admin.FindAppletReq + 97, // 143: openim.admin.admin.SearchApplet:input_type -> openim.admin.SearchAppletReq + 103, // 144: openim.admin.admin.GetClientConfig:input_type -> openim.admin.GetClientConfigReq + 99, // 145: openim.admin.admin.SetClientConfig:input_type -> openim.admin.SetClientConfigReq + 101, // 146: openim.admin.admin.DelClientConfig:input_type -> openim.admin.DelClientConfigReq + 105, // 147: openim.admin.admin.GetUserToken:input_type -> openim.admin.GetUserTokenReq + 87, // 148: openim.admin.admin.InvalidateToken:input_type -> openim.admin.InvalidateTokenReq + 108, // 149: openim.admin.admin.LatestApplicationVersion:input_type -> openim.admin.LatestApplicationVersionReq + 110, // 150: openim.admin.admin.AddApplicationVersion:input_type -> openim.admin.AddApplicationVersionReq + 112, // 151: openim.admin.admin.UpdateApplicationVersion:input_type -> openim.admin.UpdateApplicationVersionReq + 114, // 152: openim.admin.admin.DeleteApplicationVersion:input_type -> openim.admin.DeleteApplicationVersionReq + 116, // 153: openim.admin.admin.PageApplicationVersion:input_type -> openim.admin.PageApplicationVersionReq + 124, // 154: openim.admin.admin.AddSensitiveWord:input_type -> openim.admin.AddSensitiveWordReq + 126, // 155: openim.admin.admin.UpdateSensitiveWord:input_type -> openim.admin.UpdateSensitiveWordReq + 128, // 156: openim.admin.admin.DeleteSensitiveWord:input_type -> openim.admin.DeleteSensitiveWordReq + 130, // 157: openim.admin.admin.GetSensitiveWord:input_type -> openim.admin.GetSensitiveWordReq + 132, // 158: openim.admin.admin.SearchSensitiveWords:input_type -> openim.admin.SearchSensitiveWordsReq + 134, // 159: openim.admin.admin.BatchAddSensitiveWords:input_type -> openim.admin.BatchAddSensitiveWordsReq + 136, // 160: openim.admin.admin.BatchUpdateSensitiveWords:input_type -> openim.admin.BatchUpdateSensitiveWordsReq + 138, // 161: openim.admin.admin.BatchDeleteSensitiveWords:input_type -> openim.admin.BatchDeleteSensitiveWordsReq + 140, // 162: openim.admin.admin.AddSensitiveWordGroup:input_type -> openim.admin.AddSensitiveWordGroupReq + 142, // 163: openim.admin.admin.UpdateSensitiveWordGroup:input_type -> openim.admin.UpdateSensitiveWordGroupReq + 144, // 164: openim.admin.admin.DeleteSensitiveWordGroup:input_type -> openim.admin.DeleteSensitiveWordGroupReq + 146, // 165: openim.admin.admin.GetSensitiveWordGroup:input_type -> openim.admin.GetSensitiveWordGroupReq + 148, // 166: openim.admin.admin.GetAllSensitiveWordGroups:input_type -> openim.admin.GetAllSensitiveWordGroupsReq + 150, // 167: openim.admin.admin.GetSensitiveWordConfig:input_type -> openim.admin.GetSensitiveWordConfigReq + 152, // 168: openim.admin.admin.UpdateSensitiveWordConfig:input_type -> openim.admin.UpdateSensitiveWordConfigReq + 154, // 169: openim.admin.admin.GetSensitiveWordLogs:input_type -> openim.admin.GetSensitiveWordLogsReq + 159, // 170: openim.admin.admin.DeleteSensitiveWordLogs:input_type -> openim.admin.DeleteSensitiveWordLogsReq + 157, // 171: openim.admin.admin.GetUserLoginRecords:input_type -> openim.admin.GetUserLoginRecordsReq + 161, // 172: openim.admin.admin.GetSensitiveWordStats:input_type -> openim.admin.GetSensitiveWordStatsReq + 163, // 173: openim.admin.admin.GetSensitiveWordLogStats:input_type -> openim.admin.GetSensitiveWordLogStatsReq + 165, // 174: openim.admin.admin.GetScheduledTasks:input_type -> openim.admin.GetScheduledTasksReq + 169, // 175: openim.admin.admin.DeleteScheduledTask:input_type -> openim.admin.DeleteScheduledTaskReq + 172, // 176: openim.admin.admin.CreateSystemConfig:input_type -> openim.admin.CreateSystemConfigReq + 174, // 177: openim.admin.admin.GetSystemConfig:input_type -> openim.admin.GetSystemConfigReq + 176, // 178: openim.admin.admin.GetAllSystemConfigs:input_type -> openim.admin.GetAllSystemConfigsReq + 178, // 179: openim.admin.admin.UpdateSystemConfig:input_type -> openim.admin.UpdateSystemConfigReq + 180, // 180: openim.admin.admin.UpdateSystemConfigValue:input_type -> openim.admin.UpdateSystemConfigValueReq + 182, // 181: openim.admin.admin.UpdateSystemConfigEnabled:input_type -> openim.admin.UpdateSystemConfigEnabledReq + 184, // 182: openim.admin.admin.DeleteSystemConfig:input_type -> openim.admin.DeleteSystemConfigReq + 186, // 183: openim.admin.admin.GetEnabledSystemConfigs:input_type -> openim.admin.GetEnabledSystemConfigsReq + 191, // 184: openim.admin.admin.GetUserWallet:input_type -> openim.admin.GetUserWalletReq + 193, // 185: openim.admin.admin.UpdateUserWalletBalance:input_type -> openim.admin.UpdateUserWalletBalanceReq + 195, // 186: openim.admin.admin.GetUserWalletBalanceRecords:input_type -> openim.admin.GetUserWalletBalanceRecordsReq + 202, // 187: openim.admin.admin.BatchUpdateWalletBalance:input_type -> openim.admin.BatchUpdateWalletBalanceReq + 205, // 188: openim.admin.admin.GetWallets:input_type -> openim.admin.GetWalletsReq + 197, // 189: openim.admin.admin.UpdateUserPaymentPassword:input_type -> openim.admin.UpdateUserPaymentPasswordReq + 199, // 190: openim.admin.admin.SetUserWithdrawAccount:input_type -> openim.admin.SetUserWithdrawAccountReq + 219, // 191: openim.admin.admin.GetRealNameAuths:input_type -> openim.admin.GetRealNameAuthsReq + 222, // 192: openim.admin.admin.AuditRealNameAuth:input_type -> openim.admin.AuditRealNameAuthReq + 209, // 193: openim.admin.admin.CreateWithdraw:input_type -> openim.admin.CreateWithdrawReq + 211, // 194: openim.admin.admin.GetWithdraw:input_type -> openim.admin.GetWithdrawReq + 213, // 195: openim.admin.admin.GetUserWithdraws:input_type -> openim.admin.GetUserWithdrawsReq + 215, // 196: openim.admin.admin.GetWithdraws:input_type -> openim.admin.GetWithdrawsReq + 217, // 197: openim.admin.admin.AuditWithdraw:input_type -> openim.admin.AuditWithdrawReq + 224, // 198: openim.admin.admin.GetStatistics:input_type -> openim.admin.GetStatisticsReq + 1, // 199: openim.admin.admin.Login:output_type -> openim.admin.LoginResp + 7, // 200: openim.admin.admin.ChangePassword:output_type -> openim.admin.ChangePasswordResp + 5, // 201: openim.admin.admin.AdminUpdateInfo:output_type -> openim.admin.AdminUpdateInfoResp + 17, // 202: openim.admin.admin.GetAdminInfo:output_type -> openim.admin.GetAdminInfoResp + 3, // 203: openim.admin.admin.AddAdminAccount:output_type -> openim.admin.AddAdminAccountResp + 10, // 204: openim.admin.admin.ChangeAdminPassword:output_type -> openim.admin.ChangeAdminPasswordResp + 12, // 205: openim.admin.admin.ChangeOperationPassword:output_type -> openim.admin.ChangeOperationPasswordResp + 19, // 206: openim.admin.admin.SetGoogleAuthKey:output_type -> openim.admin.SetGoogleAuthKeyResp + 14, // 207: openim.admin.admin.DelAdminAccount:output_type -> openim.admin.DelAdminAccountResp + 16, // 208: openim.admin.admin.SearchAdminAccount:output_type -> openim.admin.SearchAdminAccountResp + 21, // 209: openim.admin.admin.AddDefaultFriend:output_type -> openim.admin.AddDefaultFriendResp + 23, // 210: openim.admin.admin.DelDefaultFriend:output_type -> openim.admin.DelDefaultFriendResp + 25, // 211: openim.admin.admin.FindDefaultFriend:output_type -> openim.admin.FindDefaultFriendResp + 28, // 212: openim.admin.admin.SearchDefaultFriend:output_type -> openim.admin.SearchDefaultFriendResp + 30, // 213: openim.admin.admin.AddDefaultGroup:output_type -> openim.admin.AddDefaultGroupResp + 32, // 214: openim.admin.admin.DelDefaultGroup:output_type -> openim.admin.DelDefaultGroupResp + 34, // 215: openim.admin.admin.FindDefaultGroup:output_type -> openim.admin.FindDefaultGroupResp + 37, // 216: openim.admin.admin.SearchDefaultGroup:output_type -> openim.admin.SearchDefaultGroupResp + 39, // 217: openim.admin.admin.AddInvitationCode:output_type -> openim.admin.AddInvitationCodeResp + 41, // 218: openim.admin.admin.GenInvitationCode:output_type -> openim.admin.GenInvitationCodeResp + 43, // 219: openim.admin.admin.FindInvitationCode:output_type -> openim.admin.FindInvitationCodeResp + 45, // 220: openim.admin.admin.UseInvitationCode:output_type -> openim.admin.UseInvitationCodeResp + 47, // 221: openim.admin.admin.DelInvitationCode:output_type -> openim.admin.DelInvitationCodeResp + 50, // 222: openim.admin.admin.SearchInvitationCode:output_type -> openim.admin.SearchInvitationCodeResp + 53, // 223: openim.admin.admin.SearchUserIPLimitLogin:output_type -> openim.admin.SearchUserIPLimitLoginResp + 56, // 224: openim.admin.admin.AddUserIPLimitLogin:output_type -> openim.admin.AddUserIPLimitLoginResp + 58, // 225: openim.admin.admin.DelUserIPLimitLogin:output_type -> openim.admin.DelUserIPLimitLoginResp + 62, // 226: openim.admin.admin.SearchIPForbidden:output_type -> openim.admin.SearchIPForbiddenResp + 64, // 227: openim.admin.admin.AddIPForbidden:output_type -> openim.admin.AddIPForbiddenResp + 66, // 228: openim.admin.admin.DelIPForbidden:output_type -> openim.admin.DelIPForbiddenResp + 72, // 229: openim.admin.admin.CancellationUser:output_type -> openim.admin.CancellationUserResp + 74, // 230: openim.admin.admin.BlockUser:output_type -> openim.admin.BlockUserResp + 76, // 231: openim.admin.admin.UnblockUser:output_type -> openim.admin.UnblockUserResp + 79, // 232: openim.admin.admin.SearchBlockUser:output_type -> openim.admin.SearchBlockUserResp + 82, // 233: openim.admin.admin.FindUserBlockInfo:output_type -> openim.admin.FindUserBlockInfoResp + 68, // 234: openim.admin.admin.CheckRegisterForbidden:output_type -> openim.admin.CheckRegisterForbiddenResp + 70, // 235: openim.admin.admin.CheckLoginForbidden:output_type -> openim.admin.CheckLoginForbiddenResp + 84, // 236: openim.admin.admin.CreateToken:output_type -> openim.admin.CreateTokenResp + 86, // 237: openim.admin.admin.ParseToken:output_type -> openim.admin.ParseTokenResp + 90, // 238: openim.admin.admin.AddApplet:output_type -> openim.admin.AddAppletResp + 92, // 239: openim.admin.admin.DelApplet:output_type -> openim.admin.DelAppletResp + 94, // 240: openim.admin.admin.UpdateApplet:output_type -> openim.admin.UpdateAppletResp + 96, // 241: openim.admin.admin.FindApplet:output_type -> openim.admin.FindAppletResp + 98, // 242: openim.admin.admin.SearchApplet:output_type -> openim.admin.SearchAppletResp + 104, // 243: openim.admin.admin.GetClientConfig:output_type -> openim.admin.GetClientConfigResp + 100, // 244: openim.admin.admin.SetClientConfig:output_type -> openim.admin.SetClientConfigResp + 102, // 245: openim.admin.admin.DelClientConfig:output_type -> openim.admin.DelClientConfigResp + 106, // 246: openim.admin.admin.GetUserToken:output_type -> openim.admin.GetUserTokenResp + 88, // 247: openim.admin.admin.InvalidateToken:output_type -> openim.admin.InvalidateTokenResp + 109, // 248: openim.admin.admin.LatestApplicationVersion:output_type -> openim.admin.LatestApplicationVersionResp + 111, // 249: openim.admin.admin.AddApplicationVersion:output_type -> openim.admin.AddApplicationVersionResp + 113, // 250: openim.admin.admin.UpdateApplicationVersion:output_type -> openim.admin.UpdateApplicationVersionResp + 115, // 251: openim.admin.admin.DeleteApplicationVersion:output_type -> openim.admin.DeleteApplicationVersionResp + 117, // 252: openim.admin.admin.PageApplicationVersion:output_type -> openim.admin.PageApplicationVersionResp + 125, // 253: openim.admin.admin.AddSensitiveWord:output_type -> openim.admin.AddSensitiveWordResp + 127, // 254: openim.admin.admin.UpdateSensitiveWord:output_type -> openim.admin.UpdateSensitiveWordResp + 129, // 255: openim.admin.admin.DeleteSensitiveWord:output_type -> openim.admin.DeleteSensitiveWordResp + 131, // 256: openim.admin.admin.GetSensitiveWord:output_type -> openim.admin.GetSensitiveWordResp + 133, // 257: openim.admin.admin.SearchSensitiveWords:output_type -> openim.admin.SearchSensitiveWordsResp + 135, // 258: openim.admin.admin.BatchAddSensitiveWords:output_type -> openim.admin.BatchAddSensitiveWordsResp + 137, // 259: openim.admin.admin.BatchUpdateSensitiveWords:output_type -> openim.admin.BatchUpdateSensitiveWordsResp + 139, // 260: openim.admin.admin.BatchDeleteSensitiveWords:output_type -> openim.admin.BatchDeleteSensitiveWordsResp + 141, // 261: openim.admin.admin.AddSensitiveWordGroup:output_type -> openim.admin.AddSensitiveWordGroupResp + 143, // 262: openim.admin.admin.UpdateSensitiveWordGroup:output_type -> openim.admin.UpdateSensitiveWordGroupResp + 145, // 263: openim.admin.admin.DeleteSensitiveWordGroup:output_type -> openim.admin.DeleteSensitiveWordGroupResp + 147, // 264: openim.admin.admin.GetSensitiveWordGroup:output_type -> openim.admin.GetSensitiveWordGroupResp + 149, // 265: openim.admin.admin.GetAllSensitiveWordGroups:output_type -> openim.admin.GetAllSensitiveWordGroupsResp + 151, // 266: openim.admin.admin.GetSensitiveWordConfig:output_type -> openim.admin.GetSensitiveWordConfigResp + 153, // 267: openim.admin.admin.UpdateSensitiveWordConfig:output_type -> openim.admin.UpdateSensitiveWordConfigResp + 155, // 268: openim.admin.admin.GetSensitiveWordLogs:output_type -> openim.admin.GetSensitiveWordLogsResp + 160, // 269: openim.admin.admin.DeleteSensitiveWordLogs:output_type -> openim.admin.DeleteSensitiveWordLogsResp + 158, // 270: openim.admin.admin.GetUserLoginRecords:output_type -> openim.admin.GetUserLoginRecordsResp + 162, // 271: openim.admin.admin.GetSensitiveWordStats:output_type -> openim.admin.GetSensitiveWordStatsResp + 164, // 272: openim.admin.admin.GetSensitiveWordLogStats:output_type -> openim.admin.GetSensitiveWordLogStatsResp + 168, // 273: openim.admin.admin.GetScheduledTasks:output_type -> openim.admin.GetScheduledTasksResp + 170, // 274: openim.admin.admin.DeleteScheduledTask:output_type -> openim.admin.DeleteScheduledTaskResp + 173, // 275: openim.admin.admin.CreateSystemConfig:output_type -> openim.admin.CreateSystemConfigResp + 175, // 276: openim.admin.admin.GetSystemConfig:output_type -> openim.admin.GetSystemConfigResp + 177, // 277: openim.admin.admin.GetAllSystemConfigs:output_type -> openim.admin.GetAllSystemConfigsResp + 179, // 278: openim.admin.admin.UpdateSystemConfig:output_type -> openim.admin.UpdateSystemConfigResp + 181, // 279: openim.admin.admin.UpdateSystemConfigValue:output_type -> openim.admin.UpdateSystemConfigValueResp + 183, // 280: openim.admin.admin.UpdateSystemConfigEnabled:output_type -> openim.admin.UpdateSystemConfigEnabledResp + 185, // 281: openim.admin.admin.DeleteSystemConfig:output_type -> openim.admin.DeleteSystemConfigResp + 187, // 282: openim.admin.admin.GetEnabledSystemConfigs:output_type -> openim.admin.GetEnabledSystemConfigsResp + 192, // 283: openim.admin.admin.GetUserWallet:output_type -> openim.admin.GetUserWalletResp + 194, // 284: openim.admin.admin.UpdateUserWalletBalance:output_type -> openim.admin.UpdateUserWalletBalanceResp + 196, // 285: openim.admin.admin.GetUserWalletBalanceRecords:output_type -> openim.admin.GetUserWalletBalanceRecordsResp + 204, // 286: openim.admin.admin.BatchUpdateWalletBalance:output_type -> openim.admin.BatchUpdateWalletBalanceResp + 207, // 287: openim.admin.admin.GetWallets:output_type -> openim.admin.GetWalletsResp + 198, // 288: openim.admin.admin.UpdateUserPaymentPassword:output_type -> openim.admin.UpdateUserPaymentPasswordResp + 200, // 289: openim.admin.admin.SetUserWithdrawAccount:output_type -> openim.admin.SetUserWithdrawAccountResp + 221, // 290: openim.admin.admin.GetRealNameAuths:output_type -> openim.admin.GetRealNameAuthsResp + 223, // 291: openim.admin.admin.AuditRealNameAuth:output_type -> openim.admin.AuditRealNameAuthResp + 210, // 292: openim.admin.admin.CreateWithdraw:output_type -> openim.admin.CreateWithdrawResp + 212, // 293: openim.admin.admin.GetWithdraw:output_type -> openim.admin.GetWithdrawResp + 214, // 294: openim.admin.admin.GetUserWithdraws:output_type -> openim.admin.GetUserWithdrawsResp + 216, // 295: openim.admin.admin.GetWithdraws:output_type -> openim.admin.GetWithdrawsResp + 218, // 296: openim.admin.admin.AuditWithdraw:output_type -> openim.admin.AuditWithdrawResp + 225, // 297: openim.admin.admin.GetStatistics:output_type -> openim.admin.GetStatisticsResp + 199, // [199:298] is the sub-list for method output_type + 100, // [100:199] is the sub-list for method input_type + 100, // [100:100] is the sub-list for extension type_name + 100, // [100:100] is the sub-list for extension extendee + 0, // [0:100] is the sub-list for field type_name +} + +func init() { file_admin_admin_proto_init() } +func file_admin_admin_proto_init() { + if File_admin_admin_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_admin_admin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddAdminAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddAdminAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AdminUpdateInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AdminUpdateInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAdminInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangeAdminPasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangeAdminPasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangeOperationPasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangeOperationPasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelAdminAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelAdminAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchAdminAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchAdminAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAdminInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetGoogleAuthKeyReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetGoogleAuthKeyResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddDefaultFriendReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddDefaultFriendResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelDefaultFriendReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelDefaultFriendResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindDefaultFriendReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindDefaultFriendResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDefaultFriendReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DefaultFriendAttribute); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDefaultFriendResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddDefaultGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddDefaultGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelDefaultGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelDefaultGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindDefaultGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindDefaultGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDefaultGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupAttribute); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDefaultGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UseInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UseInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvitationRegister); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchInvitationCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchInvitationCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserIPLimitLoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LimitUserLoginIP); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserIPLimitLoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserIPLimitLogin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddUserIPLimitLoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddUserIPLimitLoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelUserIPLimitLoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelUserIPLimitLoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IPForbidden); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IPForbiddenAdd); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchIPForbiddenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchIPForbiddenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddIPForbiddenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddIPForbiddenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelIPForbiddenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelIPForbiddenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckRegisterForbiddenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckRegisterForbiddenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckLoginForbiddenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckLoginForbiddenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancellationUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancellationUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnblockUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnblockUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchBlockUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockUserInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchBlockUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserBlockInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserBlockInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTokenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTokenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ParseTokenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ParseTokenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvalidateTokenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvalidateTokenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddAppletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddAppletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelAppletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelAppletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateAppletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateAppletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindAppletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindAppletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchAppletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchAppletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetClientConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetClientConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelClientConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelClientConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetClientConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetClientConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserTokenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserTokenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplicationVersion); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LatestApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LatestApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[113].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[114].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[115].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[116].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PageApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[117].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PageApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[118].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[119].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordGroupInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[120].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordConfigInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[121].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordLogInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[122].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordStatsInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[123].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordLogStatsInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[124].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[125].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[126].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[127].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[128].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[129].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[130].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[131].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[132].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[133].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[134].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchAddSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[135].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchAddSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[136].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[137].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[138].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchDeleteSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[139].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchDeleteSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[140].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[141].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[142].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[143].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[144].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[145].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[146].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[147].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[148].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSensitiveWordGroupsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[149].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSensitiveWordGroupsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[150].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[151].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[152].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[153].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[154].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[155].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[156].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserLoginRecordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[157].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserLoginRecordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[158].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserLoginRecordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[159].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordLogsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[160].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordLogsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[161].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordStatsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[162].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordStatsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[163].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogStatsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[164].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogStatsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[165].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTasksReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[166].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScheduledTaskMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[167].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScheduledTaskInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[168].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTasksResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[169].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteScheduledTaskReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[170].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteScheduledTaskResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[171].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SystemConfigInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[172].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSystemConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[173].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSystemConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[174].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSystemConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[175].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSystemConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[176].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSystemConfigsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[177].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSystemConfigsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[178].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[179].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[180].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigValueReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[181].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigValueResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[182].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigEnabledReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[183].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSystemConfigEnabledResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[184].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSystemConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[185].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSystemConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[186].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetEnabledSystemConfigsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[187].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetEnabledSystemConfigsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[188].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RealNameAuthInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[189].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WalletInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[190].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WalletBalanceRecordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[191].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWalletReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[192].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWalletResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[193].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserWalletBalanceReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[194].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserWalletBalanceResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[195].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWalletBalanceRecordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[196].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWalletBalanceRecordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[197].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserPaymentPasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[198].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserPaymentPasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[199].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetUserWithdrawAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[200].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetUserWithdrawAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[201].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateUserItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[202].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateWalletBalanceReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[203].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateResultItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[204].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateWalletBalanceResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[205].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[206].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WalletListItemInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[207].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[208].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WithdrawInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[209].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateWithdrawReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[210].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateWithdrawResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[211].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[212].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[213].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWithdrawsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[214].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserWithdrawsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[215].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[216].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[217].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditWithdrawReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[218].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditWithdrawResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[219].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRealNameAuthsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[220].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RealNameAuthListItemInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[221].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRealNameAuthsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[222].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditRealNameAuthReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[223].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditRealNameAuthResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[224].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetStatisticsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[225].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetStatisticsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_admin_admin_proto_rawDesc, + NumEnums: 0, + NumMessages: 230, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_admin_admin_proto_goTypes, + DependencyIndexes: file_admin_admin_proto_depIdxs, + MessageInfos: file_admin_admin_proto_msgTypes, + }.Build() + File_admin_admin_proto = out.File + file_admin_admin_proto_rawDesc = nil + file_admin_admin_proto_goTypes = nil + file_admin_admin_proto_depIdxs = nil +} diff --git a/pkg/protocol/admin/admin.proto b/pkg/protocol/admin/admin.proto new file mode 100644 index 0000000..b644087 --- /dev/null +++ b/pkg/protocol/admin/admin.proto @@ -0,0 +1,1457 @@ +syntax = "proto3"; +package openim.admin; + +import "common/common.proto"; +import "sdkws/sdkws.proto"; +import "wrapperspb/wrapperspb.proto"; + +option go_package = "git.imall.cloud/openim/chat/pkg/protocol/admin"; + +// login +message LoginReq { + string account = 1; + string password = 2; + string version = 3; + string googleAuthCode = 4; // Google Authenticator 验证码(如果设置了 googleAuthKey 则必填) +} + +message LoginResp { + string adminAccount = 1; + string adminToken = 2; + string nickname = 3; + string faceURL = 4; + int32 level = 5; + string adminUserID = 6; +} + +message AddAdminAccountReq { + string account = 1; + string password = 2; + string faceURL = 3; + string nickname = 4; +} + +message AddAdminAccountResp {} + +message AdminUpdateInfoReq { + openim.protobuf.StringValue account = 1; + openim.protobuf.StringValue password = 2; + openim.protobuf.StringValue faceURL = 3; + openim.protobuf.StringValue nickname = 4; + openim.protobuf.Int32Value level = 6; + openim.protobuf.StringValue googleAuthKey = 7; + openim.protobuf.StringValue operationPassword = 9; +} + +message AdminUpdateInfoResp { + string userID = 1; + string nickname = 2; + string faceURL = 3; +} + +message ChangePasswordReq { + string password = 1; + string currentOperationPassword = 2; // 当前操作密码(修改操作密码时需要) + string newOperationPassword = 3; // 新操作密码(可选,如果提供则修改操作密码) +} + +message ChangePasswordResp {} + +message GetAdminInfoReq {} + +message ChangeAdminPasswordReq { + string userID = 1; + string currentPassword = 2; + string newPassword = 3; +} + +message ChangeAdminPasswordResp {} + +message ChangeOperationPasswordReq { + string currentPassword = 1; // 当前操作密码(如果已设置) + string newPassword = 2; // 新操作密码 +} + +message ChangeOperationPasswordResp {} + +message DelAdminAccountReq { + repeated string userIDs = 1; +} + +message DelAdminAccountResp {} + +message SearchAdminAccountReq { + string keyword = 1; // 搜索关键词(可选),支持账号、昵称、用户ID的模糊搜索 + openim.sdkws.RequestPagination pagination = 2; +} + +message SearchAdminAccountResp { + uint32 total = 1; + repeated GetAdminInfoResp adminAccounts = 2; +} + +message GetAdminInfoResp { + string account = 2; + string password = 3; + string faceURL = 4; + string nickname = 5; + string userID = 6; + int32 level = 7; + int64 createTime = 8; + string googleAuthKey = 9; + string operationPassword = 11; +} + +// 设置谷歌身份验证密钥请求 +message SetGoogleAuthKeyReq { + int32 operationType = 1; // 操作类型:1-新设置(如果为空则设置,如果已存在则返回错误),2-强制覆盖旧的(即使存在也生成新的),3-清空(删除现有的密钥) + string userID = 2; // 目标管理员ID,可选;为空时默认当前登录管理员,非空时仅超级管理员可操作 +} + +// 设置谷歌身份验证密钥响应 +message SetGoogleAuthKeyResp { + string googleAuthKey = 1; // 生成的谷歌身份验证密钥(Base32编码),操作类型为3(清空)时为空字符串 + string qrCodeURL = 2; // 二维码URL(otpauth格式),用于扫码绑定到Google Authenticator,操作类型为3(清空)时为空字符串 + int32 operationType = 3; // 实际执行的操作类型:1-新设置,2-强制覆盖,3-清空 +} + +// ################### Default Friend ################### + +message AddDefaultFriendReq { + repeated string userIDs = 1; +} + +message AddDefaultFriendResp {} + +message DelDefaultFriendReq { + repeated string userIDs = 1; +} + +message DelDefaultFriendResp {} + +message FindDefaultFriendReq {} + +message FindDefaultFriendResp { + repeated string userIDs = 1; +} + +message SearchDefaultFriendReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message DefaultFriendAttribute { + string userID = 1; + int64 createTime = 2; + openim.chat.common.UserPublicInfo user = 3; +} + +message SearchDefaultFriendResp { + uint32 total = 1; + repeated DefaultFriendAttribute users = 2; +} + +// ################### DefaultGroup ################### + +message AddDefaultGroupReq { + repeated string groupIDs = 1; +} + +message AddDefaultGroupResp {} + +message DelDefaultGroupReq { + repeated string groupIDs = 1; +} + +message DelDefaultGroupResp {} + +message FindDefaultGroupReq {} + +message FindDefaultGroupResp { + repeated string groupIDs = 1; +} + +message SearchDefaultGroupReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message GroupAttribute { + string groupID = 1; + int64 createTime = 2; + openim.sdkws.GroupInfo group = 3; +} + +message SearchDefaultGroupResp { + uint32 total = 1; + repeated string groupIDs = 2; +} + +// ################### InvitationCode ################### + +message AddInvitationCodeReq { + repeated string codes = 1; +} + +message AddInvitationCodeResp {} + +message GenInvitationCodeReq { + int32 len = 1; + int32 num = 2; + string chars = 3; +} + +message GenInvitationCodeResp {} + +message FindInvitationCodeReq { + repeated string codes = 1; +} + +message FindInvitationCodeResp { + repeated InvitationRegister codes = 1; +} + +message UseInvitationCodeReq { + string code = 1; + string userID = 2; +} + +message UseInvitationCodeResp {} + +message DelInvitationCodeReq { + repeated string codes = 1; +} + +message DelInvitationCodeResp {} + +message InvitationRegister { + string invitationCode = 1; + int64 createTime = 2; + string usedUserID = 3; + openim.chat.common.UserPublicInfo usedUser = 4; +} + +message SearchInvitationCodeReq { + int32 status = 1; + repeated string userIDs = 2; + repeated string codes = 3; + string keyword = 4; + openim.sdkws.RequestPagination pagination = 5; +} + +message SearchInvitationCodeResp { + uint32 total = 1; + repeated InvitationRegister list = 2; +} + +// ################### User Login IP Limit ################### + +message SearchUserIPLimitLoginReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message LimitUserLoginIP { + string userID = 1; + string ip = 2; + int64 createTime = 3; + openim.chat.common.UserPublicInfo user = 4; +} + +message SearchUserIPLimitLoginResp { + uint32 total = 1; + repeated LimitUserLoginIP limits = 2; +} + +message UserIPLimitLogin { + string userID = 1; + string ip = 2; +} + +message AddUserIPLimitLoginReq { + repeated UserIPLimitLogin limits = 1; +} + +message AddUserIPLimitLoginResp {} + +message DelUserIPLimitLoginReq { + repeated UserIPLimitLogin limits = 1; +} + +message DelUserIPLimitLoginResp {} + +// ################### User IP Limit ################### + +message IPForbidden { + string ip = 1; + bool limitRegister = 2; + bool limitLogin = 3; + int64 createTime = 4; +} + +message IPForbiddenAdd { + string ip = 1; + bool limitRegister = 2; + bool limitLogin = 3; +} + +message SearchIPForbiddenReq { + string keyword = 1; + int32 status = 2; + openim.sdkws.RequestPagination pagination = 3; +} + +message SearchIPForbiddenResp { + uint32 total = 1; + repeated IPForbidden forbiddens = 2; +} + +message AddIPForbiddenReq { + repeated IPForbiddenAdd forbiddens = 1; +} +message AddIPForbiddenResp {} + +message DelIPForbiddenReq { + repeated string ips = 1; +} +message DelIPForbiddenResp {} + +// ################### User Limit ################### +message CheckRegisterForbiddenReq { + string ip = 1; +} + +message CheckRegisterForbiddenResp {} + +message CheckLoginForbiddenReq { + string ip = 1; + string userID = 2; +} + +message CheckLoginForbiddenResp {} + +// ################### login out ################### +message CancellationUserReq { + string userID = 1; + string reason = 2; +} + +message CancellationUserResp {} + +// ################### Block User, Unblock User ################### +message BlockUserReq { + string userID = 1; + string reason = 2; +} + +message BlockUserResp {} + +message UnblockUserReq { + repeated string userIDs = 1; +} + +message UnblockUserResp {} + +message SearchBlockUserReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message BlockUserInfo { + string userID = 1; + string account = 2; + string phoneNumber = 3; + string areaCode = 4; + string email = 5; + string nickname = 6; + string faceURL = 7; + int32 gender = 8; + string reason = 9; + string opUserID = 10; + int64 createTime = 11; +} + +message SearchBlockUserResp { + uint32 total = 1; + repeated BlockUserInfo users = 2; +} + +message FindUserBlockInfoReq { + repeated string userIDs = 1; +} + +message BlockInfo { + string userID = 1; + string reason = 2; + string opUserID = 3; + int64 createTime = 4; +} + +message FindUserBlockInfoResp { + repeated BlockInfo blocks = 2; +} + +// ################### TOKEN ################### + +message CreateTokenReq { + string userID = 1; + int32 userType = 32; +} + +message CreateTokenResp { + string token = 1; +} + +message ParseTokenReq { + string token = 1; +} + +message ParseTokenResp { + string userID = 1; + int32 userType = 2; + int64 expireTimeSeconds = 3; +} + +message InvalidateTokenReq { + string userID = 1; +} + +message InvalidateTokenResp {} + +// ################### mini program ################### + +message AddAppletReq { + string id = 1; + string name = 2; + string appID = 3; + string icon = 4; + string url = 5; + string md5 = 6; + int64 size = 7; + string version = 8; + uint32 priority = 9; + uint32 status = 10; + int64 createTime = 11; +} + +message AddAppletResp {} + +message DelAppletReq { + repeated string appletIds = 1; +} + +message DelAppletResp {} + +message UpdateAppletReq { + string id = 1; + openim.protobuf.StringValue name = 2; + openim.protobuf.StringValue appID = 3; + openim.protobuf.StringValue icon = 4; + openim.protobuf.StringValue url = 5; + openim.protobuf.StringValue md5 = 6; + openim.protobuf.Int64Value size = 7; + openim.protobuf.StringValue version = 8; + openim.protobuf.UInt32Value priority = 9; + openim.protobuf.UInt32Value status = 10; + openim.protobuf.Int64Value createTime = 11; +} + +message UpdateAppletResp {} + +message FindAppletReq {} + +message FindAppletResp { + repeated openim.chat.common.AppletInfo applets = 1; +} + +message SearchAppletReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message SearchAppletResp { + uint32 total = 1; + repeated openim.chat.common.AppletInfo applets = 2; +} + +message SetClientConfigReq { + map config = 1; +} + +message SetClientConfigResp {} + +message DelClientConfigReq { + repeated string keys = 1; +} + +message DelClientConfigResp {} + +message GetClientConfigReq {} + +message GetClientConfigResp { + map config = 1; +} + +message GetUserTokenReq { + string userID = 1; +} + +message GetUserTokenResp { + map tokensMap = 1; +} + + +message ApplicationVersion { + string id = 1; + string platform = 2; + string version = 3; + string url = 4; + string text = 5; + bool force = 6; + bool latest = 7; + bool hot = 8; + int64 createTime = 9; +} + +message LatestApplicationVersionReq { + string platform = 2; + string version = 3; +} + +message LatestApplicationVersionResp { + ApplicationVersion version = 1; +} + +message AddApplicationVersionReq { + string platform = 1; + string version = 2; + string url = 3; + string text = 4; + bool force = 5; + bool latest = 6; + bool hot = 7; +} + +message AddApplicationVersionResp { + +} + +message UpdateApplicationVersionReq { + string id = 1; + openim.protobuf.StringValue platform = 2; + openim.protobuf.StringValue version = 3; + openim.protobuf.StringValue url = 4; + openim.protobuf.StringValue text = 5; + openim.protobuf.BoolValue force = 6; + openim.protobuf.BoolValue latest = 7; + openim.protobuf.BoolValue hot = 8; +} + +message UpdateApplicationVersionResp { + +} + +message DeleteApplicationVersionReq { + repeated string id = 1; +} + +message DeleteApplicationVersionResp { + +} + +message PageApplicationVersionReq { + repeated string platform = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message PageApplicationVersionResp { + int64 total = 1; + repeated ApplicationVersion versions = 2; +} + + +service admin { + // Login + rpc Login(LoginReq) returns (LoginResp); + rpc ChangePassword(ChangePasswordReq) returns (ChangePasswordResp); + rpc AdminUpdateInfo(AdminUpdateInfoReq) returns (AdminUpdateInfoResp); + // Get administrator information + rpc GetAdminInfo(GetAdminInfoReq) returns (GetAdminInfoResp); + rpc AddAdminAccount(AddAdminAccountReq) returns (AddAdminAccountResp); + rpc ChangeAdminPassword(ChangeAdminPasswordReq) returns (ChangeAdminPasswordResp); + rpc ChangeOperationPassword(ChangeOperationPasswordReq) returns (ChangeOperationPasswordResp); + rpc SetGoogleAuthKey(SetGoogleAuthKeyReq) returns (SetGoogleAuthKeyResp); + rpc DelAdminAccount(DelAdminAccountReq) returns (DelAdminAccountResp); + rpc SearchAdminAccount(SearchAdminAccountReq) returns (SearchAdminAccountResp); + + // Add Remove Get default friend list on registration + rpc AddDefaultFriend(AddDefaultFriendReq) returns (AddDefaultFriendResp); + rpc DelDefaultFriend(DelDefaultFriendReq) returns (DelDefaultFriendResp); + rpc FindDefaultFriend(FindDefaultFriendReq) returns (FindDefaultFriendResp); + rpc SearchDefaultFriend(SearchDefaultFriendReq) returns (SearchDefaultFriendResp); + + rpc AddDefaultGroup(AddDefaultGroupReq) returns (AddDefaultGroupResp); + rpc DelDefaultGroup(DelDefaultGroupReq) returns (DelDefaultGroupResp); + rpc FindDefaultGroup(FindDefaultGroupReq) returns (FindDefaultGroupResp); + rpc SearchDefaultGroup(SearchDefaultGroupReq) returns (SearchDefaultGroupResp); + + // Invitation Code Generate Query Get + rpc AddInvitationCode(AddInvitationCodeReq) returns (AddInvitationCodeResp); + rpc GenInvitationCode(GenInvitationCodeReq) returns (GenInvitationCodeResp); + rpc FindInvitationCode(FindInvitationCodeReq) returns (FindInvitationCodeResp); + rpc UseInvitationCode(UseInvitationCodeReq) returns (UseInvitationCodeResp); + rpc DelInvitationCode(DelInvitationCodeReq) returns (DelInvitationCodeResp); + rpc SearchInvitationCode(SearchInvitationCodeReq) returns (SearchInvitationCodeResp); + + // User login ip limit Query Add Remove + rpc SearchUserIPLimitLogin(SearchUserIPLimitLoginReq) returns (SearchUserIPLimitLoginResp); + rpc AddUserIPLimitLogin(AddUserIPLimitLoginReq) returns (AddUserIPLimitLoginResp); + rpc DelUserIPLimitLogin(DelUserIPLimitLoginReq) returns (DelUserIPLimitLoginResp); + + // Prohibit users from registering at certain ip Query Add Remove + rpc SearchIPForbidden(SearchIPForbiddenReq) returns (SearchIPForbiddenResp); + rpc AddIPForbidden(AddIPForbiddenReq) returns (AddIPForbiddenResp); + rpc DelIPForbidden(DelIPForbiddenReq) returns (DelIPForbiddenResp); + + // User Management Related Add Block/Unblock Pull + rpc CancellationUser(CancellationUserReq) returns (CancellationUserResp); + rpc BlockUser(BlockUserReq) returns (BlockUserResp); + rpc UnblockUser(UnblockUserReq) returns (UnblockUserResp); + rpc SearchBlockUser(SearchBlockUserReq) returns (SearchBlockUserResp); + rpc FindUserBlockInfo(FindUserBlockInfoReq) returns (FindUserBlockInfoResp); + + rpc CheckRegisterForbidden(CheckRegisterForbiddenReq) returns (CheckRegisterForbiddenResp); + rpc CheckLoginForbidden(CheckLoginForbiddenReq) returns (CheckLoginForbiddenResp); + + // create token + rpc CreateToken(CreateTokenReq) returns (CreateTokenResp); + // parse token + rpc ParseToken(ParseTokenReq) returns (ParseTokenResp); + + // app + rpc AddApplet(AddAppletReq) returns (AddAppletResp); + rpc DelApplet(DelAppletReq) returns (DelAppletResp); + rpc UpdateApplet(UpdateAppletReq) returns (UpdateAppletResp); + rpc FindApplet(FindAppletReq) returns (FindAppletResp); + rpc SearchApplet(SearchAppletReq) returns (SearchAppletResp); + + // Client Configuration + rpc GetClientConfig(GetClientConfigReq) returns (GetClientConfigResp); + rpc SetClientConfig(SetClientConfigReq) returns (SetClientConfigResp); + rpc DelClientConfig(DelClientConfigReq) returns (DelClientConfigResp); + + rpc GetUserToken(GetUserTokenReq) returns (GetUserTokenResp); + + // invalidate token + rpc InvalidateToken(InvalidateTokenReq) returns (InvalidateTokenResp); + + rpc LatestApplicationVersion(LatestApplicationVersionReq) returns (LatestApplicationVersionResp); + rpc AddApplicationVersion(AddApplicationVersionReq) returns (AddApplicationVersionResp); + rpc UpdateApplicationVersion(UpdateApplicationVersionReq) returns (UpdateApplicationVersionResp); + rpc DeleteApplicationVersion(DeleteApplicationVersionReq) returns (DeleteApplicationVersionResp); + rpc PageApplicationVersion(PageApplicationVersionReq) returns (PageApplicationVersionResp); + + // ==================== 敏感词管理 ==================== + + // 敏感词管理 + rpc AddSensitiveWord(AddSensitiveWordReq) returns (AddSensitiveWordResp); + rpc UpdateSensitiveWord(UpdateSensitiveWordReq) returns (UpdateSensitiveWordResp); + rpc DeleteSensitiveWord(DeleteSensitiveWordReq) returns (DeleteSensitiveWordResp); + rpc GetSensitiveWord(GetSensitiveWordReq) returns (GetSensitiveWordResp); + rpc SearchSensitiveWords(SearchSensitiveWordsReq) returns (SearchSensitiveWordsResp); + rpc BatchAddSensitiveWords(BatchAddSensitiveWordsReq) returns (BatchAddSensitiveWordsResp); + rpc BatchUpdateSensitiveWords(BatchUpdateSensitiveWordsReq) returns (BatchUpdateSensitiveWordsResp); + rpc BatchDeleteSensitiveWords(BatchDeleteSensitiveWordsReq) returns (BatchDeleteSensitiveWordsResp); + + // 敏感词分组管理 + rpc AddSensitiveWordGroup(AddSensitiveWordGroupReq) returns (AddSensitiveWordGroupResp); + rpc UpdateSensitiveWordGroup(UpdateSensitiveWordGroupReq) returns (UpdateSensitiveWordGroupResp); + rpc DeleteSensitiveWordGroup(DeleteSensitiveWordGroupReq) returns (DeleteSensitiveWordGroupResp); + rpc GetSensitiveWordGroup(GetSensitiveWordGroupReq) returns (GetSensitiveWordGroupResp); + rpc GetAllSensitiveWordGroups(GetAllSensitiveWordGroupsReq) returns (GetAllSensitiveWordGroupsResp); + + // 敏感词配置管理 + rpc GetSensitiveWordConfig(GetSensitiveWordConfigReq) returns (GetSensitiveWordConfigResp); + rpc UpdateSensitiveWordConfig(UpdateSensitiveWordConfigReq) returns (UpdateSensitiveWordConfigResp); + + // 敏感词日志管理 + rpc GetSensitiveWordLogs(GetSensitiveWordLogsReq) returns (GetSensitiveWordLogsResp); + rpc DeleteSensitiveWordLogs(DeleteSensitiveWordLogsReq) returns (DeleteSensitiveWordLogsResp); + + // 用户登录记录管理 + rpc GetUserLoginRecords(GetUserLoginRecordsReq) returns (GetUserLoginRecordsResp); + + // 敏感词统计 + rpc GetSensitiveWordStats(GetSensitiveWordStatsReq) returns (GetSensitiveWordStatsResp); + rpc GetSensitiveWordLogStats(GetSensitiveWordLogStatsReq) returns (GetSensitiveWordLogStatsResp); + + // ==================== 定时任务管理 ==================== + rpc GetScheduledTasks(GetScheduledTasksReq) returns (GetScheduledTasksResp); + rpc DeleteScheduledTask(DeleteScheduledTaskReq) returns (DeleteScheduledTaskResp); + + // ==================== 系统配置管理 ==================== + rpc CreateSystemConfig(CreateSystemConfigReq) returns (CreateSystemConfigResp); + rpc GetSystemConfig(GetSystemConfigReq) returns (GetSystemConfigResp); + rpc GetAllSystemConfigs(GetAllSystemConfigsReq) returns (GetAllSystemConfigsResp); + rpc UpdateSystemConfig(UpdateSystemConfigReq) returns (UpdateSystemConfigResp); + rpc UpdateSystemConfigValue(UpdateSystemConfigValueReq) returns (UpdateSystemConfigValueResp); + rpc UpdateSystemConfigEnabled(UpdateSystemConfigEnabledReq) returns (UpdateSystemConfigEnabledResp); + rpc DeleteSystemConfig(DeleteSystemConfigReq) returns (DeleteSystemConfigResp); + rpc GetEnabledSystemConfigs(GetEnabledSystemConfigsReq) returns (GetEnabledSystemConfigsResp); + + // ==================== 钱包管理相关 RPC ==================== + + // 获取用户钱包信息 + rpc GetUserWallet(GetUserWalletReq) returns (GetUserWalletResp); + + // 更新用户余额(后台充值/扣款) + rpc UpdateUserWalletBalance(UpdateUserWalletBalanceReq) returns (UpdateUserWalletBalanceResp); + + // 获取用户余额变动记录列表 + rpc GetUserWalletBalanceRecords(GetUserWalletBalanceRecordsReq) returns (GetUserWalletBalanceRecordsResp); + + // 批量更新用户余额(后台批量充值/扣款) + rpc BatchUpdateWalletBalance(BatchUpdateWalletBalanceReq) returns (BatchUpdateWalletBalanceResp); + + // 获取钱包列表 + rpc GetWallets(GetWalletsReq) returns (GetWalletsResp); + + // 修改用户支付密码(后台) + rpc UpdateUserPaymentPassword(UpdateUserPaymentPasswordReq) returns (UpdateUserPaymentPasswordResp); + + // 设置用户提款账号(后台) + rpc SetUserWithdrawAccount(SetUserWithdrawAccountReq) returns (SetUserWithdrawAccountResp); + + // ==================== 实名认证审核相关 RPC ==================== + + // 获取实名认证列表(支持按审核状态筛选) + rpc GetRealNameAuths(GetRealNameAuthsReq) returns (GetRealNameAuthsResp); + + // 审核实名认证(通过/拒绝) + rpc AuditRealNameAuth(AuditRealNameAuthReq) returns (AuditRealNameAuthResp); + + // ==================== 提现管理相关 RPC ==================== + + // 创建提现记录(用户端发起提现) + rpc CreateWithdraw(CreateWithdrawReq) returns (CreateWithdrawResp); + + // 获取提现记录详情 + rpc GetWithdraw(GetWithdrawReq) returns (GetWithdrawResp); + + // 获取用户的提现记录列表 + rpc GetUserWithdraws(GetUserWithdrawsReq) returns (GetUserWithdrawsResp); + + // 获取提现记录列表(后台,支持按状态筛选) + rpc GetWithdraws(GetWithdrawsReq) returns (GetWithdrawsResp); + + // 审核提现(后台) + rpc AuditWithdraw(AuditWithdrawReq) returns (AuditWithdrawResp); + + // 系统统计 + rpc GetStatistics(GetStatisticsReq) returns (GetStatisticsResp); +} + +// ==================== 敏感词管理相关消息 ==================== + +// 敏感词信息 +message SensitiveWordInfo { + string id = 1; + string word = 2; + int32 level = 3; + int32 type = 4; + int32 action = 5; + int32 status = 6; + string creator = 7; + string updater = 8; + int64 create_time = 9; + int64 update_time = 10; + string remark = 11; +} + +// 敏感词分组信息 +message SensitiveWordGroupInfo { + string id = 1; + string name = 2; + string remark = 3; + int64 create_time = 4; + int64 update_time = 5; +} + +// 敏感词配置信息 +message SensitiveWordConfigInfo { + string id = 1; + bool enable_filter = 2; + int32 filter_mode = 3; + string replace_char = 4; + repeated string whitelist_users = 5; + repeated string whitelist_groups = 6; + bool log_enabled = 7; + bool auto_approve = 8; + int64 update_time = 9; +} + +// 敏感词日志信息 +message SensitiveWordLogInfo { + string id = 1; + string user_id = 2; + string group_id = 3; + string content = 4; + repeated string matched_words = 5; + int32 action = 6; + string processed_text = 7; + int64 create_time = 8; +} + +// 敏感词统计信息 +message SensitiveWordStatsInfo { + int64 total = 1; + int64 enabled = 2; + int64 disabled = 3; + int64 replace = 4; + int64 block = 5; +} + +// 敏感词日志统计信息 +message SensitiveWordLogStatsInfo { + int64 total = 1; + int64 replace = 2; + int64 block = 3; +} + +// ==================== 敏感词管理请求和响应 ==================== + +// 添加敏感词 +message AddSensitiveWordReq { + string word = 1; + int32 level = 2; + int32 type = 3; + int32 action = 4; + int32 status = 5; + string remark = 6; +} + +message AddSensitiveWordResp {} + +// 更新敏感词 +message UpdateSensitiveWordReq { + string id = 1; + string word = 2; + int32 level = 3; + int32 type = 4; + int32 action = 5; + int32 status = 6; + string remark = 7; +} + +message UpdateSensitiveWordResp {} + +// 删除敏感词 +message DeleteSensitiveWordReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordResp {} + +// 获取敏感词 +message GetSensitiveWordReq { + string id = 1; +} + +message GetSensitiveWordResp { + SensitiveWordInfo word = 1; +} + +// 搜索敏感词 +message SearchSensitiveWordsReq { + string keyword = 1; + int32 action = 2; + int32 status = 3; + openim.sdkws.RequestPagination pagination = 4; +} + +message SearchSensitiveWordsResp { + int64 total = 1; + repeated SensitiveWordInfo words = 2; +} + +// 批量添加敏感词 +message BatchAddSensitiveWordsReq { + repeated SensitiveWordInfo words = 1; +} + +message BatchAddSensitiveWordsResp { + repeated string ids = 1; +} + +// 批量更新敏感词 +message BatchUpdateSensitiveWordsReq { + map updates = 1; +} + +message BatchUpdateSensitiveWordsResp {} + +// 批量删除敏感词 +message BatchDeleteSensitiveWordsReq { + repeated string ids = 1; +} + +message BatchDeleteSensitiveWordsResp {} + +// ==================== 敏感词分组管理请求和响应 ==================== + +// 添加敏感词分组 +message AddSensitiveWordGroupReq { + string name = 1; + string remark = 2; +} + +message AddSensitiveWordGroupResp {} + +// 更新敏感词分组 +message UpdateSensitiveWordGroupReq { + string id = 1; + string name = 2; + string remark = 3; +} + +message UpdateSensitiveWordGroupResp {} + +// 删除敏感词分组 +message DeleteSensitiveWordGroupReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordGroupResp {} + +// 获取敏感词分组 +message GetSensitiveWordGroupReq { + string id = 1; +} + +message GetSensitiveWordGroupResp { + SensitiveWordGroupInfo group = 1; +} + +// 获取所有敏感词分组 +message GetAllSensitiveWordGroupsReq {} + +message GetAllSensitiveWordGroupsResp { + repeated SensitiveWordGroupInfo groups = 1; +} + +// ==================== 敏感词配置管理请求和响应 ==================== + +// 获取敏感词配置 +message GetSensitiveWordConfigReq {} + +message GetSensitiveWordConfigResp { + SensitiveWordConfigInfo config = 1; +} + +// 更新敏感词配置 +message UpdateSensitiveWordConfigReq { + SensitiveWordConfigInfo config = 1; +} + +message UpdateSensitiveWordConfigResp {} + +// ==================== 敏感词日志管理请求和响应 ==================== + +// 获取敏感词日志 +message GetSensitiveWordLogsReq { + string user_id = 1; + string group_id = 2; + openim.sdkws.RequestPagination pagination = 3; +} + +message GetSensitiveWordLogsResp { + int64 total = 1; + repeated SensitiveWordLogInfo logs = 2; +} + +// 用户登录记录信息 +message UserLoginRecordInfo { + string user_id = 1; // 用户ID + int64 login_time = 2; // 登录时间(毫秒时间戳) + string ip = 3; // 登录IP + string device_id = 4; // 设备ID + string platform = 5; // 平台 + string face_url = 6; // 用户头像 + string nickname = 7; // 用户昵称 +} + +// 查询用户登录记录请求 +message GetUserLoginRecordsReq { + string user_id = 1; // 用户ID(可选,如果提供则查询该用户的登录记录) + string ip = 2; // IP地址(可选,如果提供则查询使用该IP的所有登录记录) + openim.sdkws.RequestPagination pagination = 3; // 分页信息 +} + +// 查询用户登录记录响应 +message GetUserLoginRecordsResp { + int64 total = 1; // 总数 + repeated UserLoginRecordInfo records = 2; // 登录记录列表 +} + +// 删除敏感词日志 +message DeleteSensitiveWordLogsReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordLogsResp {} + +// ==================== 敏感词统计请求和响应 ==================== + +// 获取敏感词统计 +message GetSensitiveWordStatsReq {} + +message GetSensitiveWordStatsResp { + SensitiveWordStatsInfo stats = 1; +} + +// 获取敏感词日志统计 +message GetSensitiveWordLogStatsReq { + int64 start_time = 1; + int64 end_time = 2; +} + +message GetSensitiveWordLogStatsResp { + SensitiveWordLogStatsInfo stats = 1; +} + +// ==================== 定时任务管理请求和响应 ==================== + +// 获取定时任务列表请求 +message GetScheduledTasksReq { + openim.sdkws.RequestPagination pagination = 1; // 分页信息 +} + +// 定时任务消息内容 +message ScheduledTaskMessage { + int32 type = 1; // 消息类型:1-文本,2-图片,3-视频 + string content = 2; // 消息内容(文本内容、图片URL、视频URL等) + string thumbnail = 3; // 缩略图URL(用于图片和视频) + int32 duration = 4; // 时长(秒,用于视频) + int64 fileSize = 5; // 文件大小(字节,用于图片和视频) + int32 width = 6; // 宽度(像素,用于图片和视频) + int32 height = 7; // 高度(像素,用于图片和视频) +} + +// 定时任务信息 +message ScheduledTaskInfo { + string id = 1; // 任务ID + string userID = 2; // 用户ID + string name = 3; // 任务名称 + string cronExpression = 4; // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + repeated ScheduledTaskMessage messages = 5; // 消息列表(支持多条消息一起发送) + repeated string recvIDs = 6; // 接收者ID列表(单聊,可以多个) + repeated string groupIDs = 7; // 群组ID列表(群聊,可以多个) + int32 status = 8; // 状态:0-已禁用,1-已启用 + int64 createTime = 9; // 创建时间(毫秒时间戳) + int64 updateTime = 10; // 更新时间(毫秒时间戳) +} + +// 获取定时任务列表响应 +message GetScheduledTasksResp { + int64 total = 1; // 总数 + repeated ScheduledTaskInfo tasks = 2; // 任务列表 +} + +// 删除定时任务请求 +message DeleteScheduledTaskReq { + repeated string taskIDs = 1; // 任务ID列表 +} + +// 删除定时任务响应 +message DeleteScheduledTaskResp {} + +// ==================== 系统配置管理请求和响应 ==================== + +// 系统配置信息 +message SystemConfigInfo { + string key = 1; // 配置键(唯一标识) + string title = 2; // 配置标题 + string value = 3; // 配置值(字符串形式存储,根据ValueType解析) + int32 valueType = 4; // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + string description = 5; // 配置描述 + bool enabled = 6; // 是否启用(用于开关类配置) + bool showInApp = 7; // 是否在APP端展示 + int64 createTime = 8; // 创建时间(毫秒时间戳) + int64 updateTime = 9; // 更新时间(毫秒时间戳) +} + +// 创建系统配置 +message CreateSystemConfigReq { + string key = 1; // 配置键(唯一标识) + string title = 2; // 配置标题 + string value = 3; // 配置值 + int32 valueType = 4; // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + string description = 5; // 配置描述 + bool enabled = 6; // 是否启用 + bool showInApp = 7; // 是否在APP端展示(默认为false) +} + +message CreateSystemConfigResp {} + +// 获取系统配置 +message GetSystemConfigReq { + string key = 1; // 配置键 +} + +message GetSystemConfigResp { + SystemConfigInfo config = 1; // 配置信息 +} + +// 获取所有系统配置(分页) +message GetAllSystemConfigsReq { + openim.sdkws.RequestPagination pagination = 1; // 分页信息 +} + +message GetAllSystemConfigsResp { + uint32 total = 1; // 总数 + repeated SystemConfigInfo list = 2; // 配置列表 +} + +// 更新系统配置 +message UpdateSystemConfigReq { + string key = 1; // 配置键 + openim.protobuf.StringValue title = 2; // 配置标题(可选) + openim.protobuf.StringValue value = 3; // 配置值(可选) + openim.protobuf.Int32Value valueType = 4; // 配置值类型(可选) + openim.protobuf.StringValue description = 5; // 配置描述(可选) + openim.protobuf.BoolValue enabled = 6; // 是否启用(可选) + openim.protobuf.BoolValue showInApp = 7; // 是否在APP端展示(可选) +} + +message UpdateSystemConfigResp {} + +// 更新系统配置值 +message UpdateSystemConfigValueReq { + string key = 1; // 配置键 + string value = 2; // 配置值 +} + +message UpdateSystemConfigValueResp {} + +// 更新系统配置启用状态 +message UpdateSystemConfigEnabledReq { + string key = 1; // 配置键 + bool enabled = 2; // 是否启用 +} + +message UpdateSystemConfigEnabledResp {} + +// 删除系统配置 +message DeleteSystemConfigReq { + repeated string keys = 1; // 配置键列表 +} + +message DeleteSystemConfigResp {} + +// 获取所有已启用的配置 +message GetEnabledSystemConfigsReq {} + +message GetEnabledSystemConfigsResp { + repeated SystemConfigInfo list = 1; // 配置列表 +} + +// ==================== 钱包管理相关消息 ==================== + +// 实名认证信息 +message RealNameAuthInfo { + string idCard = 1; // 身份证号 + string name = 2; // 真实姓名 + string idCardPhotoFront = 3; // 身份证正面照片URL + string idCardPhotoBack = 4; // 身份证反面照片URL + int32 auditStatus = 5; // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +// 钱包信息 +message WalletInfo { + string userID = 1; // 用户ID + int64 balance = 2; // 余额(单位:分) + string withdrawAccount = 3; // 提现账号 + RealNameAuthInfo realNameAuth = 4; // 实名认证信息 + string withdrawReceiveAccount = 5; // 提现收款账号 + bool hasPaymentPassword = 6; // 是否已设置支付密码 + int64 createTime = 7; // 创建时间(毫秒时间戳) + int64 updateTime = 8; // 更新时间(毫秒时间戳) +} + +// 余额变动记录信息 +message WalletBalanceRecordInfo { + string id = 1; // 记录ID + string userID = 2; // 用户ID + int64 amount = 3; // 变动金额(单位:分,正数表示增加,负数表示减少) + int32 type = 4; // 变动类型:1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 + int64 beforeBalance = 5; // 变动前余额(单位:分) + int64 afterBalance = 6; // 变动后余额(单位:分) + string orderID = 7; // 关联订单ID(可选) + string transactionID = 8; // 交易ID(可选) + string redPacketID = 9; // 红包ID(可选) + string remark = 10; // 备注 + int64 createTime = 11; // 创建时间(毫秒时间戳) +} + +// 获取用户钱包信息请求 +message GetUserWalletReq { + string userID = 1; // 用户ID +} + +// 获取用户钱包信息响应 +message GetUserWalletResp { + WalletInfo wallet = 1; // 钱包信息 +} + +// 更新用户余额请求 +message UpdateUserWalletBalanceReq { + string userID = 1; // 用户ID + int64 amount = 2; // 变动金额(单位:分,正数表示增加,负数表示减少) + int32 type = 3; // 变动类型:6-后台充值,99-其他(后台操作) + string remark = 4; // 备注 + string operationPassword = 5; // 操作密码(超级管理员必须提供并验证) +} + +// 更新用户余额响应 +message UpdateUserWalletBalanceResp { + int64 balance = 1; // 更新后的余额(单位:分) +} + +// 获取用户余额变动记录列表请求 +message GetUserWalletBalanceRecordsReq { + string userID = 1; // 用户ID + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +// 获取用户余额变动记录列表响应 +message GetUserWalletBalanceRecordsResp { + uint32 total = 1; // 总数 + repeated WalletBalanceRecordInfo list = 2; // 记录列表 +} + +// 修改用户支付密码请求 +message UpdateUserPaymentPasswordReq { + string userID = 1; // 用户ID + string paymentPassword = 2; // 新的支付密码(需要加密后存储) +} + +// 修改用户支付密码响应 +message UpdateUserPaymentPasswordResp {} + +// 设置用户提款账号请求 +message SetUserWithdrawAccountReq { + string userID = 1; // 用户ID + string withdrawAccount = 2; // 提款账号 +} + +// 设置用户提款账号响应 +message SetUserWithdrawAccountResp {} + +// 批量更新用户余额请求 - 单个用户的操作项 +message BatchUpdateUserItem { + string userID = 1; // 用户ID(选填,与 phoneNumber/account 至少提供一个) + string phoneNumber = 2; // 手机号(选填) + string account = 3; // 账号(选填) + int64 amount = 4; // 金额(分)(选填,如果不填则使用默认金额) + string operation = 5; // 操作类型(选填,如果不填则使用默认操作):set/add/subtract + string remark = 6; // 备注信息(选填) +} + +// 批量更新用户余额请求 +message BatchUpdateWalletBalanceReq { + repeated BatchUpdateUserItem users = 1; // 用户列表(必填) + int64 amount = 2; // 默认金额(分),用户未指定时使用此值 + string operation = 3; // 默认操作类型:set/add/subtract,默认为add + string operationPassword = 4; // 操作密码(超级管理员必须提供并验证) +} + +// 批量更新用户余额响应 - 单个用户的结果 +message BatchUpdateResultItem { + string userID = 1; // 用户ID + string phoneNumber = 2; // 手机号 + string account = 3; // 账号 + bool success = 4; // 是否成功 + string message = 5; // 结果消息 + int64 oldBalance = 6; // 修改前余额(分) + int64 newBalance = 7; // 修改后余额(分) + string remark = 8; // 备注信息 +} + +// 批量更新用户余额响应 +message BatchUpdateWalletBalanceResp { + uint32 total = 1; // 总处理数量 + uint32 success = 2; // 成功数量 + uint32 failed = 3; // 失败数量 + repeated BatchUpdateResultItem results = 4; // 结果列表 +} + +// 获取钱包列表请求 +message GetWalletsReq { + string userID = 1; // 用户ID(选填,支持精确查询) + string phoneNumber = 2; // 手机号(选填,支持模糊搜索) + string account = 3; // 账号(选填,支持模糊搜索) + openim.sdkws.RequestPagination pagination = 4; // 分页信息 +} + +// 钱包列表项信息 +message WalletListItemInfo { + string userID = 1; // 用户ID + string nickname = 2; // 用户昵称 + string faceURL = 3; // 用户头像 + int64 balance = 4; // 余额(分) + int64 createTime = 5; // 创建时间戳(毫秒) + int64 updateTime = 6; // 更新时间戳(毫秒) +} + +// 获取钱包列表响应 +message GetWalletsResp { + uint32 total = 1; // 总数 + repeated WalletListItemInfo wallets = 2; // 钱包列表 +} + +// ==================== 提现管理相关消息 ==================== + +// 提现记录信息 +message WithdrawInfo { + string id = 1; // 提现ID + string userID = 2; // 用户ID + int64 amount = 3; // 提现金额(单位:分) + string withdrawAccount = 4; // 提现账号 + int32 status = 5; // 审核状态:1-待审核,2-已通过,3-已拒绝 + string auditorID = 6; // 审核人ID(管理员ID) + int64 auditTime = 7; // 审核时间(毫秒时间戳) + string auditRemark = 8; // 审核备注 + string ip = 9; // 提现IP + string deviceID = 10; // 设备ID + string platform = 11; // 平台(iOS、Android、Web等) + string deviceModel = 12; // 设备型号 + string deviceBrand = 13; // 设备品牌 + string osVersion = 14; // 操作系统版本 + string appVersion = 15; // 应用版本 + int64 createTime = 16; // 创建时间(毫秒时间戳) + int64 updateTime = 17; // 更新时间(毫秒时间戳) + RealNameAuthInfo realNameAuth = 18; // 用户实名认证信息 +} + +// 创建提现记录请求 +message CreateWithdrawReq { + string userID = 1; // 用户ID + int64 amount = 2; // 提现金额(单位:分) + string withdrawAccount = 3; // 提现账号 + string ip = 4; // 提现IP + string deviceID = 5; // 设备ID + string platform = 6; // 平台 + string deviceModel = 7; // 设备型号 + string deviceBrand = 8; // 设备品牌 + string osVersion = 9; // 操作系统版本 + string appVersion = 10; // 应用版本 +} + +// 创建提现记录响应 +message CreateWithdrawResp { + string withdrawID = 1; // 提现ID +} + +// 获取提现记录详情请求 +message GetWithdrawReq { + string withdrawID = 1; // 提现ID +} + +// 获取提现记录详情响应 +message GetWithdrawResp { + WithdrawInfo withdraw = 1; // 提现记录信息 +} + +// 获取用户的提现记录列表请求 +message GetUserWithdrawsReq { + string userID = 1; // 用户ID + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +// 获取用户的提现记录列表响应 +message GetUserWithdrawsResp { + uint32 total = 1; // 总数 + repeated WithdrawInfo list = 2; // 提现记录列表 +} + +// 获取提现记录列表请求(后台) +message GetWithdrawsReq { + int32 status = 1; // 状态筛选(0表示全部) + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +// 获取提现记录列表响应(后台) +message GetWithdrawsResp { + uint32 total = 1; // 总数 + repeated WithdrawInfo list = 2; // 提现记录列表 +} + +// 审核提现请求 +message AuditWithdrawReq { + repeated string withdrawIDs = 1; // 提现申请ID列表(支持批量审核) + int32 status = 2; // 审核状态:2-已通过,3-已拒绝 + string auditRemark = 3; // 审核备注 +} + +// 审核提现响应 +message AuditWithdrawResp { + uint32 successCount = 1; // 成功审核的数量 + uint32 failCount = 2; // 失败审核的数量 + repeated string failedIDs = 3; // 失败的提现申请ID列表 +} + +// ==================== 实名认证审核相关消息 ==================== + +// 获取实名认证列表请求 +message GetRealNameAuthsReq { + int32 auditStatus = 1; // 审核状态筛选(0-未审核,1-审核通过,2-审核拒绝,0表示全部) + string userID = 3; // 用户ID搜索(可选,为空时不过滤) + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +// 实名认证列表项信息 +message RealNameAuthListItemInfo { + string userID = 1; // 用户ID + string nickname = 2; // 用户昵称 + string faceURL = 3; // 用户头像 + string idCard = 4; // 身份证号 + string name = 5; // 真实姓名 + string idCardPhotoFront = 6; // 身份证正面照片URL + string idCardPhotoBack = 7; // 身份证反面照片URL + int32 auditStatus = 8; // 审核状态:0-未审核,1-审核通过,2-审核拒绝 + int64 createTime = 9; // 创建时间戳(毫秒) + int64 updateTime = 10; // 更新时间戳(毫秒) +} + +// 获取实名认证列表响应 +message GetRealNameAuthsResp { + uint32 total = 1; // 总数 + repeated RealNameAuthListItemInfo list = 2; // 实名认证列表 +} + +// 审核实名认证请求 +message AuditRealNameAuthReq { + string userID = 1; // 用户ID + int32 auditStatus = 2; // 审核状态:1-审核通过,2-审核拒绝 + string auditRemark = 3; // 审核备注(可选) +} + +// 审核实名认证响应 +message AuditRealNameAuthResp {} + +// ==================== 系统统计请求和响应 ==================== + +// 获取系统统计数据 +message GetStatisticsReq {} + +message GetStatisticsResp { + int64 totalUsers = 1; // 用户总数 + int64 todayRegisteredUsers = 2; // 今天注册的用户数 + int64 todayActiveUsers = 3; // 今天活跃用户数(今天登录的用户数) + int64 todayMessages = 4; // 今天发送消息总数 + int64 totalMessages = 5; // 历史发送的消息总数 + int64 totalGroups = 6; // 群聊总数 + int64 totalFriends = 7; // 好友关系总数 + int64 onlineUsers = 8; // 当前在线用户数 + int64 todayNewGroups = 9; // 今天新建群聊数 +} diff --git a/pkg/protocol/admin/admin_grpc.pb.go b/pkg/protocol/admin/admin_grpc.pb.go new file mode 100644 index 0000000..45ad5d5 --- /dev/null +++ b/pkg/protocol/admin/admin_grpc.pb.go @@ -0,0 +1,3915 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v6.33.0 +// source: admin/admin.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Admin_Login_FullMethodName = "/openim.admin.admin/Login" + Admin_ChangePassword_FullMethodName = "/openim.admin.admin/ChangePassword" + Admin_AdminUpdateInfo_FullMethodName = "/openim.admin.admin/AdminUpdateInfo" + Admin_GetAdminInfo_FullMethodName = "/openim.admin.admin/GetAdminInfo" + Admin_AddAdminAccount_FullMethodName = "/openim.admin.admin/AddAdminAccount" + Admin_ChangeAdminPassword_FullMethodName = "/openim.admin.admin/ChangeAdminPassword" + Admin_ChangeOperationPassword_FullMethodName = "/openim.admin.admin/ChangeOperationPassword" + Admin_SetGoogleAuthKey_FullMethodName = "/openim.admin.admin/SetGoogleAuthKey" + Admin_DelAdminAccount_FullMethodName = "/openim.admin.admin/DelAdminAccount" + Admin_SearchAdminAccount_FullMethodName = "/openim.admin.admin/SearchAdminAccount" + Admin_AddDefaultFriend_FullMethodName = "/openim.admin.admin/AddDefaultFriend" + Admin_DelDefaultFriend_FullMethodName = "/openim.admin.admin/DelDefaultFriend" + Admin_FindDefaultFriend_FullMethodName = "/openim.admin.admin/FindDefaultFriend" + Admin_SearchDefaultFriend_FullMethodName = "/openim.admin.admin/SearchDefaultFriend" + Admin_AddDefaultGroup_FullMethodName = "/openim.admin.admin/AddDefaultGroup" + Admin_DelDefaultGroup_FullMethodName = "/openim.admin.admin/DelDefaultGroup" + Admin_FindDefaultGroup_FullMethodName = "/openim.admin.admin/FindDefaultGroup" + Admin_SearchDefaultGroup_FullMethodName = "/openim.admin.admin/SearchDefaultGroup" + Admin_AddInvitationCode_FullMethodName = "/openim.admin.admin/AddInvitationCode" + Admin_GenInvitationCode_FullMethodName = "/openim.admin.admin/GenInvitationCode" + Admin_FindInvitationCode_FullMethodName = "/openim.admin.admin/FindInvitationCode" + Admin_UseInvitationCode_FullMethodName = "/openim.admin.admin/UseInvitationCode" + Admin_DelInvitationCode_FullMethodName = "/openim.admin.admin/DelInvitationCode" + Admin_SearchInvitationCode_FullMethodName = "/openim.admin.admin/SearchInvitationCode" + Admin_SearchUserIPLimitLogin_FullMethodName = "/openim.admin.admin/SearchUserIPLimitLogin" + Admin_AddUserIPLimitLogin_FullMethodName = "/openim.admin.admin/AddUserIPLimitLogin" + Admin_DelUserIPLimitLogin_FullMethodName = "/openim.admin.admin/DelUserIPLimitLogin" + Admin_SearchIPForbidden_FullMethodName = "/openim.admin.admin/SearchIPForbidden" + Admin_AddIPForbidden_FullMethodName = "/openim.admin.admin/AddIPForbidden" + Admin_DelIPForbidden_FullMethodName = "/openim.admin.admin/DelIPForbidden" + Admin_CancellationUser_FullMethodName = "/openim.admin.admin/CancellationUser" + Admin_BlockUser_FullMethodName = "/openim.admin.admin/BlockUser" + Admin_UnblockUser_FullMethodName = "/openim.admin.admin/UnblockUser" + Admin_SearchBlockUser_FullMethodName = "/openim.admin.admin/SearchBlockUser" + Admin_FindUserBlockInfo_FullMethodName = "/openim.admin.admin/FindUserBlockInfo" + Admin_CheckRegisterForbidden_FullMethodName = "/openim.admin.admin/CheckRegisterForbidden" + Admin_CheckLoginForbidden_FullMethodName = "/openim.admin.admin/CheckLoginForbidden" + Admin_CreateToken_FullMethodName = "/openim.admin.admin/CreateToken" + Admin_ParseToken_FullMethodName = "/openim.admin.admin/ParseToken" + Admin_AddApplet_FullMethodName = "/openim.admin.admin/AddApplet" + Admin_DelApplet_FullMethodName = "/openim.admin.admin/DelApplet" + Admin_UpdateApplet_FullMethodName = "/openim.admin.admin/UpdateApplet" + Admin_FindApplet_FullMethodName = "/openim.admin.admin/FindApplet" + Admin_SearchApplet_FullMethodName = "/openim.admin.admin/SearchApplet" + Admin_GetClientConfig_FullMethodName = "/openim.admin.admin/GetClientConfig" + Admin_SetClientConfig_FullMethodName = "/openim.admin.admin/SetClientConfig" + Admin_DelClientConfig_FullMethodName = "/openim.admin.admin/DelClientConfig" + Admin_GetUserToken_FullMethodName = "/openim.admin.admin/GetUserToken" + Admin_InvalidateToken_FullMethodName = "/openim.admin.admin/InvalidateToken" + Admin_LatestApplicationVersion_FullMethodName = "/openim.admin.admin/LatestApplicationVersion" + Admin_AddApplicationVersion_FullMethodName = "/openim.admin.admin/AddApplicationVersion" + Admin_UpdateApplicationVersion_FullMethodName = "/openim.admin.admin/UpdateApplicationVersion" + Admin_DeleteApplicationVersion_FullMethodName = "/openim.admin.admin/DeleteApplicationVersion" + Admin_PageApplicationVersion_FullMethodName = "/openim.admin.admin/PageApplicationVersion" + Admin_AddSensitiveWord_FullMethodName = "/openim.admin.admin/AddSensitiveWord" + Admin_UpdateSensitiveWord_FullMethodName = "/openim.admin.admin/UpdateSensitiveWord" + Admin_DeleteSensitiveWord_FullMethodName = "/openim.admin.admin/DeleteSensitiveWord" + Admin_GetSensitiveWord_FullMethodName = "/openim.admin.admin/GetSensitiveWord" + Admin_SearchSensitiveWords_FullMethodName = "/openim.admin.admin/SearchSensitiveWords" + Admin_BatchAddSensitiveWords_FullMethodName = "/openim.admin.admin/BatchAddSensitiveWords" + Admin_BatchUpdateSensitiveWords_FullMethodName = "/openim.admin.admin/BatchUpdateSensitiveWords" + Admin_BatchDeleteSensitiveWords_FullMethodName = "/openim.admin.admin/BatchDeleteSensitiveWords" + Admin_AddSensitiveWordGroup_FullMethodName = "/openim.admin.admin/AddSensitiveWordGroup" + Admin_UpdateSensitiveWordGroup_FullMethodName = "/openim.admin.admin/UpdateSensitiveWordGroup" + Admin_DeleteSensitiveWordGroup_FullMethodName = "/openim.admin.admin/DeleteSensitiveWordGroup" + Admin_GetSensitiveWordGroup_FullMethodName = "/openim.admin.admin/GetSensitiveWordGroup" + Admin_GetAllSensitiveWordGroups_FullMethodName = "/openim.admin.admin/GetAllSensitiveWordGroups" + Admin_GetSensitiveWordConfig_FullMethodName = "/openim.admin.admin/GetSensitiveWordConfig" + Admin_UpdateSensitiveWordConfig_FullMethodName = "/openim.admin.admin/UpdateSensitiveWordConfig" + Admin_GetSensitiveWordLogs_FullMethodName = "/openim.admin.admin/GetSensitiveWordLogs" + Admin_DeleteSensitiveWordLogs_FullMethodName = "/openim.admin.admin/DeleteSensitiveWordLogs" + Admin_GetUserLoginRecords_FullMethodName = "/openim.admin.admin/GetUserLoginRecords" + Admin_GetSensitiveWordStats_FullMethodName = "/openim.admin.admin/GetSensitiveWordStats" + Admin_GetSensitiveWordLogStats_FullMethodName = "/openim.admin.admin/GetSensitiveWordLogStats" + Admin_GetScheduledTasks_FullMethodName = "/openim.admin.admin/GetScheduledTasks" + Admin_DeleteScheduledTask_FullMethodName = "/openim.admin.admin/DeleteScheduledTask" + Admin_CreateSystemConfig_FullMethodName = "/openim.admin.admin/CreateSystemConfig" + Admin_GetSystemConfig_FullMethodName = "/openim.admin.admin/GetSystemConfig" + Admin_GetAllSystemConfigs_FullMethodName = "/openim.admin.admin/GetAllSystemConfigs" + Admin_UpdateSystemConfig_FullMethodName = "/openim.admin.admin/UpdateSystemConfig" + Admin_UpdateSystemConfigValue_FullMethodName = "/openim.admin.admin/UpdateSystemConfigValue" + Admin_UpdateSystemConfigEnabled_FullMethodName = "/openim.admin.admin/UpdateSystemConfigEnabled" + Admin_DeleteSystemConfig_FullMethodName = "/openim.admin.admin/DeleteSystemConfig" + Admin_GetEnabledSystemConfigs_FullMethodName = "/openim.admin.admin/GetEnabledSystemConfigs" + Admin_GetUserWallet_FullMethodName = "/openim.admin.admin/GetUserWallet" + Admin_UpdateUserWalletBalance_FullMethodName = "/openim.admin.admin/UpdateUserWalletBalance" + Admin_GetUserWalletBalanceRecords_FullMethodName = "/openim.admin.admin/GetUserWalletBalanceRecords" + Admin_BatchUpdateWalletBalance_FullMethodName = "/openim.admin.admin/BatchUpdateWalletBalance" + Admin_GetWallets_FullMethodName = "/openim.admin.admin/GetWallets" + Admin_UpdateUserPaymentPassword_FullMethodName = "/openim.admin.admin/UpdateUserPaymentPassword" + Admin_SetUserWithdrawAccount_FullMethodName = "/openim.admin.admin/SetUserWithdrawAccount" + Admin_GetRealNameAuths_FullMethodName = "/openim.admin.admin/GetRealNameAuths" + Admin_AuditRealNameAuth_FullMethodName = "/openim.admin.admin/AuditRealNameAuth" + Admin_CreateWithdraw_FullMethodName = "/openim.admin.admin/CreateWithdraw" + Admin_GetWithdraw_FullMethodName = "/openim.admin.admin/GetWithdraw" + Admin_GetUserWithdraws_FullMethodName = "/openim.admin.admin/GetUserWithdraws" + Admin_GetWithdraws_FullMethodName = "/openim.admin.admin/GetWithdraws" + Admin_AuditWithdraw_FullMethodName = "/openim.admin.admin/AuditWithdraw" + Admin_GetStatistics_FullMethodName = "/openim.admin.admin/GetStatistics" +) + +// AdminClient is the client API for Admin service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AdminClient interface { + // Login + Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) + ChangePassword(ctx context.Context, in *ChangePasswordReq, opts ...grpc.CallOption) (*ChangePasswordResp, error) + AdminUpdateInfo(ctx context.Context, in *AdminUpdateInfoReq, opts ...grpc.CallOption) (*AdminUpdateInfoResp, error) + // Get administrator information + GetAdminInfo(ctx context.Context, in *GetAdminInfoReq, opts ...grpc.CallOption) (*GetAdminInfoResp, error) + AddAdminAccount(ctx context.Context, in *AddAdminAccountReq, opts ...grpc.CallOption) (*AddAdminAccountResp, error) + ChangeAdminPassword(ctx context.Context, in *ChangeAdminPasswordReq, opts ...grpc.CallOption) (*ChangeAdminPasswordResp, error) + ChangeOperationPassword(ctx context.Context, in *ChangeOperationPasswordReq, opts ...grpc.CallOption) (*ChangeOperationPasswordResp, error) + SetGoogleAuthKey(ctx context.Context, in *SetGoogleAuthKeyReq, opts ...grpc.CallOption) (*SetGoogleAuthKeyResp, error) + DelAdminAccount(ctx context.Context, in *DelAdminAccountReq, opts ...grpc.CallOption) (*DelAdminAccountResp, error) + SearchAdminAccount(ctx context.Context, in *SearchAdminAccountReq, opts ...grpc.CallOption) (*SearchAdminAccountResp, error) + // Add Remove Get default friend list on registration + AddDefaultFriend(ctx context.Context, in *AddDefaultFriendReq, opts ...grpc.CallOption) (*AddDefaultFriendResp, error) + DelDefaultFriend(ctx context.Context, in *DelDefaultFriendReq, opts ...grpc.CallOption) (*DelDefaultFriendResp, error) + FindDefaultFriend(ctx context.Context, in *FindDefaultFriendReq, opts ...grpc.CallOption) (*FindDefaultFriendResp, error) + SearchDefaultFriend(ctx context.Context, in *SearchDefaultFriendReq, opts ...grpc.CallOption) (*SearchDefaultFriendResp, error) + AddDefaultGroup(ctx context.Context, in *AddDefaultGroupReq, opts ...grpc.CallOption) (*AddDefaultGroupResp, error) + DelDefaultGroup(ctx context.Context, in *DelDefaultGroupReq, opts ...grpc.CallOption) (*DelDefaultGroupResp, error) + FindDefaultGroup(ctx context.Context, in *FindDefaultGroupReq, opts ...grpc.CallOption) (*FindDefaultGroupResp, error) + SearchDefaultGroup(ctx context.Context, in *SearchDefaultGroupReq, opts ...grpc.CallOption) (*SearchDefaultGroupResp, error) + // Invitation Code Generate Query Get + AddInvitationCode(ctx context.Context, in *AddInvitationCodeReq, opts ...grpc.CallOption) (*AddInvitationCodeResp, error) + GenInvitationCode(ctx context.Context, in *GenInvitationCodeReq, opts ...grpc.CallOption) (*GenInvitationCodeResp, error) + FindInvitationCode(ctx context.Context, in *FindInvitationCodeReq, opts ...grpc.CallOption) (*FindInvitationCodeResp, error) + UseInvitationCode(ctx context.Context, in *UseInvitationCodeReq, opts ...grpc.CallOption) (*UseInvitationCodeResp, error) + DelInvitationCode(ctx context.Context, in *DelInvitationCodeReq, opts ...grpc.CallOption) (*DelInvitationCodeResp, error) + SearchInvitationCode(ctx context.Context, in *SearchInvitationCodeReq, opts ...grpc.CallOption) (*SearchInvitationCodeResp, error) + // User login ip limit Query Add Remove + SearchUserIPLimitLogin(ctx context.Context, in *SearchUserIPLimitLoginReq, opts ...grpc.CallOption) (*SearchUserIPLimitLoginResp, error) + AddUserIPLimitLogin(ctx context.Context, in *AddUserIPLimitLoginReq, opts ...grpc.CallOption) (*AddUserIPLimitLoginResp, error) + DelUserIPLimitLogin(ctx context.Context, in *DelUserIPLimitLoginReq, opts ...grpc.CallOption) (*DelUserIPLimitLoginResp, error) + // Prohibit users from registering at certain ip Query Add Remove + SearchIPForbidden(ctx context.Context, in *SearchIPForbiddenReq, opts ...grpc.CallOption) (*SearchIPForbiddenResp, error) + AddIPForbidden(ctx context.Context, in *AddIPForbiddenReq, opts ...grpc.CallOption) (*AddIPForbiddenResp, error) + DelIPForbidden(ctx context.Context, in *DelIPForbiddenReq, opts ...grpc.CallOption) (*DelIPForbiddenResp, error) + // User Management Related Add Block/Unblock Pull + CancellationUser(ctx context.Context, in *CancellationUserReq, opts ...grpc.CallOption) (*CancellationUserResp, error) + BlockUser(ctx context.Context, in *BlockUserReq, opts ...grpc.CallOption) (*BlockUserResp, error) + UnblockUser(ctx context.Context, in *UnblockUserReq, opts ...grpc.CallOption) (*UnblockUserResp, error) + SearchBlockUser(ctx context.Context, in *SearchBlockUserReq, opts ...grpc.CallOption) (*SearchBlockUserResp, error) + FindUserBlockInfo(ctx context.Context, in *FindUserBlockInfoReq, opts ...grpc.CallOption) (*FindUserBlockInfoResp, error) + CheckRegisterForbidden(ctx context.Context, in *CheckRegisterForbiddenReq, opts ...grpc.CallOption) (*CheckRegisterForbiddenResp, error) + CheckLoginForbidden(ctx context.Context, in *CheckLoginForbiddenReq, opts ...grpc.CallOption) (*CheckLoginForbiddenResp, error) + // create token + CreateToken(ctx context.Context, in *CreateTokenReq, opts ...grpc.CallOption) (*CreateTokenResp, error) + // parse token + ParseToken(ctx context.Context, in *ParseTokenReq, opts ...grpc.CallOption) (*ParseTokenResp, error) + // app + AddApplet(ctx context.Context, in *AddAppletReq, opts ...grpc.CallOption) (*AddAppletResp, error) + DelApplet(ctx context.Context, in *DelAppletReq, opts ...grpc.CallOption) (*DelAppletResp, error) + UpdateApplet(ctx context.Context, in *UpdateAppletReq, opts ...grpc.CallOption) (*UpdateAppletResp, error) + FindApplet(ctx context.Context, in *FindAppletReq, opts ...grpc.CallOption) (*FindAppletResp, error) + SearchApplet(ctx context.Context, in *SearchAppletReq, opts ...grpc.CallOption) (*SearchAppletResp, error) + // Client Configuration + GetClientConfig(ctx context.Context, in *GetClientConfigReq, opts ...grpc.CallOption) (*GetClientConfigResp, error) + SetClientConfig(ctx context.Context, in *SetClientConfigReq, opts ...grpc.CallOption) (*SetClientConfigResp, error) + DelClientConfig(ctx context.Context, in *DelClientConfigReq, opts ...grpc.CallOption) (*DelClientConfigResp, error) + GetUserToken(ctx context.Context, in *GetUserTokenReq, opts ...grpc.CallOption) (*GetUserTokenResp, error) + // invalidate token + InvalidateToken(ctx context.Context, in *InvalidateTokenReq, opts ...grpc.CallOption) (*InvalidateTokenResp, error) + LatestApplicationVersion(ctx context.Context, in *LatestApplicationVersionReq, opts ...grpc.CallOption) (*LatestApplicationVersionResp, error) + AddApplicationVersion(ctx context.Context, in *AddApplicationVersionReq, opts ...grpc.CallOption) (*AddApplicationVersionResp, error) + UpdateApplicationVersion(ctx context.Context, in *UpdateApplicationVersionReq, opts ...grpc.CallOption) (*UpdateApplicationVersionResp, error) + DeleteApplicationVersion(ctx context.Context, in *DeleteApplicationVersionReq, opts ...grpc.CallOption) (*DeleteApplicationVersionResp, error) + PageApplicationVersion(ctx context.Context, in *PageApplicationVersionReq, opts ...grpc.CallOption) (*PageApplicationVersionResp, error) + // 敏感词管理 + AddSensitiveWord(ctx context.Context, in *AddSensitiveWordReq, opts ...grpc.CallOption) (*AddSensitiveWordResp, error) + UpdateSensitiveWord(ctx context.Context, in *UpdateSensitiveWordReq, opts ...grpc.CallOption) (*UpdateSensitiveWordResp, error) + DeleteSensitiveWord(ctx context.Context, in *DeleteSensitiveWordReq, opts ...grpc.CallOption) (*DeleteSensitiveWordResp, error) + GetSensitiveWord(ctx context.Context, in *GetSensitiveWordReq, opts ...grpc.CallOption) (*GetSensitiveWordResp, error) + SearchSensitiveWords(ctx context.Context, in *SearchSensitiveWordsReq, opts ...grpc.CallOption) (*SearchSensitiveWordsResp, error) + BatchAddSensitiveWords(ctx context.Context, in *BatchAddSensitiveWordsReq, opts ...grpc.CallOption) (*BatchAddSensitiveWordsResp, error) + BatchUpdateSensitiveWords(ctx context.Context, in *BatchUpdateSensitiveWordsReq, opts ...grpc.CallOption) (*BatchUpdateSensitiveWordsResp, error) + BatchDeleteSensitiveWords(ctx context.Context, in *BatchDeleteSensitiveWordsReq, opts ...grpc.CallOption) (*BatchDeleteSensitiveWordsResp, error) + // 敏感词分组管理 + AddSensitiveWordGroup(ctx context.Context, in *AddSensitiveWordGroupReq, opts ...grpc.CallOption) (*AddSensitiveWordGroupResp, error) + UpdateSensitiveWordGroup(ctx context.Context, in *UpdateSensitiveWordGroupReq, opts ...grpc.CallOption) (*UpdateSensitiveWordGroupResp, error) + DeleteSensitiveWordGroup(ctx context.Context, in *DeleteSensitiveWordGroupReq, opts ...grpc.CallOption) (*DeleteSensitiveWordGroupResp, error) + GetSensitiveWordGroup(ctx context.Context, in *GetSensitiveWordGroupReq, opts ...grpc.CallOption) (*GetSensitiveWordGroupResp, error) + GetAllSensitiveWordGroups(ctx context.Context, in *GetAllSensitiveWordGroupsReq, opts ...grpc.CallOption) (*GetAllSensitiveWordGroupsResp, error) + // 敏感词配置管理 + GetSensitiveWordConfig(ctx context.Context, in *GetSensitiveWordConfigReq, opts ...grpc.CallOption) (*GetSensitiveWordConfigResp, error) + UpdateSensitiveWordConfig(ctx context.Context, in *UpdateSensitiveWordConfigReq, opts ...grpc.CallOption) (*UpdateSensitiveWordConfigResp, error) + // 敏感词日志管理 + GetSensitiveWordLogs(ctx context.Context, in *GetSensitiveWordLogsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogsResp, error) + DeleteSensitiveWordLogs(ctx context.Context, in *DeleteSensitiveWordLogsReq, opts ...grpc.CallOption) (*DeleteSensitiveWordLogsResp, error) + // 用户登录记录管理 + GetUserLoginRecords(ctx context.Context, in *GetUserLoginRecordsReq, opts ...grpc.CallOption) (*GetUserLoginRecordsResp, error) + // 敏感词统计 + GetSensitiveWordStats(ctx context.Context, in *GetSensitiveWordStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordStatsResp, error) + GetSensitiveWordLogStats(ctx context.Context, in *GetSensitiveWordLogStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogStatsResp, error) + // ==================== 定时任务管理 ==================== + GetScheduledTasks(ctx context.Context, in *GetScheduledTasksReq, opts ...grpc.CallOption) (*GetScheduledTasksResp, error) + DeleteScheduledTask(ctx context.Context, in *DeleteScheduledTaskReq, opts ...grpc.CallOption) (*DeleteScheduledTaskResp, error) + // ==================== 系统配置管理 ==================== + CreateSystemConfig(ctx context.Context, in *CreateSystemConfigReq, opts ...grpc.CallOption) (*CreateSystemConfigResp, error) + GetSystemConfig(ctx context.Context, in *GetSystemConfigReq, opts ...grpc.CallOption) (*GetSystemConfigResp, error) + GetAllSystemConfigs(ctx context.Context, in *GetAllSystemConfigsReq, opts ...grpc.CallOption) (*GetAllSystemConfigsResp, error) + UpdateSystemConfig(ctx context.Context, in *UpdateSystemConfigReq, opts ...grpc.CallOption) (*UpdateSystemConfigResp, error) + UpdateSystemConfigValue(ctx context.Context, in *UpdateSystemConfigValueReq, opts ...grpc.CallOption) (*UpdateSystemConfigValueResp, error) + UpdateSystemConfigEnabled(ctx context.Context, in *UpdateSystemConfigEnabledReq, opts ...grpc.CallOption) (*UpdateSystemConfigEnabledResp, error) + DeleteSystemConfig(ctx context.Context, in *DeleteSystemConfigReq, opts ...grpc.CallOption) (*DeleteSystemConfigResp, error) + GetEnabledSystemConfigs(ctx context.Context, in *GetEnabledSystemConfigsReq, opts ...grpc.CallOption) (*GetEnabledSystemConfigsResp, error) + // 获取用户钱包信息 + GetUserWallet(ctx context.Context, in *GetUserWalletReq, opts ...grpc.CallOption) (*GetUserWalletResp, error) + // 更新用户余额(后台充值/扣款) + UpdateUserWalletBalance(ctx context.Context, in *UpdateUserWalletBalanceReq, opts ...grpc.CallOption) (*UpdateUserWalletBalanceResp, error) + // 获取用户余额变动记录列表 + GetUserWalletBalanceRecords(ctx context.Context, in *GetUserWalletBalanceRecordsReq, opts ...grpc.CallOption) (*GetUserWalletBalanceRecordsResp, error) + // 批量更新用户余额(后台批量充值/扣款) + BatchUpdateWalletBalance(ctx context.Context, in *BatchUpdateWalletBalanceReq, opts ...grpc.CallOption) (*BatchUpdateWalletBalanceResp, error) + // 获取钱包列表 + GetWallets(ctx context.Context, in *GetWalletsReq, opts ...grpc.CallOption) (*GetWalletsResp, error) + // 修改用户支付密码(后台) + UpdateUserPaymentPassword(ctx context.Context, in *UpdateUserPaymentPasswordReq, opts ...grpc.CallOption) (*UpdateUserPaymentPasswordResp, error) + // 设置用户提款账号(后台) + SetUserWithdrawAccount(ctx context.Context, in *SetUserWithdrawAccountReq, opts ...grpc.CallOption) (*SetUserWithdrawAccountResp, error) + // 获取实名认证列表(支持按审核状态筛选) + GetRealNameAuths(ctx context.Context, in *GetRealNameAuthsReq, opts ...grpc.CallOption) (*GetRealNameAuthsResp, error) + // 审核实名认证(通过/拒绝) + AuditRealNameAuth(ctx context.Context, in *AuditRealNameAuthReq, opts ...grpc.CallOption) (*AuditRealNameAuthResp, error) + // 创建提现记录(用户端发起提现) + CreateWithdraw(ctx context.Context, in *CreateWithdrawReq, opts ...grpc.CallOption) (*CreateWithdrawResp, error) + // 获取提现记录详情 + GetWithdraw(ctx context.Context, in *GetWithdrawReq, opts ...grpc.CallOption) (*GetWithdrawResp, error) + // 获取用户的提现记录列表 + GetUserWithdraws(ctx context.Context, in *GetUserWithdrawsReq, opts ...grpc.CallOption) (*GetUserWithdrawsResp, error) + // 获取提现记录列表(后台,支持按状态筛选) + GetWithdraws(ctx context.Context, in *GetWithdrawsReq, opts ...grpc.CallOption) (*GetWithdrawsResp, error) + // 审核提现(后台) + AuditWithdraw(ctx context.Context, in *AuditWithdrawReq, opts ...grpc.CallOption) (*AuditWithdrawResp, error) + // 系统统计 + GetStatistics(ctx context.Context, in *GetStatisticsReq, opts ...grpc.CallOption) (*GetStatisticsResp, error) +} + +type adminClient struct { + cc grpc.ClientConnInterface +} + +func NewAdminClient(cc grpc.ClientConnInterface) AdminClient { + return &adminClient{cc} +} + +func (c *adminClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LoginResp) + err := c.cc.Invoke(ctx, Admin_Login_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) ChangePassword(ctx context.Context, in *ChangePasswordReq, opts ...grpc.CallOption) (*ChangePasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ChangePasswordResp) + err := c.cc.Invoke(ctx, Admin_ChangePassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AdminUpdateInfo(ctx context.Context, in *AdminUpdateInfoReq, opts ...grpc.CallOption) (*AdminUpdateInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AdminUpdateInfoResp) + err := c.cc.Invoke(ctx, Admin_AdminUpdateInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetAdminInfo(ctx context.Context, in *GetAdminInfoReq, opts ...grpc.CallOption) (*GetAdminInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAdminInfoResp) + err := c.cc.Invoke(ctx, Admin_GetAdminInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddAdminAccount(ctx context.Context, in *AddAdminAccountReq, opts ...grpc.CallOption) (*AddAdminAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddAdminAccountResp) + err := c.cc.Invoke(ctx, Admin_AddAdminAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) ChangeAdminPassword(ctx context.Context, in *ChangeAdminPasswordReq, opts ...grpc.CallOption) (*ChangeAdminPasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ChangeAdminPasswordResp) + err := c.cc.Invoke(ctx, Admin_ChangeAdminPassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) ChangeOperationPassword(ctx context.Context, in *ChangeOperationPasswordReq, opts ...grpc.CallOption) (*ChangeOperationPasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ChangeOperationPasswordResp) + err := c.cc.Invoke(ctx, Admin_ChangeOperationPassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SetGoogleAuthKey(ctx context.Context, in *SetGoogleAuthKeyReq, opts ...grpc.CallOption) (*SetGoogleAuthKeyResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetGoogleAuthKeyResp) + err := c.cc.Invoke(ctx, Admin_SetGoogleAuthKey_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelAdminAccount(ctx context.Context, in *DelAdminAccountReq, opts ...grpc.CallOption) (*DelAdminAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelAdminAccountResp) + err := c.cc.Invoke(ctx, Admin_DelAdminAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchAdminAccount(ctx context.Context, in *SearchAdminAccountReq, opts ...grpc.CallOption) (*SearchAdminAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchAdminAccountResp) + err := c.cc.Invoke(ctx, Admin_SearchAdminAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddDefaultFriend(ctx context.Context, in *AddDefaultFriendReq, opts ...grpc.CallOption) (*AddDefaultFriendResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddDefaultFriendResp) + err := c.cc.Invoke(ctx, Admin_AddDefaultFriend_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelDefaultFriend(ctx context.Context, in *DelDefaultFriendReq, opts ...grpc.CallOption) (*DelDefaultFriendResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelDefaultFriendResp) + err := c.cc.Invoke(ctx, Admin_DelDefaultFriend_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) FindDefaultFriend(ctx context.Context, in *FindDefaultFriendReq, opts ...grpc.CallOption) (*FindDefaultFriendResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindDefaultFriendResp) + err := c.cc.Invoke(ctx, Admin_FindDefaultFriend_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchDefaultFriend(ctx context.Context, in *SearchDefaultFriendReq, opts ...grpc.CallOption) (*SearchDefaultFriendResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchDefaultFriendResp) + err := c.cc.Invoke(ctx, Admin_SearchDefaultFriend_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddDefaultGroup(ctx context.Context, in *AddDefaultGroupReq, opts ...grpc.CallOption) (*AddDefaultGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddDefaultGroupResp) + err := c.cc.Invoke(ctx, Admin_AddDefaultGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelDefaultGroup(ctx context.Context, in *DelDefaultGroupReq, opts ...grpc.CallOption) (*DelDefaultGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelDefaultGroupResp) + err := c.cc.Invoke(ctx, Admin_DelDefaultGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) FindDefaultGroup(ctx context.Context, in *FindDefaultGroupReq, opts ...grpc.CallOption) (*FindDefaultGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindDefaultGroupResp) + err := c.cc.Invoke(ctx, Admin_FindDefaultGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchDefaultGroup(ctx context.Context, in *SearchDefaultGroupReq, opts ...grpc.CallOption) (*SearchDefaultGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchDefaultGroupResp) + err := c.cc.Invoke(ctx, Admin_SearchDefaultGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddInvitationCode(ctx context.Context, in *AddInvitationCodeReq, opts ...grpc.CallOption) (*AddInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_AddInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GenInvitationCode(ctx context.Context, in *GenInvitationCodeReq, opts ...grpc.CallOption) (*GenInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GenInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_GenInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) FindInvitationCode(ctx context.Context, in *FindInvitationCodeReq, opts ...grpc.CallOption) (*FindInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_FindInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UseInvitationCode(ctx context.Context, in *UseInvitationCodeReq, opts ...grpc.CallOption) (*UseInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UseInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_UseInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelInvitationCode(ctx context.Context, in *DelInvitationCodeReq, opts ...grpc.CallOption) (*DelInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_DelInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchInvitationCode(ctx context.Context, in *SearchInvitationCodeReq, opts ...grpc.CallOption) (*SearchInvitationCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchInvitationCodeResp) + err := c.cc.Invoke(ctx, Admin_SearchInvitationCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchUserIPLimitLogin(ctx context.Context, in *SearchUserIPLimitLoginReq, opts ...grpc.CallOption) (*SearchUserIPLimitLoginResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchUserIPLimitLoginResp) + err := c.cc.Invoke(ctx, Admin_SearchUserIPLimitLogin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddUserIPLimitLogin(ctx context.Context, in *AddUserIPLimitLoginReq, opts ...grpc.CallOption) (*AddUserIPLimitLoginResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddUserIPLimitLoginResp) + err := c.cc.Invoke(ctx, Admin_AddUserIPLimitLogin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelUserIPLimitLogin(ctx context.Context, in *DelUserIPLimitLoginReq, opts ...grpc.CallOption) (*DelUserIPLimitLoginResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelUserIPLimitLoginResp) + err := c.cc.Invoke(ctx, Admin_DelUserIPLimitLogin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchIPForbidden(ctx context.Context, in *SearchIPForbiddenReq, opts ...grpc.CallOption) (*SearchIPForbiddenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchIPForbiddenResp) + err := c.cc.Invoke(ctx, Admin_SearchIPForbidden_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddIPForbidden(ctx context.Context, in *AddIPForbiddenReq, opts ...grpc.CallOption) (*AddIPForbiddenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddIPForbiddenResp) + err := c.cc.Invoke(ctx, Admin_AddIPForbidden_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelIPForbidden(ctx context.Context, in *DelIPForbiddenReq, opts ...grpc.CallOption) (*DelIPForbiddenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelIPForbiddenResp) + err := c.cc.Invoke(ctx, Admin_DelIPForbidden_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CancellationUser(ctx context.Context, in *CancellationUserReq, opts ...grpc.CallOption) (*CancellationUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CancellationUserResp) + err := c.cc.Invoke(ctx, Admin_CancellationUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) BlockUser(ctx context.Context, in *BlockUserReq, opts ...grpc.CallOption) (*BlockUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BlockUserResp) + err := c.cc.Invoke(ctx, Admin_BlockUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UnblockUser(ctx context.Context, in *UnblockUserReq, opts ...grpc.CallOption) (*UnblockUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UnblockUserResp) + err := c.cc.Invoke(ctx, Admin_UnblockUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchBlockUser(ctx context.Context, in *SearchBlockUserReq, opts ...grpc.CallOption) (*SearchBlockUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchBlockUserResp) + err := c.cc.Invoke(ctx, Admin_SearchBlockUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) FindUserBlockInfo(ctx context.Context, in *FindUserBlockInfoReq, opts ...grpc.CallOption) (*FindUserBlockInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindUserBlockInfoResp) + err := c.cc.Invoke(ctx, Admin_FindUserBlockInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CheckRegisterForbidden(ctx context.Context, in *CheckRegisterForbiddenReq, opts ...grpc.CallOption) (*CheckRegisterForbiddenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckRegisterForbiddenResp) + err := c.cc.Invoke(ctx, Admin_CheckRegisterForbidden_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CheckLoginForbidden(ctx context.Context, in *CheckLoginForbiddenReq, opts ...grpc.CallOption) (*CheckLoginForbiddenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckLoginForbiddenResp) + err := c.cc.Invoke(ctx, Admin_CheckLoginForbidden_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CreateToken(ctx context.Context, in *CreateTokenReq, opts ...grpc.CallOption) (*CreateTokenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateTokenResp) + err := c.cc.Invoke(ctx, Admin_CreateToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) ParseToken(ctx context.Context, in *ParseTokenReq, opts ...grpc.CallOption) (*ParseTokenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ParseTokenResp) + err := c.cc.Invoke(ctx, Admin_ParseToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddApplet(ctx context.Context, in *AddAppletReq, opts ...grpc.CallOption) (*AddAppletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddAppletResp) + err := c.cc.Invoke(ctx, Admin_AddApplet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelApplet(ctx context.Context, in *DelAppletReq, opts ...grpc.CallOption) (*DelAppletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelAppletResp) + err := c.cc.Invoke(ctx, Admin_DelApplet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateApplet(ctx context.Context, in *UpdateAppletReq, opts ...grpc.CallOption) (*UpdateAppletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateAppletResp) + err := c.cc.Invoke(ctx, Admin_UpdateApplet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) FindApplet(ctx context.Context, in *FindAppletReq, opts ...grpc.CallOption) (*FindAppletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindAppletResp) + err := c.cc.Invoke(ctx, Admin_FindApplet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchApplet(ctx context.Context, in *SearchAppletReq, opts ...grpc.CallOption) (*SearchAppletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchAppletResp) + err := c.cc.Invoke(ctx, Admin_SearchApplet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetClientConfig(ctx context.Context, in *GetClientConfigReq, opts ...grpc.CallOption) (*GetClientConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetClientConfigResp) + err := c.cc.Invoke(ctx, Admin_GetClientConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SetClientConfig(ctx context.Context, in *SetClientConfigReq, opts ...grpc.CallOption) (*SetClientConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetClientConfigResp) + err := c.cc.Invoke(ctx, Admin_SetClientConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DelClientConfig(ctx context.Context, in *DelClientConfigReq, opts ...grpc.CallOption) (*DelClientConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelClientConfigResp) + err := c.cc.Invoke(ctx, Admin_DelClientConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetUserToken(ctx context.Context, in *GetUserTokenReq, opts ...grpc.CallOption) (*GetUserTokenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserTokenResp) + err := c.cc.Invoke(ctx, Admin_GetUserToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) InvalidateToken(ctx context.Context, in *InvalidateTokenReq, opts ...grpc.CallOption) (*InvalidateTokenResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InvalidateTokenResp) + err := c.cc.Invoke(ctx, Admin_InvalidateToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) LatestApplicationVersion(ctx context.Context, in *LatestApplicationVersionReq, opts ...grpc.CallOption) (*LatestApplicationVersionResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LatestApplicationVersionResp) + err := c.cc.Invoke(ctx, Admin_LatestApplicationVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddApplicationVersion(ctx context.Context, in *AddApplicationVersionReq, opts ...grpc.CallOption) (*AddApplicationVersionResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddApplicationVersionResp) + err := c.cc.Invoke(ctx, Admin_AddApplicationVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateApplicationVersion(ctx context.Context, in *UpdateApplicationVersionReq, opts ...grpc.CallOption) (*UpdateApplicationVersionResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateApplicationVersionResp) + err := c.cc.Invoke(ctx, Admin_UpdateApplicationVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteApplicationVersion(ctx context.Context, in *DeleteApplicationVersionReq, opts ...grpc.CallOption) (*DeleteApplicationVersionResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteApplicationVersionResp) + err := c.cc.Invoke(ctx, Admin_DeleteApplicationVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) PageApplicationVersion(ctx context.Context, in *PageApplicationVersionReq, opts ...grpc.CallOption) (*PageApplicationVersionResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PageApplicationVersionResp) + err := c.cc.Invoke(ctx, Admin_PageApplicationVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddSensitiveWord(ctx context.Context, in *AddSensitiveWordReq, opts ...grpc.CallOption) (*AddSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddSensitiveWordResp) + err := c.cc.Invoke(ctx, Admin_AddSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSensitiveWord(ctx context.Context, in *UpdateSensitiveWordReq, opts ...grpc.CallOption) (*UpdateSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordResp) + err := c.cc.Invoke(ctx, Admin_UpdateSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteSensitiveWord(ctx context.Context, in *DeleteSensitiveWordReq, opts ...grpc.CallOption) (*DeleteSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordResp) + err := c.cc.Invoke(ctx, Admin_DeleteSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWord(ctx context.Context, in *GetSensitiveWordReq, opts ...grpc.CallOption) (*GetSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SearchSensitiveWords(ctx context.Context, in *SearchSensitiveWordsReq, opts ...grpc.CallOption) (*SearchSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchSensitiveWordsResp) + err := c.cc.Invoke(ctx, Admin_SearchSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) BatchAddSensitiveWords(ctx context.Context, in *BatchAddSensitiveWordsReq, opts ...grpc.CallOption) (*BatchAddSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchAddSensitiveWordsResp) + err := c.cc.Invoke(ctx, Admin_BatchAddSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) BatchUpdateSensitiveWords(ctx context.Context, in *BatchUpdateSensitiveWordsReq, opts ...grpc.CallOption) (*BatchUpdateSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchUpdateSensitiveWordsResp) + err := c.cc.Invoke(ctx, Admin_BatchUpdateSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) BatchDeleteSensitiveWords(ctx context.Context, in *BatchDeleteSensitiveWordsReq, opts ...grpc.CallOption) (*BatchDeleteSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchDeleteSensitiveWordsResp) + err := c.cc.Invoke(ctx, Admin_BatchDeleteSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddSensitiveWordGroup(ctx context.Context, in *AddSensitiveWordGroupReq, opts ...grpc.CallOption) (*AddSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Admin_AddSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSensitiveWordGroup(ctx context.Context, in *UpdateSensitiveWordGroupReq, opts ...grpc.CallOption) (*UpdateSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Admin_UpdateSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteSensitiveWordGroup(ctx context.Context, in *DeleteSensitiveWordGroupReq, opts ...grpc.CallOption) (*DeleteSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Admin_DeleteSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWordGroup(ctx context.Context, in *GetSensitiveWordGroupReq, opts ...grpc.CallOption) (*GetSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetAllSensitiveWordGroups(ctx context.Context, in *GetAllSensitiveWordGroupsReq, opts ...grpc.CallOption) (*GetAllSensitiveWordGroupsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAllSensitiveWordGroupsResp) + err := c.cc.Invoke(ctx, Admin_GetAllSensitiveWordGroups_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWordConfig(ctx context.Context, in *GetSensitiveWordConfigReq, opts ...grpc.CallOption) (*GetSensitiveWordConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordConfigResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWordConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSensitiveWordConfig(ctx context.Context, in *UpdateSensitiveWordConfigReq, opts ...grpc.CallOption) (*UpdateSensitiveWordConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordConfigResp) + err := c.cc.Invoke(ctx, Admin_UpdateSensitiveWordConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWordLogs(ctx context.Context, in *GetSensitiveWordLogsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordLogsResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWordLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteSensitiveWordLogs(ctx context.Context, in *DeleteSensitiveWordLogsReq, opts ...grpc.CallOption) (*DeleteSensitiveWordLogsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordLogsResp) + err := c.cc.Invoke(ctx, Admin_DeleteSensitiveWordLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetUserLoginRecords(ctx context.Context, in *GetUserLoginRecordsReq, opts ...grpc.CallOption) (*GetUserLoginRecordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserLoginRecordsResp) + err := c.cc.Invoke(ctx, Admin_GetUserLoginRecords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWordStats(ctx context.Context, in *GetSensitiveWordStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordStatsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordStatsResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWordStats_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSensitiveWordLogStats(ctx context.Context, in *GetSensitiveWordLogStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogStatsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordLogStatsResp) + err := c.cc.Invoke(ctx, Admin_GetSensitiveWordLogStats_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetScheduledTasks(ctx context.Context, in *GetScheduledTasksReq, opts ...grpc.CallOption) (*GetScheduledTasksResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetScheduledTasksResp) + err := c.cc.Invoke(ctx, Admin_GetScheduledTasks_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteScheduledTask(ctx context.Context, in *DeleteScheduledTaskReq, opts ...grpc.CallOption) (*DeleteScheduledTaskResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteScheduledTaskResp) + err := c.cc.Invoke(ctx, Admin_DeleteScheduledTask_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CreateSystemConfig(ctx context.Context, in *CreateSystemConfigReq, opts ...grpc.CallOption) (*CreateSystemConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateSystemConfigResp) + err := c.cc.Invoke(ctx, Admin_CreateSystemConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetSystemConfig(ctx context.Context, in *GetSystemConfigReq, opts ...grpc.CallOption) (*GetSystemConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSystemConfigResp) + err := c.cc.Invoke(ctx, Admin_GetSystemConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetAllSystemConfigs(ctx context.Context, in *GetAllSystemConfigsReq, opts ...grpc.CallOption) (*GetAllSystemConfigsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAllSystemConfigsResp) + err := c.cc.Invoke(ctx, Admin_GetAllSystemConfigs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSystemConfig(ctx context.Context, in *UpdateSystemConfigReq, opts ...grpc.CallOption) (*UpdateSystemConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSystemConfigResp) + err := c.cc.Invoke(ctx, Admin_UpdateSystemConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSystemConfigValue(ctx context.Context, in *UpdateSystemConfigValueReq, opts ...grpc.CallOption) (*UpdateSystemConfigValueResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSystemConfigValueResp) + err := c.cc.Invoke(ctx, Admin_UpdateSystemConfigValue_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateSystemConfigEnabled(ctx context.Context, in *UpdateSystemConfigEnabledReq, opts ...grpc.CallOption) (*UpdateSystemConfigEnabledResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSystemConfigEnabledResp) + err := c.cc.Invoke(ctx, Admin_UpdateSystemConfigEnabled_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteSystemConfig(ctx context.Context, in *DeleteSystemConfigReq, opts ...grpc.CallOption) (*DeleteSystemConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSystemConfigResp) + err := c.cc.Invoke(ctx, Admin_DeleteSystemConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetEnabledSystemConfigs(ctx context.Context, in *GetEnabledSystemConfigsReq, opts ...grpc.CallOption) (*GetEnabledSystemConfigsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetEnabledSystemConfigsResp) + err := c.cc.Invoke(ctx, Admin_GetEnabledSystemConfigs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetUserWallet(ctx context.Context, in *GetUserWalletReq, opts ...grpc.CallOption) (*GetUserWalletResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserWalletResp) + err := c.cc.Invoke(ctx, Admin_GetUserWallet_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateUserWalletBalance(ctx context.Context, in *UpdateUserWalletBalanceReq, opts ...grpc.CallOption) (*UpdateUserWalletBalanceResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateUserWalletBalanceResp) + err := c.cc.Invoke(ctx, Admin_UpdateUserWalletBalance_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetUserWalletBalanceRecords(ctx context.Context, in *GetUserWalletBalanceRecordsReq, opts ...grpc.CallOption) (*GetUserWalletBalanceRecordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserWalletBalanceRecordsResp) + err := c.cc.Invoke(ctx, Admin_GetUserWalletBalanceRecords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) BatchUpdateWalletBalance(ctx context.Context, in *BatchUpdateWalletBalanceReq, opts ...grpc.CallOption) (*BatchUpdateWalletBalanceResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchUpdateWalletBalanceResp) + err := c.cc.Invoke(ctx, Admin_BatchUpdateWalletBalance_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetWallets(ctx context.Context, in *GetWalletsReq, opts ...grpc.CallOption) (*GetWalletsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWalletsResp) + err := c.cc.Invoke(ctx, Admin_GetWallets_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateUserPaymentPassword(ctx context.Context, in *UpdateUserPaymentPasswordReq, opts ...grpc.CallOption) (*UpdateUserPaymentPasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateUserPaymentPasswordResp) + err := c.cc.Invoke(ctx, Admin_UpdateUserPaymentPassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) SetUserWithdrawAccount(ctx context.Context, in *SetUserWithdrawAccountReq, opts ...grpc.CallOption) (*SetUserWithdrawAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetUserWithdrawAccountResp) + err := c.cc.Invoke(ctx, Admin_SetUserWithdrawAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetRealNameAuths(ctx context.Context, in *GetRealNameAuthsReq, opts ...grpc.CallOption) (*GetRealNameAuthsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRealNameAuthsResp) + err := c.cc.Invoke(ctx, Admin_GetRealNameAuths_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AuditRealNameAuth(ctx context.Context, in *AuditRealNameAuthReq, opts ...grpc.CallOption) (*AuditRealNameAuthResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AuditRealNameAuthResp) + err := c.cc.Invoke(ctx, Admin_AuditRealNameAuth_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) CreateWithdraw(ctx context.Context, in *CreateWithdrawReq, opts ...grpc.CallOption) (*CreateWithdrawResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateWithdrawResp) + err := c.cc.Invoke(ctx, Admin_CreateWithdraw_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetWithdraw(ctx context.Context, in *GetWithdrawReq, opts ...grpc.CallOption) (*GetWithdrawResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWithdrawResp) + err := c.cc.Invoke(ctx, Admin_GetWithdraw_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetUserWithdraws(ctx context.Context, in *GetUserWithdrawsReq, opts ...grpc.CallOption) (*GetUserWithdrawsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserWithdrawsResp) + err := c.cc.Invoke(ctx, Admin_GetUserWithdraws_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetWithdraws(ctx context.Context, in *GetWithdrawsReq, opts ...grpc.CallOption) (*GetWithdrawsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWithdrawsResp) + err := c.cc.Invoke(ctx, Admin_GetWithdraws_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AuditWithdraw(ctx context.Context, in *AuditWithdrawReq, opts ...grpc.CallOption) (*AuditWithdrawResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AuditWithdrawResp) + err := c.cc.Invoke(ctx, Admin_AuditWithdraw_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) GetStatistics(ctx context.Context, in *GetStatisticsReq, opts ...grpc.CallOption) (*GetStatisticsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetStatisticsResp) + err := c.cc.Invoke(ctx, Admin_GetStatistics_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdminServer is the server API for Admin service. +// All implementations must embed UnimplementedAdminServer +// for forward compatibility. +type AdminServer interface { + // Login + Login(context.Context, *LoginReq) (*LoginResp, error) + ChangePassword(context.Context, *ChangePasswordReq) (*ChangePasswordResp, error) + AdminUpdateInfo(context.Context, *AdminUpdateInfoReq) (*AdminUpdateInfoResp, error) + // Get administrator information + GetAdminInfo(context.Context, *GetAdminInfoReq) (*GetAdminInfoResp, error) + AddAdminAccount(context.Context, *AddAdminAccountReq) (*AddAdminAccountResp, error) + ChangeAdminPassword(context.Context, *ChangeAdminPasswordReq) (*ChangeAdminPasswordResp, error) + ChangeOperationPassword(context.Context, *ChangeOperationPasswordReq) (*ChangeOperationPasswordResp, error) + SetGoogleAuthKey(context.Context, *SetGoogleAuthKeyReq) (*SetGoogleAuthKeyResp, error) + DelAdminAccount(context.Context, *DelAdminAccountReq) (*DelAdminAccountResp, error) + SearchAdminAccount(context.Context, *SearchAdminAccountReq) (*SearchAdminAccountResp, error) + // Add Remove Get default friend list on registration + AddDefaultFriend(context.Context, *AddDefaultFriendReq) (*AddDefaultFriendResp, error) + DelDefaultFriend(context.Context, *DelDefaultFriendReq) (*DelDefaultFriendResp, error) + FindDefaultFriend(context.Context, *FindDefaultFriendReq) (*FindDefaultFriendResp, error) + SearchDefaultFriend(context.Context, *SearchDefaultFriendReq) (*SearchDefaultFriendResp, error) + AddDefaultGroup(context.Context, *AddDefaultGroupReq) (*AddDefaultGroupResp, error) + DelDefaultGroup(context.Context, *DelDefaultGroupReq) (*DelDefaultGroupResp, error) + FindDefaultGroup(context.Context, *FindDefaultGroupReq) (*FindDefaultGroupResp, error) + SearchDefaultGroup(context.Context, *SearchDefaultGroupReq) (*SearchDefaultGroupResp, error) + // Invitation Code Generate Query Get + AddInvitationCode(context.Context, *AddInvitationCodeReq) (*AddInvitationCodeResp, error) + GenInvitationCode(context.Context, *GenInvitationCodeReq) (*GenInvitationCodeResp, error) + FindInvitationCode(context.Context, *FindInvitationCodeReq) (*FindInvitationCodeResp, error) + UseInvitationCode(context.Context, *UseInvitationCodeReq) (*UseInvitationCodeResp, error) + DelInvitationCode(context.Context, *DelInvitationCodeReq) (*DelInvitationCodeResp, error) + SearchInvitationCode(context.Context, *SearchInvitationCodeReq) (*SearchInvitationCodeResp, error) + // User login ip limit Query Add Remove + SearchUserIPLimitLogin(context.Context, *SearchUserIPLimitLoginReq) (*SearchUserIPLimitLoginResp, error) + AddUserIPLimitLogin(context.Context, *AddUserIPLimitLoginReq) (*AddUserIPLimitLoginResp, error) + DelUserIPLimitLogin(context.Context, *DelUserIPLimitLoginReq) (*DelUserIPLimitLoginResp, error) + // Prohibit users from registering at certain ip Query Add Remove + SearchIPForbidden(context.Context, *SearchIPForbiddenReq) (*SearchIPForbiddenResp, error) + AddIPForbidden(context.Context, *AddIPForbiddenReq) (*AddIPForbiddenResp, error) + DelIPForbidden(context.Context, *DelIPForbiddenReq) (*DelIPForbiddenResp, error) + // User Management Related Add Block/Unblock Pull + CancellationUser(context.Context, *CancellationUserReq) (*CancellationUserResp, error) + BlockUser(context.Context, *BlockUserReq) (*BlockUserResp, error) + UnblockUser(context.Context, *UnblockUserReq) (*UnblockUserResp, error) + SearchBlockUser(context.Context, *SearchBlockUserReq) (*SearchBlockUserResp, error) + FindUserBlockInfo(context.Context, *FindUserBlockInfoReq) (*FindUserBlockInfoResp, error) + CheckRegisterForbidden(context.Context, *CheckRegisterForbiddenReq) (*CheckRegisterForbiddenResp, error) + CheckLoginForbidden(context.Context, *CheckLoginForbiddenReq) (*CheckLoginForbiddenResp, error) + // create token + CreateToken(context.Context, *CreateTokenReq) (*CreateTokenResp, error) + // parse token + ParseToken(context.Context, *ParseTokenReq) (*ParseTokenResp, error) + // app + AddApplet(context.Context, *AddAppletReq) (*AddAppletResp, error) + DelApplet(context.Context, *DelAppletReq) (*DelAppletResp, error) + UpdateApplet(context.Context, *UpdateAppletReq) (*UpdateAppletResp, error) + FindApplet(context.Context, *FindAppletReq) (*FindAppletResp, error) + SearchApplet(context.Context, *SearchAppletReq) (*SearchAppletResp, error) + // Client Configuration + GetClientConfig(context.Context, *GetClientConfigReq) (*GetClientConfigResp, error) + SetClientConfig(context.Context, *SetClientConfigReq) (*SetClientConfigResp, error) + DelClientConfig(context.Context, *DelClientConfigReq) (*DelClientConfigResp, error) + GetUserToken(context.Context, *GetUserTokenReq) (*GetUserTokenResp, error) + // invalidate token + InvalidateToken(context.Context, *InvalidateTokenReq) (*InvalidateTokenResp, error) + LatestApplicationVersion(context.Context, *LatestApplicationVersionReq) (*LatestApplicationVersionResp, error) + AddApplicationVersion(context.Context, *AddApplicationVersionReq) (*AddApplicationVersionResp, error) + UpdateApplicationVersion(context.Context, *UpdateApplicationVersionReq) (*UpdateApplicationVersionResp, error) + DeleteApplicationVersion(context.Context, *DeleteApplicationVersionReq) (*DeleteApplicationVersionResp, error) + PageApplicationVersion(context.Context, *PageApplicationVersionReq) (*PageApplicationVersionResp, error) + // 敏感词管理 + AddSensitiveWord(context.Context, *AddSensitiveWordReq) (*AddSensitiveWordResp, error) + UpdateSensitiveWord(context.Context, *UpdateSensitiveWordReq) (*UpdateSensitiveWordResp, error) + DeleteSensitiveWord(context.Context, *DeleteSensitiveWordReq) (*DeleteSensitiveWordResp, error) + GetSensitiveWord(context.Context, *GetSensitiveWordReq) (*GetSensitiveWordResp, error) + SearchSensitiveWords(context.Context, *SearchSensitiveWordsReq) (*SearchSensitiveWordsResp, error) + BatchAddSensitiveWords(context.Context, *BatchAddSensitiveWordsReq) (*BatchAddSensitiveWordsResp, error) + BatchUpdateSensitiveWords(context.Context, *BatchUpdateSensitiveWordsReq) (*BatchUpdateSensitiveWordsResp, error) + BatchDeleteSensitiveWords(context.Context, *BatchDeleteSensitiveWordsReq) (*BatchDeleteSensitiveWordsResp, error) + // 敏感词分组管理 + AddSensitiveWordGroup(context.Context, *AddSensitiveWordGroupReq) (*AddSensitiveWordGroupResp, error) + UpdateSensitiveWordGroup(context.Context, *UpdateSensitiveWordGroupReq) (*UpdateSensitiveWordGroupResp, error) + DeleteSensitiveWordGroup(context.Context, *DeleteSensitiveWordGroupReq) (*DeleteSensitiveWordGroupResp, error) + GetSensitiveWordGroup(context.Context, *GetSensitiveWordGroupReq) (*GetSensitiveWordGroupResp, error) + GetAllSensitiveWordGroups(context.Context, *GetAllSensitiveWordGroupsReq) (*GetAllSensitiveWordGroupsResp, error) + // 敏感词配置管理 + GetSensitiveWordConfig(context.Context, *GetSensitiveWordConfigReq) (*GetSensitiveWordConfigResp, error) + UpdateSensitiveWordConfig(context.Context, *UpdateSensitiveWordConfigReq) (*UpdateSensitiveWordConfigResp, error) + // 敏感词日志管理 + GetSensitiveWordLogs(context.Context, *GetSensitiveWordLogsReq) (*GetSensitiveWordLogsResp, error) + DeleteSensitiveWordLogs(context.Context, *DeleteSensitiveWordLogsReq) (*DeleteSensitiveWordLogsResp, error) + // 用户登录记录管理 + GetUserLoginRecords(context.Context, *GetUserLoginRecordsReq) (*GetUserLoginRecordsResp, error) + // 敏感词统计 + GetSensitiveWordStats(context.Context, *GetSensitiveWordStatsReq) (*GetSensitiveWordStatsResp, error) + GetSensitiveWordLogStats(context.Context, *GetSensitiveWordLogStatsReq) (*GetSensitiveWordLogStatsResp, error) + // ==================== 定时任务管理 ==================== + GetScheduledTasks(context.Context, *GetScheduledTasksReq) (*GetScheduledTasksResp, error) + DeleteScheduledTask(context.Context, *DeleteScheduledTaskReq) (*DeleteScheduledTaskResp, error) + // ==================== 系统配置管理 ==================== + CreateSystemConfig(context.Context, *CreateSystemConfigReq) (*CreateSystemConfigResp, error) + GetSystemConfig(context.Context, *GetSystemConfigReq) (*GetSystemConfigResp, error) + GetAllSystemConfigs(context.Context, *GetAllSystemConfigsReq) (*GetAllSystemConfigsResp, error) + UpdateSystemConfig(context.Context, *UpdateSystemConfigReq) (*UpdateSystemConfigResp, error) + UpdateSystemConfigValue(context.Context, *UpdateSystemConfigValueReq) (*UpdateSystemConfigValueResp, error) + UpdateSystemConfigEnabled(context.Context, *UpdateSystemConfigEnabledReq) (*UpdateSystemConfigEnabledResp, error) + DeleteSystemConfig(context.Context, *DeleteSystemConfigReq) (*DeleteSystemConfigResp, error) + GetEnabledSystemConfigs(context.Context, *GetEnabledSystemConfigsReq) (*GetEnabledSystemConfigsResp, error) + // 获取用户钱包信息 + GetUserWallet(context.Context, *GetUserWalletReq) (*GetUserWalletResp, error) + // 更新用户余额(后台充值/扣款) + UpdateUserWalletBalance(context.Context, *UpdateUserWalletBalanceReq) (*UpdateUserWalletBalanceResp, error) + // 获取用户余额变动记录列表 + GetUserWalletBalanceRecords(context.Context, *GetUserWalletBalanceRecordsReq) (*GetUserWalletBalanceRecordsResp, error) + // 批量更新用户余额(后台批量充值/扣款) + BatchUpdateWalletBalance(context.Context, *BatchUpdateWalletBalanceReq) (*BatchUpdateWalletBalanceResp, error) + // 获取钱包列表 + GetWallets(context.Context, *GetWalletsReq) (*GetWalletsResp, error) + // 修改用户支付密码(后台) + UpdateUserPaymentPassword(context.Context, *UpdateUserPaymentPasswordReq) (*UpdateUserPaymentPasswordResp, error) + // 设置用户提款账号(后台) + SetUserWithdrawAccount(context.Context, *SetUserWithdrawAccountReq) (*SetUserWithdrawAccountResp, error) + // 获取实名认证列表(支持按审核状态筛选) + GetRealNameAuths(context.Context, *GetRealNameAuthsReq) (*GetRealNameAuthsResp, error) + // 审核实名认证(通过/拒绝) + AuditRealNameAuth(context.Context, *AuditRealNameAuthReq) (*AuditRealNameAuthResp, error) + // 创建提现记录(用户端发起提现) + CreateWithdraw(context.Context, *CreateWithdrawReq) (*CreateWithdrawResp, error) + // 获取提现记录详情 + GetWithdraw(context.Context, *GetWithdrawReq) (*GetWithdrawResp, error) + // 获取用户的提现记录列表 + GetUserWithdraws(context.Context, *GetUserWithdrawsReq) (*GetUserWithdrawsResp, error) + // 获取提现记录列表(后台,支持按状态筛选) + GetWithdraws(context.Context, *GetWithdrawsReq) (*GetWithdrawsResp, error) + // 审核提现(后台) + AuditWithdraw(context.Context, *AuditWithdrawReq) (*AuditWithdrawResp, error) + // 系统统计 + GetStatistics(context.Context, *GetStatisticsReq) (*GetStatisticsResp, error) + mustEmbedUnimplementedAdminServer() +} + +// UnimplementedAdminServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAdminServer struct{} + +func (UnimplementedAdminServer) Login(context.Context, *LoginReq) (*LoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") +} +func (UnimplementedAdminServer) ChangePassword(context.Context, *ChangePasswordReq) (*ChangePasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangePassword not implemented") +} +func (UnimplementedAdminServer) AdminUpdateInfo(context.Context, *AdminUpdateInfoReq) (*AdminUpdateInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateInfo not implemented") +} +func (UnimplementedAdminServer) GetAdminInfo(context.Context, *GetAdminInfoReq) (*GetAdminInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAdminInfo not implemented") +} +func (UnimplementedAdminServer) AddAdminAccount(context.Context, *AddAdminAccountReq) (*AddAdminAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddAdminAccount not implemented") +} +func (UnimplementedAdminServer) ChangeAdminPassword(context.Context, *ChangeAdminPasswordReq) (*ChangeAdminPasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangeAdminPassword not implemented") +} +func (UnimplementedAdminServer) ChangeOperationPassword(context.Context, *ChangeOperationPasswordReq) (*ChangeOperationPasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangeOperationPassword not implemented") +} +func (UnimplementedAdminServer) SetGoogleAuthKey(context.Context, *SetGoogleAuthKeyReq) (*SetGoogleAuthKeyResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetGoogleAuthKey not implemented") +} +func (UnimplementedAdminServer) DelAdminAccount(context.Context, *DelAdminAccountReq) (*DelAdminAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelAdminAccount not implemented") +} +func (UnimplementedAdminServer) SearchAdminAccount(context.Context, *SearchAdminAccountReq) (*SearchAdminAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchAdminAccount not implemented") +} +func (UnimplementedAdminServer) AddDefaultFriend(context.Context, *AddDefaultFriendReq) (*AddDefaultFriendResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddDefaultFriend not implemented") +} +func (UnimplementedAdminServer) DelDefaultFriend(context.Context, *DelDefaultFriendReq) (*DelDefaultFriendResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelDefaultFriend not implemented") +} +func (UnimplementedAdminServer) FindDefaultFriend(context.Context, *FindDefaultFriendReq) (*FindDefaultFriendResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindDefaultFriend not implemented") +} +func (UnimplementedAdminServer) SearchDefaultFriend(context.Context, *SearchDefaultFriendReq) (*SearchDefaultFriendResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchDefaultFriend not implemented") +} +func (UnimplementedAdminServer) AddDefaultGroup(context.Context, *AddDefaultGroupReq) (*AddDefaultGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddDefaultGroup not implemented") +} +func (UnimplementedAdminServer) DelDefaultGroup(context.Context, *DelDefaultGroupReq) (*DelDefaultGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelDefaultGroup not implemented") +} +func (UnimplementedAdminServer) FindDefaultGroup(context.Context, *FindDefaultGroupReq) (*FindDefaultGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindDefaultGroup not implemented") +} +func (UnimplementedAdminServer) SearchDefaultGroup(context.Context, *SearchDefaultGroupReq) (*SearchDefaultGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchDefaultGroup not implemented") +} +func (UnimplementedAdminServer) AddInvitationCode(context.Context, *AddInvitationCodeReq) (*AddInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddInvitationCode not implemented") +} +func (UnimplementedAdminServer) GenInvitationCode(context.Context, *GenInvitationCodeReq) (*GenInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenInvitationCode not implemented") +} +func (UnimplementedAdminServer) FindInvitationCode(context.Context, *FindInvitationCodeReq) (*FindInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindInvitationCode not implemented") +} +func (UnimplementedAdminServer) UseInvitationCode(context.Context, *UseInvitationCodeReq) (*UseInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UseInvitationCode not implemented") +} +func (UnimplementedAdminServer) DelInvitationCode(context.Context, *DelInvitationCodeReq) (*DelInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelInvitationCode not implemented") +} +func (UnimplementedAdminServer) SearchInvitationCode(context.Context, *SearchInvitationCodeReq) (*SearchInvitationCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchInvitationCode not implemented") +} +func (UnimplementedAdminServer) SearchUserIPLimitLogin(context.Context, *SearchUserIPLimitLoginReq) (*SearchUserIPLimitLoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchUserIPLimitLogin not implemented") +} +func (UnimplementedAdminServer) AddUserIPLimitLogin(context.Context, *AddUserIPLimitLoginReq) (*AddUserIPLimitLoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddUserIPLimitLogin not implemented") +} +func (UnimplementedAdminServer) DelUserIPLimitLogin(context.Context, *DelUserIPLimitLoginReq) (*DelUserIPLimitLoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelUserIPLimitLogin not implemented") +} +func (UnimplementedAdminServer) SearchIPForbidden(context.Context, *SearchIPForbiddenReq) (*SearchIPForbiddenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchIPForbidden not implemented") +} +func (UnimplementedAdminServer) AddIPForbidden(context.Context, *AddIPForbiddenReq) (*AddIPForbiddenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddIPForbidden not implemented") +} +func (UnimplementedAdminServer) DelIPForbidden(context.Context, *DelIPForbiddenReq) (*DelIPForbiddenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelIPForbidden not implemented") +} +func (UnimplementedAdminServer) CancellationUser(context.Context, *CancellationUserReq) (*CancellationUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancellationUser not implemented") +} +func (UnimplementedAdminServer) BlockUser(context.Context, *BlockUserReq) (*BlockUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BlockUser not implemented") +} +func (UnimplementedAdminServer) UnblockUser(context.Context, *UnblockUserReq) (*UnblockUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnblockUser not implemented") +} +func (UnimplementedAdminServer) SearchBlockUser(context.Context, *SearchBlockUserReq) (*SearchBlockUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchBlockUser not implemented") +} +func (UnimplementedAdminServer) FindUserBlockInfo(context.Context, *FindUserBlockInfoReq) (*FindUserBlockInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindUserBlockInfo not implemented") +} +func (UnimplementedAdminServer) CheckRegisterForbidden(context.Context, *CheckRegisterForbiddenReq) (*CheckRegisterForbiddenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckRegisterForbidden not implemented") +} +func (UnimplementedAdminServer) CheckLoginForbidden(context.Context, *CheckLoginForbiddenReq) (*CheckLoginForbiddenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckLoginForbidden not implemented") +} +func (UnimplementedAdminServer) CreateToken(context.Context, *CreateTokenReq) (*CreateTokenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateToken not implemented") +} +func (UnimplementedAdminServer) ParseToken(context.Context, *ParseTokenReq) (*ParseTokenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ParseToken not implemented") +} +func (UnimplementedAdminServer) AddApplet(context.Context, *AddAppletReq) (*AddAppletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddApplet not implemented") +} +func (UnimplementedAdminServer) DelApplet(context.Context, *DelAppletReq) (*DelAppletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelApplet not implemented") +} +func (UnimplementedAdminServer) UpdateApplet(context.Context, *UpdateAppletReq) (*UpdateAppletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateApplet not implemented") +} +func (UnimplementedAdminServer) FindApplet(context.Context, *FindAppletReq) (*FindAppletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindApplet not implemented") +} +func (UnimplementedAdminServer) SearchApplet(context.Context, *SearchAppletReq) (*SearchAppletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchApplet not implemented") +} +func (UnimplementedAdminServer) GetClientConfig(context.Context, *GetClientConfigReq) (*GetClientConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetClientConfig not implemented") +} +func (UnimplementedAdminServer) SetClientConfig(context.Context, *SetClientConfigReq) (*SetClientConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetClientConfig not implemented") +} +func (UnimplementedAdminServer) DelClientConfig(context.Context, *DelClientConfigReq) (*DelClientConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelClientConfig not implemented") +} +func (UnimplementedAdminServer) GetUserToken(context.Context, *GetUserTokenReq) (*GetUserTokenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserToken not implemented") +} +func (UnimplementedAdminServer) InvalidateToken(context.Context, *InvalidateTokenReq) (*InvalidateTokenResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method InvalidateToken not implemented") +} +func (UnimplementedAdminServer) LatestApplicationVersion(context.Context, *LatestApplicationVersionReq) (*LatestApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LatestApplicationVersion not implemented") +} +func (UnimplementedAdminServer) AddApplicationVersion(context.Context, *AddApplicationVersionReq) (*AddApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddApplicationVersion not implemented") +} +func (UnimplementedAdminServer) UpdateApplicationVersion(context.Context, *UpdateApplicationVersionReq) (*UpdateApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateApplicationVersion not implemented") +} +func (UnimplementedAdminServer) DeleteApplicationVersion(context.Context, *DeleteApplicationVersionReq) (*DeleteApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteApplicationVersion not implemented") +} +func (UnimplementedAdminServer) PageApplicationVersion(context.Context, *PageApplicationVersionReq) (*PageApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PageApplicationVersion not implemented") +} +func (UnimplementedAdminServer) AddSensitiveWord(context.Context, *AddSensitiveWordReq) (*AddSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSensitiveWord not implemented") +} +func (UnimplementedAdminServer) UpdateSensitiveWord(context.Context, *UpdateSensitiveWordReq) (*UpdateSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWord not implemented") +} +func (UnimplementedAdminServer) DeleteSensitiveWord(context.Context, *DeleteSensitiveWordReq) (*DeleteSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWord not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWord(context.Context, *GetSensitiveWordReq) (*GetSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWord not implemented") +} +func (UnimplementedAdminServer) SearchSensitiveWords(context.Context, *SearchSensitiveWordsReq) (*SearchSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchSensitiveWords not implemented") +} +func (UnimplementedAdminServer) BatchAddSensitiveWords(context.Context, *BatchAddSensitiveWordsReq) (*BatchAddSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchAddSensitiveWords not implemented") +} +func (UnimplementedAdminServer) BatchUpdateSensitiveWords(context.Context, *BatchUpdateSensitiveWordsReq) (*BatchUpdateSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchUpdateSensitiveWords not implemented") +} +func (UnimplementedAdminServer) BatchDeleteSensitiveWords(context.Context, *BatchDeleteSensitiveWordsReq) (*BatchDeleteSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchDeleteSensitiveWords not implemented") +} +func (UnimplementedAdminServer) AddSensitiveWordGroup(context.Context, *AddSensitiveWordGroupReq) (*AddSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSensitiveWordGroup not implemented") +} +func (UnimplementedAdminServer) UpdateSensitiveWordGroup(context.Context, *UpdateSensitiveWordGroupReq) (*UpdateSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWordGroup not implemented") +} +func (UnimplementedAdminServer) DeleteSensitiveWordGroup(context.Context, *DeleteSensitiveWordGroupReq) (*DeleteSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWordGroup not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWordGroup(context.Context, *GetSensitiveWordGroupReq) (*GetSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordGroup not implemented") +} +func (UnimplementedAdminServer) GetAllSensitiveWordGroups(context.Context, *GetAllSensitiveWordGroupsReq) (*GetAllSensitiveWordGroupsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAllSensitiveWordGroups not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWordConfig(context.Context, *GetSensitiveWordConfigReq) (*GetSensitiveWordConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordConfig not implemented") +} +func (UnimplementedAdminServer) UpdateSensitiveWordConfig(context.Context, *UpdateSensitiveWordConfigReq) (*UpdateSensitiveWordConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWordConfig not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWordLogs(context.Context, *GetSensitiveWordLogsReq) (*GetSensitiveWordLogsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordLogs not implemented") +} +func (UnimplementedAdminServer) DeleteSensitiveWordLogs(context.Context, *DeleteSensitiveWordLogsReq) (*DeleteSensitiveWordLogsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWordLogs not implemented") +} +func (UnimplementedAdminServer) GetUserLoginRecords(context.Context, *GetUserLoginRecordsReq) (*GetUserLoginRecordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserLoginRecords not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWordStats(context.Context, *GetSensitiveWordStatsReq) (*GetSensitiveWordStatsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordStats not implemented") +} +func (UnimplementedAdminServer) GetSensitiveWordLogStats(context.Context, *GetSensitiveWordLogStatsReq) (*GetSensitiveWordLogStatsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordLogStats not implemented") +} +func (UnimplementedAdminServer) GetScheduledTasks(context.Context, *GetScheduledTasksReq) (*GetScheduledTasksResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetScheduledTasks not implemented") +} +func (UnimplementedAdminServer) DeleteScheduledTask(context.Context, *DeleteScheduledTaskReq) (*DeleteScheduledTaskResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteScheduledTask not implemented") +} +func (UnimplementedAdminServer) CreateSystemConfig(context.Context, *CreateSystemConfigReq) (*CreateSystemConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateSystemConfig not implemented") +} +func (UnimplementedAdminServer) GetSystemConfig(context.Context, *GetSystemConfigReq) (*GetSystemConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSystemConfig not implemented") +} +func (UnimplementedAdminServer) GetAllSystemConfigs(context.Context, *GetAllSystemConfigsReq) (*GetAllSystemConfigsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAllSystemConfigs not implemented") +} +func (UnimplementedAdminServer) UpdateSystemConfig(context.Context, *UpdateSystemConfigReq) (*UpdateSystemConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSystemConfig not implemented") +} +func (UnimplementedAdminServer) UpdateSystemConfigValue(context.Context, *UpdateSystemConfigValueReq) (*UpdateSystemConfigValueResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSystemConfigValue not implemented") +} +func (UnimplementedAdminServer) UpdateSystemConfigEnabled(context.Context, *UpdateSystemConfigEnabledReq) (*UpdateSystemConfigEnabledResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSystemConfigEnabled not implemented") +} +func (UnimplementedAdminServer) DeleteSystemConfig(context.Context, *DeleteSystemConfigReq) (*DeleteSystemConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSystemConfig not implemented") +} +func (UnimplementedAdminServer) GetEnabledSystemConfigs(context.Context, *GetEnabledSystemConfigsReq) (*GetEnabledSystemConfigsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEnabledSystemConfigs not implemented") +} +func (UnimplementedAdminServer) GetUserWallet(context.Context, *GetUserWalletReq) (*GetUserWalletResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserWallet not implemented") +} +func (UnimplementedAdminServer) UpdateUserWalletBalance(context.Context, *UpdateUserWalletBalanceReq) (*UpdateUserWalletBalanceResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserWalletBalance not implemented") +} +func (UnimplementedAdminServer) GetUserWalletBalanceRecords(context.Context, *GetUserWalletBalanceRecordsReq) (*GetUserWalletBalanceRecordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserWalletBalanceRecords not implemented") +} +func (UnimplementedAdminServer) BatchUpdateWalletBalance(context.Context, *BatchUpdateWalletBalanceReq) (*BatchUpdateWalletBalanceResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchUpdateWalletBalance not implemented") +} +func (UnimplementedAdminServer) GetWallets(context.Context, *GetWalletsReq) (*GetWalletsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWallets not implemented") +} +func (UnimplementedAdminServer) UpdateUserPaymentPassword(context.Context, *UpdateUserPaymentPasswordReq) (*UpdateUserPaymentPasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserPaymentPassword not implemented") +} +func (UnimplementedAdminServer) SetUserWithdrawAccount(context.Context, *SetUserWithdrawAccountReq) (*SetUserWithdrawAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetUserWithdrawAccount not implemented") +} +func (UnimplementedAdminServer) GetRealNameAuths(context.Context, *GetRealNameAuthsReq) (*GetRealNameAuthsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRealNameAuths not implemented") +} +func (UnimplementedAdminServer) AuditRealNameAuth(context.Context, *AuditRealNameAuthReq) (*AuditRealNameAuthResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AuditRealNameAuth not implemented") +} +func (UnimplementedAdminServer) CreateWithdraw(context.Context, *CreateWithdrawReq) (*CreateWithdrawResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateWithdraw not implemented") +} +func (UnimplementedAdminServer) GetWithdraw(context.Context, *GetWithdrawReq) (*GetWithdrawResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWithdraw not implemented") +} +func (UnimplementedAdminServer) GetUserWithdraws(context.Context, *GetUserWithdrawsReq) (*GetUserWithdrawsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserWithdraws not implemented") +} +func (UnimplementedAdminServer) GetWithdraws(context.Context, *GetWithdrawsReq) (*GetWithdrawsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWithdraws not implemented") +} +func (UnimplementedAdminServer) AuditWithdraw(context.Context, *AuditWithdrawReq) (*AuditWithdrawResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AuditWithdraw not implemented") +} +func (UnimplementedAdminServer) GetStatistics(context.Context, *GetStatisticsReq) (*GetStatisticsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStatistics not implemented") +} +func (UnimplementedAdminServer) mustEmbedUnimplementedAdminServer() {} +func (UnimplementedAdminServer) testEmbeddedByValue() {} + +// UnsafeAdminServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdminServer will +// result in compilation errors. +type UnsafeAdminServer interface { + mustEmbedUnimplementedAdminServer() +} + +func RegisterAdminServer(s grpc.ServiceRegistrar, srv AdminServer) { + // If the following call pancis, it indicates UnimplementedAdminServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Admin_ServiceDesc, srv) +} + +func _Admin_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).Login(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_Login_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).Login(ctx, req.(*LoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_ChangePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ChangePasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).ChangePassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_ChangePassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).ChangePassword(ctx, req.(*ChangePasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AdminUpdateInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdminUpdateInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AdminUpdateInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AdminUpdateInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AdminUpdateInfo(ctx, req.(*AdminUpdateInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetAdminInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAdminInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetAdminInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetAdminInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetAdminInfo(ctx, req.(*GetAdminInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddAdminAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddAdminAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddAdminAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddAdminAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddAdminAccount(ctx, req.(*AddAdminAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_ChangeAdminPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ChangeAdminPasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).ChangeAdminPassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_ChangeAdminPassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).ChangeAdminPassword(ctx, req.(*ChangeAdminPasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_ChangeOperationPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ChangeOperationPasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).ChangeOperationPassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_ChangeOperationPassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).ChangeOperationPassword(ctx, req.(*ChangeOperationPasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SetGoogleAuthKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetGoogleAuthKeyReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SetGoogleAuthKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SetGoogleAuthKey_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SetGoogleAuthKey(ctx, req.(*SetGoogleAuthKeyReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelAdminAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelAdminAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelAdminAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelAdminAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelAdminAccount(ctx, req.(*DelAdminAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchAdminAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchAdminAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchAdminAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchAdminAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchAdminAccount(ctx, req.(*SearchAdminAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddDefaultFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddDefaultFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddDefaultFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddDefaultFriend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddDefaultFriend(ctx, req.(*AddDefaultFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelDefaultFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelDefaultFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelDefaultFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelDefaultFriend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelDefaultFriend(ctx, req.(*DelDefaultFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_FindDefaultFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindDefaultFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).FindDefaultFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_FindDefaultFriend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).FindDefaultFriend(ctx, req.(*FindDefaultFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchDefaultFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchDefaultFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchDefaultFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchDefaultFriend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchDefaultFriend(ctx, req.(*SearchDefaultFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddDefaultGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddDefaultGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddDefaultGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddDefaultGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddDefaultGroup(ctx, req.(*AddDefaultGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelDefaultGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelDefaultGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelDefaultGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelDefaultGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelDefaultGroup(ctx, req.(*DelDefaultGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_FindDefaultGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindDefaultGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).FindDefaultGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_FindDefaultGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).FindDefaultGroup(ctx, req.(*FindDefaultGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchDefaultGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchDefaultGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchDefaultGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchDefaultGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchDefaultGroup(ctx, req.(*SearchDefaultGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddInvitationCode(ctx, req.(*AddInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GenInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GenInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GenInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GenInvitationCode(ctx, req.(*GenInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_FindInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).FindInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_FindInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).FindInvitationCode(ctx, req.(*FindInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UseInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UseInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UseInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UseInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UseInvitationCode(ctx, req.(*UseInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelInvitationCode(ctx, req.(*DelInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchInvitationCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchInvitationCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchInvitationCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchInvitationCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchInvitationCode(ctx, req.(*SearchInvitationCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchUserIPLimitLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchUserIPLimitLoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchUserIPLimitLogin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchUserIPLimitLogin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchUserIPLimitLogin(ctx, req.(*SearchUserIPLimitLoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddUserIPLimitLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddUserIPLimitLoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddUserIPLimitLogin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddUserIPLimitLogin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddUserIPLimitLogin(ctx, req.(*AddUserIPLimitLoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelUserIPLimitLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelUserIPLimitLoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelUserIPLimitLogin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelUserIPLimitLogin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelUserIPLimitLogin(ctx, req.(*DelUserIPLimitLoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchIPForbidden_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchIPForbiddenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchIPForbidden(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchIPForbidden_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchIPForbidden(ctx, req.(*SearchIPForbiddenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddIPForbidden_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddIPForbiddenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddIPForbidden(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddIPForbidden_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddIPForbidden(ctx, req.(*AddIPForbiddenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelIPForbidden_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelIPForbiddenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelIPForbidden(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelIPForbidden_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelIPForbidden(ctx, req.(*DelIPForbiddenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CancellationUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CancellationUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CancellationUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CancellationUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CancellationUser(ctx, req.(*CancellationUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_BlockUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BlockUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).BlockUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_BlockUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).BlockUser(ctx, req.(*BlockUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UnblockUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnblockUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UnblockUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UnblockUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UnblockUser(ctx, req.(*UnblockUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchBlockUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchBlockUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchBlockUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchBlockUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchBlockUser(ctx, req.(*SearchBlockUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_FindUserBlockInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindUserBlockInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).FindUserBlockInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_FindUserBlockInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).FindUserBlockInfo(ctx, req.(*FindUserBlockInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CheckRegisterForbidden_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckRegisterForbiddenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CheckRegisterForbidden(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CheckRegisterForbidden_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CheckRegisterForbidden(ctx, req.(*CheckRegisterForbiddenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CheckLoginForbidden_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckLoginForbiddenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CheckLoginForbidden(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CheckLoginForbidden_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CheckLoginForbidden(ctx, req.(*CheckLoginForbiddenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CreateToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateTokenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CreateToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CreateToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CreateToken(ctx, req.(*CreateTokenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_ParseToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ParseTokenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).ParseToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_ParseToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).ParseToken(ctx, req.(*ParseTokenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddApplet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddAppletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddApplet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddApplet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddApplet(ctx, req.(*AddAppletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelApplet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelAppletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelApplet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelApplet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelApplet(ctx, req.(*DelAppletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateApplet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAppletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateApplet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateApplet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateApplet(ctx, req.(*UpdateAppletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_FindApplet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindAppletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).FindApplet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_FindApplet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).FindApplet(ctx, req.(*FindAppletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchApplet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchAppletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchApplet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchApplet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchApplet(ctx, req.(*SearchAppletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetClientConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetClientConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetClientConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetClientConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetClientConfig(ctx, req.(*GetClientConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SetClientConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetClientConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SetClientConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SetClientConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SetClientConfig(ctx, req.(*SetClientConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DelClientConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelClientConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DelClientConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DelClientConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DelClientConfig(ctx, req.(*DelClientConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetUserToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserTokenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetUserToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetUserToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetUserToken(ctx, req.(*GetUserTokenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_InvalidateToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InvalidateTokenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).InvalidateToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_InvalidateToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).InvalidateToken(ctx, req.(*InvalidateTokenReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_LatestApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LatestApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).LatestApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_LatestApplicationVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).LatestApplicationVersion(ctx, req.(*LatestApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddApplicationVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddApplicationVersion(ctx, req.(*AddApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateApplicationVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateApplicationVersion(ctx, req.(*UpdateApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteApplicationVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteApplicationVersion(ctx, req.(*DeleteApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_PageApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PageApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).PageApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_PageApplicationVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).PageApplicationVersion(ctx, req.(*PageApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddSensitiveWord(ctx, req.(*AddSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSensitiveWord(ctx, req.(*UpdateSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteSensitiveWord(ctx, req.(*DeleteSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWord(ctx, req.(*GetSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SearchSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SearchSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SearchSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SearchSensitiveWords(ctx, req.(*SearchSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_BatchAddSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchAddSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).BatchAddSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_BatchAddSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).BatchAddSensitiveWords(ctx, req.(*BatchAddSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_BatchUpdateSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchUpdateSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).BatchUpdateSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_BatchUpdateSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).BatchUpdateSensitiveWords(ctx, req.(*BatchUpdateSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_BatchDeleteSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchDeleteSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).BatchDeleteSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_BatchDeleteSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).BatchDeleteSensitiveWords(ctx, req.(*BatchDeleteSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AddSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddSensitiveWordGroup(ctx, req.(*AddSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSensitiveWordGroup(ctx, req.(*UpdateSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteSensitiveWordGroup(ctx, req.(*DeleteSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWordGroup(ctx, req.(*GetSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetAllSensitiveWordGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllSensitiveWordGroupsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetAllSensitiveWordGroups(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetAllSensitiveWordGroups_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetAllSensitiveWordGroups(ctx, req.(*GetAllSensitiveWordGroupsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWordConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWordConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWordConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWordConfig(ctx, req.(*GetSensitiveWordConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSensitiveWordConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSensitiveWordConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSensitiveWordConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSensitiveWordConfig(ctx, req.(*UpdateSensitiveWordConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWordLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWordLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWordLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWordLogs(ctx, req.(*GetSensitiveWordLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteSensitiveWordLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteSensitiveWordLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteSensitiveWordLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteSensitiveWordLogs(ctx, req.(*DeleteSensitiveWordLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetUserLoginRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserLoginRecordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetUserLoginRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetUserLoginRecords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetUserLoginRecords(ctx, req.(*GetUserLoginRecordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWordStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordStatsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWordStats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWordStats_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWordStats(ctx, req.(*GetSensitiveWordStatsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSensitiveWordLogStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordLogStatsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSensitiveWordLogStats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSensitiveWordLogStats_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSensitiveWordLogStats(ctx, req.(*GetSensitiveWordLogStatsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetScheduledTasks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetScheduledTasksReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetScheduledTasks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetScheduledTasks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetScheduledTasks(ctx, req.(*GetScheduledTasksReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteScheduledTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteScheduledTaskReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteScheduledTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteScheduledTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteScheduledTask(ctx, req.(*DeleteScheduledTaskReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CreateSystemConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSystemConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CreateSystemConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CreateSystemConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CreateSystemConfig(ctx, req.(*CreateSystemConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetSystemConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSystemConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetSystemConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetSystemConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetSystemConfig(ctx, req.(*GetSystemConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetAllSystemConfigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllSystemConfigsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetAllSystemConfigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetAllSystemConfigs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetAllSystemConfigs(ctx, req.(*GetAllSystemConfigsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSystemConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSystemConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSystemConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSystemConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSystemConfig(ctx, req.(*UpdateSystemConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSystemConfigValue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSystemConfigValueReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSystemConfigValue(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSystemConfigValue_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSystemConfigValue(ctx, req.(*UpdateSystemConfigValueReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateSystemConfigEnabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSystemConfigEnabledReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateSystemConfigEnabled(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateSystemConfigEnabled_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateSystemConfigEnabled(ctx, req.(*UpdateSystemConfigEnabledReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteSystemConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSystemConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteSystemConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_DeleteSystemConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteSystemConfig(ctx, req.(*DeleteSystemConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetEnabledSystemConfigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetEnabledSystemConfigsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetEnabledSystemConfigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetEnabledSystemConfigs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetEnabledSystemConfigs(ctx, req.(*GetEnabledSystemConfigsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetUserWallet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserWalletReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetUserWallet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetUserWallet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetUserWallet(ctx, req.(*GetUserWalletReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateUserWalletBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserWalletBalanceReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateUserWalletBalance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateUserWalletBalance_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateUserWalletBalance(ctx, req.(*UpdateUserWalletBalanceReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetUserWalletBalanceRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserWalletBalanceRecordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetUserWalletBalanceRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetUserWalletBalanceRecords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetUserWalletBalanceRecords(ctx, req.(*GetUserWalletBalanceRecordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_BatchUpdateWalletBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchUpdateWalletBalanceReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).BatchUpdateWalletBalance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_BatchUpdateWalletBalance_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).BatchUpdateWalletBalance(ctx, req.(*BatchUpdateWalletBalanceReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetWallets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWalletsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetWallets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetWallets_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetWallets(ctx, req.(*GetWalletsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateUserPaymentPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserPaymentPasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateUserPaymentPassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_UpdateUserPaymentPassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateUserPaymentPassword(ctx, req.(*UpdateUserPaymentPasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_SetUserWithdrawAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetUserWithdrawAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).SetUserWithdrawAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_SetUserWithdrawAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).SetUserWithdrawAccount(ctx, req.(*SetUserWithdrawAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetRealNameAuths_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRealNameAuthsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetRealNameAuths(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetRealNameAuths_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetRealNameAuths(ctx, req.(*GetRealNameAuthsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AuditRealNameAuth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AuditRealNameAuthReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AuditRealNameAuth(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AuditRealNameAuth_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AuditRealNameAuth(ctx, req.(*AuditRealNameAuthReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_CreateWithdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateWithdrawReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).CreateWithdraw(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_CreateWithdraw_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).CreateWithdraw(ctx, req.(*CreateWithdrawReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetWithdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWithdrawReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetWithdraw(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetWithdraw_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetWithdraw(ctx, req.(*GetWithdrawReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetUserWithdraws_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserWithdrawsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetUserWithdraws(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetUserWithdraws_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetUserWithdraws(ctx, req.(*GetUserWithdrawsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetWithdraws_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWithdrawsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetWithdraws(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetWithdraws_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetWithdraws(ctx, req.(*GetWithdrawsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AuditWithdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AuditWithdrawReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AuditWithdraw(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_AuditWithdraw_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AuditWithdraw(ctx, req.(*AuditWithdrawReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_GetStatistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetStatisticsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).GetStatistics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Admin_GetStatistics_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).GetStatistics(ctx, req.(*GetStatisticsReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Admin_ServiceDesc is the grpc.ServiceDesc for Admin service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Admin_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openim.admin.admin", + HandlerType: (*AdminServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Login", + Handler: _Admin_Login_Handler, + }, + { + MethodName: "ChangePassword", + Handler: _Admin_ChangePassword_Handler, + }, + { + MethodName: "AdminUpdateInfo", + Handler: _Admin_AdminUpdateInfo_Handler, + }, + { + MethodName: "GetAdminInfo", + Handler: _Admin_GetAdminInfo_Handler, + }, + { + MethodName: "AddAdminAccount", + Handler: _Admin_AddAdminAccount_Handler, + }, + { + MethodName: "ChangeAdminPassword", + Handler: _Admin_ChangeAdminPassword_Handler, + }, + { + MethodName: "ChangeOperationPassword", + Handler: _Admin_ChangeOperationPassword_Handler, + }, + { + MethodName: "SetGoogleAuthKey", + Handler: _Admin_SetGoogleAuthKey_Handler, + }, + { + MethodName: "DelAdminAccount", + Handler: _Admin_DelAdminAccount_Handler, + }, + { + MethodName: "SearchAdminAccount", + Handler: _Admin_SearchAdminAccount_Handler, + }, + { + MethodName: "AddDefaultFriend", + Handler: _Admin_AddDefaultFriend_Handler, + }, + { + MethodName: "DelDefaultFriend", + Handler: _Admin_DelDefaultFriend_Handler, + }, + { + MethodName: "FindDefaultFriend", + Handler: _Admin_FindDefaultFriend_Handler, + }, + { + MethodName: "SearchDefaultFriend", + Handler: _Admin_SearchDefaultFriend_Handler, + }, + { + MethodName: "AddDefaultGroup", + Handler: _Admin_AddDefaultGroup_Handler, + }, + { + MethodName: "DelDefaultGroup", + Handler: _Admin_DelDefaultGroup_Handler, + }, + { + MethodName: "FindDefaultGroup", + Handler: _Admin_FindDefaultGroup_Handler, + }, + { + MethodName: "SearchDefaultGroup", + Handler: _Admin_SearchDefaultGroup_Handler, + }, + { + MethodName: "AddInvitationCode", + Handler: _Admin_AddInvitationCode_Handler, + }, + { + MethodName: "GenInvitationCode", + Handler: _Admin_GenInvitationCode_Handler, + }, + { + MethodName: "FindInvitationCode", + Handler: _Admin_FindInvitationCode_Handler, + }, + { + MethodName: "UseInvitationCode", + Handler: _Admin_UseInvitationCode_Handler, + }, + { + MethodName: "DelInvitationCode", + Handler: _Admin_DelInvitationCode_Handler, + }, + { + MethodName: "SearchInvitationCode", + Handler: _Admin_SearchInvitationCode_Handler, + }, + { + MethodName: "SearchUserIPLimitLogin", + Handler: _Admin_SearchUserIPLimitLogin_Handler, + }, + { + MethodName: "AddUserIPLimitLogin", + Handler: _Admin_AddUserIPLimitLogin_Handler, + }, + { + MethodName: "DelUserIPLimitLogin", + Handler: _Admin_DelUserIPLimitLogin_Handler, + }, + { + MethodName: "SearchIPForbidden", + Handler: _Admin_SearchIPForbidden_Handler, + }, + { + MethodName: "AddIPForbidden", + Handler: _Admin_AddIPForbidden_Handler, + }, + { + MethodName: "DelIPForbidden", + Handler: _Admin_DelIPForbidden_Handler, + }, + { + MethodName: "CancellationUser", + Handler: _Admin_CancellationUser_Handler, + }, + { + MethodName: "BlockUser", + Handler: _Admin_BlockUser_Handler, + }, + { + MethodName: "UnblockUser", + Handler: _Admin_UnblockUser_Handler, + }, + { + MethodName: "SearchBlockUser", + Handler: _Admin_SearchBlockUser_Handler, + }, + { + MethodName: "FindUserBlockInfo", + Handler: _Admin_FindUserBlockInfo_Handler, + }, + { + MethodName: "CheckRegisterForbidden", + Handler: _Admin_CheckRegisterForbidden_Handler, + }, + { + MethodName: "CheckLoginForbidden", + Handler: _Admin_CheckLoginForbidden_Handler, + }, + { + MethodName: "CreateToken", + Handler: _Admin_CreateToken_Handler, + }, + { + MethodName: "ParseToken", + Handler: _Admin_ParseToken_Handler, + }, + { + MethodName: "AddApplet", + Handler: _Admin_AddApplet_Handler, + }, + { + MethodName: "DelApplet", + Handler: _Admin_DelApplet_Handler, + }, + { + MethodName: "UpdateApplet", + Handler: _Admin_UpdateApplet_Handler, + }, + { + MethodName: "FindApplet", + Handler: _Admin_FindApplet_Handler, + }, + { + MethodName: "SearchApplet", + Handler: _Admin_SearchApplet_Handler, + }, + { + MethodName: "GetClientConfig", + Handler: _Admin_GetClientConfig_Handler, + }, + { + MethodName: "SetClientConfig", + Handler: _Admin_SetClientConfig_Handler, + }, + { + MethodName: "DelClientConfig", + Handler: _Admin_DelClientConfig_Handler, + }, + { + MethodName: "GetUserToken", + Handler: _Admin_GetUserToken_Handler, + }, + { + MethodName: "InvalidateToken", + Handler: _Admin_InvalidateToken_Handler, + }, + { + MethodName: "LatestApplicationVersion", + Handler: _Admin_LatestApplicationVersion_Handler, + }, + { + MethodName: "AddApplicationVersion", + Handler: _Admin_AddApplicationVersion_Handler, + }, + { + MethodName: "UpdateApplicationVersion", + Handler: _Admin_UpdateApplicationVersion_Handler, + }, + { + MethodName: "DeleteApplicationVersion", + Handler: _Admin_DeleteApplicationVersion_Handler, + }, + { + MethodName: "PageApplicationVersion", + Handler: _Admin_PageApplicationVersion_Handler, + }, + { + MethodName: "AddSensitiveWord", + Handler: _Admin_AddSensitiveWord_Handler, + }, + { + MethodName: "UpdateSensitiveWord", + Handler: _Admin_UpdateSensitiveWord_Handler, + }, + { + MethodName: "DeleteSensitiveWord", + Handler: _Admin_DeleteSensitiveWord_Handler, + }, + { + MethodName: "GetSensitiveWord", + Handler: _Admin_GetSensitiveWord_Handler, + }, + { + MethodName: "SearchSensitiveWords", + Handler: _Admin_SearchSensitiveWords_Handler, + }, + { + MethodName: "BatchAddSensitiveWords", + Handler: _Admin_BatchAddSensitiveWords_Handler, + }, + { + MethodName: "BatchUpdateSensitiveWords", + Handler: _Admin_BatchUpdateSensitiveWords_Handler, + }, + { + MethodName: "BatchDeleteSensitiveWords", + Handler: _Admin_BatchDeleteSensitiveWords_Handler, + }, + { + MethodName: "AddSensitiveWordGroup", + Handler: _Admin_AddSensitiveWordGroup_Handler, + }, + { + MethodName: "UpdateSensitiveWordGroup", + Handler: _Admin_UpdateSensitiveWordGroup_Handler, + }, + { + MethodName: "DeleteSensitiveWordGroup", + Handler: _Admin_DeleteSensitiveWordGroup_Handler, + }, + { + MethodName: "GetSensitiveWordGroup", + Handler: _Admin_GetSensitiveWordGroup_Handler, + }, + { + MethodName: "GetAllSensitiveWordGroups", + Handler: _Admin_GetAllSensitiveWordGroups_Handler, + }, + { + MethodName: "GetSensitiveWordConfig", + Handler: _Admin_GetSensitiveWordConfig_Handler, + }, + { + MethodName: "UpdateSensitiveWordConfig", + Handler: _Admin_UpdateSensitiveWordConfig_Handler, + }, + { + MethodName: "GetSensitiveWordLogs", + Handler: _Admin_GetSensitiveWordLogs_Handler, + }, + { + MethodName: "DeleteSensitiveWordLogs", + Handler: _Admin_DeleteSensitiveWordLogs_Handler, + }, + { + MethodName: "GetUserLoginRecords", + Handler: _Admin_GetUserLoginRecords_Handler, + }, + { + MethodName: "GetSensitiveWordStats", + Handler: _Admin_GetSensitiveWordStats_Handler, + }, + { + MethodName: "GetSensitiveWordLogStats", + Handler: _Admin_GetSensitiveWordLogStats_Handler, + }, + { + MethodName: "GetScheduledTasks", + Handler: _Admin_GetScheduledTasks_Handler, + }, + { + MethodName: "DeleteScheduledTask", + Handler: _Admin_DeleteScheduledTask_Handler, + }, + { + MethodName: "CreateSystemConfig", + Handler: _Admin_CreateSystemConfig_Handler, + }, + { + MethodName: "GetSystemConfig", + Handler: _Admin_GetSystemConfig_Handler, + }, + { + MethodName: "GetAllSystemConfigs", + Handler: _Admin_GetAllSystemConfigs_Handler, + }, + { + MethodName: "UpdateSystemConfig", + Handler: _Admin_UpdateSystemConfig_Handler, + }, + { + MethodName: "UpdateSystemConfigValue", + Handler: _Admin_UpdateSystemConfigValue_Handler, + }, + { + MethodName: "UpdateSystemConfigEnabled", + Handler: _Admin_UpdateSystemConfigEnabled_Handler, + }, + { + MethodName: "DeleteSystemConfig", + Handler: _Admin_DeleteSystemConfig_Handler, + }, + { + MethodName: "GetEnabledSystemConfigs", + Handler: _Admin_GetEnabledSystemConfigs_Handler, + }, + { + MethodName: "GetUserWallet", + Handler: _Admin_GetUserWallet_Handler, + }, + { + MethodName: "UpdateUserWalletBalance", + Handler: _Admin_UpdateUserWalletBalance_Handler, + }, + { + MethodName: "GetUserWalletBalanceRecords", + Handler: _Admin_GetUserWalletBalanceRecords_Handler, + }, + { + MethodName: "BatchUpdateWalletBalance", + Handler: _Admin_BatchUpdateWalletBalance_Handler, + }, + { + MethodName: "GetWallets", + Handler: _Admin_GetWallets_Handler, + }, + { + MethodName: "UpdateUserPaymentPassword", + Handler: _Admin_UpdateUserPaymentPassword_Handler, + }, + { + MethodName: "SetUserWithdrawAccount", + Handler: _Admin_SetUserWithdrawAccount_Handler, + }, + { + MethodName: "GetRealNameAuths", + Handler: _Admin_GetRealNameAuths_Handler, + }, + { + MethodName: "AuditRealNameAuth", + Handler: _Admin_AuditRealNameAuth_Handler, + }, + { + MethodName: "CreateWithdraw", + Handler: _Admin_CreateWithdraw_Handler, + }, + { + MethodName: "GetWithdraw", + Handler: _Admin_GetWithdraw_Handler, + }, + { + MethodName: "GetUserWithdraws", + Handler: _Admin_GetUserWithdraws_Handler, + }, + { + MethodName: "GetWithdraws", + Handler: _Admin_GetWithdraws_Handler, + }, + { + MethodName: "AuditWithdraw", + Handler: _Admin_AuditWithdraw_Handler, + }, + { + MethodName: "GetStatistics", + Handler: _Admin_GetStatistics_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "admin/admin.proto", +} diff --git a/pkg/protocol/admin/api.go b/pkg/protocol/admin/api.go new file mode 100644 index 0000000..d52c5cf --- /dev/null +++ b/pkg/protocol/admin/api.go @@ -0,0 +1,21 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +import "github.com/openimsdk/tools/utils/datautil" + +func (x *GetClientConfigResp) ApiFormat() { + datautil.InitMap(&x.Config) +} diff --git a/pkg/protocol/bot/bot.pb.go b/pkg/protocol/bot/bot.pb.go new file mode 100644 index 0000000..b801253 --- /dev/null +++ b/pkg/protocol/bot/bot.pb.go @@ -0,0 +1,830 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.1 +// protoc v5.29.0 +// source: bot/bot.proto + +package bot + +import ( + reflect "reflect" + sync "sync" + + sdkws "git.imall.cloud/openim/protocol/sdkws" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Agent struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Key string `protobuf:"bytes,5,opt,name=key,proto3" json:"key"` + Identity string `protobuf:"bytes,6,opt,name=identity,proto3" json:"identity"` + Model string `protobuf:"bytes,7,opt,name=model,proto3" json:"model"` + Prompts string `protobuf:"bytes,8,opt,name=prompts,proto3" json:"prompts"` + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Agent) Reset() { + *x = Agent{} + mi := &file_bot_bot_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Agent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Agent) ProtoMessage() {} + +func (x *Agent) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Agent.ProtoReflect.Descriptor instead. +func (*Agent) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{0} +} + +func (x *Agent) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *Agent) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *Agent) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *Agent) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Agent) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Agent) GetIdentity() string { + if x != nil { + return x.Identity + } + return "" +} + +func (x *Agent) GetModel() string { + if x != nil { + return x.Model + } + return "" +} + +func (x *Agent) GetPrompts() string { + if x != nil { + return x.Prompts + } + return "" +} + +func (x *Agent) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type CreateAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Agent *Agent `protobuf:"bytes,1,opt,name=agent,proto3" json:"agent"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAgentReq) Reset() { + *x = CreateAgentReq{} + mi := &file_bot_bot_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAgentReq) ProtoMessage() {} + +func (x *CreateAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAgentReq.ProtoReflect.Descriptor instead. +func (*CreateAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateAgentReq) GetAgent() *Agent { + if x != nil { + return x.Agent + } + return nil +} + +type CreateAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAgentResp) Reset() { + *x = CreateAgentResp{} + mi := &file_bot_bot_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAgentResp) ProtoMessage() {} + +func (x *CreateAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAgentResp.ProtoReflect.Descriptor instead. +func (*CreateAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{2} +} + +type UpdateAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname *string `protobuf:"bytes,2,opt,name=nickname,proto3,oneof" json:"nickname"` + FaceURL *string `protobuf:"bytes,3,opt,name=faceURL,proto3,oneof" json:"faceURL"` + Url *string `protobuf:"bytes,4,opt,name=url,proto3,oneof" json:"url"` + Key *string `protobuf:"bytes,5,opt,name=key,proto3,oneof" json:"key"` + Identity *string `protobuf:"bytes,6,opt,name=identity,proto3,oneof" json:"identity"` + Model *string `protobuf:"bytes,7,opt,name=model,proto3,oneof" json:"model"` + Prompts *string `protobuf:"bytes,8,opt,name=prompts,proto3,oneof" json:"prompts"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAgentReq) Reset() { + *x = UpdateAgentReq{} + mi := &file_bot_bot_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAgentReq) ProtoMessage() {} + +func (x *UpdateAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAgentReq.ProtoReflect.Descriptor instead. +func (*UpdateAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{3} +} + +func (x *UpdateAgentReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UpdateAgentReq) GetNickname() string { + if x != nil && x.Nickname != nil { + return *x.Nickname + } + return "" +} + +func (x *UpdateAgentReq) GetFaceURL() string { + if x != nil && x.FaceURL != nil { + return *x.FaceURL + } + return "" +} + +func (x *UpdateAgentReq) GetUrl() string { + if x != nil && x.Url != nil { + return *x.Url + } + return "" +} + +func (x *UpdateAgentReq) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *UpdateAgentReq) GetIdentity() string { + if x != nil && x.Identity != nil { + return *x.Identity + } + return "" +} + +func (x *UpdateAgentReq) GetModel() string { + if x != nil && x.Model != nil { + return *x.Model + } + return "" +} + +func (x *UpdateAgentReq) GetPrompts() string { + if x != nil && x.Prompts != nil { + return *x.Prompts + } + return "" +} + +type UpdateAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAgentResp) Reset() { + *x = UpdateAgentResp{} + mi := &file_bot_bot_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAgentResp) ProtoMessage() {} + +func (x *UpdateAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAgentResp.ProtoReflect.Descriptor instead. +func (*UpdateAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{4} +} + +type PageFindAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` + UserIDs []string `protobuf:"bytes,2,rep,name=userIDs,proto3" json:"userIDs"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PageFindAgentReq) Reset() { + *x = PageFindAgentReq{} + mi := &file_bot_bot_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PageFindAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageFindAgentReq) ProtoMessage() {} + +func (x *PageFindAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageFindAgentReq.ProtoReflect.Descriptor instead. +func (*PageFindAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{5} +} + +func (x *PageFindAgentReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *PageFindAgentReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type PageFindAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Agents []*Agent `protobuf:"bytes,2,rep,name=agents,proto3" json:"agents"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PageFindAgentResp) Reset() { + *x = PageFindAgentResp{} + mi := &file_bot_bot_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PageFindAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageFindAgentResp) ProtoMessage() {} + +func (x *PageFindAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageFindAgentResp.ProtoReflect.Descriptor instead. +func (*PageFindAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{6} +} + +func (x *PageFindAgentResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *PageFindAgentResp) GetAgents() []*Agent { + if x != nil { + return x.Agents + } + return nil +} + +type DeleteAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAgentReq) Reset() { + *x = DeleteAgentReq{} + mi := &file_bot_bot_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAgentReq) ProtoMessage() {} + +func (x *DeleteAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAgentReq.ProtoReflect.Descriptor instead. +func (*DeleteAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteAgentReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type DeleteAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAgentResp) Reset() { + *x = DeleteAgentResp{} + mi := &file_bot_bot_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAgentResp) ProtoMessage() {} + +func (x *DeleteAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAgentResp.ProtoReflect.Descriptor instead. +func (*DeleteAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{8} +} + +type SendBotMessageReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + AgentID string `protobuf:"bytes,1,opt,name=agentID,proto3" json:"agentID"` + ConversationID string `protobuf:"bytes,2,opt,name=conversationID,proto3" json:"conversationID"` + ContentType int32 `protobuf:"varint,3,opt,name=contentType,proto3" json:"contentType"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content"` + Ex string `protobuf:"bytes,5,opt,name=ex,proto3" json:"ex"` + Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendBotMessageReq) Reset() { + *x = SendBotMessageReq{} + mi := &file_bot_bot_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendBotMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendBotMessageReq) ProtoMessage() {} + +func (x *SendBotMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendBotMessageReq.ProtoReflect.Descriptor instead. +func (*SendBotMessageReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{9} +} + +func (x *SendBotMessageReq) GetAgentID() string { + if x != nil { + return x.AgentID + } + return "" +} + +func (x *SendBotMessageReq) GetConversationID() string { + if x != nil { + return x.ConversationID + } + return "" +} + +func (x *SendBotMessageReq) GetContentType() int32 { + if x != nil { + return x.ContentType + } + return 0 +} + +func (x *SendBotMessageReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *SendBotMessageReq) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +func (x *SendBotMessageReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +type SendBotMessageResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendBotMessageResp) Reset() { + *x = SendBotMessageResp{} + mi := &file_bot_bot_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendBotMessageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendBotMessageResp) ProtoMessage() {} + +func (x *SendBotMessageResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendBotMessageResp.ProtoReflect.Descriptor instead. +func (*SendBotMessageResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{10} +} + +var File_bot_bot_proto protoreflect.FileDescriptor + +var file_bot_bot_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x62, 0x6f, 0x74, 0x2f, 0x62, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0a, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x1a, 0x11, 0x73, 0x64, 0x6b, + 0x77, 0x73, 0x2f, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe5, + 0x01, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, + 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x27, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x22, 0xbd, 0x02, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x1f, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, + 0x12, 0x1d, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x01, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x88, 0x01, 0x01, 0x12, + 0x15, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x04, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x19, + 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, + 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, + 0x4c, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6b, 0x65, + 0x79, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6d, 0x0a, 0x10, 0x50, 0x61, 0x67, 0x65, 0x46, + 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x54, 0x0a, 0x11, 0x50, 0x61, 0x67, 0x65, 0x46, 0x69, + 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x12, 0x29, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x2a, 0x0a, 0x0e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, + 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xb3, 0x01, 0x0a, 0x11, + 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x26, 0x0a, 0x0e, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x32, 0xfc, 0x02, 0x0a, 0x03, 0x62, 0x6f, 0x74, 0x12, + 0x46, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x62, 0x6f, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x4c, 0x0a, 0x0d, 0x50, 0x61, 0x67, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x50, 0x61, + 0x67, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1d, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, + 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, + 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4f, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x62, 0x6f, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, 0x63, + 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x2f, 0x62, 0x6f, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_bot_bot_proto_rawDescOnce sync.Once + file_bot_bot_proto_rawDescData = file_bot_bot_proto_rawDesc +) + +func file_bot_bot_proto_rawDescGZIP() []byte { + file_bot_bot_proto_rawDescOnce.Do(func() { + file_bot_bot_proto_rawDescData = protoimpl.X.CompressGZIP(file_bot_bot_proto_rawDescData) + }) + return file_bot_bot_proto_rawDescData +} + +var file_bot_bot_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_bot_bot_proto_goTypes = []any{ + (*Agent)(nil), // 0: openim.bot.Agent + (*CreateAgentReq)(nil), // 1: openim.bot.CreateAgentReq + (*CreateAgentResp)(nil), // 2: openim.bot.CreateAgentResp + (*UpdateAgentReq)(nil), // 3: openim.bot.UpdateAgentReq + (*UpdateAgentResp)(nil), // 4: openim.bot.UpdateAgentResp + (*PageFindAgentReq)(nil), // 5: openim.bot.PageFindAgentReq + (*PageFindAgentResp)(nil), // 6: openim.bot.PageFindAgentResp + (*DeleteAgentReq)(nil), // 7: openim.bot.DeleteAgentReq + (*DeleteAgentResp)(nil), // 8: openim.bot.DeleteAgentResp + (*SendBotMessageReq)(nil), // 9: openim.bot.SendBotMessageReq + (*SendBotMessageResp)(nil), // 10: openim.bot.SendBotMessageResp + (*sdkws.RequestPagination)(nil), // 11: openim.sdkws.RequestPagination +} +var file_bot_bot_proto_depIdxs = []int32{ + 0, // 0: openim.bot.CreateAgentReq.agent:type_name -> openim.bot.Agent + 11, // 1: openim.bot.PageFindAgentReq.pagination:type_name -> openim.sdkws.RequestPagination + 0, // 2: openim.bot.PageFindAgentResp.agents:type_name -> openim.bot.Agent + 1, // 3: openim.bot.bot.CreateAgent:input_type -> openim.bot.CreateAgentReq + 3, // 4: openim.bot.bot.UpdateAgent:input_type -> openim.bot.UpdateAgentReq + 5, // 5: openim.bot.bot.PageFindAgent:input_type -> openim.bot.PageFindAgentReq + 7, // 6: openim.bot.bot.DeleteAgent:input_type -> openim.bot.DeleteAgentReq + 9, // 7: openim.bot.bot.SendBotMessage:input_type -> openim.bot.SendBotMessageReq + 2, // 8: openim.bot.bot.CreateAgent:output_type -> openim.bot.CreateAgentResp + 4, // 9: openim.bot.bot.UpdateAgent:output_type -> openim.bot.UpdateAgentResp + 6, // 10: openim.bot.bot.PageFindAgent:output_type -> openim.bot.PageFindAgentResp + 8, // 11: openim.bot.bot.DeleteAgent:output_type -> openim.bot.DeleteAgentResp + 10, // 12: openim.bot.bot.SendBotMessage:output_type -> openim.bot.SendBotMessageResp + 8, // [8:13] is the sub-list for method output_type + 3, // [3:8] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_bot_bot_proto_init() } +func file_bot_bot_proto_init() { + if File_bot_bot_proto != nil { + return + } + file_bot_bot_proto_msgTypes[3].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bot_bot_proto_rawDesc, + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_bot_bot_proto_goTypes, + DependencyIndexes: file_bot_bot_proto_depIdxs, + MessageInfos: file_bot_bot_proto_msgTypes, + }.Build() + File_bot_bot_proto = out.File + file_bot_bot_proto_rawDesc = nil + file_bot_bot_proto_goTypes = nil + file_bot_bot_proto_depIdxs = nil +} diff --git a/pkg/protocol/bot/bot.proto b/pkg/protocol/bot/bot.proto new file mode 100644 index 0000000..3f8ee41 --- /dev/null +++ b/pkg/protocol/bot/bot.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; +package openim.bot; + +import "sdkws/sdkws.proto"; + +option go_package = "git.imall.cloud/openim/chat/pkg/protocol/bot"; + +message Agent { + string userID = 1; + string nickname = 2; + string faceURL = 3; + string url = 4; + string key = 5; + string identity = 6; + string model = 7; + string prompts = 8; + int64 createTime = 9; +} + +message CreateAgentReq { + Agent agent = 1; +} + +message CreateAgentResp { +} + +message UpdateAgentReq { + string userID = 1; + optional string nickname = 2; + optional string faceURL = 3; + optional string url = 4; + optional string key = 5; + optional string identity = 6; + optional string model = 7; + optional string prompts = 8; +} + +message UpdateAgentResp { +} + +message PageFindAgentReq { + openim.sdkws.RequestPagination pagination = 1; + repeated string userIDs = 2; +} + +message PageFindAgentResp { + int64 total = 1; + repeated Agent agents = 2; +} + +message DeleteAgentReq{ + repeated string userIDs = 1; +} +message DeleteAgentResp{} + +message SendBotMessageReq{ + string agentID = 1; + string conversationID = 2; + int32 contentType = 3; + string content = 4; + string ex = 5; + string key = 6; +} +message SendBotMessageResp{} + +service bot { + rpc CreateAgent(CreateAgentReq) returns (CreateAgentResp); + rpc UpdateAgent(UpdateAgentReq) returns (UpdateAgentResp); + rpc PageFindAgent(PageFindAgentReq) returns (PageFindAgentResp); + rpc DeleteAgent(DeleteAgentReq) returns (DeleteAgentResp); + + rpc SendBotMessage(SendBotMessageReq) returns (SendBotMessageResp); +} diff --git a/pkg/protocol/bot/bot_grpc.pb.go b/pkg/protocol/bot/bot_grpc.pb.go new file mode 100644 index 0000000..98f38cc --- /dev/null +++ b/pkg/protocol/bot/bot_grpc.pb.go @@ -0,0 +1,273 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.29.0 +// source: bot/bot.proto + +package bot + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Bot_CreateAgent_FullMethodName = "/openim.bot.bot/CreateAgent" + Bot_UpdateAgent_FullMethodName = "/openim.bot.bot/UpdateAgent" + Bot_PageFindAgent_FullMethodName = "/openim.bot.bot/PageFindAgent" + Bot_DeleteAgent_FullMethodName = "/openim.bot.bot/DeleteAgent" + Bot_SendBotMessage_FullMethodName = "/openim.bot.bot/SendBotMessage" +) + +// BotClient is the client API for Bot service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BotClient interface { + CreateAgent(ctx context.Context, in *CreateAgentReq, opts ...grpc.CallOption) (*CreateAgentResp, error) + UpdateAgent(ctx context.Context, in *UpdateAgentReq, opts ...grpc.CallOption) (*UpdateAgentResp, error) + PageFindAgent(ctx context.Context, in *PageFindAgentReq, opts ...grpc.CallOption) (*PageFindAgentResp, error) + DeleteAgent(ctx context.Context, in *DeleteAgentReq, opts ...grpc.CallOption) (*DeleteAgentResp, error) + SendBotMessage(ctx context.Context, in *SendBotMessageReq, opts ...grpc.CallOption) (*SendBotMessageResp, error) +} + +type botClient struct { + cc grpc.ClientConnInterface +} + +func NewBotClient(cc grpc.ClientConnInterface) BotClient { + return &botClient{cc} +} + +func (c *botClient) CreateAgent(ctx context.Context, in *CreateAgentReq, opts ...grpc.CallOption) (*CreateAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateAgentResp) + err := c.cc.Invoke(ctx, Bot_CreateAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) UpdateAgent(ctx context.Context, in *UpdateAgentReq, opts ...grpc.CallOption) (*UpdateAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateAgentResp) + err := c.cc.Invoke(ctx, Bot_UpdateAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) PageFindAgent(ctx context.Context, in *PageFindAgentReq, opts ...grpc.CallOption) (*PageFindAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PageFindAgentResp) + err := c.cc.Invoke(ctx, Bot_PageFindAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) DeleteAgent(ctx context.Context, in *DeleteAgentReq, opts ...grpc.CallOption) (*DeleteAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteAgentResp) + err := c.cc.Invoke(ctx, Bot_DeleteAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) SendBotMessage(ctx context.Context, in *SendBotMessageReq, opts ...grpc.CallOption) (*SendBotMessageResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SendBotMessageResp) + err := c.cc.Invoke(ctx, Bot_SendBotMessage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BotServer is the server API for Bot service. +// All implementations must embed UnimplementedBotServer +// for forward compatibility. +type BotServer interface { + CreateAgent(context.Context, *CreateAgentReq) (*CreateAgentResp, error) + UpdateAgent(context.Context, *UpdateAgentReq) (*UpdateAgentResp, error) + PageFindAgent(context.Context, *PageFindAgentReq) (*PageFindAgentResp, error) + DeleteAgent(context.Context, *DeleteAgentReq) (*DeleteAgentResp, error) + SendBotMessage(context.Context, *SendBotMessageReq) (*SendBotMessageResp, error) + mustEmbedUnimplementedBotServer() +} + +// UnimplementedBotServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedBotServer struct{} + +func (UnimplementedBotServer) CreateAgent(context.Context, *CreateAgentReq) (*CreateAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateAgent not implemented") +} +func (UnimplementedBotServer) UpdateAgent(context.Context, *UpdateAgentReq) (*UpdateAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateAgent not implemented") +} +func (UnimplementedBotServer) PageFindAgent(context.Context, *PageFindAgentReq) (*PageFindAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PageFindAgent not implemented") +} +func (UnimplementedBotServer) DeleteAgent(context.Context, *DeleteAgentReq) (*DeleteAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteAgent not implemented") +} +func (UnimplementedBotServer) SendBotMessage(context.Context, *SendBotMessageReq) (*SendBotMessageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendBotMessage not implemented") +} +func (UnimplementedBotServer) mustEmbedUnimplementedBotServer() {} +func (UnimplementedBotServer) testEmbeddedByValue() {} + +// UnsafeBotServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BotServer will +// result in compilation errors. +type UnsafeBotServer interface { + mustEmbedUnimplementedBotServer() +} + +func RegisterBotServer(s grpc.ServiceRegistrar, srv BotServer) { + // If the following call pancis, it indicates UnimplementedBotServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Bot_ServiceDesc, srv) +} + +func _Bot_CreateAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).CreateAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_CreateAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).CreateAgent(ctx, req.(*CreateAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_UpdateAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).UpdateAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_UpdateAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).UpdateAgent(ctx, req.(*UpdateAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_PageFindAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PageFindAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).PageFindAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_PageFindAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).PageFindAgent(ctx, req.(*PageFindAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_DeleteAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).DeleteAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_DeleteAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).DeleteAgent(ctx, req.(*DeleteAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_SendBotMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendBotMessageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).SendBotMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_SendBotMessage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).SendBotMessage(ctx, req.(*SendBotMessageReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Bot_ServiceDesc is the grpc.ServiceDesc for Bot service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Bot_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openim.bot.bot", + HandlerType: (*BotServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateAgent", + Handler: _Bot_CreateAgent_Handler, + }, + { + MethodName: "UpdateAgent", + Handler: _Bot_UpdateAgent_Handler, + }, + { + MethodName: "PageFindAgent", + Handler: _Bot_PageFindAgent_Handler, + }, + { + MethodName: "DeleteAgent", + Handler: _Bot_DeleteAgent_Handler, + }, + { + MethodName: "SendBotMessage", + Handler: _Bot_SendBotMessage_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "bot/bot.proto", +} diff --git a/pkg/protocol/chat/chat.go b/pkg/protocol/chat/chat.go new file mode 100644 index 0000000..481e0fe --- /dev/null +++ b/pkg/protocol/chat/chat.go @@ -0,0 +1,519 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "regexp" + "strconv" + + "git.imall.cloud/openim/chat/pkg/common/constant" + constantpb "git.imall.cloud/openim/protocol/constant" + "github.com/openimsdk/tools/errs" +) + +func (x *UpdateUserInfoReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + if x.Email != nil && x.Email.Value != "" { + if err := EmailCheck(x.Email.Value); err != nil { + return err + } + } + return nil +} + +func (x *FindUserPublicInfoReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *SearchUserPublicInfoReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *FindUserFullInfoReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *SendVerifyCodeReq) Check() error { + if x.UsedFor < constant.VerificationCodeForRegister || x.UsedFor > constant.VerificationCodeForH5Register { + return errs.ErrArgs.WrapMsg("usedFor flied is empty") + } + if x.Email == "" { + if x.AreaCode == "" { + return errs.ErrArgs.WrapMsg("AreaCode is empty") + } else if err := AreaCodeCheck(x.AreaCode); err != nil { + return err + } + if x.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("PhoneNumber is empty") + } else if err := PhoneNumberCheck(x.PhoneNumber); err != nil { + return err + } + } else { + if err := EmailCheck(x.Email); err != nil { + return err + } + } + + return nil +} + +func (x *VerifyCodeReq) Check() error { + // 如果提供了account,验证account格式,此时不需要AreaCode和PhoneNumber + if x.Account != "" { + if err := AccountCheck(x.Account); err != nil { + return err + } + // account验证时,VerifyCode是必需的 + if x.VerifyCode == "" { + return errs.ErrArgs.WrapMsg("VerifyCode is empty") + } + return nil + } + + // 如果没有提供account,则验证phone或email + if x.Email == "" { + if x.AreaCode == "" { + return errs.ErrArgs.WrapMsg("AreaCode is empty") + } else if err := AreaCodeCheck(x.AreaCode); err != nil { + return err + } + if x.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("PhoneNumber is empty") + } else if err := PhoneNumberCheck(x.PhoneNumber); err != nil { + return err + } + } else { + if err := EmailCheck(x.Email); err != nil { + return err + } + } + if x.VerifyCode == "" { + return errs.ErrArgs.WrapMsg("VerifyCode is empty") + } + return nil +} + +func (x *RegisterUserReq) Check() error { + //if x.VerifyCode == "" { + // return errs.ErrArgs.WrapMsg("VerifyCode is empty") + //} + if x.User.Nickname == "" { + return errs.ErrArgs.WrapMsg("Nickname is nil") + } + if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.HarmonyOSPlatformID { + return errs.ErrArgs.WrapMsg("platform is invalid") + } + if x.User == nil { + return errs.ErrArgs.WrapMsg("user is empty") + } + + // 如果提供了account,验证account格式,此时不需要AreaCode和PhoneNumber + if x.User.Account != "" { + if err := AccountCheck(x.User.Account); err != nil { + return err + } + // account注册时,不需要验证phone和email + return nil + } + + // 如果没有提供account,则验证phone或email + if x.User.Email == "" { + if x.User.AreaCode == "" { + return errs.ErrArgs.WrapMsg("AreaCode is empty") + } else if err := AreaCodeCheck(x.User.AreaCode); err != nil { + return err + } + if x.User.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("PhoneNumber is empty") + } else if err := PhoneNumberCheck(x.User.PhoneNumber); err != nil { + return err + } + } else { + if err := EmailCheck(x.User.Email); err != nil { + return err + } + } + return nil +} + +func (x *LoginReq) Check() error { + if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.HarmonyOSPlatformID { + return errs.ErrArgs.WrapMsg("platform is invalid") + } + // 支持三种登录方式:account、phone、email + if x.Account != "" { + // 使用account登录,不需要验证phone和email + return nil + } else if x.Email != "" { + // 使用email登录 + if err := EmailCheck(x.Email); err != nil { + return err + } + } else { + // 使用phone登录 + if x.AreaCode == "" { + return errs.ErrArgs.WrapMsg("AreaCode is empty") + } else if err := AreaCodeCheck(x.AreaCode); err != nil { + return err + } + if x.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("PhoneNumber is empty") + } else if err := PhoneNumberCheck(x.PhoneNumber); err != nil { + return err + } + } + return nil +} + +func (x *ResetPasswordReq) Check() error { + if x.Password == "" { + return errs.ErrArgs.WrapMsg("password is empty") + } + if x.Email == "" { + if x.AreaCode == "" { + return errs.ErrArgs.WrapMsg("AreaCode is empty") + } else if err := AreaCodeCheck(x.AreaCode); err != nil { + return err + } + if x.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("PhoneNumber is empty") + } else if err := PhoneNumberCheck(x.PhoneNumber); err != nil { + return err + } + } else { + if err := EmailCheck(x.Email); err != nil { + return err + } + } + if x.VerifyCode == "" { + return errs.ErrArgs.WrapMsg("VerifyCode is empty") + } + return nil +} + +func (x *ChangePasswordReq) Check() error { + if x.UserID == "" { + return errs.ErrArgs.WrapMsg("userID is empty") + } + + if x.NewPassword == "" { + return errs.ErrArgs.WrapMsg("newPassword is empty") + } + + return nil +} + +func (x *FindUserAccountReq) Check() error { + if x.UserIDs == nil { + return errs.ErrArgs.WrapMsg("userIDs is empty") + } + return nil +} + +func (x *FindAccountUserReq) Check() error { + if x.Accounts == nil { + return errs.ErrArgs.WrapMsg("Accounts is empty") + } + return nil +} + +func (x *SearchUserFullInfoReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is empty") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + if x.Normal < constant.FinDAllUser || x.Normal > constant.FindNormalUser { + return errs.ErrArgs.WrapMsg("normal flied is invalid") + } + return nil +} + +func (x *GetTokenForVideoMeetingReq) Check() error { + if x.Room == "" { + errs.ErrArgs.WrapMsg("Room is empty") + } + if x.Identity == "" { + errs.ErrArgs.WrapMsg("User Identity is empty") + } + return nil +} + +func EmailCheck(email string) error { + pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` + if err := regexMatch(pattern, email); err != nil { + return errs.WrapMsg(err, "Email is invalid") + } + return nil +} + +func AreaCodeCheck(areaCode string) error { + //pattern := `\+[1-9][0-9]{1,2}` + //if err := regexMatch(pattern, areaCode); err != nil { + // return errs.WrapMsg(err, "AreaCode is invalid") + //} + return nil +} + +func PhoneNumberCheck(phoneNumber string) error { + if phoneNumber == "" { + return errs.ErrArgs.WrapMsg("phoneNumber is empty") + } + _, err := strconv.ParseUint(phoneNumber, 10, 64) + if err != nil { + return errs.ErrArgs.WrapMsg("phoneNumber is invalid") + } + return nil +} + +func AccountCheck(account string) error { + if account == "" { + return errs.ErrArgs.WrapMsg("account is empty") + } + // 验证长度:6到20位 + if len(account) < 6 || len(account) > 20 { + return errs.ErrArgs.WrapMsg("account must be between 6 and 20 characters") + } + // 验证格式:只能包含数字、字母、下划线(_)、横线(-) + pattern := `^[a-zA-Z0-9_-]+$` + if err := regexMatch(pattern, account); err != nil { + return errs.WrapMsg(err, "account must contain only letters, numbers, underscores, and hyphens") + } + return nil +} + +func regexMatch(pattern string, target string) error { + reg := regexp.MustCompile(pattern) + ok := reg.MatchString(target) + if !ok { + return errs.ErrArgs + } + return nil +} + +func (x *SearchUserInfoReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("Pagination is nil") + } + if x.Pagination.PageNumber < 1 { + return errs.ErrArgs.WrapMsg("pageNumber is invalid") + } + if x.Pagination.ShowNumber < 1 { + return errs.ErrArgs.WrapMsg("showNumber is invalid") + } + return nil +} + +func (x *AddUserAccountReq) Check() error { + if x.User == nil { + return errs.ErrArgs.WrapMsg("user is empty") + } + + if x.User.Email == "" { + if x.User.AreaCode == "" || x.User.PhoneNumber == "" { + return errs.ErrArgs.WrapMsg("area code or phone number is empty") + } + if x.User.AreaCode[0] != '+' { + x.User.AreaCode = "+" + x.User.AreaCode + } + if _, err := strconv.ParseUint(x.User.AreaCode[1:], 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("area code must be number") + } + if _, err := strconv.ParseUint(x.User.PhoneNumber, 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("phone number must be number") + } + } else { + if err := EmailCheck(x.User.Email); err != nil { + return errs.ErrArgs.WrapMsg("email must be right") + } + } + + return nil +} + +// 敏感词检测相关 Check() 方法 +func (x *GetSensitiveWordsReq) Check() error { + // 获取敏感词列表不需要参数验证 + return nil +} + +func (x *CheckSensitiveWordsReq) Check() error { + if x.Content == "" { + return errs.ErrArgs.WrapMsg("content is empty") + } + return nil +} + +// ==================== 敏感词管理相关 Check() 方法 ==================== + +func (x *AddSensitiveWordReq) Check() error { + if x.Word == "" { + return errs.ErrArgs.WrapMsg("word is empty") + } + return nil +} + +func (x *UpdateSensitiveWordReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *DeleteSensitiveWordReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *SearchSensitiveWordsReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is nil") + } + if x.Pagination.ShowNumber == 0 { + return errs.ErrArgs.WrapMsg("showNumber is empty") + } + if x.Pagination.PageNumber == 0 { + return errs.ErrArgs.WrapMsg("pageNumber is empty") + } + return nil +} + +func (x *BatchAddSensitiveWordsReq) Check() error { + if len(x.Words) == 0 { + return errs.ErrArgs.WrapMsg("words is empty") + } + return nil +} + +func (x *BatchUpdateSensitiveWordsReq) Check() error { + if len(x.Updates) == 0 { + return errs.ErrArgs.WrapMsg("updates is empty") + } + return nil +} + +func (x *BatchDeleteSensitiveWordsReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *AddSensitiveWordGroupReq) Check() error { + if x.Name == "" { + return errs.ErrArgs.WrapMsg("name is empty") + } + return nil +} + +func (x *UpdateSensitiveWordGroupReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *DeleteSensitiveWordGroupReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordGroupReq) Check() error { + if x.Id == "" { + return errs.ErrArgs.WrapMsg("id is empty") + } + return nil +} + +func (x *GetAllSensitiveWordGroupsReq) Check() error { + return nil +} + +func (x *GetSensitiveWordConfigReq) Check() error { + return nil +} + +func (x *UpdateSensitiveWordConfigReq) Check() error { + if x.Config == nil { + return errs.ErrArgs.WrapMsg("config is nil") + } + return nil +} + +func (x *GetSensitiveWordLogsReq) Check() error { + if x.Pagination == nil { + return errs.ErrArgs.WrapMsg("pagination is nil") + } + if x.Pagination.ShowNumber == 0 { + return errs.ErrArgs.WrapMsg("showNumber is empty") + } + if x.Pagination.PageNumber == 0 { + return errs.ErrArgs.WrapMsg("pageNumber is empty") + } + return nil +} + +func (x *DeleteSensitiveWordLogsReq) Check() error { + if len(x.Ids) == 0 { + return errs.ErrArgs.WrapMsg("ids is empty") + } + return nil +} + +func (x *GetSensitiveWordStatsReq) Check() error { + return nil +} + +func (x *GetSensitiveWordLogStatsReq) Check() error { + if x.StartTime == 0 || x.EndTime == 0 { + return errs.ErrArgs.WrapMsg("startTime or endTime is empty") + } + if x.StartTime > x.EndTime { + return errs.ErrArgs.WrapMsg("startTime must be less than endTime") + } + return nil +} diff --git a/pkg/protocol/chat/chat.pb.go b/pkg/protocol/chat/chat.pb.go new file mode 100644 index 0000000..8424315 --- /dev/null +++ b/pkg/protocol/chat/chat.pb.go @@ -0,0 +1,13236 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v6.33.0 +// source: chat/chat.proto + +package chat + +import ( + common "git.imall.cloud/openim/chat/pkg/protocol/common" + sdkws "git.imall.cloud/openim/protocol/sdkws" + wrapperspb "git.imall.cloud/openim/protocol/wrapperspb" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UserIdentity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email"` + AreaCode string `protobuf:"bytes,2,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,3,opt,name=phoneNumber,proto3" json:"phoneNumber"` + DeviceID string `protobuf:"bytes,4,opt,name=deviceID,proto3" json:"deviceID"` + Platform int32 `protobuf:"varint,5,opt,name=platform,proto3" json:"platform"` + Account string `protobuf:"bytes,6,opt,name=account,proto3" json:"account"` +} + +func (x *UserIdentity) Reset() { + *x = UserIdentity{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserIdentity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserIdentity) ProtoMessage() {} + +func (x *UserIdentity) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserIdentity.ProtoReflect.Descriptor instead. +func (*UserIdentity) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{0} +} + +func (x *UserIdentity) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UserIdentity) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *UserIdentity) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *UserIdentity) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *UserIdentity) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *UserIdentity) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +type UpdateUserInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Account *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=account,proto3" json:"account"` + PhoneNumber *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=phoneNumber,proto3" json:"phoneNumber"` + AreaCode *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=areaCode,proto3" json:"areaCode"` + Email *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=email,proto3" json:"email"` + Nickname *wrapperspb.StringValue `protobuf:"bytes,6,opt,name=nickname,proto3" json:"nickname"` + FaceURL *wrapperspb.StringValue `protobuf:"bytes,7,opt,name=faceURL,proto3" json:"faceURL"` + Gender *wrapperspb.Int32Value `protobuf:"bytes,8,opt,name=gender,proto3" json:"gender"` + Level *wrapperspb.Int32Value `protobuf:"bytes,9,opt,name=level,proto3" json:"level"` + Birth *wrapperspb.Int64Value `protobuf:"bytes,10,opt,name=birth,proto3" json:"birth"` + AllowAddFriend *wrapperspb.Int32Value `protobuf:"bytes,11,opt,name=allowAddFriend,proto3" json:"allowAddFriend"` + AllowBeep *wrapperspb.Int32Value `protobuf:"bytes,12,opt,name=allowBeep,proto3" json:"allowBeep"` + AllowVibration *wrapperspb.Int32Value `protobuf:"bytes,13,opt,name=allowVibration,proto3" json:"allowVibration"` + GlobalRecvMsgOpt *wrapperspb.Int32Value `protobuf:"bytes,14,opt,name=globalRecvMsgOpt,proto3" json:"globalRecvMsgOpt"` + RegisterType *wrapperspb.Int32Value `protobuf:"bytes,15,opt,name=RegisterType,proto3" json:"RegisterType"` + UserType int32 `protobuf:"varint,16,opt,name=userType,proto3" json:"userType"` // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + UserFlag *wrapperspb.StringValue `protobuf:"bytes,17,opt,name=userFlag,proto3" json:"userFlag"` // 用户标签/标识,类似UserType的字符串版本 +} + +func (x *UpdateUserInfoReq) Reset() { + *x = UpdateUserInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserInfoReq) ProtoMessage() {} + +func (x *UpdateUserInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserInfoReq.ProtoReflect.Descriptor instead. +func (*UpdateUserInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{1} +} + +func (x *UpdateUserInfoReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UpdateUserInfoReq) GetAccount() *wrapperspb.StringValue { + if x != nil { + return x.Account + } + return nil +} + +func (x *UpdateUserInfoReq) GetPhoneNumber() *wrapperspb.StringValue { + if x != nil { + return x.PhoneNumber + } + return nil +} + +func (x *UpdateUserInfoReq) GetAreaCode() *wrapperspb.StringValue { + if x != nil { + return x.AreaCode + } + return nil +} + +func (x *UpdateUserInfoReq) GetEmail() *wrapperspb.StringValue { + if x != nil { + return x.Email + } + return nil +} + +func (x *UpdateUserInfoReq) GetNickname() *wrapperspb.StringValue { + if x != nil { + return x.Nickname + } + return nil +} + +func (x *UpdateUserInfoReq) GetFaceURL() *wrapperspb.StringValue { + if x != nil { + return x.FaceURL + } + return nil +} + +func (x *UpdateUserInfoReq) GetGender() *wrapperspb.Int32Value { + if x != nil { + return x.Gender + } + return nil +} + +func (x *UpdateUserInfoReq) GetLevel() *wrapperspb.Int32Value { + if x != nil { + return x.Level + } + return nil +} + +func (x *UpdateUserInfoReq) GetBirth() *wrapperspb.Int64Value { + if x != nil { + return x.Birth + } + return nil +} + +func (x *UpdateUserInfoReq) GetAllowAddFriend() *wrapperspb.Int32Value { + if x != nil { + return x.AllowAddFriend + } + return nil +} + +func (x *UpdateUserInfoReq) GetAllowBeep() *wrapperspb.Int32Value { + if x != nil { + return x.AllowBeep + } + return nil +} + +func (x *UpdateUserInfoReq) GetAllowVibration() *wrapperspb.Int32Value { + if x != nil { + return x.AllowVibration + } + return nil +} + +func (x *UpdateUserInfoReq) GetGlobalRecvMsgOpt() *wrapperspb.Int32Value { + if x != nil { + return x.GlobalRecvMsgOpt + } + return nil +} + +func (x *UpdateUserInfoReq) GetRegisterType() *wrapperspb.Int32Value { + if x != nil { + return x.RegisterType + } + return nil +} + +func (x *UpdateUserInfoReq) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +func (x *UpdateUserInfoReq) GetUserFlag() *wrapperspb.StringValue { + if x != nil { + return x.UserFlag + } + return nil +} + +type UpdateUserInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FaceUrl string `protobuf:"bytes,1,opt,name=faceUrl,proto3" json:"faceUrl"` + NickName string `protobuf:"bytes,2,opt,name=nickName,proto3" json:"nickName"` +} + +func (x *UpdateUserInfoResp) Reset() { + *x = UpdateUserInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserInfoResp) ProtoMessage() {} + +func (x *UpdateUserInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserInfoResp.ProtoReflect.Descriptor instead. +func (*UpdateUserInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{2} +} + +func (x *UpdateUserInfoResp) GetFaceUrl() string { + if x != nil { + return x.FaceUrl + } + return "" +} + +func (x *UpdateUserInfoResp) GetNickName() string { + if x != nil { + return x.NickName + } + return "" +} + +type FindUserPublicInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *FindUserPublicInfoReq) Reset() { + *x = FindUserPublicInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserPublicInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserPublicInfoReq) ProtoMessage() {} + +func (x *FindUserPublicInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserPublicInfoReq.ProtoReflect.Descriptor instead. +func (*FindUserPublicInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{3} +} + +func (x *FindUserPublicInfoReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type FindUserPublicInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*common.UserPublicInfo `protobuf:"bytes,1,rep,name=users,proto3" json:"users"` +} + +func (x *FindUserPublicInfoResp) Reset() { + *x = FindUserPublicInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserPublicInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserPublicInfoResp) ProtoMessage() {} + +func (x *FindUserPublicInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserPublicInfoResp.ProtoReflect.Descriptor instead. +func (*FindUserPublicInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{4} +} + +func (x *FindUserPublicInfoResp) GetUsers() []*common.UserPublicInfo { + if x != nil { + return x.Users + } + return nil +} + +type SearchUserPublicInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` + Genders int32 `protobuf:"varint,3,opt,name=genders,proto3" json:"genders"` +} + +func (x *SearchUserPublicInfoReq) Reset() { + *x = SearchUserPublicInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserPublicInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserPublicInfoReq) ProtoMessage() {} + +func (x *SearchUserPublicInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserPublicInfoReq.ProtoReflect.Descriptor instead. +func (*SearchUserPublicInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{5} +} + +func (x *SearchUserPublicInfoReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchUserPublicInfoReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *SearchUserPublicInfoReq) GetGenders() int32 { + if x != nil { + return x.Genders + } + return 0 +} + +type SearchUserPublicInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Users []*common.UserPublicInfo `protobuf:"bytes,2,rep,name=users,proto3" json:"users"` +} + +func (x *SearchUserPublicInfoResp) Reset() { + *x = SearchUserPublicInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserPublicInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserPublicInfoResp) ProtoMessage() {} + +func (x *SearchUserPublicInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserPublicInfoResp.ProtoReflect.Descriptor instead. +func (*SearchUserPublicInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{6} +} + +func (x *SearchUserPublicInfoResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchUserPublicInfoResp) GetUsers() []*common.UserPublicInfo { + if x != nil { + return x.Users + } + return nil +} + +type FindUserFullInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *FindUserFullInfoReq) Reset() { + *x = FindUserFullInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserFullInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserFullInfoReq) ProtoMessage() {} + +func (x *FindUserFullInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserFullInfoReq.ProtoReflect.Descriptor instead. +func (*FindUserFullInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{7} +} + +func (x *FindUserFullInfoReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type FindUserFullInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*common.UserFullInfo `protobuf:"bytes,1,rep,name=users,proto3" json:"users"` +} + +func (x *FindUserFullInfoResp) Reset() { + *x = FindUserFullInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserFullInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserFullInfoResp) ProtoMessage() {} + +func (x *FindUserFullInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserFullInfoResp.ProtoReflect.Descriptor instead. +func (*FindUserFullInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{8} +} + +func (x *FindUserFullInfoResp) GetUsers() []*common.UserFullInfo { + if x != nil { + return x.Users + } + return nil +} + +type SendVerifyCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UsedFor int32 `protobuf:"varint,1,opt,name=usedFor,proto3" json:"usedFor"` + Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip"` + InvitationCode string `protobuf:"bytes,3,opt,name=invitationCode,proto3" json:"invitationCode"` + DeviceID string `protobuf:"bytes,4,opt,name=deviceID,proto3" json:"deviceID"` + Platform int32 `protobuf:"varint,5,opt,name=platform,proto3" json:"platform"` + AreaCode string `protobuf:"bytes,6,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,7,opt,name=phoneNumber,proto3" json:"phoneNumber"` + Email string `protobuf:"bytes,8,opt,name=email,proto3" json:"email"` +} + +func (x *SendVerifyCodeReq) Reset() { + *x = SendVerifyCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendVerifyCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendVerifyCodeReq) ProtoMessage() {} + +func (x *SendVerifyCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendVerifyCodeReq.ProtoReflect.Descriptor instead. +func (*SendVerifyCodeReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{9} +} + +func (x *SendVerifyCodeReq) GetUsedFor() int32 { + if x != nil { + return x.UsedFor + } + return 0 +} + +func (x *SendVerifyCodeReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *SendVerifyCodeReq) GetInvitationCode() string { + if x != nil { + return x.InvitationCode + } + return "" +} + +func (x *SendVerifyCodeReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *SendVerifyCodeReq) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *SendVerifyCodeReq) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *SendVerifyCodeReq) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *SendVerifyCodeReq) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type SendVerifyCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SendVerifyCodeResp) Reset() { + *x = SendVerifyCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendVerifyCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendVerifyCodeResp) ProtoMessage() {} + +func (x *SendVerifyCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendVerifyCodeResp.ProtoReflect.Descriptor instead. +func (*SendVerifyCodeResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{10} +} + +type VerifyCodeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AreaCode string `protobuf:"bytes,1,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` + VerifyCode string `protobuf:"bytes,3,opt,name=verifyCode,proto3" json:"verifyCode"` + Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email"` + CaptchaID string `protobuf:"bytes,5,opt,name=captchaID,proto3" json:"captchaID"` // 图片验证码ID(可选,如果提供则验证图片验证码) + Account string `protobuf:"bytes,6,opt,name=account,proto3" json:"account"` // 用户名(用于账号注册验证) +} + +func (x *VerifyCodeReq) Reset() { + *x = VerifyCodeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyCodeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyCodeReq) ProtoMessage() {} + +func (x *VerifyCodeReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyCodeReq.ProtoReflect.Descriptor instead. +func (*VerifyCodeReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{11} +} + +func (x *VerifyCodeReq) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *VerifyCodeReq) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *VerifyCodeReq) GetVerifyCode() string { + if x != nil { + return x.VerifyCode + } + return "" +} + +func (x *VerifyCodeReq) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *VerifyCodeReq) GetCaptchaID() string { + if x != nil { + return x.CaptchaID + } + return "" +} + +func (x *VerifyCodeReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +type VerifyCodeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RegisterToken string `protobuf:"bytes,1,opt,name=registerToken,proto3" json:"registerToken"` // H5注册token(仅在验证图片验证码成功后返回,用于后续注册,有效期120秒) +} + +func (x *VerifyCodeResp) Reset() { + *x = VerifyCodeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyCodeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyCodeResp) ProtoMessage() {} + +func (x *VerifyCodeResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyCodeResp.ProtoReflect.Descriptor instead. +func (*VerifyCodeResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{12} +} + +func (x *VerifyCodeResp) GetRegisterToken() string { + if x != nil { + return x.RegisterToken + } + return "" +} + +type GetCaptchaImageReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetCaptchaImageReq) Reset() { + *x = GetCaptchaImageReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetCaptchaImageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCaptchaImageReq) ProtoMessage() {} + +func (x *GetCaptchaImageReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCaptchaImageReq.ProtoReflect.Descriptor instead. +func (*GetCaptchaImageReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{13} +} + +type GetCaptchaImageResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CaptchaID string `protobuf:"bytes,1,opt,name=captchaID,proto3" json:"captchaID"` // 验证码ID,用于后续验证 + Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code"` // 6位数字验证码(用于生成图片) +} + +func (x *GetCaptchaImageResp) Reset() { + *x = GetCaptchaImageResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetCaptchaImageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCaptchaImageResp) ProtoMessage() {} + +func (x *GetCaptchaImageResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCaptchaImageResp.ProtoReflect.Descriptor instead. +func (*GetCaptchaImageResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{14} +} + +func (x *GetCaptchaImageResp) GetCaptchaID() string { + if x != nil { + return x.CaptchaID + } + return "" +} + +func (x *GetCaptchaImageResp) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +type RegisterUserInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` + Birth int64 `protobuf:"varint,4,opt,name=birth,proto3" json:"birth"` + Gender int32 `protobuf:"varint,5,opt,name=gender,proto3" json:"gender"` + AreaCode string `protobuf:"bytes,6,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,7,opt,name=phoneNumber,proto3" json:"phoneNumber"` + Email string `protobuf:"bytes,8,opt,name=email,proto3" json:"email"` + Account string `protobuf:"bytes,9,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,10,opt,name=password,proto3" json:"password"` + RegisterType int32 `protobuf:"varint,11,opt,name=RegisterType,proto3" json:"RegisterType"` + UserType int32 `protobuf:"varint,12,opt,name=userType,proto3" json:"userType"` // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + UserFlag string `protobuf:"bytes,13,opt,name=userFlag,proto3" json:"userFlag"` // 用户标签/标识 +} + +func (x *RegisterUserInfo) Reset() { + *x = RegisterUserInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterUserInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterUserInfo) ProtoMessage() {} + +func (x *RegisterUserInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterUserInfo.ProtoReflect.Descriptor instead. +func (*RegisterUserInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{15} +} + +func (x *RegisterUserInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *RegisterUserInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *RegisterUserInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *RegisterUserInfo) GetBirth() int64 { + if x != nil { + return x.Birth + } + return 0 +} + +func (x *RegisterUserInfo) GetGender() int32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *RegisterUserInfo) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *RegisterUserInfo) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *RegisterUserInfo) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *RegisterUserInfo) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *RegisterUserInfo) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *RegisterUserInfo) GetRegisterType() int32 { + if x != nil { + return x.RegisterType + } + return 0 +} + +func (x *RegisterUserInfo) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +func (x *RegisterUserInfo) GetUserFlag() string { + if x != nil { + return x.UserFlag + } + return "" +} + +type RegisterUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InvitationCode string `protobuf:"bytes,1,opt,name=invitationCode,proto3" json:"invitationCode"` + VerifyCode string `protobuf:"bytes,2,opt,name=verifyCode,proto3" json:"verifyCode"` + Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip"` + DeviceID string `protobuf:"bytes,4,opt,name=deviceID,proto3" json:"deviceID"` + Platform int32 `protobuf:"varint,5,opt,name=platform,proto3" json:"platform"` + AutoLogin bool `protobuf:"varint,6,opt,name=autoLogin,proto3" json:"autoLogin"` + User *RegisterUserInfo `protobuf:"bytes,7,opt,name=user,proto3" json:"user"` + RegisterToken string `protobuf:"bytes,8,opt,name=registerToken,proto3" json:"registerToken"` // H5注册token(可选,用于H5注册场景,验证手机号合法性) +} + +func (x *RegisterUserReq) Reset() { + *x = RegisterUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterUserReq) ProtoMessage() {} + +func (x *RegisterUserReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterUserReq.ProtoReflect.Descriptor instead. +func (*RegisterUserReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{16} +} + +func (x *RegisterUserReq) GetInvitationCode() string { + if x != nil { + return x.InvitationCode + } + return "" +} + +func (x *RegisterUserReq) GetVerifyCode() string { + if x != nil { + return x.VerifyCode + } + return "" +} + +func (x *RegisterUserReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *RegisterUserReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *RegisterUserReq) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *RegisterUserReq) GetAutoLogin() bool { + if x != nil { + return x.AutoLogin + } + return false +} + +func (x *RegisterUserReq) GetUser() *RegisterUserInfo { + if x != nil { + return x.User + } + return nil +} + +func (x *RegisterUserReq) GetRegisterToken() string { + if x != nil { + return x.RegisterToken + } + return "" +} + +type RegisterUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + ChatToken string `protobuf:"bytes,3,opt,name=chatToken,proto3" json:"chatToken"` +} + +func (x *RegisterUserResp) Reset() { + *x = RegisterUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterUserResp) ProtoMessage() {} + +func (x *RegisterUserResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterUserResp.ProtoReflect.Descriptor instead. +func (*RegisterUserResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{17} +} + +func (x *RegisterUserResp) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *RegisterUserResp) GetChatToken() string { + if x != nil { + return x.ChatToken + } + return "" +} + +type AddUserAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip"` + DeviceID string `protobuf:"bytes,2,opt,name=deviceID,proto3" json:"deviceID"` + Platform int32 `protobuf:"varint,3,opt,name=platform,proto3" json:"platform"` + User *RegisterUserInfo `protobuf:"bytes,4,opt,name=user,proto3" json:"user"` +} + +func (x *AddUserAccountReq) Reset() { + *x = AddUserAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUserAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUserAccountReq) ProtoMessage() {} + +func (x *AddUserAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddUserAccountReq.ProtoReflect.Descriptor instead. +func (*AddUserAccountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{18} +} + +func (x *AddUserAccountReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *AddUserAccountReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *AddUserAccountReq) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *AddUserAccountReq) GetUser() *RegisterUserInfo { + if x != nil { + return x.User + } + return nil +} + +type AddUserAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddUserAccountResp) Reset() { + *x = AddUserAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUserAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUserAccountResp) ProtoMessage() {} + +func (x *AddUserAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddUserAccountResp.ProtoReflect.Descriptor instead. +func (*AddUserAccountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{19} +} + +type LoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AreaCode string `protobuf:"bytes,1,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` + VerifyCode string `protobuf:"bytes,3,opt,name=verifyCode,proto3" json:"verifyCode"` + Account string `protobuf:"bytes,4,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password"` + Platform int32 `protobuf:"varint,6,opt,name=platform,proto3" json:"platform"` + DeviceID string `protobuf:"bytes,7,opt,name=deviceID,proto3" json:"deviceID"` + Ip string `protobuf:"bytes,8,opt,name=ip,proto3" json:"ip"` + Email string `protobuf:"bytes,9,opt,name=email,proto3" json:"email"` +} + +func (x *LoginReq) Reset() { + *x = LoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginReq) ProtoMessage() {} + +func (x *LoginReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginReq.ProtoReflect.Descriptor instead. +func (*LoginReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{20} +} + +func (x *LoginReq) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *LoginReq) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *LoginReq) GetVerifyCode() string { + if x != nil { + return x.VerifyCode + } + return "" +} + +func (x *LoginReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *LoginReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *LoginReq) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *LoginReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *LoginReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *LoginReq) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type ResetPasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AreaCode string `protobuf:"bytes,1,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber"` + VerifyCode string `protobuf:"bytes,3,opt,name=verifyCode,proto3" json:"verifyCode"` + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email"` +} + +func (x *ResetPasswordReq) Reset() { + *x = ResetPasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResetPasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetPasswordReq) ProtoMessage() {} + +func (x *ResetPasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetPasswordReq.ProtoReflect.Descriptor instead. +func (*ResetPasswordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{21} +} + +func (x *ResetPasswordReq) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *ResetPasswordReq) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *ResetPasswordReq) GetVerifyCode() string { + if x != nil { + return x.VerifyCode + } + return "" +} + +func (x *ResetPasswordReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *ResetPasswordReq) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type ResetPasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ResetPasswordResp) Reset() { + *x = ResetPasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResetPasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetPasswordResp) ProtoMessage() {} + +func (x *ResetPasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetPasswordResp.ProtoReflect.Descriptor instead. +func (*ResetPasswordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{22} +} + +type ChangePasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + CurrentPassword string `protobuf:"bytes,2,opt,name=currentPassword,proto3" json:"currentPassword"` + NewPassword string `protobuf:"bytes,3,opt,name=newPassword,proto3" json:"newPassword"` +} + +func (x *ChangePasswordReq) Reset() { + *x = ChangePasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordReq) ProtoMessage() {} + +func (x *ChangePasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordReq.ProtoReflect.Descriptor instead. +func (*ChangePasswordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{23} +} + +func (x *ChangePasswordReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *ChangePasswordReq) GetCurrentPassword() string { + if x != nil { + return x.CurrentPassword + } + return "" +} + +func (x *ChangePasswordReq) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +type ChangePasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChangePasswordResp) Reset() { + *x = ChangePasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordResp) ProtoMessage() {} + +func (x *ChangePasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordResp.ProtoReflect.Descriptor instead. +func (*ChangePasswordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{24} +} + +type FindUserAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *FindUserAccountReq) Reset() { + *x = FindUserAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserAccountReq) ProtoMessage() {} + +func (x *FindUserAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserAccountReq.ProtoReflect.Descriptor instead. +func (*FindUserAccountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{25} +} + +func (x *FindUserAccountReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type FindUserAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserAccountMap map[string]string `protobuf:"bytes,1,rep,name=userAccountMap,proto3" json:"userAccountMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // userID account +} + +func (x *FindUserAccountResp) Reset() { + *x = FindUserAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindUserAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindUserAccountResp) ProtoMessage() {} + +func (x *FindUserAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindUserAccountResp.ProtoReflect.Descriptor instead. +func (*FindUserAccountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{26} +} + +func (x *FindUserAccountResp) GetUserAccountMap() map[string]string { + if x != nil { + return x.UserAccountMap + } + return nil +} + +type FindAccountUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Accounts []string `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts"` +} + +func (x *FindAccountUserReq) Reset() { + *x = FindAccountUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindAccountUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindAccountUserReq) ProtoMessage() {} + +func (x *FindAccountUserReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindAccountUserReq.ProtoReflect.Descriptor instead. +func (*FindAccountUserReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{27} +} + +func (x *FindAccountUserReq) GetAccounts() []string { + if x != nil { + return x.Accounts + } + return nil +} + +type FindAccountUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccountUserMap map[string]string `protobuf:"bytes,1,rep,name=accountUserMap,proto3" json:"accountUserMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // account userID +} + +func (x *FindAccountUserResp) Reset() { + *x = FindAccountUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindAccountUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindAccountUserResp) ProtoMessage() {} + +func (x *FindAccountUserResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindAccountUserResp.ProtoReflect.Descriptor instead. +func (*FindAccountUserResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{28} +} + +func (x *FindAccountUserResp) GetAccountUserMap() map[string]string { + if x != nil { + return x.AccountUserMap + } + return nil +} + +type SignalRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FileName string `protobuf:"bytes,1,opt,name=fileName,proto3" json:"fileName"` + MediaType string `protobuf:"bytes,2,opt,name=mediaType,proto3" json:"mediaType"` + RoomType string `protobuf:"bytes,3,opt,name=roomType,proto3" json:"roomType"` + SenderID string `protobuf:"bytes,4,opt,name=senderID,proto3" json:"senderID"` + SenderNickname string `protobuf:"bytes,5,opt,name=senderNickname,proto3" json:"senderNickname"` + RecvID string `protobuf:"bytes,6,opt,name=recvID,proto3" json:"recvID"` + RecvNickname string `protobuf:"bytes,7,opt,name=recvNickname,proto3" json:"recvNickname"` + GroupID string `protobuf:"bytes,8,opt,name=groupID,proto3" json:"groupID"` + GroupName string `protobuf:"bytes,9,opt,name=groupName,proto3" json:"groupName"` + InviterUserList []*common.UserPublicInfo `protobuf:"bytes,10,rep,name=inviterUserList,proto3" json:"inviterUserList"` + Duration int32 `protobuf:"varint,11,opt,name=duration,proto3" json:"duration"` + CreateTime int64 `protobuf:"varint,12,opt,name=createTime,proto3" json:"createTime"` + Size string `protobuf:"bytes,13,opt,name=size,proto3" json:"size"` + DownloadURL string `protobuf:"bytes,14,opt,name=downloadURL,proto3" json:"downloadURL"` +} + +func (x *SignalRecord) Reset() { + *x = SignalRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalRecord) ProtoMessage() {} + +func (x *SignalRecord) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalRecord.ProtoReflect.Descriptor instead. +func (*SignalRecord) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{29} +} + +func (x *SignalRecord) GetFileName() string { + if x != nil { + return x.FileName + } + return "" +} + +func (x *SignalRecord) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *SignalRecord) GetRoomType() string { + if x != nil { + return x.RoomType + } + return "" +} + +func (x *SignalRecord) GetSenderID() string { + if x != nil { + return x.SenderID + } + return "" +} + +func (x *SignalRecord) GetSenderNickname() string { + if x != nil { + return x.SenderNickname + } + return "" +} + +func (x *SignalRecord) GetRecvID() string { + if x != nil { + return x.RecvID + } + return "" +} + +func (x *SignalRecord) GetRecvNickname() string { + if x != nil { + return x.RecvNickname + } + return "" +} + +func (x *SignalRecord) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *SignalRecord) GetGroupName() string { + if x != nil { + return x.GroupName + } + return "" +} + +func (x *SignalRecord) GetInviterUserList() []*common.UserPublicInfo { + if x != nil { + return x.InviterUserList + } + return nil +} + +func (x *SignalRecord) GetDuration() int32 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *SignalRecord) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SignalRecord) GetSize() string { + if x != nil { + return x.Size + } + return "" +} + +func (x *SignalRecord) GetDownloadURL() string { + if x != nil { + return x.DownloadURL + } + return "" +} + +type OpenIMCallbackReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command"` + Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body"` +} + +func (x *OpenIMCallbackReq) Reset() { + *x = OpenIMCallbackReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenIMCallbackReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenIMCallbackReq) ProtoMessage() {} + +func (x *OpenIMCallbackReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenIMCallbackReq.ProtoReflect.Descriptor instead. +func (*OpenIMCallbackReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{30} +} + +func (x *OpenIMCallbackReq) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *OpenIMCallbackReq) GetBody() string { + if x != nil { + return x.Body + } + return "" +} + +type OpenIMCallbackResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *OpenIMCallbackResp) Reset() { + *x = OpenIMCallbackResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OpenIMCallbackResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpenIMCallbackResp) ProtoMessage() {} + +func (x *OpenIMCallbackResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpenIMCallbackResp.ProtoReflect.Descriptor instead. +func (*OpenIMCallbackResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{31} +} + +type SearchUserFullInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` + Genders int32 `protobuf:"varint,3,opt,name=genders,proto3" json:"genders"` + Normal int32 `protobuf:"varint,4,opt,name=normal,proto3" json:"normal"` + StartTime int64 `protobuf:"varint,5,opt,name=startTime,proto3" json:"startTime"` // 注册时间范围开始时间(毫秒时间戳) + EndTime int64 `protobuf:"varint,6,opt,name=endTime,proto3" json:"endTime"` // 注册时间范围结束时间(毫秒时间戳) + RealNameKeyword string `protobuf:"bytes,7,opt,name=realNameKeyword,proto3" json:"realNameKeyword"` // 真实姓名搜索关键词(可选) + IdCardKeyword string `protobuf:"bytes,8,opt,name=idCardKeyword,proto3" json:"idCardKeyword"` // 身份证号搜索关键词(可选) +} + +func (x *SearchUserFullInfoReq) Reset() { + *x = SearchUserFullInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserFullInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserFullInfoReq) ProtoMessage() {} + +func (x *SearchUserFullInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserFullInfoReq.ProtoReflect.Descriptor instead. +func (*SearchUserFullInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{32} +} + +func (x *SearchUserFullInfoReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchUserFullInfoReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *SearchUserFullInfoReq) GetGenders() int32 { + if x != nil { + return x.Genders + } + return 0 +} + +func (x *SearchUserFullInfoReq) GetNormal() int32 { + if x != nil { + return x.Normal + } + return 0 +} + +func (x *SearchUserFullInfoReq) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *SearchUserFullInfoReq) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +func (x *SearchUserFullInfoReq) GetRealNameKeyword() string { + if x != nil { + return x.RealNameKeyword + } + return "" +} + +func (x *SearchUserFullInfoReq) GetIdCardKeyword() string { + if x != nil { + return x.IdCardKeyword + } + return "" +} + +type SearchUserFullInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Users []*common.UserFullInfo `protobuf:"bytes,2,rep,name=users,proto3" json:"users"` +} + +func (x *SearchUserFullInfoResp) Reset() { + *x = SearchUserFullInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserFullInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserFullInfoResp) ProtoMessage() {} + +func (x *SearchUserFullInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserFullInfoResp.ProtoReflect.Descriptor instead. +func (*SearchUserFullInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{33} +} + +func (x *SearchUserFullInfoResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchUserFullInfoResp) GetUsers() []*common.UserFullInfo { + if x != nil { + return x.Users + } + return nil +} + +type UserLoginCountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start"` + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end"` +} + +func (x *UserLoginCountReq) Reset() { + *x = UserLoginCountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserLoginCountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserLoginCountReq) ProtoMessage() {} + +func (x *UserLoginCountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserLoginCountReq.ProtoReflect.Descriptor instead. +func (*UserLoginCountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{34} +} + +func (x *UserLoginCountReq) GetStart() int64 { + if x != nil { + return x.Start + } + return 0 +} + +func (x *UserLoginCountReq) GetEnd() int64 { + if x != nil { + return x.End + } + return 0 +} + +type UserLoginCountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LoginCount int64 `protobuf:"varint,1,opt,name=loginCount,proto3" json:"loginCount"` + UnloginCount int64 `protobuf:"varint,2,opt,name=unloginCount,proto3" json:"unloginCount"` + Count map[string]int64 `protobuf:"bytes,3,rep,name=count,proto3" json:"count,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` +} + +func (x *UserLoginCountResp) Reset() { + *x = UserLoginCountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserLoginCountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserLoginCountResp) ProtoMessage() {} + +func (x *UserLoginCountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserLoginCountResp.ProtoReflect.Descriptor instead. +func (*UserLoginCountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{35} +} + +func (x *UserLoginCountResp) GetLoginCount() int64 { + if x != nil { + return x.LoginCount + } + return 0 +} + +func (x *UserLoginCountResp) GetUnloginCount() int64 { + if x != nil { + return x.UnloginCount + } + return 0 +} + +func (x *UserLoginCountResp) GetCount() map[string]int64 { + if x != nil { + return x.Count + } + return nil +} + +type LoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ChatToken string `protobuf:"bytes,2,opt,name=chatToken,proto3" json:"chatToken"` + UserID string `protobuf:"bytes,3,opt,name=userID,proto3" json:"userID"` +} + +func (x *LoginResp) Reset() { + *x = LoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginResp) ProtoMessage() {} + +func (x *LoginResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginResp.ProtoReflect.Descriptor instead. +func (*LoginResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{36} +} + +func (x *LoginResp) GetChatToken() string { + if x != nil { + return x.ChatToken + } + return "" +} + +func (x *LoginResp) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type SearchUserInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` + Genders []int32 `protobuf:"varint,3,rep,packed,name=genders,proto3" json:"genders"` + UserIDs []string `protobuf:"bytes,4,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *SearchUserInfoReq) Reset() { + *x = SearchUserInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserInfoReq) ProtoMessage() {} + +func (x *SearchUserInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserInfoReq.ProtoReflect.Descriptor instead. +func (*SearchUserInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{37} +} + +func (x *SearchUserInfoReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchUserInfoReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *SearchUserInfoReq) GetGenders() []int32 { + if x != nil { + return x.Genders + } + return nil +} + +func (x *SearchUserInfoReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type SearchUserInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Users []*common.UserFullInfo `protobuf:"bytes,2,rep,name=users,proto3" json:"users"` +} + +func (x *SearchUserInfoResp) Reset() { + *x = SearchUserInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchUserInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchUserInfoResp) ProtoMessage() {} + +func (x *SearchUserInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchUserInfoResp.ProtoReflect.Descriptor instead. +func (*SearchUserInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{38} +} + +func (x *SearchUserInfoResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchUserInfoResp) GetUsers() []*common.UserFullInfo { + if x != nil { + return x.Users + } + return nil +} + +type GetTokenForVideoMeetingReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Room string `protobuf:"bytes,1,opt,name=room,proto3" json:"room"` + Identity string `protobuf:"bytes,2,opt,name=identity,proto3" json:"identity"` +} + +func (x *GetTokenForVideoMeetingReq) Reset() { + *x = GetTokenForVideoMeetingReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTokenForVideoMeetingReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTokenForVideoMeetingReq) ProtoMessage() {} + +func (x *GetTokenForVideoMeetingReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTokenForVideoMeetingReq.ProtoReflect.Descriptor instead. +func (*GetTokenForVideoMeetingReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{39} +} + +func (x *GetTokenForVideoMeetingReq) GetRoom() string { + if x != nil { + return x.Room + } + return "" +} + +func (x *GetTokenForVideoMeetingReq) GetIdentity() string { + if x != nil { + return x.Identity + } + return "" +} + +type GetTokenForVideoMeetingResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServerUrl string `protobuf:"bytes,1,opt,name=serverUrl,proto3" json:"serverUrl"` + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token"` +} + +func (x *GetTokenForVideoMeetingResp) Reset() { + *x = GetTokenForVideoMeetingResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTokenForVideoMeetingResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTokenForVideoMeetingResp) ProtoMessage() {} + +func (x *GetTokenForVideoMeetingResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTokenForVideoMeetingResp.ProtoReflect.Descriptor instead. +func (*GetTokenForVideoMeetingResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{40} +} + +func (x *GetTokenForVideoMeetingResp) GetServerUrl() string { + if x != nil { + return x.ServerUrl + } + return "" +} + +func (x *GetTokenForVideoMeetingResp) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type CheckUserExistReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *RegisterUserInfo `protobuf:"bytes,1,opt,name=user,proto3" json:"user"` +} + +func (x *CheckUserExistReq) Reset() { + *x = CheckUserExistReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckUserExistReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckUserExistReq) ProtoMessage() {} + +func (x *CheckUserExistReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckUserExistReq.ProtoReflect.Descriptor instead. +func (*CheckUserExistReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{41} +} + +func (x *CheckUserExistReq) GetUser() *RegisterUserInfo { + if x != nil { + return x.User + } + return nil +} + +type CheckUserExistResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Userid string `protobuf:"bytes,1,opt,name=userid,proto3" json:"userid"` + IsRegistered bool `protobuf:"varint,2,opt,name=isRegistered,proto3" json:"isRegistered"` +} + +func (x *CheckUserExistResp) Reset() { + *x = CheckUserExistResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckUserExistResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckUserExistResp) ProtoMessage() {} + +func (x *CheckUserExistResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckUserExistResp.ProtoReflect.Descriptor instead. +func (*CheckUserExistResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{42} +} + +func (x *CheckUserExistResp) GetUserid() string { + if x != nil { + return x.Userid + } + return "" +} + +func (x *CheckUserExistResp) GetIsRegistered() bool { + if x != nil { + return x.IsRegistered + } + return false +} + +type DelUserAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` +} + +func (x *DelUserAccountReq) Reset() { + *x = DelUserAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelUserAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelUserAccountReq) ProtoMessage() {} + +func (x *DelUserAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelUserAccountReq.ProtoReflect.Descriptor instead. +func (*DelUserAccountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{43} +} + +func (x *DelUserAccountReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type DelUserAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DelUserAccountResp) Reset() { + *x = DelUserAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DelUserAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DelUserAccountResp) ProtoMessage() {} + +func (x *DelUserAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DelUserAccountResp.ProtoReflect.Descriptor instead. +func (*DelUserAccountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{44} +} + +type SetAllowRegisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AllowRegister bool `protobuf:"varint,1,opt,name=allowRegister,proto3" json:"allowRegister"` +} + +func (x *SetAllowRegisterReq) Reset() { + *x = SetAllowRegisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetAllowRegisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetAllowRegisterReq) ProtoMessage() {} + +func (x *SetAllowRegisterReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetAllowRegisterReq.ProtoReflect.Descriptor instead. +func (*SetAllowRegisterReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{45} +} + +func (x *SetAllowRegisterReq) GetAllowRegister() bool { + if x != nil { + return x.AllowRegister + } + return false +} + +type SetAllowRegisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetAllowRegisterResp) Reset() { + *x = SetAllowRegisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetAllowRegisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetAllowRegisterResp) ProtoMessage() {} + +func (x *SetAllowRegisterResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetAllowRegisterResp.ProtoReflect.Descriptor instead. +func (*SetAllowRegisterResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{46} +} + +type GetAllowRegisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAllowRegisterReq) Reset() { + *x = GetAllowRegisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllowRegisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllowRegisterReq) ProtoMessage() {} + +func (x *GetAllowRegisterReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllowRegisterReq.ProtoReflect.Descriptor instead. +func (*GetAllowRegisterReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{47} +} + +type GetAllowRegisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AllowRegister bool `protobuf:"varint,1,opt,name=allowRegister,proto3" json:"allowRegister"` +} + +func (x *GetAllowRegisterResp) Reset() { + *x = GetAllowRegisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllowRegisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllowRegisterResp) ProtoMessage() {} + +func (x *GetAllowRegisterResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllowRegisterResp.ProtoReflect.Descriptor instead. +func (*GetAllowRegisterResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{48} +} + +func (x *GetAllowRegisterResp) GetAllowRegister() bool { + if x != nil { + return x.AllowRegister + } + return false +} + +// 敏感词信息(简化版,客户端用) +type SensitiveWordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word string `protobuf:"bytes,1,opt,name=word,proto3" json:"word"` // 敏感词内容 + Action int32 `protobuf:"varint,2,opt,name=action,proto3" json:"action"` // 处理动作 1:替换为*** 2:拦截不发 + ReplaceChar string `protobuf:"bytes,3,opt,name=replaceChar,proto3" json:"replaceChar"` // 替换字符 +} + +func (x *SensitiveWordInfo) Reset() { + *x = SensitiveWordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordInfo) ProtoMessage() {} + +func (x *SensitiveWordInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{49} +} + +func (x *SensitiveWordInfo) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *SensitiveWordInfo) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SensitiveWordInfo) GetReplaceChar() string { + if x != nil { + return x.ReplaceChar + } + return "" +} + +// 获取敏感词列表请求 +type GetSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSensitiveWordsReq) Reset() { + *x = GetSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordsReq) ProtoMessage() {} + +func (x *GetSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[50] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{50} +} + +// 获取敏感词列表响应 +type GetSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Words []*SensitiveWordInfo `protobuf:"bytes,1,rep,name=words,proto3" json:"words"` // 敏感词列表 + EnableFilter bool `protobuf:"varint,2,opt,name=enableFilter,proto3" json:"enableFilter"` // 是否启用过滤 + DefaultReplaceChar string `protobuf:"bytes,3,opt,name=defaultReplaceChar,proto3" json:"defaultReplaceChar"` // 默认替换字符 +} + +func (x *GetSensitiveWordsResp) Reset() { + *x = GetSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordsResp) ProtoMessage() {} + +func (x *GetSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[51] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{51} +} + +func (x *GetSensitiveWordsResp) GetWords() []*SensitiveWordInfo { + if x != nil { + return x.Words + } + return nil +} + +func (x *GetSensitiveWordsResp) GetEnableFilter() bool { + if x != nil { + return x.EnableFilter + } + return false +} + +func (x *GetSensitiveWordsResp) GetDefaultReplaceChar() string { + if x != nil { + return x.DefaultReplaceChar + } + return "" +} + +// 检测敏感词请求(用户发送消息时调用) +type CheckSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content"` // 要检测的内容 +} + +func (x *CheckSensitiveWordsReq) Reset() { + *x = CheckSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckSensitiveWordsReq) ProtoMessage() {} + +func (x *CheckSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[52] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*CheckSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{52} +} + +func (x *CheckSensitiveWordsReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +// 检测敏感词响应 +type CheckSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HasSensitive bool `protobuf:"varint,1,opt,name=hasSensitive,proto3" json:"hasSensitive"` // 是否包含敏感词 + FilteredContent string `protobuf:"bytes,2,opt,name=filteredContent,proto3" json:"filteredContent"` // 过滤后的内容(如果被替换) + MatchedWords []string `protobuf:"bytes,3,rep,name=matchedWords,proto3" json:"matchedWords"` // 匹配到的敏感词列表 +} + +func (x *CheckSensitiveWordsResp) Reset() { + *x = CheckSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckSensitiveWordsResp) ProtoMessage() {} + +func (x *CheckSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[53] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*CheckSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{53} +} + +func (x *CheckSensitiveWordsResp) GetHasSensitive() bool { + if x != nil { + return x.HasSensitive + } + return false +} + +func (x *CheckSensitiveWordsResp) GetFilteredContent() string { + if x != nil { + return x.FilteredContent + } + return "" +} + +func (x *CheckSensitiveWordsResp) GetMatchedWords() []string { + if x != nil { + return x.MatchedWords + } + return nil +} + +// 敏感词详细信息(管理端) +type SensitiveWordDetailInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Word string `protobuf:"bytes,2,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,5,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` + Creator string `protobuf:"bytes,7,opt,name=creator,proto3" json:"creator"` + Updater string `protobuf:"bytes,8,opt,name=updater,proto3" json:"updater"` + CreateTime int64 `protobuf:"varint,9,opt,name=create_time,json=createTime,proto3" json:"create_time"` + UpdateTime int64 `protobuf:"varint,10,opt,name=update_time,json=updateTime,proto3" json:"update_time"` + Remark string `protobuf:"bytes,11,opt,name=remark,proto3" json:"remark"` +} + +func (x *SensitiveWordDetailInfo) Reset() { + *x = SensitiveWordDetailInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordDetailInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordDetailInfo) ProtoMessage() {} + +func (x *SensitiveWordDetailInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordDetailInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordDetailInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{54} +} + +func (x *SensitiveWordDetailInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordDetailInfo) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *SensitiveWordDetailInfo) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetCreator() string { + if x != nil { + return x.Creator + } + return "" +} + +func (x *SensitiveWordDetailInfo) GetUpdater() string { + if x != nil { + return x.Updater + } + return "" +} + +func (x *SensitiveWordDetailInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +func (x *SensitiveWordDetailInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +// 敏感词分组信息 +type SensitiveWordGroupInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark"` + CreateTime int64 `protobuf:"varint,4,opt,name=create_time,json=createTime,proto3" json:"create_time"` + UpdateTime int64 `protobuf:"varint,5,opt,name=update_time,json=updateTime,proto3" json:"update_time"` +} + +func (x *SensitiveWordGroupInfo) Reset() { + *x = SensitiveWordGroupInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordGroupInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordGroupInfo) ProtoMessage() {} + +func (x *SensitiveWordGroupInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordGroupInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordGroupInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{55} +} + +func (x *SensitiveWordGroupInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *SensitiveWordGroupInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *SensitiveWordGroupInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 敏感词配置信息 +type SensitiveWordConfigInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + EnableFilter bool `protobuf:"varint,2,opt,name=enable_filter,json=enableFilter,proto3" json:"enable_filter"` + FilterMode int32 `protobuf:"varint,3,opt,name=filter_mode,json=filterMode,proto3" json:"filter_mode"` + ReplaceChar string `protobuf:"bytes,4,opt,name=replace_char,json=replaceChar,proto3" json:"replace_char"` + WhitelistUsers []string `protobuf:"bytes,5,rep,name=whitelist_users,json=whitelistUsers,proto3" json:"whitelist_users"` + WhitelistGroups []string `protobuf:"bytes,6,rep,name=whitelist_groups,json=whitelistGroups,proto3" json:"whitelist_groups"` + LogEnabled bool `protobuf:"varint,7,opt,name=log_enabled,json=logEnabled,proto3" json:"log_enabled"` + AutoApprove bool `protobuf:"varint,8,opt,name=auto_approve,json=autoApprove,proto3" json:"auto_approve"` + UpdateTime int64 `protobuf:"varint,9,opt,name=update_time,json=updateTime,proto3" json:"update_time"` +} + +func (x *SensitiveWordConfigInfo) Reset() { + *x = SensitiveWordConfigInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordConfigInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordConfigInfo) ProtoMessage() {} + +func (x *SensitiveWordConfigInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[56] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordConfigInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordConfigInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{56} +} + +func (x *SensitiveWordConfigInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordConfigInfo) GetEnableFilter() bool { + if x != nil { + return x.EnableFilter + } + return false +} + +func (x *SensitiveWordConfigInfo) GetFilterMode() int32 { + if x != nil { + return x.FilterMode + } + return 0 +} + +func (x *SensitiveWordConfigInfo) GetReplaceChar() string { + if x != nil { + return x.ReplaceChar + } + return "" +} + +func (x *SensitiveWordConfigInfo) GetWhitelistUsers() []string { + if x != nil { + return x.WhitelistUsers + } + return nil +} + +func (x *SensitiveWordConfigInfo) GetWhitelistGroups() []string { + if x != nil { + return x.WhitelistGroups + } + return nil +} + +func (x *SensitiveWordConfigInfo) GetLogEnabled() bool { + if x != nil { + return x.LogEnabled + } + return false +} + +func (x *SensitiveWordConfigInfo) GetAutoApprove() bool { + if x != nil { + return x.AutoApprove + } + return false +} + +func (x *SensitiveWordConfigInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 敏感词日志信息 +type SensitiveWordLogInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id"` + GroupId string `protobuf:"bytes,3,opt,name=group_id,json=groupId,proto3" json:"group_id"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content"` + MatchedWords []string `protobuf:"bytes,5,rep,name=matched_words,json=matchedWords,proto3" json:"matched_words"` + Action int32 `protobuf:"varint,6,opt,name=action,proto3" json:"action"` + ProcessedText string `protobuf:"bytes,7,opt,name=processed_text,json=processedText,proto3" json:"processed_text"` + CreateTime int64 `protobuf:"varint,8,opt,name=create_time,json=createTime,proto3" json:"create_time"` +} + +func (x *SensitiveWordLogInfo) Reset() { + *x = SensitiveWordLogInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordLogInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordLogInfo) ProtoMessage() {} + +func (x *SensitiveWordLogInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[57] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordLogInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordLogInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{57} +} + +func (x *SensitiveWordLogInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SensitiveWordLogInfo) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *SensitiveWordLogInfo) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *SensitiveWordLogInfo) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *SensitiveWordLogInfo) GetMatchedWords() []string { + if x != nil { + return x.MatchedWords + } + return nil +} + +func (x *SensitiveWordLogInfo) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SensitiveWordLogInfo) GetProcessedText() string { + if x != nil { + return x.ProcessedText + } + return "" +} + +func (x *SensitiveWordLogInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +// 敏感词统计信息 +type SensitiveWordStatsInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Enabled int64 `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled"` + Disabled int64 `protobuf:"varint,3,opt,name=disabled,proto3" json:"disabled"` + Replace int64 `protobuf:"varint,4,opt,name=replace,proto3" json:"replace"` + Block int64 `protobuf:"varint,5,opt,name=block,proto3" json:"block"` +} + +func (x *SensitiveWordStatsInfo) Reset() { + *x = SensitiveWordStatsInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordStatsInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordStatsInfo) ProtoMessage() {} + +func (x *SensitiveWordStatsInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[58] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordStatsInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordStatsInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{58} +} + +func (x *SensitiveWordStatsInfo) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetEnabled() int64 { + if x != nil { + return x.Enabled + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetDisabled() int64 { + if x != nil { + return x.Disabled + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetReplace() int64 { + if x != nil { + return x.Replace + } + return 0 +} + +func (x *SensitiveWordStatsInfo) GetBlock() int64 { + if x != nil { + return x.Block + } + return 0 +} + +// 敏感词日志统计信息 +type SensitiveWordLogStatsInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Replace int64 `protobuf:"varint,2,opt,name=replace,proto3" json:"replace"` + Block int64 `protobuf:"varint,3,opt,name=block,proto3" json:"block"` +} + +func (x *SensitiveWordLogStatsInfo) Reset() { + *x = SensitiveWordLogStatsInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SensitiveWordLogStatsInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SensitiveWordLogStatsInfo) ProtoMessage() {} + +func (x *SensitiveWordLogStatsInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[59] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SensitiveWordLogStatsInfo.ProtoReflect.Descriptor instead. +func (*SensitiveWordLogStatsInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{59} +} + +func (x *SensitiveWordLogStatsInfo) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SensitiveWordLogStatsInfo) GetReplace() int64 { + if x != nil { + return x.Replace + } + return 0 +} + +func (x *SensitiveWordLogStatsInfo) GetBlock() int64 { + if x != nil { + return x.Block + } + return 0 +} + +// 添加敏感词 +type AddSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word string `protobuf:"bytes,1,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,2,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,3,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,4,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,5,opt,name=status,proto3" json:"status"` + Remark string `protobuf:"bytes,6,opt,name=remark,proto3" json:"remark"` +} + +func (x *AddSensitiveWordReq) Reset() { + *x = AddSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordReq) ProtoMessage() {} + +func (x *AddSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[60] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{60} +} + +func (x *AddSensitiveWordReq) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *AddSensitiveWordReq) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *AddSensitiveWordReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *AddSensitiveWordReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *AddSensitiveWordReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *AddSensitiveWordReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type AddSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddSensitiveWordResp) Reset() { + *x = AddSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordResp) ProtoMessage() {} + +func (x *AddSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[61] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{61} +} + +// 更新敏感词 +type UpdateSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Word string `protobuf:"bytes,2,opt,name=word,proto3" json:"word"` + Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level"` + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` + Action int32 `protobuf:"varint,5,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` + Remark string `protobuf:"bytes,7,opt,name=remark,proto3" json:"remark"` +} + +func (x *UpdateSensitiveWordReq) Reset() { + *x = UpdateSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[62] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{62} +} + +func (x *UpdateSensitiveWordReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateSensitiveWordReq) GetWord() string { + if x != nil { + return x.Word + } + return "" +} + +func (x *UpdateSensitiveWordReq) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *UpdateSensitiveWordReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type UpdateSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordResp) Reset() { + *x = UpdateSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[63] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{63} +} + +// 删除敏感词 +type DeleteSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordReq) Reset() { + *x = DeleteSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{64} +} + +func (x *DeleteSensitiveWordReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordResp) Reset() { + *x = DeleteSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{65} +} + +// 获取敏感词 +type GetSensitiveWordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` +} + +func (x *GetSensitiveWordReq) Reset() { + *x = GetSensitiveWordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordReq) ProtoMessage() {} + +func (x *GetSensitiveWordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{66} +} + +func (x *GetSensitiveWordReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetSensitiveWordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word *SensitiveWordDetailInfo `protobuf:"bytes,1,opt,name=word,proto3" json:"word"` +} + +func (x *GetSensitiveWordResp) Reset() { + *x = GetSensitiveWordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordResp) ProtoMessage() {} + +func (x *GetSensitiveWordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[67] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{67} +} + +func (x *GetSensitiveWordResp) GetWord() *SensitiveWordDetailInfo { + if x != nil { + return x.Word + } + return nil +} + +// 搜索敏感词 +type SearchSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` + Action int32 `protobuf:"varint,2,opt,name=action,proto3" json:"action"` + Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *SearchSensitiveWordsReq) Reset() { + *x = SearchSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchSensitiveWordsReq) ProtoMessage() {} + +func (x *SearchSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[68] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*SearchSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{68} +} + +func (x *SearchSensitiveWordsReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchSensitiveWordsReq) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *SearchSensitiveWordsReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *SearchSensitiveWordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Words []*SensitiveWordDetailInfo `protobuf:"bytes,2,rep,name=words,proto3" json:"words"` +} + +func (x *SearchSensitiveWordsResp) Reset() { + *x = SearchSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchSensitiveWordsResp) ProtoMessage() {} + +func (x *SearchSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[69] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*SearchSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{69} +} + +func (x *SearchSensitiveWordsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchSensitiveWordsResp) GetWords() []*SensitiveWordDetailInfo { + if x != nil { + return x.Words + } + return nil +} + +// 批量添加敏感词 +type BatchAddSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Words []*SensitiveWordDetailInfo `protobuf:"bytes,1,rep,name=words,proto3" json:"words"` +} + +func (x *BatchAddSensitiveWordsReq) Reset() { + *x = BatchAddSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchAddSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchAddSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchAddSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchAddSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchAddSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{70} +} + +func (x *BatchAddSensitiveWordsReq) GetWords() []*SensitiveWordDetailInfo { + if x != nil { + return x.Words + } + return nil +} + +type BatchAddSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchAddSensitiveWordsResp) Reset() { + *x = BatchAddSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchAddSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchAddSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchAddSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[71] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchAddSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchAddSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{71} +} + +// 批量更新敏感词 +type BatchUpdateSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Updates map[string]*SensitiveWordDetailInfo `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *BatchUpdateSensitiveWordsReq) Reset() { + *x = BatchUpdateSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchUpdateSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[72] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchUpdateSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{72} +} + +func (x *BatchUpdateSensitiveWordsReq) GetUpdates() map[string]*SensitiveWordDetailInfo { + if x != nil { + return x.Updates + } + return nil +} + +type BatchUpdateSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchUpdateSensitiveWordsResp) Reset() { + *x = BatchUpdateSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchUpdateSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchUpdateSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchUpdateSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{73} +} + +// 批量删除敏感词 +type BatchDeleteSensitiveWordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *BatchDeleteSensitiveWordsReq) Reset() { + *x = BatchDeleteSensitiveWordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchDeleteSensitiveWordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchDeleteSensitiveWordsReq) ProtoMessage() {} + +func (x *BatchDeleteSensitiveWordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[74] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchDeleteSensitiveWordsReq.ProtoReflect.Descriptor instead. +func (*BatchDeleteSensitiveWordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{74} +} + +func (x *BatchDeleteSensitiveWordsReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type BatchDeleteSensitiveWordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchDeleteSensitiveWordsResp) Reset() { + *x = BatchDeleteSensitiveWordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchDeleteSensitiveWordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchDeleteSensitiveWordsResp) ProtoMessage() {} + +func (x *BatchDeleteSensitiveWordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[75] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BatchDeleteSensitiveWordsResp.ProtoReflect.Descriptor instead. +func (*BatchDeleteSensitiveWordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{75} +} + +// 添加敏感词分组 +type AddSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,2,opt,name=remark,proto3" json:"remark"` +} + +func (x *AddSensitiveWordGroupReq) Reset() { + *x = AddSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordGroupReq) ProtoMessage() {} + +func (x *AddSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[76] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{76} +} + +func (x *AddSensitiveWordGroupReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddSensitiveWordGroupReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type AddSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddSensitiveWordGroupResp) Reset() { + *x = AddSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSensitiveWordGroupResp) ProtoMessage() {} + +func (x *AddSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[77] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*AddSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{77} +} + +// 更新敏感词分组 +type UpdateSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark"` +} + +func (x *UpdateSensitiveWordGroupReq) Reset() { + *x = UpdateSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordGroupReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[78] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{78} +} + +func (x *UpdateSensitiveWordGroupReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateSensitiveWordGroupReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateSensitiveWordGroupReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type UpdateSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordGroupResp) Reset() { + *x = UpdateSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordGroupResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[79] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{79} +} + +// 删除敏感词分组 +type DeleteSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordGroupReq) Reset() { + *x = DeleteSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordGroupReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[80] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{80} +} + +func (x *DeleteSensitiveWordGroupReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordGroupResp) Reset() { + *x = DeleteSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[81] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordGroupResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[81] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{81} +} + +// 获取敏感词分组 +type GetSensitiveWordGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` +} + +func (x *GetSensitiveWordGroupReq) Reset() { + *x = GetSensitiveWordGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[82] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordGroupReq) ProtoMessage() {} + +func (x *GetSensitiveWordGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[82] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordGroupReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordGroupReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{82} +} + +func (x *GetSensitiveWordGroupReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetSensitiveWordGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group *SensitiveWordGroupInfo `protobuf:"bytes,1,opt,name=group,proto3" json:"group"` +} + +func (x *GetSensitiveWordGroupResp) Reset() { + *x = GetSensitiveWordGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[83] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordGroupResp) ProtoMessage() {} + +func (x *GetSensitiveWordGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[83] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordGroupResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordGroupResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{83} +} + +func (x *GetSensitiveWordGroupResp) GetGroup() *SensitiveWordGroupInfo { + if x != nil { + return x.Group + } + return nil +} + +// 获取所有敏感词分组 +type GetAllSensitiveWordGroupsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAllSensitiveWordGroupsReq) Reset() { + *x = GetAllSensitiveWordGroupsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[84] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSensitiveWordGroupsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSensitiveWordGroupsReq) ProtoMessage() {} + +func (x *GetAllSensitiveWordGroupsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[84] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSensitiveWordGroupsReq.ProtoReflect.Descriptor instead. +func (*GetAllSensitiveWordGroupsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{84} +} + +type GetAllSensitiveWordGroupsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Groups []*SensitiveWordGroupInfo `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups"` +} + +func (x *GetAllSensitiveWordGroupsResp) Reset() { + *x = GetAllSensitiveWordGroupsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[85] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllSensitiveWordGroupsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllSensitiveWordGroupsResp) ProtoMessage() {} + +func (x *GetAllSensitiveWordGroupsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[85] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllSensitiveWordGroupsResp.ProtoReflect.Descriptor instead. +func (*GetAllSensitiveWordGroupsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{85} +} + +func (x *GetAllSensitiveWordGroupsResp) GetGroups() []*SensitiveWordGroupInfo { + if x != nil { + return x.Groups + } + return nil +} + +// 获取敏感词配置 +type GetSensitiveWordConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSensitiveWordConfigReq) Reset() { + *x = GetSensitiveWordConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[86] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordConfigReq) ProtoMessage() {} + +func (x *GetSensitiveWordConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[86] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordConfigReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordConfigReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{86} +} + +type GetSensitiveWordConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *SensitiveWordConfigInfo `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` +} + +func (x *GetSensitiveWordConfigResp) Reset() { + *x = GetSensitiveWordConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[87] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordConfigResp) ProtoMessage() {} + +func (x *GetSensitiveWordConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[87] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordConfigResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordConfigResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{87} +} + +func (x *GetSensitiveWordConfigResp) GetConfig() *SensitiveWordConfigInfo { + if x != nil { + return x.Config + } + return nil +} + +// 更新敏感词配置 +type UpdateSensitiveWordConfigReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *SensitiveWordConfigInfo `protobuf:"bytes,1,opt,name=config,proto3" json:"config"` +} + +func (x *UpdateSensitiveWordConfigReq) Reset() { + *x = UpdateSensitiveWordConfigReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[88] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordConfigReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordConfigReq) ProtoMessage() {} + +func (x *UpdateSensitiveWordConfigReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[88] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordConfigReq.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordConfigReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{88} +} + +func (x *UpdateSensitiveWordConfigReq) GetConfig() *SensitiveWordConfigInfo { + if x != nil { + return x.Config + } + return nil +} + +type UpdateSensitiveWordConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateSensitiveWordConfigResp) Reset() { + *x = UpdateSensitiveWordConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[89] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateSensitiveWordConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSensitiveWordConfigResp) ProtoMessage() {} + +func (x *UpdateSensitiveWordConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[89] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateSensitiveWordConfigResp.ProtoReflect.Descriptor instead. +func (*UpdateSensitiveWordConfigResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{89} +} + +// 获取敏感词日志 +type GetSensitiveWordLogsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` + GroupId string `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *GetSensitiveWordLogsReq) Reset() { + *x = GetSensitiveWordLogsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[90] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogsReq) ProtoMessage() {} + +func (x *GetSensitiveWordLogsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[90] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{90} +} + +func (x *GetSensitiveWordLogsReq) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetSensitiveWordLogsReq) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *GetSensitiveWordLogsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetSensitiveWordLogsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Logs []*SensitiveWordLogInfo `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs"` +} + +func (x *GetSensitiveWordLogsResp) Reset() { + *x = GetSensitiveWordLogsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[91] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogsResp) ProtoMessage() {} + +func (x *GetSensitiveWordLogsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[91] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{91} +} + +func (x *GetSensitiveWordLogsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetSensitiveWordLogsResp) GetLogs() []*SensitiveWordLogInfo { + if x != nil { + return x.Logs + } + return nil +} + +// 用户登录记录信息 +type UserLoginRecordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` // 用户ID + LoginTime int64 `protobuf:"varint,2,opt,name=login_time,json=loginTime,proto3" json:"login_time"` // 登录时间(毫秒时间戳) + Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip"` // 登录IP + DeviceId string `protobuf:"bytes,4,opt,name=device_id,json=deviceId,proto3" json:"device_id"` // 设备ID + Platform string `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform"` // 平台 + FaceUrl string `protobuf:"bytes,6,opt,name=face_url,json=faceUrl,proto3" json:"face_url"` // 用户头像 + Nickname string `protobuf:"bytes,7,opt,name=nickname,proto3" json:"nickname"` // 用户昵称 +} + +func (x *UserLoginRecordInfo) Reset() { + *x = UserLoginRecordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[92] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserLoginRecordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserLoginRecordInfo) ProtoMessage() {} + +func (x *UserLoginRecordInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[92] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserLoginRecordInfo.ProtoReflect.Descriptor instead. +func (*UserLoginRecordInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{92} +} + +func (x *UserLoginRecordInfo) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UserLoginRecordInfo) GetLoginTime() int64 { + if x != nil { + return x.LoginTime + } + return 0 +} + +func (x *UserLoginRecordInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *UserLoginRecordInfo) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *UserLoginRecordInfo) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *UserLoginRecordInfo) GetFaceUrl() string { + if x != nil { + return x.FaceUrl + } + return "" +} + +func (x *UserLoginRecordInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +// 查询用户登录记录请求 +type GetUserLoginRecordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id"` // 用户ID(可选,如果提供则查询该用户的登录记录) + Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip"` // IP地址(可选,如果提供则查询使用该IP的所有登录记录) + Pagination *sdkws.RequestPagination `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetUserLoginRecordsReq) Reset() { + *x = GetUserLoginRecordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[93] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserLoginRecordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserLoginRecordsReq) ProtoMessage() {} + +func (x *GetUserLoginRecordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[93] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserLoginRecordsReq.ProtoReflect.Descriptor instead. +func (*GetUserLoginRecordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{93} +} + +func (x *GetUserLoginRecordsReq) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetUserLoginRecordsReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *GetUserLoginRecordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 查询用户登录记录响应 +type GetUserLoginRecordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Records []*UserLoginRecordInfo `protobuf:"bytes,2,rep,name=records,proto3" json:"records"` // 登录记录列表 +} + +func (x *GetUserLoginRecordsResp) Reset() { + *x = GetUserLoginRecordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[94] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserLoginRecordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserLoginRecordsResp) ProtoMessage() {} + +func (x *GetUserLoginRecordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[94] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserLoginRecordsResp.ProtoReflect.Descriptor instead. +func (*GetUserLoginRecordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{94} +} + +func (x *GetUserLoginRecordsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetUserLoginRecordsResp) GetRecords() []*UserLoginRecordInfo { + if x != nil { + return x.Records + } + return nil +} + +// 删除敏感词日志 +type DeleteSensitiveWordLogsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids"` +} + +func (x *DeleteSensitiveWordLogsReq) Reset() { + *x = DeleteSensitiveWordLogsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[95] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordLogsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordLogsReq) ProtoMessage() {} + +func (x *DeleteSensitiveWordLogsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[95] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordLogsReq.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordLogsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{95} +} + +func (x *DeleteSensitiveWordLogsReq) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type DeleteSensitiveWordLogsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteSensitiveWordLogsResp) Reset() { + *x = DeleteSensitiveWordLogsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[96] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSensitiveWordLogsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSensitiveWordLogsResp) ProtoMessage() {} + +func (x *DeleteSensitiveWordLogsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[96] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSensitiveWordLogsResp.ProtoReflect.Descriptor instead. +func (*DeleteSensitiveWordLogsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{96} +} + +// 获取敏感词统计 +type GetSensitiveWordStatsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSensitiveWordStatsReq) Reset() { + *x = GetSensitiveWordStatsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[97] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordStatsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordStatsReq) ProtoMessage() {} + +func (x *GetSensitiveWordStatsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[97] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordStatsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordStatsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{97} +} + +type GetSensitiveWordStatsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *SensitiveWordStatsInfo `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats"` +} + +func (x *GetSensitiveWordStatsResp) Reset() { + *x = GetSensitiveWordStatsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[98] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordStatsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordStatsResp) ProtoMessage() {} + +func (x *GetSensitiveWordStatsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[98] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordStatsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordStatsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{98} +} + +func (x *GetSensitiveWordStatsResp) GetStats() *SensitiveWordStatsInfo { + if x != nil { + return x.Stats + } + return nil +} + +// 获取敏感词日志统计 +type GetSensitiveWordLogStatsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartTime int64 `protobuf:"varint,1,opt,name=start_time,json=startTime,proto3" json:"start_time"` + EndTime int64 `protobuf:"varint,2,opt,name=end_time,json=endTime,proto3" json:"end_time"` +} + +func (x *GetSensitiveWordLogStatsReq) Reset() { + *x = GetSensitiveWordLogStatsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[99] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogStatsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogStatsReq) ProtoMessage() {} + +func (x *GetSensitiveWordLogStatsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[99] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogStatsReq.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogStatsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{99} +} + +func (x *GetSensitiveWordLogStatsReq) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *GetSensitiveWordLogStatsReq) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +type GetSensitiveWordLogStatsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *SensitiveWordLogStatsInfo `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats"` +} + +func (x *GetSensitiveWordLogStatsResp) Reset() { + *x = GetSensitiveWordLogStatsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[100] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSensitiveWordLogStatsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSensitiveWordLogStatsResp) ProtoMessage() {} + +func (x *GetSensitiveWordLogStatsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[100] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSensitiveWordLogStatsResp.ProtoReflect.Descriptor instead. +func (*GetSensitiveWordLogStatsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{100} +} + +func (x *GetSensitiveWordLogStatsResp) GetStats() *SensitiveWordLogStatsInfo { + if x != nil { + return x.Stats + } + return nil +} + +type AddFriendReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` +} + +func (x *AddFriendReq) Reset() { + *x = AddFriendReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[101] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddFriendReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddFriendReq) ProtoMessage() {} + +func (x *AddFriendReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[101] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddFriendReq.ProtoReflect.Descriptor instead. +func (*AddFriendReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{101} +} + +func (x *AddFriendReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +type AddFriendResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddFriendResp) Reset() { + *x = AddFriendResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[102] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddFriendResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddFriendResp) ProtoMessage() {} + +func (x *AddFriendResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[102] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddFriendResp.ProtoReflect.Descriptor instead. +func (*AddFriendResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{102} +} + +// 收藏信息 +type FavoriteInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 收藏ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Type int32 `protobuf:"varint,3,opt,name=type,proto3" json:"type"` // 收藏类型:1-文本,2-图片,3-链接,4-文件,5-语音,6-视频,7-位置 + Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title"` // 标题 + Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content"` // 内容 + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description"` // 描述 + Thumbnail string `protobuf:"bytes,7,opt,name=thumbnail,proto3" json:"thumbnail"` // 缩略图URL + LinkURL string `protobuf:"bytes,8,opt,name=linkURL,proto3" json:"linkURL"` // 链接URL + FileSize int64 `protobuf:"varint,9,opt,name=fileSize,proto3" json:"fileSize"` // 文件大小(字节) + Duration int32 `protobuf:"varint,10,opt,name=duration,proto3" json:"duration"` // 时长(秒) + Location string `protobuf:"bytes,11,opt,name=location,proto3" json:"location"` // 位置信息(JSON格式) + Tags []string `protobuf:"bytes,12,rep,name=tags,proto3" json:"tags"` // 标签列表 + Remark string `protobuf:"bytes,13,opt,name=remark,proto3" json:"remark"` // 备注 + CreateTime int64 `protobuf:"varint,14,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,15,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *FavoriteInfo) Reset() { + *x = FavoriteInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FavoriteInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FavoriteInfo) ProtoMessage() {} + +func (x *FavoriteInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[103] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FavoriteInfo.ProtoReflect.Descriptor instead. +func (*FavoriteInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{103} +} + +func (x *FavoriteInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *FavoriteInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *FavoriteInfo) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *FavoriteInfo) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *FavoriteInfo) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *FavoriteInfo) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *FavoriteInfo) GetThumbnail() string { + if x != nil { + return x.Thumbnail + } + return "" +} + +func (x *FavoriteInfo) GetLinkURL() string { + if x != nil { + return x.LinkURL + } + return "" +} + +func (x *FavoriteInfo) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *FavoriteInfo) GetDuration() int32 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *FavoriteInfo) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *FavoriteInfo) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *FavoriteInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *FavoriteInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *FavoriteInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 创建收藏请求 +type CreateFavoriteReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type"` // 收藏类型 + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 标题 + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content"` // 内容 + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description"` // 描述 + Thumbnail string `protobuf:"bytes,5,opt,name=thumbnail,proto3" json:"thumbnail"` // 缩略图URL + LinkURL string `protobuf:"bytes,6,opt,name=linkURL,proto3" json:"linkURL"` // 链接URL + FileSize int64 `protobuf:"varint,7,opt,name=fileSize,proto3" json:"fileSize"` // 文件大小(字节) + Duration int32 `protobuf:"varint,8,opt,name=duration,proto3" json:"duration"` // 时长(秒) + Location string `protobuf:"bytes,9,opt,name=location,proto3" json:"location"` // 位置信息(JSON格式) + Tags []string `protobuf:"bytes,10,rep,name=tags,proto3" json:"tags"` // 标签列表 + Remark string `protobuf:"bytes,11,opt,name=remark,proto3" json:"remark"` // 备注 +} + +func (x *CreateFavoriteReq) Reset() { + *x = CreateFavoriteReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateFavoriteReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateFavoriteReq) ProtoMessage() {} + +func (x *CreateFavoriteReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[104] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateFavoriteReq.ProtoReflect.Descriptor instead. +func (*CreateFavoriteReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{104} +} + +func (x *CreateFavoriteReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *CreateFavoriteReq) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreateFavoriteReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *CreateFavoriteReq) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CreateFavoriteReq) GetThumbnail() string { + if x != nil { + return x.Thumbnail + } + return "" +} + +func (x *CreateFavoriteReq) GetLinkURL() string { + if x != nil { + return x.LinkURL + } + return "" +} + +func (x *CreateFavoriteReq) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *CreateFavoriteReq) GetDuration() int32 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *CreateFavoriteReq) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *CreateFavoriteReq) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *CreateFavoriteReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +type CreateFavoriteResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FavoriteID string `protobuf:"bytes,1,opt,name=favoriteID,proto3" json:"favoriteID"` // 收藏ID +} + +func (x *CreateFavoriteResp) Reset() { + *x = CreateFavoriteResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateFavoriteResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateFavoriteResp) ProtoMessage() {} + +func (x *CreateFavoriteResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[105] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateFavoriteResp.ProtoReflect.Descriptor instead. +func (*CreateFavoriteResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{105} +} + +func (x *CreateFavoriteResp) GetFavoriteID() string { + if x != nil { + return x.FavoriteID + } + return "" +} + +// 获取收藏请求 +type GetFavoriteReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FavoriteID string `protobuf:"bytes,1,opt,name=favoriteID,proto3" json:"favoriteID"` // 收藏ID +} + +func (x *GetFavoriteReq) Reset() { + *x = GetFavoriteReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoriteReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoriteReq) ProtoMessage() {} + +func (x *GetFavoriteReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[106] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoriteReq.ProtoReflect.Descriptor instead. +func (*GetFavoriteReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{106} +} + +func (x *GetFavoriteReq) GetFavoriteID() string { + if x != nil { + return x.FavoriteID + } + return "" +} + +type GetFavoriteResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Favorite *FavoriteInfo `protobuf:"bytes,1,opt,name=favorite,proto3" json:"favorite"` // 收藏信息 +} + +func (x *GetFavoriteResp) Reset() { + *x = GetFavoriteResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoriteResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoriteResp) ProtoMessage() {} + +func (x *GetFavoriteResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[107] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoriteResp.ProtoReflect.Descriptor instead. +func (*GetFavoriteResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{107} +} + +func (x *GetFavoriteResp) GetFavorite() *FavoriteInfo { + if x != nil { + return x.Favorite + } + return nil +} + +// 获取收藏列表请求 +type GetFavoritesReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type"` // 收藏类型(可选,0表示全部) + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetFavoritesReq) Reset() { + *x = GetFavoritesReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoritesReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoritesReq) ProtoMessage() {} + +func (x *GetFavoritesReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[108] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoritesReq.ProtoReflect.Descriptor instead. +func (*GetFavoritesReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{108} +} + +func (x *GetFavoritesReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *GetFavoritesReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetFavoritesResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Favorites []*FavoriteInfo `protobuf:"bytes,2,rep,name=favorites,proto3" json:"favorites"` // 收藏列表 +} + +func (x *GetFavoritesResp) Reset() { + *x = GetFavoritesResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[109] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoritesResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoritesResp) ProtoMessage() {} + +func (x *GetFavoritesResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[109] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoritesResp.ProtoReflect.Descriptor instead. +func (*GetFavoritesResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{109} +} + +func (x *GetFavoritesResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetFavoritesResp) GetFavorites() []*FavoriteInfo { + if x != nil { + return x.Favorites + } + return nil +} + +// 搜索收藏请求 +type SearchFavoritesReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword"` // 关键词 + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *SearchFavoritesReq) Reset() { + *x = SearchFavoritesReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[110] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchFavoritesReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchFavoritesReq) ProtoMessage() {} + +func (x *SearchFavoritesReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[110] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchFavoritesReq.ProtoReflect.Descriptor instead. +func (*SearchFavoritesReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{110} +} + +func (x *SearchFavoritesReq) GetKeyword() string { + if x != nil { + return x.Keyword + } + return "" +} + +func (x *SearchFavoritesReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type SearchFavoritesResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Favorites []*FavoriteInfo `protobuf:"bytes,2,rep,name=favorites,proto3" json:"favorites"` // 收藏列表 +} + +func (x *SearchFavoritesResp) Reset() { + *x = SearchFavoritesResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[111] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchFavoritesResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchFavoritesResp) ProtoMessage() {} + +func (x *SearchFavoritesResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[111] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchFavoritesResp.ProtoReflect.Descriptor instead. +func (*SearchFavoritesResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{111} +} + +func (x *SearchFavoritesResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *SearchFavoritesResp) GetFavorites() []*FavoriteInfo { + if x != nil { + return x.Favorites + } + return nil +} + +// 更新收藏请求 +type UpdateFavoriteReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FavoriteID string `protobuf:"bytes,1,opt,name=favoriteID,proto3" json:"favoriteID"` // 收藏ID + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 标题(可选) + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description"` // 描述(可选) + Remark string `protobuf:"bytes,4,opt,name=remark,proto3" json:"remark"` // 备注(可选) + Tags []string `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags"` // 标签列表(可选) +} + +func (x *UpdateFavoriteReq) Reset() { + *x = UpdateFavoriteReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[112] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateFavoriteReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateFavoriteReq) ProtoMessage() {} + +func (x *UpdateFavoriteReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[112] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateFavoriteReq.ProtoReflect.Descriptor instead. +func (*UpdateFavoriteReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{112} +} + +func (x *UpdateFavoriteReq) GetFavoriteID() string { + if x != nil { + return x.FavoriteID + } + return "" +} + +func (x *UpdateFavoriteReq) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *UpdateFavoriteReq) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *UpdateFavoriteReq) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *UpdateFavoriteReq) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +type UpdateFavoriteResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateFavoriteResp) Reset() { + *x = UpdateFavoriteResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[113] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateFavoriteResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateFavoriteResp) ProtoMessage() {} + +func (x *UpdateFavoriteResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[113] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateFavoriteResp.ProtoReflect.Descriptor instead. +func (*UpdateFavoriteResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{113} +} + +// 删除收藏请求 +type DeleteFavoriteReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FavoriteIDs []string `protobuf:"bytes,1,rep,name=favoriteIDs,proto3" json:"favoriteIDs"` // 收藏ID列表 +} + +func (x *DeleteFavoriteReq) Reset() { + *x = DeleteFavoriteReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[114] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteFavoriteReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteFavoriteReq) ProtoMessage() {} + +func (x *DeleteFavoriteReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[114] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteFavoriteReq.ProtoReflect.Descriptor instead. +func (*DeleteFavoriteReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{114} +} + +func (x *DeleteFavoriteReq) GetFavoriteIDs() []string { + if x != nil { + return x.FavoriteIDs + } + return nil +} + +type DeleteFavoriteResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteFavoriteResp) Reset() { + *x = DeleteFavoriteResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[115] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteFavoriteResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteFavoriteResp) ProtoMessage() {} + +func (x *DeleteFavoriteResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[115] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteFavoriteResp.ProtoReflect.Descriptor instead. +func (*DeleteFavoriteResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{115} +} + +// 根据标签获取收藏请求 +type GetFavoritesByTagsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags"` // 标签列表 + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetFavoritesByTagsReq) Reset() { + *x = GetFavoritesByTagsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[116] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoritesByTagsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoritesByTagsReq) ProtoMessage() {} + +func (x *GetFavoritesByTagsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[116] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoritesByTagsReq.ProtoReflect.Descriptor instead. +func (*GetFavoritesByTagsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{116} +} + +func (x *GetFavoritesByTagsReq) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *GetFavoritesByTagsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetFavoritesByTagsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Favorites []*FavoriteInfo `protobuf:"bytes,2,rep,name=favorites,proto3" json:"favorites"` // 收藏列表 +} + +func (x *GetFavoritesByTagsResp) Reset() { + *x = GetFavoritesByTagsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoritesByTagsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoritesByTagsResp) ProtoMessage() {} + +func (x *GetFavoritesByTagsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[117] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoritesByTagsResp.ProtoReflect.Descriptor instead. +func (*GetFavoritesByTagsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{117} +} + +func (x *GetFavoritesByTagsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetFavoritesByTagsResp) GetFavorites() []*FavoriteInfo { + if x != nil { + return x.Favorites + } + return nil +} + +// 获取收藏数量请求 +type GetFavoriteCountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetFavoriteCountReq) Reset() { + *x = GetFavoriteCountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[118] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoriteCountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoriteCountReq) ProtoMessage() {} + +func (x *GetFavoriteCountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[118] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoriteCountReq.ProtoReflect.Descriptor instead. +func (*GetFavoriteCountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{118} +} + +type GetFavoriteCountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count"` // 收藏数量 +} + +func (x *GetFavoriteCountResp) Reset() { + *x = GetFavoriteCountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[119] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFavoriteCountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFavoriteCountResp) ProtoMessage() {} + +func (x *GetFavoriteCountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[119] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFavoriteCountResp.ProtoReflect.Descriptor instead. +func (*GetFavoriteCountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{119} +} + +func (x *GetFavoriteCountResp) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + +// 消息内容 +type ScheduledTaskMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type"` // 消息类型:1-文本,2-图片,3-视频 + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content"` // 消息内容(文本内容、图片URL、视频URL等) + Thumbnail string `protobuf:"bytes,3,opt,name=thumbnail,proto3" json:"thumbnail"` // 缩略图URL(用于图片和视频) + Duration int32 `protobuf:"varint,4,opt,name=duration,proto3" json:"duration"` // 时长(秒,用于视频) + FileSize int64 `protobuf:"varint,5,opt,name=fileSize,proto3" json:"fileSize"` // 文件大小(字节,用于图片和视频) + Width int32 `protobuf:"varint,6,opt,name=width,proto3" json:"width"` // 宽度(像素,用于图片和视频) + Height int32 `protobuf:"varint,7,opt,name=height,proto3" json:"height"` // 高度(像素,用于图片和视频) +} + +func (x *ScheduledTaskMessage) Reset() { + *x = ScheduledTaskMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[120] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScheduledTaskMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduledTaskMessage) ProtoMessage() {} + +func (x *ScheduledTaskMessage) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[120] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduledTaskMessage.ProtoReflect.Descriptor instead. +func (*ScheduledTaskMessage) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{120} +} + +func (x *ScheduledTaskMessage) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *ScheduledTaskMessage) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *ScheduledTaskMessage) GetThumbnail() string { + if x != nil { + return x.Thumbnail + } + return "" +} + +func (x *ScheduledTaskMessage) GetDuration() int32 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *ScheduledTaskMessage) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *ScheduledTaskMessage) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *ScheduledTaskMessage) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +// 定时任务信息 +type ScheduledTaskInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 任务ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name"` // 任务名称 + CronExpression string `protobuf:"bytes,4,opt,name=cronExpression,proto3" json:"cronExpression"` // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + Messages []*ScheduledTaskMessage `protobuf:"bytes,5,rep,name=messages,proto3" json:"messages"` // 消息列表(支持多条消息一起发送) + RecvIDs []string `protobuf:"bytes,6,rep,name=recvIDs,proto3" json:"recvIDs"` // 接收者ID列表(单聊,可以多个) + GroupIDs []string `protobuf:"bytes,7,rep,name=groupIDs,proto3" json:"groupIDs"` // 群组ID列表(群聊,可以多个) + Status int32 `protobuf:"varint,8,opt,name=status,proto3" json:"status"` // 状态:0-已禁用,1-已启用 + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,10,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *ScheduledTaskInfo) Reset() { + *x = ScheduledTaskInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[121] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScheduledTaskInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduledTaskInfo) ProtoMessage() {} + +func (x *ScheduledTaskInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[121] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduledTaskInfo.ProtoReflect.Descriptor instead. +func (*ScheduledTaskInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{121} +} + +func (x *ScheduledTaskInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ScheduledTaskInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *ScheduledTaskInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ScheduledTaskInfo) GetCronExpression() string { + if x != nil { + return x.CronExpression + } + return "" +} + +func (x *ScheduledTaskInfo) GetMessages() []*ScheduledTaskMessage { + if x != nil { + return x.Messages + } + return nil +} + +func (x *ScheduledTaskInfo) GetRecvIDs() []string { + if x != nil { + return x.RecvIDs + } + return nil +} + +func (x *ScheduledTaskInfo) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +func (x *ScheduledTaskInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *ScheduledTaskInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *ScheduledTaskInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 创建定时任务请求 +type CreateScheduledTaskReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name"` // 任务名称 + CronExpression string `protobuf:"bytes,2,opt,name=cronExpression,proto3" json:"cronExpression"` // Crontab表达式 + Messages []*ScheduledTaskMessage `protobuf:"bytes,3,rep,name=messages,proto3" json:"messages"` // 消息列表 + RecvIDs []string `protobuf:"bytes,4,rep,name=recvIDs,proto3" json:"recvIDs"` // 接收者ID列表(单聊,可以多个) + GroupIDs []string `protobuf:"bytes,5,rep,name=groupIDs,proto3" json:"groupIDs"` // 群组ID列表(群聊,可以多个) + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` // 状态:0-已禁用,1-已启用 +} + +func (x *CreateScheduledTaskReq) Reset() { + *x = CreateScheduledTaskReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[122] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateScheduledTaskReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateScheduledTaskReq) ProtoMessage() {} + +func (x *CreateScheduledTaskReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[122] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateScheduledTaskReq.ProtoReflect.Descriptor instead. +func (*CreateScheduledTaskReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{122} +} + +func (x *CreateScheduledTaskReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateScheduledTaskReq) GetCronExpression() string { + if x != nil { + return x.CronExpression + } + return "" +} + +func (x *CreateScheduledTaskReq) GetMessages() []*ScheduledTaskMessage { + if x != nil { + return x.Messages + } + return nil +} + +func (x *CreateScheduledTaskReq) GetRecvIDs() []string { + if x != nil { + return x.RecvIDs + } + return nil +} + +func (x *CreateScheduledTaskReq) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +func (x *CreateScheduledTaskReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +type CreateScheduledTaskResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskID string `protobuf:"bytes,1,opt,name=taskID,proto3" json:"taskID"` // 任务ID +} + +func (x *CreateScheduledTaskResp) Reset() { + *x = CreateScheduledTaskResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[123] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateScheduledTaskResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateScheduledTaskResp) ProtoMessage() {} + +func (x *CreateScheduledTaskResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[123] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateScheduledTaskResp.ProtoReflect.Descriptor instead. +func (*CreateScheduledTaskResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{123} +} + +func (x *CreateScheduledTaskResp) GetTaskID() string { + if x != nil { + return x.TaskID + } + return "" +} + +// 获取定时任务请求 +type GetScheduledTaskReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskID string `protobuf:"bytes,1,opt,name=taskID,proto3" json:"taskID"` // 任务ID +} + +func (x *GetScheduledTaskReq) Reset() { + *x = GetScheduledTaskReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[124] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTaskReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTaskReq) ProtoMessage() {} + +func (x *GetScheduledTaskReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[124] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTaskReq.ProtoReflect.Descriptor instead. +func (*GetScheduledTaskReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{124} +} + +func (x *GetScheduledTaskReq) GetTaskID() string { + if x != nil { + return x.TaskID + } + return "" +} + +type GetScheduledTaskResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Task *ScheduledTaskInfo `protobuf:"bytes,1,opt,name=task,proto3" json:"task"` // 任务信息 +} + +func (x *GetScheduledTaskResp) Reset() { + *x = GetScheduledTaskResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[125] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTaskResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTaskResp) ProtoMessage() {} + +func (x *GetScheduledTaskResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[125] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTaskResp.ProtoReflect.Descriptor instead. +func (*GetScheduledTaskResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{125} +} + +func (x *GetScheduledTaskResp) GetTask() *ScheduledTaskInfo { + if x != nil { + return x.Task + } + return nil +} + +// 获取定时任务列表请求 +type GetScheduledTasksReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` // 分页信息 +} + +func (x *GetScheduledTasksReq) Reset() { + *x = GetScheduledTasksReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[126] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTasksReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTasksReq) ProtoMessage() {} + +func (x *GetScheduledTasksReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[126] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTasksReq.ProtoReflect.Descriptor instead. +func (*GetScheduledTasksReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{126} +} + +func (x *GetScheduledTasksReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type GetScheduledTasksResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Tasks []*ScheduledTaskInfo `protobuf:"bytes,2,rep,name=tasks,proto3" json:"tasks"` // 任务列表 +} + +func (x *GetScheduledTasksResp) Reset() { + *x = GetScheduledTasksResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[127] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetScheduledTasksResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetScheduledTasksResp) ProtoMessage() {} + +func (x *GetScheduledTasksResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[127] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetScheduledTasksResp.ProtoReflect.Descriptor instead. +func (*GetScheduledTasksResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{127} +} + +func (x *GetScheduledTasksResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetScheduledTasksResp) GetTasks() []*ScheduledTaskInfo { + if x != nil { + return x.Tasks + } + return nil +} + +// 更新定时任务请求 +type UpdateScheduledTaskReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskID string `protobuf:"bytes,1,opt,name=taskID,proto3" json:"taskID"` // 任务ID + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` // 任务名称(可选) + CronExpression string `protobuf:"bytes,3,opt,name=cronExpression,proto3" json:"cronExpression"` // Crontab表达式(可选) + Messages []*ScheduledTaskMessage `protobuf:"bytes,4,rep,name=messages,proto3" json:"messages"` // 消息列表(可选) + RecvIDs []string `protobuf:"bytes,5,rep,name=recvIDs,proto3" json:"recvIDs"` // 接收者ID列表(可选) + GroupIDs []string `protobuf:"bytes,6,rep,name=groupIDs,proto3" json:"groupIDs"` // 群组ID列表(可选) + Status int32 `protobuf:"varint,7,opt,name=status,proto3" json:"status"` // 状态(可选) +} + +func (x *UpdateScheduledTaskReq) Reset() { + *x = UpdateScheduledTaskReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[128] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateScheduledTaskReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateScheduledTaskReq) ProtoMessage() {} + +func (x *UpdateScheduledTaskReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[128] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateScheduledTaskReq.ProtoReflect.Descriptor instead. +func (*UpdateScheduledTaskReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{128} +} + +func (x *UpdateScheduledTaskReq) GetTaskID() string { + if x != nil { + return x.TaskID + } + return "" +} + +func (x *UpdateScheduledTaskReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateScheduledTaskReq) GetCronExpression() string { + if x != nil { + return x.CronExpression + } + return "" +} + +func (x *UpdateScheduledTaskReq) GetMessages() []*ScheduledTaskMessage { + if x != nil { + return x.Messages + } + return nil +} + +func (x *UpdateScheduledTaskReq) GetRecvIDs() []string { + if x != nil { + return x.RecvIDs + } + return nil +} + +func (x *UpdateScheduledTaskReq) GetGroupIDs() []string { + if x != nil { + return x.GroupIDs + } + return nil +} + +func (x *UpdateScheduledTaskReq) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +type UpdateScheduledTaskResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateScheduledTaskResp) Reset() { + *x = UpdateScheduledTaskResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[129] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateScheduledTaskResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateScheduledTaskResp) ProtoMessage() {} + +func (x *UpdateScheduledTaskResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[129] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateScheduledTaskResp.ProtoReflect.Descriptor instead. +func (*UpdateScheduledTaskResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{129} +} + +// 删除定时任务请求 +type DeleteScheduledTaskReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskIDs []string `protobuf:"bytes,1,rep,name=taskIDs,proto3" json:"taskIDs"` // 任务ID列表 +} + +func (x *DeleteScheduledTaskReq) Reset() { + *x = DeleteScheduledTaskReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[130] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteScheduledTaskReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteScheduledTaskReq) ProtoMessage() {} + +func (x *DeleteScheduledTaskReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[130] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteScheduledTaskReq.ProtoReflect.Descriptor instead. +func (*DeleteScheduledTaskReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{130} +} + +func (x *DeleteScheduledTaskReq) GetTaskIDs() []string { + if x != nil { + return x.TaskIDs + } + return nil +} + +type DeleteScheduledTaskResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteScheduledTaskResp) Reset() { + *x = DeleteScheduledTaskResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[131] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteScheduledTaskResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteScheduledTaskResp) ProtoMessage() {} + +func (x *DeleteScheduledTaskResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[131] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteScheduledTaskResp.ProtoReflect.Descriptor instead. +func (*DeleteScheduledTaskResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{131} +} + +// 系统配置信息(客户端) +type SystemConfigInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key"` // 配置键(唯一标识) + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` // 配置标题 + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value"` // 配置值(根据 valueType 解析) + ValueType int32 `protobuf:"varint,4,opt,name=valueType,proto3" json:"valueType"` // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description"` // 配置描述 +} + +func (x *SystemConfigInfo) Reset() { + *x = SystemConfigInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[132] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SystemConfigInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemConfigInfo) ProtoMessage() {} + +func (x *SystemConfigInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[132] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SystemConfigInfo.ProtoReflect.Descriptor instead. +func (*SystemConfigInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{132} +} + +func (x *SystemConfigInfo) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *SystemConfigInfo) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *SystemConfigInfo) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *SystemConfigInfo) GetValueType() int32 { + if x != nil { + return x.ValueType + } + return 0 +} + +func (x *SystemConfigInfo) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// 获取APP端配置请求 +type GetAppSystemConfigsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAppSystemConfigsReq) Reset() { + *x = GetAppSystemConfigsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[133] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAppSystemConfigsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAppSystemConfigsReq) ProtoMessage() {} + +func (x *GetAppSystemConfigsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[133] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAppSystemConfigsReq.ProtoReflect.Descriptor instead. +func (*GetAppSystemConfigsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{133} +} + +// 获取APP端配置响应 +type GetAppSystemConfigsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Configs []*SystemConfigInfo `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs"` // 配置列表 +} + +func (x *GetAppSystemConfigsResp) Reset() { + *x = GetAppSystemConfigsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[134] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAppSystemConfigsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAppSystemConfigsResp) ProtoMessage() {} + +func (x *GetAppSystemConfigsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[134] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAppSystemConfigsResp.ProtoReflect.Descriptor instead. +func (*GetAppSystemConfigsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{134} +} + +func (x *GetAppSystemConfigsResp) GetConfigs() []*SystemConfigInfo { + if x != nil { + return x.Configs + } + return nil +} + +// 实名认证信息 +type RealNameAuthInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IdCard string `protobuf:"bytes,1,opt,name=idCard,proto3" json:"idCard"` // 身份证号 + IdCardPhotoFront string `protobuf:"bytes,2,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL + IdCardPhotoBack string `protobuf:"bytes,3,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name"` // 真实姓名 + AuditStatus int32 `protobuf:"varint,5,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +func (x *RealNameAuthInfo) Reset() { + *x = RealNameAuthInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[135] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RealNameAuthInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RealNameAuthInfo) ProtoMessage() {} + +func (x *RealNameAuthInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[135] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RealNameAuthInfo.ProtoReflect.Descriptor instead. +func (*RealNameAuthInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{135} +} + +func (x *RealNameAuthInfo) GetIdCard() string { + if x != nil { + return x.IdCard + } + return "" +} + +func (x *RealNameAuthInfo) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *RealNameAuthInfo) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +func (x *RealNameAuthInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RealNameAuthInfo) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +// 获取钱包余额请求 +type GetWalletBalanceReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetWalletBalanceReq) Reset() { + *x = GetWalletBalanceReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[136] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletBalanceReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletBalanceReq) ProtoMessage() {} + +func (x *GetWalletBalanceReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[136] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletBalanceReq.ProtoReflect.Descriptor instead. +func (*GetWalletBalanceReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{136} +} + +// 获取钱包余额响应 +type GetWalletBalanceResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Balance int64 `protobuf:"varint,1,opt,name=balance,proto3" json:"balance"` // 余额(单位:分) +} + +func (x *GetWalletBalanceResp) Reset() { + *x = GetWalletBalanceResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[137] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletBalanceResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletBalanceResp) ProtoMessage() {} + +func (x *GetWalletBalanceResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[137] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletBalanceResp.ProtoReflect.Descriptor instead. +func (*GetWalletBalanceResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{137} +} + +func (x *GetWalletBalanceResp) GetBalance() int64 { + if x != nil { + return x.Balance + } + return 0 +} + +// 获取钱包详细信息请求 +type GetWalletInfoReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetWalletInfoReq) Reset() { + *x = GetWalletInfoReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[138] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletInfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletInfoReq) ProtoMessage() {} + +func (x *GetWalletInfoReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[138] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletInfoReq.ProtoReflect.Descriptor instead. +func (*GetWalletInfoReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{138} +} + +// 获取钱包详细信息响应 +type GetWalletInfoResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Balance int64 `protobuf:"varint,1,opt,name=balance,proto3" json:"balance"` // 余额(单位:分) + WithdrawAccount string `protobuf:"bytes,2,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提现账号 + WithdrawAccountType int32 `protobuf:"varint,3,opt,name=withdrawAccountType,proto3" json:"withdrawAccountType"` // 提现账号类型:1-支付宝,2-微信,3-银行卡 + RealNameAuth *RealNameAuthInfo `protobuf:"bytes,4,opt,name=realNameAuth,proto3" json:"realNameAuth"` // 实名认证信息 + WithdrawReceiveAccount string `protobuf:"bytes,5,opt,name=withdrawReceiveAccount,proto3" json:"withdrawReceiveAccount"` // 提现收款账号 + HasPaymentPassword bool `protobuf:"varint,6,opt,name=hasPaymentPassword,proto3" json:"hasPaymentPassword"` // 是否已设置支付密码 +} + +func (x *GetWalletInfoResp) Reset() { + *x = GetWalletInfoResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[139] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletInfoResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletInfoResp) ProtoMessage() {} + +func (x *GetWalletInfoResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[139] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletInfoResp.ProtoReflect.Descriptor instead. +func (*GetWalletInfoResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{139} +} + +func (x *GetWalletInfoResp) GetBalance() int64 { + if x != nil { + return x.Balance + } + return 0 +} + +func (x *GetWalletInfoResp) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +func (x *GetWalletInfoResp) GetWithdrawAccountType() int32 { + if x != nil { + return x.WithdrawAccountType + } + return 0 +} + +func (x *GetWalletInfoResp) GetRealNameAuth() *RealNameAuthInfo { + if x != nil { + return x.RealNameAuth + } + return nil +} + +func (x *GetWalletInfoResp) GetWithdrawReceiveAccount() string { + if x != nil { + return x.WithdrawReceiveAccount + } + return "" +} + +func (x *GetWalletInfoResp) GetHasPaymentPassword() bool { + if x != nil { + return x.HasPaymentPassword + } + return false +} + +// 设置支付密码请求 +type SetPaymentPasswordReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NewPassword string `protobuf:"bytes,1,opt,name=newPassword,proto3" json:"newPassword"` // 新支付密码(必填) + OldPassword string `protobuf:"bytes,2,opt,name=oldPassword,proto3" json:"oldPassword"` // 旧支付密码(修改时必填,首次设置时不需要) +} + +func (x *SetPaymentPasswordReq) Reset() { + *x = SetPaymentPasswordReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[140] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetPaymentPasswordReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetPaymentPasswordReq) ProtoMessage() {} + +func (x *SetPaymentPasswordReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[140] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetPaymentPasswordReq.ProtoReflect.Descriptor instead. +func (*SetPaymentPasswordReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{140} +} + +func (x *SetPaymentPasswordReq) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +func (x *SetPaymentPasswordReq) GetOldPassword() string { + if x != nil { + return x.OldPassword + } + return "" +} + +// 设置支付密码响应 +type SetPaymentPasswordResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetPaymentPasswordResp) Reset() { + *x = SetPaymentPasswordResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[141] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetPaymentPasswordResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetPaymentPasswordResp) ProtoMessage() {} + +func (x *SetPaymentPasswordResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[141] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetPaymentPasswordResp.ProtoReflect.Descriptor instead. +func (*SetPaymentPasswordResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{141} +} + +// 设置提现账号请求 +type SetWithdrawAccountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` // 提现账号(必填) + AccountType int32 `protobuf:"varint,2,opt,name=accountType,proto3" json:"accountType"` // 账号类型(必填):1-支付宝,2-微信,3-银行卡 +} + +func (x *SetWithdrawAccountReq) Reset() { + *x = SetWithdrawAccountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[142] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetWithdrawAccountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetWithdrawAccountReq) ProtoMessage() {} + +func (x *SetWithdrawAccountReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[142] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetWithdrawAccountReq.ProtoReflect.Descriptor instead. +func (*SetWithdrawAccountReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{142} +} + +func (x *SetWithdrawAccountReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *SetWithdrawAccountReq) GetAccountType() int32 { + if x != nil { + return x.AccountType + } + return 0 +} + +// 设置提现账号响应 +type SetWithdrawAccountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetWithdrawAccountResp) Reset() { + *x = SetWithdrawAccountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[143] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetWithdrawAccountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetWithdrawAccountResp) ProtoMessage() {} + +func (x *SetWithdrawAccountResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[143] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetWithdrawAccountResp.ProtoReflect.Descriptor instead. +func (*SetWithdrawAccountResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{143} +} + +// 余额变动记录信息 +type WalletBalanceRecordInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 记录ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount"` // 变动金额(单位:分,正数表示增加,负数表示减少) + Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type"` // 变动类型:1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 + BeforeBalance int64 `protobuf:"varint,5,opt,name=beforeBalance,proto3" json:"beforeBalance"` // 变动前余额(单位:分) + AfterBalance int64 `protobuf:"varint,6,opt,name=afterBalance,proto3" json:"afterBalance"` // 变动后余额(单位:分) + OrderID string `protobuf:"bytes,7,opt,name=orderID,proto3" json:"orderID"` // 关联订单ID(可选) + TransactionID string `protobuf:"bytes,8,opt,name=transactionID,proto3" json:"transactionID"` // 交易ID(可选) + RedPacketID string `protobuf:"bytes,9,opt,name=redPacketID,proto3" json:"redPacketID"` // 红包ID(可选) + Remark string `protobuf:"bytes,10,opt,name=remark,proto3" json:"remark"` // 备注 + CreateTime int64 `protobuf:"varint,11,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) +} + +func (x *WalletBalanceRecordInfo) Reset() { + *x = WalletBalanceRecordInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[144] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WalletBalanceRecordInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WalletBalanceRecordInfo) ProtoMessage() {} + +func (x *WalletBalanceRecordInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[144] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WalletBalanceRecordInfo.ProtoReflect.Descriptor instead. +func (*WalletBalanceRecordInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{144} +} + +func (x *WalletBalanceRecordInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetBeforeBalance() int64 { + if x != nil { + return x.BeforeBalance + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetAfterBalance() int64 { + if x != nil { + return x.AfterBalance + } + return 0 +} + +func (x *WalletBalanceRecordInfo) GetOrderID() string { + if x != nil { + return x.OrderID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetTransactionID() string { + if x != nil { + return x.TransactionID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetRedPacketID() string { + if x != nil { + return x.RedPacketID + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *WalletBalanceRecordInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +// 获取余额明细请求 +type GetWalletBalanceRecordsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` // 分页参数 + Type int32 `protobuf:"varint,2,opt,name=type,proto3" json:"type"` // 变动类型(可选,0表示查询所有类型) +} + +func (x *GetWalletBalanceRecordsReq) Reset() { + *x = GetWalletBalanceRecordsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[145] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletBalanceRecordsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletBalanceRecordsReq) ProtoMessage() {} + +func (x *GetWalletBalanceRecordsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[145] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletBalanceRecordsReq.ProtoReflect.Descriptor instead. +func (*GetWalletBalanceRecordsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{145} +} + +func (x *GetWalletBalanceRecordsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *GetWalletBalanceRecordsReq) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +// 获取余额明细响应 +type GetWalletBalanceRecordsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Records []*WalletBalanceRecordInfo `protobuf:"bytes,2,rep,name=records,proto3" json:"records"` // 记录列表 +} + +func (x *GetWalletBalanceRecordsResp) Reset() { + *x = GetWalletBalanceRecordsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[146] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWalletBalanceRecordsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWalletBalanceRecordsResp) ProtoMessage() {} + +func (x *GetWalletBalanceRecordsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[146] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWalletBalanceRecordsResp.ProtoReflect.Descriptor instead. +func (*GetWalletBalanceRecordsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{146} +} + +func (x *GetWalletBalanceRecordsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetWalletBalanceRecordsResp) GetRecords() []*WalletBalanceRecordInfo { + if x != nil { + return x.Records + } + return nil +} + +// 提现申请信息 +type WithdrawApplicationInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` // 申请ID + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID"` // 用户ID + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount"` // 提现金额(单位:分) + WithdrawAccount string `protobuf:"bytes,4,opt,name=withdrawAccount,proto3" json:"withdrawAccount"` // 提现账号 + WithdrawAccountType int32 `protobuf:"varint,5,opt,name=withdrawAccountType,proto3" json:"withdrawAccountType"` // 提现账号类型:1-支付宝,2-微信,3-银行卡 + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status"` // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + AuditorID string `protobuf:"bytes,7,opt,name=auditorID,proto3" json:"auditorID"` // 审核人ID(管理员ID) + AuditTime int64 `protobuf:"varint,8,opt,name=auditTime,proto3" json:"auditTime"` // 审核时间(毫秒时间戳) + AuditRemark string `protobuf:"bytes,9,opt,name=auditRemark,proto3" json:"auditRemark"` // 审核备注 + Ip string `protobuf:"bytes,10,opt,name=ip,proto3" json:"ip"` // 申请IP + DeviceID string `protobuf:"bytes,11,opt,name=deviceID,proto3" json:"deviceID"` // 设备ID + Platform string `protobuf:"bytes,12,opt,name=platform,proto3" json:"platform"` // 平台(iOS、Android、Web等) + DeviceModel string `protobuf:"bytes,13,opt,name=deviceModel,proto3" json:"deviceModel"` // 设备型号 + DeviceBrand string `protobuf:"bytes,14,opt,name=deviceBrand,proto3" json:"deviceBrand"` // 设备品牌 + OsVersion string `protobuf:"bytes,15,opt,name=osVersion,proto3" json:"osVersion"` // 操作系统版本 + AppVersion string `protobuf:"bytes,16,opt,name=appVersion,proto3" json:"appVersion"` // 应用版本 + Remark string `protobuf:"bytes,17,opt,name=remark,proto3" json:"remark"` // 申请备注(由后台管理员填写) + CreateTime int64 `protobuf:"varint,18,opt,name=createTime,proto3" json:"createTime"` // 创建时间(毫秒时间戳) + UpdateTime int64 `protobuf:"varint,19,opt,name=updateTime,proto3" json:"updateTime"` // 更新时间(毫秒时间戳) +} + +func (x *WithdrawApplicationInfo) Reset() { + *x = WithdrawApplicationInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[147] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawApplicationInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawApplicationInfo) ProtoMessage() {} + +func (x *WithdrawApplicationInfo) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[147] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawApplicationInfo.ProtoReflect.Descriptor instead. +func (*WithdrawApplicationInfo) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{147} +} + +func (x *WithdrawApplicationInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *WithdrawApplicationInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *WithdrawApplicationInfo) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *WithdrawApplicationInfo) GetWithdrawAccount() string { + if x != nil { + return x.WithdrawAccount + } + return "" +} + +func (x *WithdrawApplicationInfo) GetWithdrawAccountType() int32 { + if x != nil { + return x.WithdrawAccountType + } + return 0 +} + +func (x *WithdrawApplicationInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *WithdrawApplicationInfo) GetAuditorID() string { + if x != nil { + return x.AuditorID + } + return "" +} + +func (x *WithdrawApplicationInfo) GetAuditTime() int64 { + if x != nil { + return x.AuditTime + } + return 0 +} + +func (x *WithdrawApplicationInfo) GetAuditRemark() string { + if x != nil { + return x.AuditRemark + } + return "" +} + +func (x *WithdrawApplicationInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *WithdrawApplicationInfo) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *WithdrawApplicationInfo) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *WithdrawApplicationInfo) GetDeviceModel() string { + if x != nil { + return x.DeviceModel + } + return "" +} + +func (x *WithdrawApplicationInfo) GetDeviceBrand() string { + if x != nil { + return x.DeviceBrand + } + return "" +} + +func (x *WithdrawApplicationInfo) GetOsVersion() string { + if x != nil { + return x.OsVersion + } + return "" +} + +func (x *WithdrawApplicationInfo) GetAppVersion() string { + if x != nil { + return x.AppVersion + } + return "" +} + +func (x *WithdrawApplicationInfo) GetRemark() string { + if x != nil { + return x.Remark + } + return "" +} + +func (x *WithdrawApplicationInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *WithdrawApplicationInfo) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +// 创建提现申请请求 +type CreateWithdrawApplicationReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount int64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount"` // 提现金额(单位:分) + PaymentPassword string `protobuf:"bytes,2,opt,name=paymentPassword,proto3" json:"paymentPassword"` // 支付密码(必填) + Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip"` // 申请IP + DeviceID string `protobuf:"bytes,4,opt,name=deviceID,proto3" json:"deviceID"` // 设备ID + Platform string `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform"` // 平台 + DeviceModel string `protobuf:"bytes,6,opt,name=deviceModel,proto3" json:"deviceModel"` // 设备型号 + DeviceBrand string `protobuf:"bytes,7,opt,name=deviceBrand,proto3" json:"deviceBrand"` // 设备品牌 + OsVersion string `protobuf:"bytes,8,opt,name=osVersion,proto3" json:"osVersion"` // 操作系统版本 + AppVersion string `protobuf:"bytes,9,opt,name=appVersion,proto3" json:"appVersion"` // 应用版本 +} + +func (x *CreateWithdrawApplicationReq) Reset() { + *x = CreateWithdrawApplicationReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[148] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateWithdrawApplicationReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWithdrawApplicationReq) ProtoMessage() {} + +func (x *CreateWithdrawApplicationReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[148] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWithdrawApplicationReq.ProtoReflect.Descriptor instead. +func (*CreateWithdrawApplicationReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{148} +} + +func (x *CreateWithdrawApplicationReq) GetAmount() int64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *CreateWithdrawApplicationReq) GetPaymentPassword() string { + if x != nil { + return x.PaymentPassword + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetDeviceModel() string { + if x != nil { + return x.DeviceModel + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetDeviceBrand() string { + if x != nil { + return x.DeviceBrand + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetOsVersion() string { + if x != nil { + return x.OsVersion + } + return "" +} + +func (x *CreateWithdrawApplicationReq) GetAppVersion() string { + if x != nil { + return x.AppVersion + } + return "" +} + +// 创建提现申请响应 +type CreateWithdrawApplicationResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ApplicationID string `protobuf:"bytes,1,opt,name=applicationID,proto3" json:"applicationID"` // 申请ID +} + +func (x *CreateWithdrawApplicationResp) Reset() { + *x = CreateWithdrawApplicationResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[149] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateWithdrawApplicationResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateWithdrawApplicationResp) ProtoMessage() {} + +func (x *CreateWithdrawApplicationResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[149] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateWithdrawApplicationResp.ProtoReflect.Descriptor instead. +func (*CreateWithdrawApplicationResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{149} +} + +func (x *CreateWithdrawApplicationResp) GetApplicationID() string { + if x != nil { + return x.ApplicationID + } + return "" +} + +// 获取用户的提现申请列表请求 +type GetWithdrawApplicationsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` // 分页参数 +} + +func (x *GetWithdrawApplicationsReq) Reset() { + *x = GetWithdrawApplicationsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[150] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawApplicationsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawApplicationsReq) ProtoMessage() {} + +func (x *GetWithdrawApplicationsReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[150] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawApplicationsReq.ProtoReflect.Descriptor instead. +func (*GetWithdrawApplicationsReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{150} +} + +func (x *GetWithdrawApplicationsReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +// 获取用户的提现申请列表响应 +type GetWithdrawApplicationsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total uint32 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` // 总数 + Applications []*WithdrawApplicationInfo `protobuf:"bytes,2,rep,name=applications,proto3" json:"applications"` // 申请列表 +} + +func (x *GetWithdrawApplicationsResp) Reset() { + *x = GetWithdrawApplicationsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[151] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetWithdrawApplicationsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetWithdrawApplicationsResp) ProtoMessage() {} + +func (x *GetWithdrawApplicationsResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[151] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetWithdrawApplicationsResp.ProtoReflect.Descriptor instead. +func (*GetWithdrawApplicationsResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{151} +} + +func (x *GetWithdrawApplicationsResp) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *GetWithdrawApplicationsResp) GetApplications() []*WithdrawApplicationInfo { + if x != nil { + return x.Applications + } + return nil +} + +// 实名认证请求 +type RealNameAuthReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IdCard string `protobuf:"bytes,1,opt,name=idCard,proto3" json:"idCard"` // 身份证号(必填) + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` // 真实姓名(必填) + IdCardPhotoFront string `protobuf:"bytes,3,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL(可选) + IdCardPhotoBack string `protobuf:"bytes,4,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL(可选) +} + +func (x *RealNameAuthReq) Reset() { + *x = RealNameAuthReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[152] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RealNameAuthReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RealNameAuthReq) ProtoMessage() {} + +func (x *RealNameAuthReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[152] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RealNameAuthReq.ProtoReflect.Descriptor instead. +func (*RealNameAuthReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{152} +} + +func (x *RealNameAuthReq) GetIdCard() string { + if x != nil { + return x.IdCard + } + return "" +} + +func (x *RealNameAuthReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RealNameAuthReq) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *RealNameAuthReq) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +// 实名认证响应 +type RealNameAuthResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success"` // 是否认证成功 + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message"` // 认证结果消息 + IdCardPhotoFront string `protobuf:"bytes,3,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL + IdCardPhotoBack string `protobuf:"bytes,4,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL +} + +func (x *RealNameAuthResp) Reset() { + *x = RealNameAuthResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[153] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RealNameAuthResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RealNameAuthResp) ProtoMessage() {} + +func (x *RealNameAuthResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[153] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RealNameAuthResp.ProtoReflect.Descriptor instead. +func (*RealNameAuthResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{153} +} + +func (x *RealNameAuthResp) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *RealNameAuthResp) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *RealNameAuthResp) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *RealNameAuthResp) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +var File_chat_chat_proto protoreflect.FileDescriptor + +var file_chat_chat_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x1a, 0x13, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2f, 0x73, 0x64, 0x6b, 0x77, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, + 0x70, 0x62, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x70, 0x62, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xb4, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc3, 0x07, 0x0a, 0x11, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x36, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x3e, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x38, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x38, + 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, + 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, + 0x12, 0x33, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x67, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, + 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x12, 0x43, 0x0a, 0x0e, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x12, 0x39, 0x0a, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x42, 0x65, 0x65, 0x70, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x42, 0x65, 0x65, 0x70, 0x12, 0x43, 0x0a, 0x0e, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x56, 0x69, 0x62, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x56, 0x69, 0x62, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x47, 0x0a, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x76, 0x4d, 0x73, + 0x67, 0x4f, 0x70, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, + 0x65, 0x63, 0x76, 0x4d, 0x73, 0x67, 0x4f, 0x70, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x46, 0x6c, + 0x61, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x46, 0x6c, 0x61, 0x67, + 0x22, 0x4a, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x72, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x72, 0x6c, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x31, 0x0a, 0x15, + 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, + 0x52, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x38, 0x0a, 0x05, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, + 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, + 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x73, 0x22, 0x6a, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x38, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x22, 0x2f, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x73, 0x22, 0x4e, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x22, 0xf1, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x64, 0x46, + 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x75, 0x73, 0x65, 0x64, 0x46, 0x6f, + 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0xbb, 0x01, 0x0a, 0x0d, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, + 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x44, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x44, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x36, 0x0a, 0x0e, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x22, 0x47, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, + 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, + 0x0a, 0x09, 0x63, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x63, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, + 0x22, 0xf4, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, + 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, + 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x46, 0x6c, 0x61, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x98, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0e, 0x69, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x61, 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x04, 0x75, 0x73, 0x65, + 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0x48, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, + 0x0a, 0x09, 0x63, 0x68, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8e, 0x01, 0x0a, + 0x11, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x31, 0x0a, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x14, 0x0a, + 0x12, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x22, 0xfc, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, + 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x13, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x65, 0x74, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x77, 0x0a, 0x11, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2e, 0x0a, 0x12, 0x46, + 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x13, + 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x61, + 0x70, 0x1a, 0x41, 0x0a, 0x13, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x30, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, + 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x61, 0x70, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x1a, 0x41, 0x0a, 0x13, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xdc, 0x03, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x6f, + 0x6f, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, + 0x6f, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, + 0x63, 0x76, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x63, 0x76, + 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x76, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x76, 0x4e, 0x69, + 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, + 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4c, + 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, + 0x74, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x69, 0x6e, 0x76, + 0x69, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x22, 0x41, + 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, + 0x79, 0x22, 0x14, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x22, 0xac, 0x02, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x67, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, + 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, + 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x4b, + 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x66, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, + 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x3b, + 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0xd4, 0x01, 0x0a, 0x12, + 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x75, 0x6e, 0x6c, 0x6f, 0x67, 0x69, + 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x38, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x41, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0xa2, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, + 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, + 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x62, 0x0a, 0x12, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x46, + 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x4c, + 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, + 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x51, 0x0a, 0x1b, + 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, + 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, + 0x46, 0x0a, 0x11, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x12, 0x31, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x50, 0x0a, 0x12, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x44, 0x65, 0x6c, + 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, + 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x3b, + 0x0a, 0x13, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x53, + 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x22, 0x3c, 0x0a, 0x14, 0x47, 0x65, + 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x22, 0x61, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, + 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x22, 0xa1, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x34, 0x0a, + 0x05, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x77, 0x6f, + 0x72, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, 0x72, 0x22, 0x32, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x8b, 0x01, 0x0a, 0x17, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x68, + 0x61, 0x73, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, + 0x57, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x22, 0xa5, 0x02, 0x0a, 0x17, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, + 0x61, 0x72, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, + 0x6b, 0x22, 0x96, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xcb, 0x02, 0x0a, 0x17, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0c, + 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x68, 0x61, 0x72, 0x12, + 0x27, 0x0a, 0x0f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, + 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x77, 0x68, 0x69, 0x74, + 0x65, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x61, 0x70, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, + 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf9, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, + 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x54, + 0x65, 0x78, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x72, + 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, 0x65, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x61, 0x0a, 0x19, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, + 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x9b, + 0x01, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x16, 0x0a, 0x14, + 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x22, 0xae, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x2a, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x19, 0x0a, 0x17, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x25, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, + 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x38, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, + 0x22, 0xa4, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, + 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6c, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x05, 0x77, 0x6f, 0x72, + 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, + 0x77, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x57, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, + 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x12, 0x3a, 0x0a, 0x05, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x1c, + 0x0a, 0x1a, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0xd2, 0x01, 0x0a, + 0x1c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x50, 0x0a, + 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, + 0x60, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x1f, 0x0a, 0x1d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x30, 0x0a, 0x1c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x03, 0x69, 0x64, 0x73, 0x22, 0x1f, 0x0a, 0x1d, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x46, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x1b, 0x0a, + 0x19, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x59, 0x0a, 0x1b, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x56, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x39, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, + 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x22, 0x5c, 0x0a, 0x1d, 0x47, 0x65, + 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3b, 0x0a, 0x06, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x22, 0x5a, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x3c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x22, 0x5c, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x71, 0x12, 0x3c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, + 0x1f, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x8e, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, + 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x67, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x55, + 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, + 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x47, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x3f, + 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, + 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x6b, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x2e, 0x0a, 0x1a, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x1d, 0x0a, 0x1b, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1a, 0x0a, 0x18, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x22, 0x56, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x39, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, + 0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x5c, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3c, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x26, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, + 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x0f, + 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x94, 0x03, 0x0a, 0x0c, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, + 0x6c, 0x69, 0x6e, 0x6b, 0x55, 0x52, 0x4c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, + 0x69, 0x6e, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, + 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, + 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, + 0x67, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xb1, 0x02, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, + 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x55, 0x52, 0x4c, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, + 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x34, 0x0a, 0x12, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x44, + 0x22, 0x30, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, + 0x49, 0x44, 0x22, 0x48, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x08, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x22, 0x66, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x61, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x37, + 0x0a, 0x09, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x66, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, + 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x09, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x22, 0x97, + 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, + 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x35, + 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x49, + 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x49, 0x44, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, + 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6c, 0x0a, 0x15, 0x47, + 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x67, 0x0a, 0x16, 0x47, 0x65, 0x74, + 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x09, 0x66, 0x61, 0x76, + 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x22, 0x2c, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc8, 0x01, 0x0a, 0x14, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x53, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x22, 0xc4, 0x02, 0x0a, 0x11, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, + 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x08, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, + 0x65, 0x63, 0x76, 0x49, 0x44, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, + 0x63, 0x76, 0x49, 0x44, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe1, 0x01, 0x0a, 0x16, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x44, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x31, 0x0a, + 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, + 0x22, 0x2d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x22, + 0x4a, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x74, 0x61, 0x73, 0x6b, 0x22, 0x57, 0x0a, 0x14, 0x47, + 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, + 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x63, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0xf9, 0x01, 0x0a, 0x16, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x76, 0x49, + 0x44, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, + 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x32, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, + 0x73, 0x6b, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, + 0x6b, 0x49, 0x44, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x90, 0x01, 0x0a, 0x10, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x18, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x22, 0x52, 0x0a, 0x17, + 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x22, 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, + 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x12, 0x2a, 0x0a, + 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, + 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x43, + 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, + 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x75, + 0x64, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, + 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x22, 0x30, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x22, 0xb4, 0x02, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, + 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x30, 0x0a, 0x13, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x77, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x41, 0x75, 0x74, 0x68, 0x12, 0x36, 0x0a, 0x16, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, + 0x12, 0x68, 0x61, 0x73, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x68, 0x61, 0x73, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x5b, 0x0a, + 0x15, 0x53, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6c, 0x64, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, + 0x6c, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x53, 0x65, + 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x53, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x53, 0x65, 0x74, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x22, 0xd1, 0x02, 0x0a, 0x17, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x62, 0x65, 0x66, 0x6f, + 0x72, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x61, 0x66, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, + 0x0b, 0x72, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x44, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x71, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x73, 0x0a, 0x1b, 0x47, 0x65, + 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x3e, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, + 0xcd, 0x04, 0x0a, 0x17, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x77, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x13, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, + 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1a, 0x0a, + 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x73, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, + 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, + 0xaa, 0x02, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x45, 0x0a, 0x1d, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a, + 0x0d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x22, 0x5d, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, + 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x7d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x48, 0x0a, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x93, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, + 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, + 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, + 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, + 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x22, 0x9c, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x6c, + 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, 0x61, + 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, + 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, + 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x32, 0xcd, 0x31, 0x0a, 0x04, 0x63, 0x68, 0x61, 0x74, 0x12, + 0x42, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x46, 0x72, + 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, + 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x63, 0x0a, 0x14, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5d, + 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5d, 0x0a, + 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, + 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, + 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x54, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x70, 0x74, 0x63, 0x68, 0x61, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x15, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4e, 0x0a, 0x0d, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1d, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, + 0x0e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x12, + 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x51, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x46, 0x69, 0x6e, + 0x64, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, + 0x6b, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, + 0x69, 0x6e, 0x67, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, + 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x6c, + 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x57, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5a, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x21, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x60, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x60, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x63, 0x0a, 0x14, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x73, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x69, 0x0a, 0x16, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x26, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, + 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x72, 0x0a, 0x19, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x72, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x29, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x66, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x25, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6f, 0x0a, 0x18, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x1a, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6f, 0x0a, + 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x1a, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x66, + 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x26, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x72, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2a, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x69, 0x0a, 0x16, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, + 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x63, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, + 0x73, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6c, + 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x66, + 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, + 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x26, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x73, 0x12, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, + 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x29, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x57, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x70, + 0x70, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x23, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x70, 0x70, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, + 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x4e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x27, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x5d, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x5d, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x72, + 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, + 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x27, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x4b, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, + 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, + 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x1d, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x61, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, + 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x12, + 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x48, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x12, + 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, + 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, + 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, + 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, + 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x12, + 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x51, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5d, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x73, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, + 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x42, 0x79, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, + 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5a, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x22, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x24, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x60, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, + 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x2e, 0x69, 0x6d, + 0x61, 0x6c, 0x6c, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_chat_chat_proto_rawDescOnce sync.Once + file_chat_chat_proto_rawDescData = file_chat_chat_proto_rawDesc +) + +func file_chat_chat_proto_rawDescGZIP() []byte { + file_chat_chat_proto_rawDescOnce.Do(func() { + file_chat_chat_proto_rawDescData = protoimpl.X.CompressGZIP(file_chat_chat_proto_rawDescData) + }) + return file_chat_chat_proto_rawDescData +} + +var file_chat_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 158) +var file_chat_chat_proto_goTypes = []interface{}{ + (*UserIdentity)(nil), // 0: openim.chat.UserIdentity + (*UpdateUserInfoReq)(nil), // 1: openim.chat.UpdateUserInfoReq + (*UpdateUserInfoResp)(nil), // 2: openim.chat.UpdateUserInfoResp + (*FindUserPublicInfoReq)(nil), // 3: openim.chat.FindUserPublicInfoReq + (*FindUserPublicInfoResp)(nil), // 4: openim.chat.FindUserPublicInfoResp + (*SearchUserPublicInfoReq)(nil), // 5: openim.chat.SearchUserPublicInfoReq + (*SearchUserPublicInfoResp)(nil), // 6: openim.chat.SearchUserPublicInfoResp + (*FindUserFullInfoReq)(nil), // 7: openim.chat.FindUserFullInfoReq + (*FindUserFullInfoResp)(nil), // 8: openim.chat.FindUserFullInfoResp + (*SendVerifyCodeReq)(nil), // 9: openim.chat.SendVerifyCodeReq + (*SendVerifyCodeResp)(nil), // 10: openim.chat.SendVerifyCodeResp + (*VerifyCodeReq)(nil), // 11: openim.chat.VerifyCodeReq + (*VerifyCodeResp)(nil), // 12: openim.chat.VerifyCodeResp + (*GetCaptchaImageReq)(nil), // 13: openim.chat.GetCaptchaImageReq + (*GetCaptchaImageResp)(nil), // 14: openim.chat.GetCaptchaImageResp + (*RegisterUserInfo)(nil), // 15: openim.chat.RegisterUserInfo + (*RegisterUserReq)(nil), // 16: openim.chat.RegisterUserReq + (*RegisterUserResp)(nil), // 17: openim.chat.RegisterUserResp + (*AddUserAccountReq)(nil), // 18: openim.chat.AddUserAccountReq + (*AddUserAccountResp)(nil), // 19: openim.chat.AddUserAccountResp + (*LoginReq)(nil), // 20: openim.chat.LoginReq + (*ResetPasswordReq)(nil), // 21: openim.chat.ResetPasswordReq + (*ResetPasswordResp)(nil), // 22: openim.chat.ResetPasswordResp + (*ChangePasswordReq)(nil), // 23: openim.chat.ChangePasswordReq + (*ChangePasswordResp)(nil), // 24: openim.chat.ChangePasswordResp + (*FindUserAccountReq)(nil), // 25: openim.chat.FindUserAccountReq + (*FindUserAccountResp)(nil), // 26: openim.chat.FindUserAccountResp + (*FindAccountUserReq)(nil), // 27: openim.chat.FindAccountUserReq + (*FindAccountUserResp)(nil), // 28: openim.chat.FindAccountUserResp + (*SignalRecord)(nil), // 29: openim.chat.SignalRecord + (*OpenIMCallbackReq)(nil), // 30: openim.chat.OpenIMCallbackReq + (*OpenIMCallbackResp)(nil), // 31: openim.chat.OpenIMCallbackResp + (*SearchUserFullInfoReq)(nil), // 32: openim.chat.SearchUserFullInfoReq + (*SearchUserFullInfoResp)(nil), // 33: openim.chat.SearchUserFullInfoResp + (*UserLoginCountReq)(nil), // 34: openim.chat.UserLoginCountReq + (*UserLoginCountResp)(nil), // 35: openim.chat.UserLoginCountResp + (*LoginResp)(nil), // 36: openim.chat.LoginResp + (*SearchUserInfoReq)(nil), // 37: openim.chat.SearchUserInfoReq + (*SearchUserInfoResp)(nil), // 38: openim.chat.SearchUserInfoResp + (*GetTokenForVideoMeetingReq)(nil), // 39: openim.chat.GetTokenForVideoMeetingReq + (*GetTokenForVideoMeetingResp)(nil), // 40: openim.chat.GetTokenForVideoMeetingResp + (*CheckUserExistReq)(nil), // 41: openim.chat.CheckUserExistReq + (*CheckUserExistResp)(nil), // 42: openim.chat.CheckUserExistResp + (*DelUserAccountReq)(nil), // 43: openim.chat.DelUserAccountReq + (*DelUserAccountResp)(nil), // 44: openim.chat.DelUserAccountResp + (*SetAllowRegisterReq)(nil), // 45: openim.chat.SetAllowRegisterReq + (*SetAllowRegisterResp)(nil), // 46: openim.chat.SetAllowRegisterResp + (*GetAllowRegisterReq)(nil), // 47: openim.chat.GetAllowRegisterReq + (*GetAllowRegisterResp)(nil), // 48: openim.chat.GetAllowRegisterResp + (*SensitiveWordInfo)(nil), // 49: openim.chat.SensitiveWordInfo + (*GetSensitiveWordsReq)(nil), // 50: openim.chat.GetSensitiveWordsReq + (*GetSensitiveWordsResp)(nil), // 51: openim.chat.GetSensitiveWordsResp + (*CheckSensitiveWordsReq)(nil), // 52: openim.chat.CheckSensitiveWordsReq + (*CheckSensitiveWordsResp)(nil), // 53: openim.chat.CheckSensitiveWordsResp + (*SensitiveWordDetailInfo)(nil), // 54: openim.chat.SensitiveWordDetailInfo + (*SensitiveWordGroupInfo)(nil), // 55: openim.chat.SensitiveWordGroupInfo + (*SensitiveWordConfigInfo)(nil), // 56: openim.chat.SensitiveWordConfigInfo + (*SensitiveWordLogInfo)(nil), // 57: openim.chat.SensitiveWordLogInfo + (*SensitiveWordStatsInfo)(nil), // 58: openim.chat.SensitiveWordStatsInfo + (*SensitiveWordLogStatsInfo)(nil), // 59: openim.chat.SensitiveWordLogStatsInfo + (*AddSensitiveWordReq)(nil), // 60: openim.chat.AddSensitiveWordReq + (*AddSensitiveWordResp)(nil), // 61: openim.chat.AddSensitiveWordResp + (*UpdateSensitiveWordReq)(nil), // 62: openim.chat.UpdateSensitiveWordReq + (*UpdateSensitiveWordResp)(nil), // 63: openim.chat.UpdateSensitiveWordResp + (*DeleteSensitiveWordReq)(nil), // 64: openim.chat.DeleteSensitiveWordReq + (*DeleteSensitiveWordResp)(nil), // 65: openim.chat.DeleteSensitiveWordResp + (*GetSensitiveWordReq)(nil), // 66: openim.chat.GetSensitiveWordReq + (*GetSensitiveWordResp)(nil), // 67: openim.chat.GetSensitiveWordResp + (*SearchSensitiveWordsReq)(nil), // 68: openim.chat.SearchSensitiveWordsReq + (*SearchSensitiveWordsResp)(nil), // 69: openim.chat.SearchSensitiveWordsResp + (*BatchAddSensitiveWordsReq)(nil), // 70: openim.chat.BatchAddSensitiveWordsReq + (*BatchAddSensitiveWordsResp)(nil), // 71: openim.chat.BatchAddSensitiveWordsResp + (*BatchUpdateSensitiveWordsReq)(nil), // 72: openim.chat.BatchUpdateSensitiveWordsReq + (*BatchUpdateSensitiveWordsResp)(nil), // 73: openim.chat.BatchUpdateSensitiveWordsResp + (*BatchDeleteSensitiveWordsReq)(nil), // 74: openim.chat.BatchDeleteSensitiveWordsReq + (*BatchDeleteSensitiveWordsResp)(nil), // 75: openim.chat.BatchDeleteSensitiveWordsResp + (*AddSensitiveWordGroupReq)(nil), // 76: openim.chat.AddSensitiveWordGroupReq + (*AddSensitiveWordGroupResp)(nil), // 77: openim.chat.AddSensitiveWordGroupResp + (*UpdateSensitiveWordGroupReq)(nil), // 78: openim.chat.UpdateSensitiveWordGroupReq + (*UpdateSensitiveWordGroupResp)(nil), // 79: openim.chat.UpdateSensitiveWordGroupResp + (*DeleteSensitiveWordGroupReq)(nil), // 80: openim.chat.DeleteSensitiveWordGroupReq + (*DeleteSensitiveWordGroupResp)(nil), // 81: openim.chat.DeleteSensitiveWordGroupResp + (*GetSensitiveWordGroupReq)(nil), // 82: openim.chat.GetSensitiveWordGroupReq + (*GetSensitiveWordGroupResp)(nil), // 83: openim.chat.GetSensitiveWordGroupResp + (*GetAllSensitiveWordGroupsReq)(nil), // 84: openim.chat.GetAllSensitiveWordGroupsReq + (*GetAllSensitiveWordGroupsResp)(nil), // 85: openim.chat.GetAllSensitiveWordGroupsResp + (*GetSensitiveWordConfigReq)(nil), // 86: openim.chat.GetSensitiveWordConfigReq + (*GetSensitiveWordConfigResp)(nil), // 87: openim.chat.GetSensitiveWordConfigResp + (*UpdateSensitiveWordConfigReq)(nil), // 88: openim.chat.UpdateSensitiveWordConfigReq + (*UpdateSensitiveWordConfigResp)(nil), // 89: openim.chat.UpdateSensitiveWordConfigResp + (*GetSensitiveWordLogsReq)(nil), // 90: openim.chat.GetSensitiveWordLogsReq + (*GetSensitiveWordLogsResp)(nil), // 91: openim.chat.GetSensitiveWordLogsResp + (*UserLoginRecordInfo)(nil), // 92: openim.chat.UserLoginRecordInfo + (*GetUserLoginRecordsReq)(nil), // 93: openim.chat.GetUserLoginRecordsReq + (*GetUserLoginRecordsResp)(nil), // 94: openim.chat.GetUserLoginRecordsResp + (*DeleteSensitiveWordLogsReq)(nil), // 95: openim.chat.DeleteSensitiveWordLogsReq + (*DeleteSensitiveWordLogsResp)(nil), // 96: openim.chat.DeleteSensitiveWordLogsResp + (*GetSensitiveWordStatsReq)(nil), // 97: openim.chat.GetSensitiveWordStatsReq + (*GetSensitiveWordStatsResp)(nil), // 98: openim.chat.GetSensitiveWordStatsResp + (*GetSensitiveWordLogStatsReq)(nil), // 99: openim.chat.GetSensitiveWordLogStatsReq + (*GetSensitiveWordLogStatsResp)(nil), // 100: openim.chat.GetSensitiveWordLogStatsResp + (*AddFriendReq)(nil), // 101: openim.chat.AddFriendReq + (*AddFriendResp)(nil), // 102: openim.chat.AddFriendResp + (*FavoriteInfo)(nil), // 103: openim.chat.FavoriteInfo + (*CreateFavoriteReq)(nil), // 104: openim.chat.CreateFavoriteReq + (*CreateFavoriteResp)(nil), // 105: openim.chat.CreateFavoriteResp + (*GetFavoriteReq)(nil), // 106: openim.chat.GetFavoriteReq + (*GetFavoriteResp)(nil), // 107: openim.chat.GetFavoriteResp + (*GetFavoritesReq)(nil), // 108: openim.chat.GetFavoritesReq + (*GetFavoritesResp)(nil), // 109: openim.chat.GetFavoritesResp + (*SearchFavoritesReq)(nil), // 110: openim.chat.SearchFavoritesReq + (*SearchFavoritesResp)(nil), // 111: openim.chat.SearchFavoritesResp + (*UpdateFavoriteReq)(nil), // 112: openim.chat.UpdateFavoriteReq + (*UpdateFavoriteResp)(nil), // 113: openim.chat.UpdateFavoriteResp + (*DeleteFavoriteReq)(nil), // 114: openim.chat.DeleteFavoriteReq + (*DeleteFavoriteResp)(nil), // 115: openim.chat.DeleteFavoriteResp + (*GetFavoritesByTagsReq)(nil), // 116: openim.chat.GetFavoritesByTagsReq + (*GetFavoritesByTagsResp)(nil), // 117: openim.chat.GetFavoritesByTagsResp + (*GetFavoriteCountReq)(nil), // 118: openim.chat.GetFavoriteCountReq + (*GetFavoriteCountResp)(nil), // 119: openim.chat.GetFavoriteCountResp + (*ScheduledTaskMessage)(nil), // 120: openim.chat.ScheduledTaskMessage + (*ScheduledTaskInfo)(nil), // 121: openim.chat.ScheduledTaskInfo + (*CreateScheduledTaskReq)(nil), // 122: openim.chat.CreateScheduledTaskReq + (*CreateScheduledTaskResp)(nil), // 123: openim.chat.CreateScheduledTaskResp + (*GetScheduledTaskReq)(nil), // 124: openim.chat.GetScheduledTaskReq + (*GetScheduledTaskResp)(nil), // 125: openim.chat.GetScheduledTaskResp + (*GetScheduledTasksReq)(nil), // 126: openim.chat.GetScheduledTasksReq + (*GetScheduledTasksResp)(nil), // 127: openim.chat.GetScheduledTasksResp + (*UpdateScheduledTaskReq)(nil), // 128: openim.chat.UpdateScheduledTaskReq + (*UpdateScheduledTaskResp)(nil), // 129: openim.chat.UpdateScheduledTaskResp + (*DeleteScheduledTaskReq)(nil), // 130: openim.chat.DeleteScheduledTaskReq + (*DeleteScheduledTaskResp)(nil), // 131: openim.chat.DeleteScheduledTaskResp + (*SystemConfigInfo)(nil), // 132: openim.chat.SystemConfigInfo + (*GetAppSystemConfigsReq)(nil), // 133: openim.chat.GetAppSystemConfigsReq + (*GetAppSystemConfigsResp)(nil), // 134: openim.chat.GetAppSystemConfigsResp + (*RealNameAuthInfo)(nil), // 135: openim.chat.RealNameAuthInfo + (*GetWalletBalanceReq)(nil), // 136: openim.chat.GetWalletBalanceReq + (*GetWalletBalanceResp)(nil), // 137: openim.chat.GetWalletBalanceResp + (*GetWalletInfoReq)(nil), // 138: openim.chat.GetWalletInfoReq + (*GetWalletInfoResp)(nil), // 139: openim.chat.GetWalletInfoResp + (*SetPaymentPasswordReq)(nil), // 140: openim.chat.SetPaymentPasswordReq + (*SetPaymentPasswordResp)(nil), // 141: openim.chat.SetPaymentPasswordResp + (*SetWithdrawAccountReq)(nil), // 142: openim.chat.SetWithdrawAccountReq + (*SetWithdrawAccountResp)(nil), // 143: openim.chat.SetWithdrawAccountResp + (*WalletBalanceRecordInfo)(nil), // 144: openim.chat.WalletBalanceRecordInfo + (*GetWalletBalanceRecordsReq)(nil), // 145: openim.chat.GetWalletBalanceRecordsReq + (*GetWalletBalanceRecordsResp)(nil), // 146: openim.chat.GetWalletBalanceRecordsResp + (*WithdrawApplicationInfo)(nil), // 147: openim.chat.WithdrawApplicationInfo + (*CreateWithdrawApplicationReq)(nil), // 148: openim.chat.CreateWithdrawApplicationReq + (*CreateWithdrawApplicationResp)(nil), // 149: openim.chat.CreateWithdrawApplicationResp + (*GetWithdrawApplicationsReq)(nil), // 150: openim.chat.GetWithdrawApplicationsReq + (*GetWithdrawApplicationsResp)(nil), // 151: openim.chat.GetWithdrawApplicationsResp + (*RealNameAuthReq)(nil), // 152: openim.chat.RealNameAuthReq + (*RealNameAuthResp)(nil), // 153: openim.chat.RealNameAuthResp + nil, // 154: openim.chat.FindUserAccountResp.UserAccountMapEntry + nil, // 155: openim.chat.FindAccountUserResp.AccountUserMapEntry + nil, // 156: openim.chat.UserLoginCountResp.CountEntry + nil, // 157: openim.chat.BatchUpdateSensitiveWordsReq.UpdatesEntry + (*wrapperspb.StringValue)(nil), // 158: openim.protobuf.StringValue + (*wrapperspb.Int32Value)(nil), // 159: openim.protobuf.Int32Value + (*wrapperspb.Int64Value)(nil), // 160: openim.protobuf.Int64Value + (*common.UserPublicInfo)(nil), // 161: openim.chat.common.UserPublicInfo + (*sdkws.RequestPagination)(nil), // 162: openim.sdkws.RequestPagination + (*common.UserFullInfo)(nil), // 163: openim.chat.common.UserFullInfo +} +var file_chat_chat_proto_depIdxs = []int32{ + 158, // 0: openim.chat.UpdateUserInfoReq.account:type_name -> openim.protobuf.StringValue + 158, // 1: openim.chat.UpdateUserInfoReq.phoneNumber:type_name -> openim.protobuf.StringValue + 158, // 2: openim.chat.UpdateUserInfoReq.areaCode:type_name -> openim.protobuf.StringValue + 158, // 3: openim.chat.UpdateUserInfoReq.email:type_name -> openim.protobuf.StringValue + 158, // 4: openim.chat.UpdateUserInfoReq.nickname:type_name -> openim.protobuf.StringValue + 158, // 5: openim.chat.UpdateUserInfoReq.faceURL:type_name -> openim.protobuf.StringValue + 159, // 6: openim.chat.UpdateUserInfoReq.gender:type_name -> openim.protobuf.Int32Value + 159, // 7: openim.chat.UpdateUserInfoReq.level:type_name -> openim.protobuf.Int32Value + 160, // 8: openim.chat.UpdateUserInfoReq.birth:type_name -> openim.protobuf.Int64Value + 159, // 9: openim.chat.UpdateUserInfoReq.allowAddFriend:type_name -> openim.protobuf.Int32Value + 159, // 10: openim.chat.UpdateUserInfoReq.allowBeep:type_name -> openim.protobuf.Int32Value + 159, // 11: openim.chat.UpdateUserInfoReq.allowVibration:type_name -> openim.protobuf.Int32Value + 159, // 12: openim.chat.UpdateUserInfoReq.globalRecvMsgOpt:type_name -> openim.protobuf.Int32Value + 159, // 13: openim.chat.UpdateUserInfoReq.RegisterType:type_name -> openim.protobuf.Int32Value + 158, // 14: openim.chat.UpdateUserInfoReq.userFlag:type_name -> openim.protobuf.StringValue + 161, // 15: openim.chat.FindUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo + 162, // 16: openim.chat.SearchUserPublicInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 161, // 17: openim.chat.SearchUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo + 163, // 18: openim.chat.FindUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 15, // 19: openim.chat.RegisterUserReq.user:type_name -> openim.chat.RegisterUserInfo + 15, // 20: openim.chat.AddUserAccountReq.user:type_name -> openim.chat.RegisterUserInfo + 154, // 21: openim.chat.FindUserAccountResp.userAccountMap:type_name -> openim.chat.FindUserAccountResp.UserAccountMapEntry + 155, // 22: openim.chat.FindAccountUserResp.accountUserMap:type_name -> openim.chat.FindAccountUserResp.AccountUserMapEntry + 161, // 23: openim.chat.SignalRecord.inviterUserList:type_name -> openim.chat.common.UserPublicInfo + 162, // 24: openim.chat.SearchUserFullInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 163, // 25: openim.chat.SearchUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 156, // 26: openim.chat.UserLoginCountResp.count:type_name -> openim.chat.UserLoginCountResp.CountEntry + 162, // 27: openim.chat.SearchUserInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 163, // 28: openim.chat.SearchUserInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 15, // 29: openim.chat.CheckUserExistReq.user:type_name -> openim.chat.RegisterUserInfo + 49, // 30: openim.chat.GetSensitiveWordsResp.words:type_name -> openim.chat.SensitiveWordInfo + 54, // 31: openim.chat.GetSensitiveWordResp.word:type_name -> openim.chat.SensitiveWordDetailInfo + 162, // 32: openim.chat.SearchSensitiveWordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 54, // 33: openim.chat.SearchSensitiveWordsResp.words:type_name -> openim.chat.SensitiveWordDetailInfo + 54, // 34: openim.chat.BatchAddSensitiveWordsReq.words:type_name -> openim.chat.SensitiveWordDetailInfo + 157, // 35: openim.chat.BatchUpdateSensitiveWordsReq.updates:type_name -> openim.chat.BatchUpdateSensitiveWordsReq.UpdatesEntry + 55, // 36: openim.chat.GetSensitiveWordGroupResp.group:type_name -> openim.chat.SensitiveWordGroupInfo + 55, // 37: openim.chat.GetAllSensitiveWordGroupsResp.groups:type_name -> openim.chat.SensitiveWordGroupInfo + 56, // 38: openim.chat.GetSensitiveWordConfigResp.config:type_name -> openim.chat.SensitiveWordConfigInfo + 56, // 39: openim.chat.UpdateSensitiveWordConfigReq.config:type_name -> openim.chat.SensitiveWordConfigInfo + 162, // 40: openim.chat.GetSensitiveWordLogsReq.pagination:type_name -> openim.sdkws.RequestPagination + 57, // 41: openim.chat.GetSensitiveWordLogsResp.logs:type_name -> openim.chat.SensitiveWordLogInfo + 162, // 42: openim.chat.GetUserLoginRecordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 92, // 43: openim.chat.GetUserLoginRecordsResp.records:type_name -> openim.chat.UserLoginRecordInfo + 58, // 44: openim.chat.GetSensitiveWordStatsResp.stats:type_name -> openim.chat.SensitiveWordStatsInfo + 59, // 45: openim.chat.GetSensitiveWordLogStatsResp.stats:type_name -> openim.chat.SensitiveWordLogStatsInfo + 103, // 46: openim.chat.GetFavoriteResp.favorite:type_name -> openim.chat.FavoriteInfo + 162, // 47: openim.chat.GetFavoritesReq.pagination:type_name -> openim.sdkws.RequestPagination + 103, // 48: openim.chat.GetFavoritesResp.favorites:type_name -> openim.chat.FavoriteInfo + 162, // 49: openim.chat.SearchFavoritesReq.pagination:type_name -> openim.sdkws.RequestPagination + 103, // 50: openim.chat.SearchFavoritesResp.favorites:type_name -> openim.chat.FavoriteInfo + 162, // 51: openim.chat.GetFavoritesByTagsReq.pagination:type_name -> openim.sdkws.RequestPagination + 103, // 52: openim.chat.GetFavoritesByTagsResp.favorites:type_name -> openim.chat.FavoriteInfo + 120, // 53: openim.chat.ScheduledTaskInfo.messages:type_name -> openim.chat.ScheduledTaskMessage + 120, // 54: openim.chat.CreateScheduledTaskReq.messages:type_name -> openim.chat.ScheduledTaskMessage + 121, // 55: openim.chat.GetScheduledTaskResp.task:type_name -> openim.chat.ScheduledTaskInfo + 162, // 56: openim.chat.GetScheduledTasksReq.pagination:type_name -> openim.sdkws.RequestPagination + 121, // 57: openim.chat.GetScheduledTasksResp.tasks:type_name -> openim.chat.ScheduledTaskInfo + 120, // 58: openim.chat.UpdateScheduledTaskReq.messages:type_name -> openim.chat.ScheduledTaskMessage + 132, // 59: openim.chat.GetAppSystemConfigsResp.configs:type_name -> openim.chat.SystemConfigInfo + 135, // 60: openim.chat.GetWalletInfoResp.realNameAuth:type_name -> openim.chat.RealNameAuthInfo + 162, // 61: openim.chat.GetWalletBalanceRecordsReq.pagination:type_name -> openim.sdkws.RequestPagination + 144, // 62: openim.chat.GetWalletBalanceRecordsResp.records:type_name -> openim.chat.WalletBalanceRecordInfo + 162, // 63: openim.chat.GetWithdrawApplicationsReq.pagination:type_name -> openim.sdkws.RequestPagination + 147, // 64: openim.chat.GetWithdrawApplicationsResp.applications:type_name -> openim.chat.WithdrawApplicationInfo + 54, // 65: openim.chat.BatchUpdateSensitiveWordsReq.UpdatesEntry.value:type_name -> openim.chat.SensitiveWordDetailInfo + 101, // 66: openim.chat.chat.AddFriend:input_type -> openim.chat.AddFriendReq + 1, // 67: openim.chat.chat.UpdateUserInfo:input_type -> openim.chat.UpdateUserInfoReq + 18, // 68: openim.chat.chat.AddUserAccount:input_type -> openim.chat.AddUserAccountReq + 5, // 69: openim.chat.chat.SearchUserPublicInfo:input_type -> openim.chat.SearchUserPublicInfoReq + 3, // 70: openim.chat.chat.FindUserPublicInfo:input_type -> openim.chat.FindUserPublicInfoReq + 32, // 71: openim.chat.chat.SearchUserFullInfo:input_type -> openim.chat.SearchUserFullInfoReq + 7, // 72: openim.chat.chat.FindUserFullInfo:input_type -> openim.chat.FindUserFullInfoReq + 9, // 73: openim.chat.chat.SendVerifyCode:input_type -> openim.chat.SendVerifyCodeReq + 11, // 74: openim.chat.chat.VerifyCode:input_type -> openim.chat.VerifyCodeReq + 13, // 75: openim.chat.chat.GetCaptchaImage:input_type -> openim.chat.GetCaptchaImageReq + 16, // 76: openim.chat.chat.RegisterUser:input_type -> openim.chat.RegisterUserReq + 20, // 77: openim.chat.chat.Login:input_type -> openim.chat.LoginReq + 21, // 78: openim.chat.chat.ResetPassword:input_type -> openim.chat.ResetPasswordReq + 23, // 79: openim.chat.chat.ChangePassword:input_type -> openim.chat.ChangePasswordReq + 41, // 80: openim.chat.chat.CheckUserExist:input_type -> openim.chat.CheckUserExistReq + 43, // 81: openim.chat.chat.DelUserAccount:input_type -> openim.chat.DelUserAccountReq + 25, // 82: openim.chat.chat.FindUserAccount:input_type -> openim.chat.FindUserAccountReq + 27, // 83: openim.chat.chat.FindAccountUser:input_type -> openim.chat.FindAccountUserReq + 30, // 84: openim.chat.chat.OpenIMCallback:input_type -> openim.chat.OpenIMCallbackReq + 34, // 85: openim.chat.chat.UserLoginCount:input_type -> openim.chat.UserLoginCountReq + 37, // 86: openim.chat.chat.SearchUserInfo:input_type -> openim.chat.SearchUserInfoReq + 39, // 87: openim.chat.chat.GetTokenForVideoMeeting:input_type -> openim.chat.GetTokenForVideoMeetingReq + 45, // 88: openim.chat.chat.SetAllowRegister:input_type -> openim.chat.SetAllowRegisterReq + 47, // 89: openim.chat.chat.GetAllowRegister:input_type -> openim.chat.GetAllowRegisterReq + 50, // 90: openim.chat.chat.GetSensitiveWords:input_type -> openim.chat.GetSensitiveWordsReq + 52, // 91: openim.chat.chat.CheckSensitiveWords:input_type -> openim.chat.CheckSensitiveWordsReq + 60, // 92: openim.chat.chat.AddSensitiveWord:input_type -> openim.chat.AddSensitiveWordReq + 62, // 93: openim.chat.chat.UpdateSensitiveWord:input_type -> openim.chat.UpdateSensitiveWordReq + 64, // 94: openim.chat.chat.DeleteSensitiveWord:input_type -> openim.chat.DeleteSensitiveWordReq + 66, // 95: openim.chat.chat.GetSensitiveWord:input_type -> openim.chat.GetSensitiveWordReq + 68, // 96: openim.chat.chat.SearchSensitiveWords:input_type -> openim.chat.SearchSensitiveWordsReq + 70, // 97: openim.chat.chat.BatchAddSensitiveWords:input_type -> openim.chat.BatchAddSensitiveWordsReq + 72, // 98: openim.chat.chat.BatchUpdateSensitiveWords:input_type -> openim.chat.BatchUpdateSensitiveWordsReq + 74, // 99: openim.chat.chat.BatchDeleteSensitiveWords:input_type -> openim.chat.BatchDeleteSensitiveWordsReq + 76, // 100: openim.chat.chat.AddSensitiveWordGroup:input_type -> openim.chat.AddSensitiveWordGroupReq + 78, // 101: openim.chat.chat.UpdateSensitiveWordGroup:input_type -> openim.chat.UpdateSensitiveWordGroupReq + 80, // 102: openim.chat.chat.DeleteSensitiveWordGroup:input_type -> openim.chat.DeleteSensitiveWordGroupReq + 82, // 103: openim.chat.chat.GetSensitiveWordGroup:input_type -> openim.chat.GetSensitiveWordGroupReq + 84, // 104: openim.chat.chat.GetAllSensitiveWordGroups:input_type -> openim.chat.GetAllSensitiveWordGroupsReq + 86, // 105: openim.chat.chat.GetSensitiveWordConfig:input_type -> openim.chat.GetSensitiveWordConfigReq + 88, // 106: openim.chat.chat.UpdateSensitiveWordConfig:input_type -> openim.chat.UpdateSensitiveWordConfigReq + 90, // 107: openim.chat.chat.GetSensitiveWordLogs:input_type -> openim.chat.GetSensitiveWordLogsReq + 95, // 108: openim.chat.chat.DeleteSensitiveWordLogs:input_type -> openim.chat.DeleteSensitiveWordLogsReq + 93, // 109: openim.chat.chat.GetUserLoginRecords:input_type -> openim.chat.GetUserLoginRecordsReq + 97, // 110: openim.chat.chat.GetSensitiveWordStats:input_type -> openim.chat.GetSensitiveWordStatsReq + 99, // 111: openim.chat.chat.GetSensitiveWordLogStats:input_type -> openim.chat.GetSensitiveWordLogStatsReq + 133, // 112: openim.chat.chat.GetAppSystemConfigs:input_type -> openim.chat.GetAppSystemConfigsReq + 136, // 113: openim.chat.chat.GetWalletBalance:input_type -> openim.chat.GetWalletBalanceReq + 138, // 114: openim.chat.chat.GetWalletInfo:input_type -> openim.chat.GetWalletInfoReq + 145, // 115: openim.chat.chat.GetWalletBalanceRecords:input_type -> openim.chat.GetWalletBalanceRecordsReq + 140, // 116: openim.chat.chat.SetPaymentPassword:input_type -> openim.chat.SetPaymentPasswordReq + 142, // 117: openim.chat.chat.SetWithdrawAccount:input_type -> openim.chat.SetWithdrawAccountReq + 148, // 118: openim.chat.chat.CreateWithdrawApplication:input_type -> openim.chat.CreateWithdrawApplicationReq + 150, // 119: openim.chat.chat.GetWithdrawApplications:input_type -> openim.chat.GetWithdrawApplicationsReq + 152, // 120: openim.chat.chat.RealNameAuth:input_type -> openim.chat.RealNameAuthReq + 104, // 121: openim.chat.chat.CreateFavorite:input_type -> openim.chat.CreateFavoriteReq + 106, // 122: openim.chat.chat.GetFavorite:input_type -> openim.chat.GetFavoriteReq + 108, // 123: openim.chat.chat.GetFavorites:input_type -> openim.chat.GetFavoritesReq + 110, // 124: openim.chat.chat.SearchFavorites:input_type -> openim.chat.SearchFavoritesReq + 112, // 125: openim.chat.chat.UpdateFavorite:input_type -> openim.chat.UpdateFavoriteReq + 114, // 126: openim.chat.chat.DeleteFavorite:input_type -> openim.chat.DeleteFavoriteReq + 116, // 127: openim.chat.chat.GetFavoritesByTags:input_type -> openim.chat.GetFavoritesByTagsReq + 118, // 128: openim.chat.chat.GetFavoriteCount:input_type -> openim.chat.GetFavoriteCountReq + 122, // 129: openim.chat.chat.CreateScheduledTask:input_type -> openim.chat.CreateScheduledTaskReq + 124, // 130: openim.chat.chat.GetScheduledTask:input_type -> openim.chat.GetScheduledTaskReq + 126, // 131: openim.chat.chat.GetScheduledTasks:input_type -> openim.chat.GetScheduledTasksReq + 128, // 132: openim.chat.chat.UpdateScheduledTask:input_type -> openim.chat.UpdateScheduledTaskReq + 130, // 133: openim.chat.chat.DeleteScheduledTask:input_type -> openim.chat.DeleteScheduledTaskReq + 102, // 134: openim.chat.chat.AddFriend:output_type -> openim.chat.AddFriendResp + 2, // 135: openim.chat.chat.UpdateUserInfo:output_type -> openim.chat.UpdateUserInfoResp + 19, // 136: openim.chat.chat.AddUserAccount:output_type -> openim.chat.AddUserAccountResp + 6, // 137: openim.chat.chat.SearchUserPublicInfo:output_type -> openim.chat.SearchUserPublicInfoResp + 4, // 138: openim.chat.chat.FindUserPublicInfo:output_type -> openim.chat.FindUserPublicInfoResp + 33, // 139: openim.chat.chat.SearchUserFullInfo:output_type -> openim.chat.SearchUserFullInfoResp + 8, // 140: openim.chat.chat.FindUserFullInfo:output_type -> openim.chat.FindUserFullInfoResp + 10, // 141: openim.chat.chat.SendVerifyCode:output_type -> openim.chat.SendVerifyCodeResp + 12, // 142: openim.chat.chat.VerifyCode:output_type -> openim.chat.VerifyCodeResp + 14, // 143: openim.chat.chat.GetCaptchaImage:output_type -> openim.chat.GetCaptchaImageResp + 17, // 144: openim.chat.chat.RegisterUser:output_type -> openim.chat.RegisterUserResp + 36, // 145: openim.chat.chat.Login:output_type -> openim.chat.LoginResp + 22, // 146: openim.chat.chat.ResetPassword:output_type -> openim.chat.ResetPasswordResp + 24, // 147: openim.chat.chat.ChangePassword:output_type -> openim.chat.ChangePasswordResp + 42, // 148: openim.chat.chat.CheckUserExist:output_type -> openim.chat.CheckUserExistResp + 44, // 149: openim.chat.chat.DelUserAccount:output_type -> openim.chat.DelUserAccountResp + 26, // 150: openim.chat.chat.FindUserAccount:output_type -> openim.chat.FindUserAccountResp + 28, // 151: openim.chat.chat.FindAccountUser:output_type -> openim.chat.FindAccountUserResp + 31, // 152: openim.chat.chat.OpenIMCallback:output_type -> openim.chat.OpenIMCallbackResp + 35, // 153: openim.chat.chat.UserLoginCount:output_type -> openim.chat.UserLoginCountResp + 38, // 154: openim.chat.chat.SearchUserInfo:output_type -> openim.chat.SearchUserInfoResp + 40, // 155: openim.chat.chat.GetTokenForVideoMeeting:output_type -> openim.chat.GetTokenForVideoMeetingResp + 46, // 156: openim.chat.chat.SetAllowRegister:output_type -> openim.chat.SetAllowRegisterResp + 48, // 157: openim.chat.chat.GetAllowRegister:output_type -> openim.chat.GetAllowRegisterResp + 51, // 158: openim.chat.chat.GetSensitiveWords:output_type -> openim.chat.GetSensitiveWordsResp + 53, // 159: openim.chat.chat.CheckSensitiveWords:output_type -> openim.chat.CheckSensitiveWordsResp + 61, // 160: openim.chat.chat.AddSensitiveWord:output_type -> openim.chat.AddSensitiveWordResp + 63, // 161: openim.chat.chat.UpdateSensitiveWord:output_type -> openim.chat.UpdateSensitiveWordResp + 65, // 162: openim.chat.chat.DeleteSensitiveWord:output_type -> openim.chat.DeleteSensitiveWordResp + 67, // 163: openim.chat.chat.GetSensitiveWord:output_type -> openim.chat.GetSensitiveWordResp + 69, // 164: openim.chat.chat.SearchSensitiveWords:output_type -> openim.chat.SearchSensitiveWordsResp + 71, // 165: openim.chat.chat.BatchAddSensitiveWords:output_type -> openim.chat.BatchAddSensitiveWordsResp + 73, // 166: openim.chat.chat.BatchUpdateSensitiveWords:output_type -> openim.chat.BatchUpdateSensitiveWordsResp + 75, // 167: openim.chat.chat.BatchDeleteSensitiveWords:output_type -> openim.chat.BatchDeleteSensitiveWordsResp + 77, // 168: openim.chat.chat.AddSensitiveWordGroup:output_type -> openim.chat.AddSensitiveWordGroupResp + 79, // 169: openim.chat.chat.UpdateSensitiveWordGroup:output_type -> openim.chat.UpdateSensitiveWordGroupResp + 81, // 170: openim.chat.chat.DeleteSensitiveWordGroup:output_type -> openim.chat.DeleteSensitiveWordGroupResp + 83, // 171: openim.chat.chat.GetSensitiveWordGroup:output_type -> openim.chat.GetSensitiveWordGroupResp + 85, // 172: openim.chat.chat.GetAllSensitiveWordGroups:output_type -> openim.chat.GetAllSensitiveWordGroupsResp + 87, // 173: openim.chat.chat.GetSensitiveWordConfig:output_type -> openim.chat.GetSensitiveWordConfigResp + 89, // 174: openim.chat.chat.UpdateSensitiveWordConfig:output_type -> openim.chat.UpdateSensitiveWordConfigResp + 91, // 175: openim.chat.chat.GetSensitiveWordLogs:output_type -> openim.chat.GetSensitiveWordLogsResp + 96, // 176: openim.chat.chat.DeleteSensitiveWordLogs:output_type -> openim.chat.DeleteSensitiveWordLogsResp + 94, // 177: openim.chat.chat.GetUserLoginRecords:output_type -> openim.chat.GetUserLoginRecordsResp + 98, // 178: openim.chat.chat.GetSensitiveWordStats:output_type -> openim.chat.GetSensitiveWordStatsResp + 100, // 179: openim.chat.chat.GetSensitiveWordLogStats:output_type -> openim.chat.GetSensitiveWordLogStatsResp + 134, // 180: openim.chat.chat.GetAppSystemConfigs:output_type -> openim.chat.GetAppSystemConfigsResp + 137, // 181: openim.chat.chat.GetWalletBalance:output_type -> openim.chat.GetWalletBalanceResp + 139, // 182: openim.chat.chat.GetWalletInfo:output_type -> openim.chat.GetWalletInfoResp + 146, // 183: openim.chat.chat.GetWalletBalanceRecords:output_type -> openim.chat.GetWalletBalanceRecordsResp + 141, // 184: openim.chat.chat.SetPaymentPassword:output_type -> openim.chat.SetPaymentPasswordResp + 143, // 185: openim.chat.chat.SetWithdrawAccount:output_type -> openim.chat.SetWithdrawAccountResp + 149, // 186: openim.chat.chat.CreateWithdrawApplication:output_type -> openim.chat.CreateWithdrawApplicationResp + 151, // 187: openim.chat.chat.GetWithdrawApplications:output_type -> openim.chat.GetWithdrawApplicationsResp + 153, // 188: openim.chat.chat.RealNameAuth:output_type -> openim.chat.RealNameAuthResp + 105, // 189: openim.chat.chat.CreateFavorite:output_type -> openim.chat.CreateFavoriteResp + 107, // 190: openim.chat.chat.GetFavorite:output_type -> openim.chat.GetFavoriteResp + 109, // 191: openim.chat.chat.GetFavorites:output_type -> openim.chat.GetFavoritesResp + 111, // 192: openim.chat.chat.SearchFavorites:output_type -> openim.chat.SearchFavoritesResp + 113, // 193: openim.chat.chat.UpdateFavorite:output_type -> openim.chat.UpdateFavoriteResp + 115, // 194: openim.chat.chat.DeleteFavorite:output_type -> openim.chat.DeleteFavoriteResp + 117, // 195: openim.chat.chat.GetFavoritesByTags:output_type -> openim.chat.GetFavoritesByTagsResp + 119, // 196: openim.chat.chat.GetFavoriteCount:output_type -> openim.chat.GetFavoriteCountResp + 123, // 197: openim.chat.chat.CreateScheduledTask:output_type -> openim.chat.CreateScheduledTaskResp + 125, // 198: openim.chat.chat.GetScheduledTask:output_type -> openim.chat.GetScheduledTaskResp + 127, // 199: openim.chat.chat.GetScheduledTasks:output_type -> openim.chat.GetScheduledTasksResp + 129, // 200: openim.chat.chat.UpdateScheduledTask:output_type -> openim.chat.UpdateScheduledTaskResp + 131, // 201: openim.chat.chat.DeleteScheduledTask:output_type -> openim.chat.DeleteScheduledTaskResp + 134, // [134:202] is the sub-list for method output_type + 66, // [66:134] is the sub-list for method input_type + 66, // [66:66] is the sub-list for extension type_name + 66, // [66:66] is the sub-list for extension extendee + 0, // [0:66] is the sub-list for field type_name +} + +func init() { file_chat_chat_proto_init() } +func file_chat_chat_proto_init() { + if File_chat_chat_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_chat_chat_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserIdentity); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserPublicInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserPublicInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserPublicInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserPublicInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserFullInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserFullInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendVerifyCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendVerifyCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyCodeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyCodeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCaptchaImageReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCaptchaImageResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterUserInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddUserAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddUserAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetPasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetPasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindUserAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindAccountUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FindAccountUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenIMCallbackReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OpenIMCallbackResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserFullInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserFullInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserLoginCountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserLoginCountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTokenForVideoMeetingReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTokenForVideoMeetingResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckUserExistReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckUserExistResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelUserAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DelUserAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetAllowRegisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetAllowRegisterResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllowRegisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllowRegisterResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordDetailInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordGroupInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordConfigInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordLogInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordStatsInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SensitiveWordLogStatsInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchAddSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchAddSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchDeleteSensitiveWordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchDeleteSensitiveWordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSensitiveWordGroupsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllSensitiveWordGroupsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordConfigReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateSensitiveWordConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserLoginRecordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserLoginRecordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserLoginRecordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordLogsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSensitiveWordLogsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordStatsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordStatsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogStatsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSensitiveWordLogStatsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddFriendReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddFriendResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FavoriteInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateFavoriteReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateFavoriteResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoriteReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoriteResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoritesReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoritesResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchFavoritesReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchFavoritesResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateFavoriteReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[113].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateFavoriteResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[114].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteFavoriteReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[115].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteFavoriteResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[116].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoritesByTagsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[117].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoritesByTagsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[118].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoriteCountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[119].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFavoriteCountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[120].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScheduledTaskMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[121].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScheduledTaskInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[122].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateScheduledTaskReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[123].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateScheduledTaskResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[124].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTaskReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[125].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTaskResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[126].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTasksReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[127].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetScheduledTasksResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[128].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateScheduledTaskReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[129].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateScheduledTaskResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[130].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteScheduledTaskReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[131].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteScheduledTaskResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[132].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SystemConfigInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[133].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAppSystemConfigsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[134].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAppSystemConfigsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[135].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RealNameAuthInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[136].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletBalanceReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[137].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletBalanceResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[138].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletInfoReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[139].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletInfoResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[140].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetPaymentPasswordReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[141].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetPaymentPasswordResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[142].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetWithdrawAccountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[143].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetWithdrawAccountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[144].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WalletBalanceRecordInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[145].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletBalanceRecordsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[146].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWalletBalanceRecordsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[147].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WithdrawApplicationInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[148].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateWithdrawApplicationReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[149].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateWithdrawApplicationResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[150].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawApplicationsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[151].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetWithdrawApplicationsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[152].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RealNameAuthReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[153].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RealNameAuthResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_chat_chat_proto_rawDesc, + NumEnums: 0, + NumMessages: 158, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_chat_chat_proto_goTypes, + DependencyIndexes: file_chat_chat_proto_depIdxs, + MessageInfos: file_chat_chat_proto_msgTypes, + }.Build() + File_chat_chat_proto = out.File + file_chat_chat_proto_rawDesc = nil + file_chat_chat_proto_goTypes = nil + file_chat_chat_proto_depIdxs = nil +} diff --git a/pkg/protocol/chat/chat.proto b/pkg/protocol/chat/chat.proto new file mode 100644 index 0000000..14af995 --- /dev/null +++ b/pkg/protocol/chat/chat.proto @@ -0,0 +1,1118 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; +package openim.chat; + +import "common/common.proto"; +import "sdkws/sdkws.proto"; +import "wrapperspb/wrapperspb.proto"; + +option go_package = "git.imall.cloud/openim/chat/pkg/protocol/chat"; + +message UserIdentity { + string email = 1; + string areaCode = 2; + string phoneNumber = 3; + string deviceID = 4; + int32 platform = 5; + string account = 6; +} + +message UpdateUserInfoReq { + string userID = 1; + openim.protobuf.StringValue account = 2; + openim.protobuf.StringValue phoneNumber = 3; + openim.protobuf.StringValue areaCode = 4; + openim.protobuf.StringValue email = 5; + openim.protobuf.StringValue nickname = 6; + openim.protobuf.StringValue faceURL = 7; + openim.protobuf.Int32Value gender = 8; + openim.protobuf.Int32Value level = 9; + openim.protobuf.Int64Value birth = 10; + openim.protobuf.Int32Value allowAddFriend = 11; + openim.protobuf.Int32Value allowBeep = 12; + openim.protobuf.Int32Value allowVibration = 13; + openim.protobuf.Int32Value globalRecvMsgOpt = 14; + openim.protobuf.Int32Value RegisterType = 15; + int32 userType = 16; // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + openim.protobuf.StringValue userFlag = 17; // 用户标签/标识,类似UserType的字符串版本 +} + +message UpdateUserInfoResp { + string faceUrl = 1; + string nickName = 2; +} + +message FindUserPublicInfoReq { + repeated string userIDs = 1; +} + +message FindUserPublicInfoResp { + repeated openim.chat.common.UserPublicInfo users = 1; +} + +message SearchUserPublicInfoReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; + int32 genders = 3; +} + +message SearchUserPublicInfoResp { + uint32 total = 1; + repeated openim.chat.common.UserPublicInfo users = 2; +} + +message FindUserFullInfoReq { + repeated string userIDs = 1; +} + +message FindUserFullInfoResp { + repeated openim.chat.common.UserFullInfo users = 1; +} + +message SendVerifyCodeReq { + int32 usedFor = 1; + string ip = 2; + string invitationCode = 3; + string deviceID = 4; + int32 platform = 5; + string areaCode = 6; + string phoneNumber = 7; + string email = 8; +} + +message SendVerifyCodeResp {} + +message VerifyCodeReq { + string areaCode = 1; + string phoneNumber = 2; + string verifyCode = 3; + string email = 4; + string captchaID = 5; // 图片验证码ID(可选,如果提供则验证图片验证码) + string account = 6; // 用户名(用于账号注册验证) +} + +message VerifyCodeResp { + string registerToken = 1; // H5注册token(仅在验证图片验证码成功后返回,用于后续注册,有效期120秒) +} + +message GetCaptchaImageReq {} + +message GetCaptchaImageResp { + string captchaID = 1; // 验证码ID,用于后续验证 + string code = 2; // 6位数字验证码(用于生成图片) +} + +message RegisterUserInfo { + string userID = 1; + string nickname = 2; + string faceURL = 3; + int64 birth = 4; + int32 gender = 5; + string areaCode = 6; + string phoneNumber = 7; + string email = 8; + string account = 9; + string password = 10; + int32 RegisterType = 11; + int32 userType = 12; // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + string userFlag = 13; // 用户标签/标识 +} + +message RegisterUserReq { + string invitationCode = 1; + string verifyCode = 2; + string ip = 3; + string deviceID = 4; + int32 platform = 5; + bool autoLogin = 6; + RegisterUserInfo user = 7; + string registerToken = 8; // H5注册token(可选,用于H5注册场景,验证手机号合法性) +} + +message RegisterUserResp { + string userID = 1; + string chatToken = 3; +} + +message AddUserAccountReq { + string ip = 1; + string deviceID = 2; + int32 platform = 3; + RegisterUserInfo user = 4; +} + +message AddUserAccountResp {} + +message LoginReq { + string areaCode = 1; + string phoneNumber = 2; + string verifyCode = 3; + string account = 4; + string password = 5; + int32 platform = 6; + string deviceID = 7; + string ip = 8; + string email = 9; +} + +message ResetPasswordReq { + string areaCode = 1; + string phoneNumber = 2; + string verifyCode = 3; + string password = 4; + string email = 5; +} + +message ResetPasswordResp {} + +message ChangePasswordReq { + string userID = 1; + string currentPassword = 2; + string newPassword = 3; +} + +message ChangePasswordResp {} + +message FindUserAccountReq { + repeated string userIDs = 1; +} + +message FindUserAccountResp { + map userAccountMap = 1; // userID account +} + +message FindAccountUserReq { + repeated string accounts = 1; +} + +message FindAccountUserResp { + map accountUserMap = 1; // account userID +} + +message SignalRecord { + string fileName = 1; + string mediaType = 2; + string roomType = 3; + string senderID = 4; + string senderNickname = 5; + string recvID = 6; + string recvNickname = 7; + string groupID = 8; + string groupName = 9; + repeated openim.chat.common.UserPublicInfo inviterUserList = 10; + int32 duration = 11; + int64 createTime = 12; + string size = 13; + string downloadURL = 14; +} + +message OpenIMCallbackReq { + string command = 1; + string body = 2; +} + +message OpenIMCallbackResp {} + +message SearchUserFullInfoReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; + int32 genders = 3; + int32 normal = 4; + int64 startTime = 5; // 注册时间范围开始时间(毫秒时间戳) + int64 endTime = 6; // 注册时间范围结束时间(毫秒时间戳) + string realNameKeyword = 7; // 真实姓名搜索关键词(可选) + string idCardKeyword = 8; // 身份证号搜索关键词(可选) +} + +message SearchUserFullInfoResp { + uint32 total = 1; + repeated openim.chat.common.UserFullInfo users = 2; +} + +message UserLoginCountReq { + int64 start = 1; + int64 end = 2; +} + +message UserLoginCountResp { + int64 loginCount = 1; + int64 unloginCount = 2; + map count = 3; +} + +message LoginResp { + string chatToken = 2; + string userID = 3; +} + +message SearchUserInfoReq { + string keyword = 1; + openim.sdkws.RequestPagination pagination = 2; + repeated int32 genders = 3; + repeated string userIDs = 4; +} + +message SearchUserInfoResp { + uint32 total = 1; + repeated openim.chat.common.UserFullInfo users = 2; +} + +message GetTokenForVideoMeetingReq { + string room = 1; + string identity = 2; +} + +message GetTokenForVideoMeetingResp { + string serverUrl = 1; + string token = 2; +} + +message CheckUserExistReq { + RegisterUserInfo user = 1; +} + +message CheckUserExistResp { + string userid = 1; + bool isRegistered = 2; +} + +message DelUserAccountReq { + repeated string userIDs = 1; +} +message DelUserAccountResp {} + +message SetAllowRegisterReq { + bool allowRegister = 1; +} + +message SetAllowRegisterResp { +} + +message GetAllowRegisterReq { +} + +message GetAllowRegisterResp { + bool allowRegister = 1; +} + +// ==================== 敏感词检测相关消息(用户端) ==================== + +// 敏感词信息(简化版,客户端用) +message SensitiveWordInfo { + string word = 1; // 敏感词内容 + int32 action = 2; // 处理动作 1:替换为*** 2:拦截不发 + string replaceChar = 3; // 替换字符 +} + +// 获取敏感词列表请求 +message GetSensitiveWordsReq {} + +// 获取敏感词列表响应 +message GetSensitiveWordsResp { + repeated SensitiveWordInfo words = 1; // 敏感词列表 + bool enableFilter = 2; // 是否启用过滤 + string defaultReplaceChar = 3; // 默认替换字符 +} + +// 检测敏感词请求(用户发送消息时调用) +message CheckSensitiveWordsReq { + string content = 1; // 要检测的内容 +} + +// 检测敏感词响应 +message CheckSensitiveWordsResp { + bool hasSensitive = 1; // 是否包含敏感词 + string filteredContent = 2; // 过滤后的内容(如果被替换) + repeated string matchedWords = 3; // 匹配到的敏感词列表 +} + +// ==================== 敏感词管理相关消息(管理端) ==================== + +// 敏感词详细信息(管理端) +message SensitiveWordDetailInfo { + string id = 1; + string word = 2; + int32 level = 3; + int32 type = 4; + int32 action = 5; + int32 status = 6; + string creator = 7; + string updater = 8; + int64 create_time = 9; + int64 update_time = 10; + string remark = 11; +} + +// 敏感词分组信息 +message SensitiveWordGroupInfo { + string id = 1; + string name = 2; + string remark = 3; + int64 create_time = 4; + int64 update_time = 5; +} + +// 敏感词配置信息 +message SensitiveWordConfigInfo { + string id = 1; + bool enable_filter = 2; + int32 filter_mode = 3; + string replace_char = 4; + repeated string whitelist_users = 5; + repeated string whitelist_groups = 6; + bool log_enabled = 7; + bool auto_approve = 8; + int64 update_time = 9; +} + +// 敏感词日志信息 +message SensitiveWordLogInfo { + string id = 1; + string user_id = 2; + string group_id = 3; + string content = 4; + repeated string matched_words = 5; + int32 action = 6; + string processed_text = 7; + int64 create_time = 8; +} + +// 敏感词统计信息 +message SensitiveWordStatsInfo { + int64 total = 1; + int64 enabled = 2; + int64 disabled = 3; + int64 replace = 4; + int64 block = 5; +} + +// 敏感词日志统计信息 +message SensitiveWordLogStatsInfo { + int64 total = 1; + int64 replace = 2; + int64 block = 3; +} + +// 添加敏感词 +message AddSensitiveWordReq { + string word = 1; + int32 level = 2; + int32 type = 3; + int32 action = 4; + int32 status = 5; + string remark = 6; +} + +message AddSensitiveWordResp {} + +// 更新敏感词 +message UpdateSensitiveWordReq { + string id = 1; + string word = 2; + int32 level = 3; + int32 type = 4; + int32 action = 5; + int32 status = 6; + string remark = 7; +} + +message UpdateSensitiveWordResp {} + +// 删除敏感词 +message DeleteSensitiveWordReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordResp {} + +// 获取敏感词 +message GetSensitiveWordReq { + string id = 1; +} + +message GetSensitiveWordResp { + SensitiveWordDetailInfo word = 1; +} + +// 搜索敏感词 +message SearchSensitiveWordsReq { + string keyword = 1; + int32 action = 2; + int32 status = 3; + openim.sdkws.RequestPagination pagination = 4; +} + +message SearchSensitiveWordsResp { + uint32 total = 1; + repeated SensitiveWordDetailInfo words = 2; +} + +// 批量添加敏感词 +message BatchAddSensitiveWordsReq { + repeated SensitiveWordDetailInfo words = 1; +} + +message BatchAddSensitiveWordsResp {} + +// 批量更新敏感词 +message BatchUpdateSensitiveWordsReq { + map updates = 1; +} + +message BatchUpdateSensitiveWordsResp {} + +// 批量删除敏感词 +message BatchDeleteSensitiveWordsReq { + repeated string ids = 1; +} + +message BatchDeleteSensitiveWordsResp {} + +// 添加敏感词分组 +message AddSensitiveWordGroupReq { + string name = 1; + string remark = 2; +} + +message AddSensitiveWordGroupResp {} + +// 更新敏感词分组 +message UpdateSensitiveWordGroupReq { + string id = 1; + string name = 2; + string remark = 3; +} + +message UpdateSensitiveWordGroupResp {} + +// 删除敏感词分组 +message DeleteSensitiveWordGroupReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordGroupResp {} + +// 获取敏感词分组 +message GetSensitiveWordGroupReq { + string id = 1; +} + +message GetSensitiveWordGroupResp { + SensitiveWordGroupInfo group = 1; +} + +// 获取所有敏感词分组 +message GetAllSensitiveWordGroupsReq {} + +message GetAllSensitiveWordGroupsResp { + repeated SensitiveWordGroupInfo groups = 1; +} + +// 获取敏感词配置 +message GetSensitiveWordConfigReq {} + +message GetSensitiveWordConfigResp { + SensitiveWordConfigInfo config = 1; +} + +// 更新敏感词配置 +message UpdateSensitiveWordConfigReq { + SensitiveWordConfigInfo config = 1; +} + +message UpdateSensitiveWordConfigResp {} + +// 获取敏感词日志 +message GetSensitiveWordLogsReq { + string user_id = 1; + string group_id = 2; + openim.sdkws.RequestPagination pagination = 3; +} + +message GetSensitiveWordLogsResp { + uint32 total = 1; + repeated SensitiveWordLogInfo logs = 2; +} + +// 用户登录记录信息 +message UserLoginRecordInfo { + string user_id = 1; // 用户ID + int64 login_time = 2; // 登录时间(毫秒时间戳) + string ip = 3; // 登录IP + string device_id = 4; // 设备ID + string platform = 5; // 平台 + string face_url = 6; // 用户头像 + string nickname = 7; // 用户昵称 +} + +// 查询用户登录记录请求 +message GetUserLoginRecordsReq { + string user_id = 1; // 用户ID(可选,如果提供则查询该用户的登录记录) + string ip = 2; // IP地址(可选,如果提供则查询使用该IP的所有登录记录) + openim.sdkws.RequestPagination pagination = 3; // 分页信息 +} + +// 查询用户登录记录响应 +message GetUserLoginRecordsResp { + uint32 total = 1; // 总数 + repeated UserLoginRecordInfo records = 2; // 登录记录列表 +} + +// 删除敏感词日志 +message DeleteSensitiveWordLogsReq { + repeated string ids = 1; +} + +message DeleteSensitiveWordLogsResp {} + +// 获取敏感词统计 +message GetSensitiveWordStatsReq {} + +message GetSensitiveWordStatsResp { + SensitiveWordStatsInfo stats = 1; +} + +// 获取敏感词日志统计 +message GetSensitiveWordLogStatsReq { + int64 start_time = 1; + int64 end_time = 2; +} + +message GetSensitiveWordLogStatsResp { + SensitiveWordLogStatsInfo stats = 1; +} + +message AddFriendReq { + string userID = 1; +} + +message AddFriendResp {} + +// ==================== 收藏相关消息 ==================== + +// 收藏信息 +message FavoriteInfo { + string id = 1; // 收藏ID + string userID = 2; // 用户ID + int32 type = 3; // 收藏类型:1-文本,2-图片,3-链接,4-文件,5-语音,6-视频,7-位置 + string title = 4; // 标题 + string content = 5; // 内容 + string description = 6; // 描述 + string thumbnail = 7; // 缩略图URL + string linkURL = 8; // 链接URL + int64 fileSize = 9; // 文件大小(字节) + int32 duration = 10; // 时长(秒) + string location = 11; // 位置信息(JSON格式) + repeated string tags = 12; // 标签列表 + string remark = 13; // 备注 + int64 createTime = 14; // 创建时间(毫秒时间戳) + int64 updateTime = 15; // 更新时间(毫秒时间戳) +} + +// 创建收藏请求 +message CreateFavoriteReq { + int32 type = 1; // 收藏类型 + string title = 2; // 标题 + string content = 3; // 内容 + string description = 4; // 描述 + string thumbnail = 5; // 缩略图URL + string linkURL = 6; // 链接URL + int64 fileSize = 7; // 文件大小(字节) + int32 duration = 8; // 时长(秒) + string location = 9; // 位置信息(JSON格式) + repeated string tags = 10; // 标签列表 + string remark = 11; // 备注 +} + +message CreateFavoriteResp { + string favoriteID = 1; // 收藏ID +} + +// 获取收藏请求 +message GetFavoriteReq { + string favoriteID = 1; // 收藏ID +} + +message GetFavoriteResp { + FavoriteInfo favorite = 1; // 收藏信息 +} + +// 获取收藏列表请求 +message GetFavoritesReq { + int32 type = 1; // 收藏类型(可选,0表示全部) + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +message GetFavoritesResp { + uint32 total = 1; // 总数 + repeated FavoriteInfo favorites = 2; // 收藏列表 +} + +// 搜索收藏请求 +message SearchFavoritesReq { + string keyword = 1; // 关键词 + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +message SearchFavoritesResp { + uint32 total = 1; // 总数 + repeated FavoriteInfo favorites = 2; // 收藏列表 +} + +// 更新收藏请求 +message UpdateFavoriteReq { + string favoriteID = 1; // 收藏ID + string title = 2; // 标题(可选) + string description = 3; // 描述(可选) + string remark = 4; // 备注(可选) + repeated string tags = 5; // 标签列表(可选) +} + +message UpdateFavoriteResp {} + +// 删除收藏请求 +message DeleteFavoriteReq { + repeated string favoriteIDs = 1; // 收藏ID列表 +} + +message DeleteFavoriteResp {} + +// 根据标签获取收藏请求 +message GetFavoritesByTagsReq { + repeated string tags = 1; // 标签列表 + openim.sdkws.RequestPagination pagination = 2; // 分页信息 +} + +message GetFavoritesByTagsResp { + uint32 total = 1; // 总数 + repeated FavoriteInfo favorites = 2; // 收藏列表 +} + +// 获取收藏数量请求 +message GetFavoriteCountReq {} + +message GetFavoriteCountResp { + int64 count = 1; // 收藏数量 +} + +// ==================== 定时任务相关消息 ==================== + +// 消息内容 +message ScheduledTaskMessage { + int32 type = 1; // 消息类型:1-文本,2-图片,3-视频 + string content = 2; // 消息内容(文本内容、图片URL、视频URL等) + string thumbnail = 3; // 缩略图URL(用于图片和视频) + int32 duration = 4; // 时长(秒,用于视频) + int64 fileSize = 5; // 文件大小(字节,用于图片和视频) + int32 width = 6; // 宽度(像素,用于图片和视频) + int32 height = 7; // 高度(像素,用于图片和视频) +} + +// 定时任务信息 +message ScheduledTaskInfo { + string id = 1; // 任务ID + string userID = 2; // 用户ID + string name = 3; // 任务名称 + string cronExpression = 4; // Crontab表达式:分 时 日 月 周(例如:"0 9 * * *") + repeated ScheduledTaskMessage messages = 5; // 消息列表(支持多条消息一起发送) + repeated string recvIDs = 6; // 接收者ID列表(单聊,可以多个) + repeated string groupIDs = 7; // 群组ID列表(群聊,可以多个) + int32 status = 8; // 状态:0-已禁用,1-已启用 + int64 createTime = 9; // 创建时间(毫秒时间戳) + int64 updateTime = 10; // 更新时间(毫秒时间戳) +} + +// 创建定时任务请求 +message CreateScheduledTaskReq { + string name = 1; // 任务名称 + string cronExpression = 2; // Crontab表达式 + repeated ScheduledTaskMessage messages = 3; // 消息列表 + repeated string recvIDs = 4; // 接收者ID列表(单聊,可以多个) + repeated string groupIDs = 5; // 群组ID列表(群聊,可以多个) + int32 status = 6; // 状态:0-已禁用,1-已启用 +} + +message CreateScheduledTaskResp { + string taskID = 1; // 任务ID +} + +// 获取定时任务请求 +message GetScheduledTaskReq { + string taskID = 1; // 任务ID +} + +message GetScheduledTaskResp { + ScheduledTaskInfo task = 1; // 任务信息 +} + +// 获取定时任务列表请求 +message GetScheduledTasksReq { + openim.sdkws.RequestPagination pagination = 1; // 分页信息 +} + +message GetScheduledTasksResp { + uint32 total = 1; // 总数 + repeated ScheduledTaskInfo tasks = 2; // 任务列表 +} + +// 更新定时任务请求 +message UpdateScheduledTaskReq { + string taskID = 1; // 任务ID + string name = 2; // 任务名称(可选) + string cronExpression = 3; // Crontab表达式(可选) + repeated ScheduledTaskMessage messages = 4; // 消息列表(可选) + repeated string recvIDs = 5; // 接收者ID列表(可选) + repeated string groupIDs = 6; // 群组ID列表(可选) + int32 status = 7; // 状态(可选) +} + +message UpdateScheduledTaskResp {} + +// 删除定时任务请求 +message DeleteScheduledTaskReq { + repeated string taskIDs = 1; // 任务ID列表 +} + +message DeleteScheduledTaskResp {} + +service chat { + rpc AddFriend(AddFriendReq) returns (AddFriendResp); + // Edit personal information - called by the user or an administrator + rpc UpdateUserInfo(UpdateUserInfoReq) returns (UpdateUserInfoResp); + rpc AddUserAccount(AddUserAccountReq) returns (AddUserAccountResp); + // Get user's public information - called by strangers + rpc SearchUserPublicInfo(SearchUserPublicInfoReq) returns (SearchUserPublicInfoResp); + rpc FindUserPublicInfo(FindUserPublicInfoReq) returns (FindUserPublicInfoResp); + // Search user information - called by administrators, other users get public fields + rpc SearchUserFullInfo(SearchUserFullInfoReq) returns (SearchUserFullInfoResp); + rpc FindUserFullInfo(FindUserFullInfoReq) returns (FindUserFullInfoResp); + + rpc SendVerifyCode(SendVerifyCodeReq) returns (SendVerifyCodeResp); + rpc VerifyCode(VerifyCodeReq) returns (VerifyCodeResp); + rpc GetCaptchaImage(GetCaptchaImageReq) returns (GetCaptchaImageResp); + rpc RegisterUser(RegisterUserReq) returns (RegisterUserResp); + rpc Login(LoginReq) returns (LoginResp); + rpc ResetPassword(ResetPasswordReq) returns (ResetPasswordResp); + rpc ChangePassword(ChangePasswordReq) returns (ChangePasswordResp); + rpc CheckUserExist(CheckUserExistReq) returns (CheckUserExistResp); + rpc DelUserAccount(DelUserAccountReq) returns (DelUserAccountResp); + + rpc FindUserAccount(FindUserAccountReq) returns (FindUserAccountResp); + rpc FindAccountUser(FindAccountUserReq) returns (FindAccountUserResp); + rpc OpenIMCallback(OpenIMCallbackReq) returns (OpenIMCallbackResp); + + // Statistics + rpc UserLoginCount(UserLoginCountReq) returns (UserLoginCountResp); + + rpc SearchUserInfo(SearchUserInfoReq) returns (SearchUserInfoResp); + + // Audio/video call and video meeting + rpc GetTokenForVideoMeeting(GetTokenForVideoMeetingReq) returns (GetTokenForVideoMeetingResp); + + rpc SetAllowRegister(SetAllowRegisterReq) returns(SetAllowRegisterResp); + rpc GetAllowRegister(GetAllowRegisterReq) returns(GetAllowRegisterResp); + + // ==================== 敏感词检测相关 RPC(用户端) ==================== + + // 获取敏感词列表(客户端启动时调用) + rpc GetSensitiveWords(GetSensitiveWordsReq) returns (GetSensitiveWordsResp); + + // 检测敏感词(用户发送消息时调用) + rpc CheckSensitiveWords(CheckSensitiveWordsReq) returns (CheckSensitiveWordsResp); + + // ==================== 敏感词管理相关 RPC(管理端) ==================== + + // 敏感词管理 + rpc AddSensitiveWord(AddSensitiveWordReq) returns (AddSensitiveWordResp); + rpc UpdateSensitiveWord(UpdateSensitiveWordReq) returns (UpdateSensitiveWordResp); + rpc DeleteSensitiveWord(DeleteSensitiveWordReq) returns (DeleteSensitiveWordResp); + rpc GetSensitiveWord(GetSensitiveWordReq) returns (GetSensitiveWordResp); + rpc SearchSensitiveWords(SearchSensitiveWordsReq) returns (SearchSensitiveWordsResp); + rpc BatchAddSensitiveWords(BatchAddSensitiveWordsReq) returns (BatchAddSensitiveWordsResp); + rpc BatchUpdateSensitiveWords(BatchUpdateSensitiveWordsReq) returns (BatchUpdateSensitiveWordsResp); + rpc BatchDeleteSensitiveWords(BatchDeleteSensitiveWordsReq) returns (BatchDeleteSensitiveWordsResp); + + // 敏感词分组管理 + rpc AddSensitiveWordGroup(AddSensitiveWordGroupReq) returns (AddSensitiveWordGroupResp); + rpc UpdateSensitiveWordGroup(UpdateSensitiveWordGroupReq) returns (UpdateSensitiveWordGroupResp); + rpc DeleteSensitiveWordGroup(DeleteSensitiveWordGroupReq) returns (DeleteSensitiveWordGroupResp); + rpc GetSensitiveWordGroup(GetSensitiveWordGroupReq) returns (GetSensitiveWordGroupResp); + rpc GetAllSensitiveWordGroups(GetAllSensitiveWordGroupsReq) returns (GetAllSensitiveWordGroupsResp); + + // 敏感词配置管理 + rpc GetSensitiveWordConfig(GetSensitiveWordConfigReq) returns (GetSensitiveWordConfigResp); + rpc UpdateSensitiveWordConfig(UpdateSensitiveWordConfigReq) returns (UpdateSensitiveWordConfigResp); + + // 敏感词日志管理 + rpc GetSensitiveWordLogs(GetSensitiveWordLogsReq) returns (GetSensitiveWordLogsResp); + rpc DeleteSensitiveWordLogs(DeleteSensitiveWordLogsReq) returns (DeleteSensitiveWordLogsResp); + + // 用户登录记录管理 + rpc GetUserLoginRecords(GetUserLoginRecordsReq) returns (GetUserLoginRecordsResp); + + // 敏感词统计 + rpc GetSensitiveWordStats(GetSensitiveWordStatsReq) returns (GetSensitiveWordStatsResp); + rpc GetSensitiveWordLogStats(GetSensitiveWordLogStatsReq) returns (GetSensitiveWordLogStatsResp); + + // ==================== 系统配置相关 RPC(客户端) ==================== + + // 获取APP端配置(返回所有 show_in_app=true 且 enabled=true 的配置) + rpc GetAppSystemConfigs(GetAppSystemConfigsReq) returns (GetAppSystemConfigsResp); + + // ==================== 钱包相关 RPC(客户端) ==================== + + // 获取钱包余额 + rpc GetWalletBalance(GetWalletBalanceReq) returns (GetWalletBalanceResp); + + // 获取钱包详细信息(包括余额、提现账号、实名信息等) + rpc GetWalletInfo(GetWalletInfoReq) returns (GetWalletInfoResp); + + // 获取余额明细(余额变动记录) + rpc GetWalletBalanceRecords(GetWalletBalanceRecordsReq) returns (GetWalletBalanceRecordsResp); + + // 设置支付密码(首次设置或修改) + rpc SetPaymentPassword(SetPaymentPasswordReq) returns (SetPaymentPasswordResp); + + // 设置提现账号 + rpc SetWithdrawAccount(SetWithdrawAccountReq) returns (SetWithdrawAccountResp); + + // 申请提现 + rpc CreateWithdrawApplication(CreateWithdrawApplicationReq) returns (CreateWithdrawApplicationResp); + + // 获取用户的提现申请列表 + rpc GetWithdrawApplications(GetWithdrawApplicationsReq) returns (GetWithdrawApplicationsResp); + + // 实名认证 + rpc RealNameAuth(RealNameAuthReq) returns (RealNameAuthResp); + + // ==================== 收藏相关 RPC ==================== + + // 创建收藏 + rpc CreateFavorite(CreateFavoriteReq) returns (CreateFavoriteResp); + + // 获取收藏详情 + rpc GetFavorite(GetFavoriteReq) returns (GetFavoriteResp); + + // 获取收藏列表 + rpc GetFavorites(GetFavoritesReq) returns (GetFavoritesResp); + + // 搜索收藏 + rpc SearchFavorites(SearchFavoritesReq) returns (SearchFavoritesResp); + + // 更新收藏 + rpc UpdateFavorite(UpdateFavoriteReq) returns (UpdateFavoriteResp); + + // 删除收藏 + rpc DeleteFavorite(DeleteFavoriteReq) returns (DeleteFavoriteResp); + + // 根据标签获取收藏 + rpc GetFavoritesByTags(GetFavoritesByTagsReq) returns (GetFavoritesByTagsResp); + + // 获取收藏数量 + rpc GetFavoriteCount(GetFavoriteCountReq) returns (GetFavoriteCountResp); + + // ==================== 定时任务相关 RPC ==================== + + // 创建定时任务 + rpc CreateScheduledTask(CreateScheduledTaskReq) returns (CreateScheduledTaskResp); + + // 获取定时任务详情 + rpc GetScheduledTask(GetScheduledTaskReq) returns (GetScheduledTaskResp); + + // 获取定时任务列表 + rpc GetScheduledTasks(GetScheduledTasksReq) returns (GetScheduledTasksResp); + + // 更新定时任务 + rpc UpdateScheduledTask(UpdateScheduledTaskReq) returns (UpdateScheduledTaskResp); + + // 删除定时任务 + rpc DeleteScheduledTask(DeleteScheduledTaskReq) returns (DeleteScheduledTaskResp); +} + +// ==================== 系统配置相关消息 ==================== + +// 系统配置信息(客户端) +message SystemConfigInfo { + string key = 1; // 配置键(唯一标识) + string title = 2; // 配置标题 + string value = 3; // 配置值(根据 valueType 解析) + int32 valueType = 4; // 配置值类型:1-字符串,2-数字,3-布尔,4-JSON + string description = 5; // 配置描述 +} + +// 获取APP端配置请求 +message GetAppSystemConfigsReq { +} + +// 获取APP端配置响应 +message GetAppSystemConfigsResp { + repeated SystemConfigInfo configs = 1; // 配置列表 +} + +// ==================== 钱包相关消息 ==================== + +// 实名认证信息 +message RealNameAuthInfo { + string idCard = 1; // 身份证号 + string idCardPhotoFront = 2; // 身份证正面照片URL + string idCardPhotoBack = 3; // 身份证反面照片URL + string name = 4; // 真实姓名 + int32 auditStatus = 5; // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +// 获取钱包余额请求 +message GetWalletBalanceReq { +} + +// 获取钱包余额响应 +message GetWalletBalanceResp { + int64 balance = 1; // 余额(单位:分) +} + +// 获取钱包详细信息请求 +message GetWalletInfoReq { +} + +// 获取钱包详细信息响应 +message GetWalletInfoResp { + int64 balance = 1; // 余额(单位:分) + string withdrawAccount = 2; // 提现账号 + int32 withdrawAccountType = 3; // 提现账号类型:1-支付宝,2-微信,3-银行卡 + RealNameAuthInfo realNameAuth = 4; // 实名认证信息 + string withdrawReceiveAccount = 5; // 提现收款账号 + bool hasPaymentPassword = 6; // 是否已设置支付密码 +} + +// 设置支付密码请求 +message SetPaymentPasswordReq { + string newPassword = 1; // 新支付密码(必填) + string oldPassword = 2; // 旧支付密码(修改时必填,首次设置时不需要) +} + +// 设置支付密码响应 +message SetPaymentPasswordResp { +} + +// 设置提现账号请求 +message SetWithdrawAccountReq { + string account = 1; // 提现账号(必填) + int32 accountType = 2; // 账号类型(必填):1-支付宝,2-微信,3-银行卡 +} + +// 设置提现账号响应 +message SetWithdrawAccountResp { +} + +// ==================== 余额明细相关消息 ==================== + +// 余额变动记录信息 +message WalletBalanceRecordInfo { + string id = 1; // 记录ID + string userID = 2; // 用户ID + int64 amount = 3; // 变动金额(单位:分,正数表示增加,负数表示减少) + int32 type = 4; // 变动类型:1-充值,2-提现/提款,3-消费,4-退款,5-奖励,6-后台充值,7-发红包,8-抢红包,99-其他 + int64 beforeBalance = 5; // 变动前余额(单位:分) + int64 afterBalance = 6; // 变动后余额(单位:分) + string orderID = 7; // 关联订单ID(可选) + string transactionID = 8; // 交易ID(可选) + string redPacketID = 9; // 红包ID(可选) + string remark = 10; // 备注 + int64 createTime = 11; // 创建时间(毫秒时间戳) +} + +// 获取余额明细请求 +message GetWalletBalanceRecordsReq { + openim.sdkws.RequestPagination pagination = 1; // 分页参数 + int32 type = 2; // 变动类型(可选,0表示查询所有类型) +} + +// 获取余额明细响应 +message GetWalletBalanceRecordsResp { + uint32 total = 1; // 总数 + repeated WalletBalanceRecordInfo records = 2; // 记录列表 +} + +// ==================== 提现申请相关消息 ==================== + +// 提现申请信息 +message WithdrawApplicationInfo { + string id = 1; // 申请ID + string userID = 2; // 用户ID + int64 amount = 3; // 提现金额(单位:分) + string withdrawAccount = 4; // 提现账号 + int32 withdrawAccountType = 5; // 提现账号类型:1-支付宝,2-微信,3-银行卡 + int32 status = 6; // 申请状态:1-待审核,2-已通过,3-已拒绝,4-处理中,5-已完成 + string auditorID = 7; // 审核人ID(管理员ID) + int64 auditTime = 8; // 审核时间(毫秒时间戳) + string auditRemark = 9; // 审核备注 + string ip = 10; // 申请IP + string deviceID = 11; // 设备ID + string platform = 12; // 平台(iOS、Android、Web等) + string deviceModel = 13; // 设备型号 + string deviceBrand = 14; // 设备品牌 + string osVersion = 15; // 操作系统版本 + string appVersion = 16; // 应用版本 + string remark = 17; // 申请备注(由后台管理员填写) + int64 createTime = 18; // 创建时间(毫秒时间戳) + int64 updateTime = 19; // 更新时间(毫秒时间戳) +} + +// 创建提现申请请求 +message CreateWithdrawApplicationReq { + int64 amount = 1; // 提现金额(单位:分) + string paymentPassword = 2; // 支付密码(必填) + string ip = 3; // 申请IP + string deviceID = 4; // 设备ID + string platform = 5; // 平台 + string deviceModel = 6; // 设备型号 + string deviceBrand = 7; // 设备品牌 + string osVersion = 8; // 操作系统版本 + string appVersion = 9; // 应用版本 +} + +// 创建提现申请响应 +message CreateWithdrawApplicationResp { + string applicationID = 1; // 申请ID +} + +// 获取用户的提现申请列表请求 +message GetWithdrawApplicationsReq { + openim.sdkws.RequestPagination pagination = 1; // 分页参数 +} + +// 获取用户的提现申请列表响应 +message GetWithdrawApplicationsResp { + uint32 total = 1; // 总数 + repeated WithdrawApplicationInfo applications = 2; // 申请列表 +} + +// ==================== 实名认证相关消息 ==================== + +// 实名认证请求 +message RealNameAuthReq { + string idCard = 1; // 身份证号(必填) + string name = 2; // 真实姓名(必填) + string idCardPhotoFront = 3; // 身份证正面照片URL(可选) + string idCardPhotoBack = 4; // 身份证反面照片URL(可选) +} + +// 实名认证响应 +message RealNameAuthResp { + bool success = 1; // 是否认证成功 + string message = 2; // 认证结果消息 + string idCardPhotoFront = 3; // 身份证正面照片URL + string idCardPhotoBack = 4; // 身份证反面照片URL +} diff --git a/pkg/protocol/chat/chat_grpc.pb.go b/pkg/protocol/chat/chat_grpc.pb.go new file mode 100644 index 0000000..4dd49e4 --- /dev/null +++ b/pkg/protocol/chat/chat_grpc.pb.go @@ -0,0 +1,2751 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v6.33.0 +// source: chat/chat.proto + +package chat + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Chat_AddFriend_FullMethodName = "/openim.chat.chat/AddFriend" + Chat_UpdateUserInfo_FullMethodName = "/openim.chat.chat/UpdateUserInfo" + Chat_AddUserAccount_FullMethodName = "/openim.chat.chat/AddUserAccount" + Chat_SearchUserPublicInfo_FullMethodName = "/openim.chat.chat/SearchUserPublicInfo" + Chat_FindUserPublicInfo_FullMethodName = "/openim.chat.chat/FindUserPublicInfo" + Chat_SearchUserFullInfo_FullMethodName = "/openim.chat.chat/SearchUserFullInfo" + Chat_FindUserFullInfo_FullMethodName = "/openim.chat.chat/FindUserFullInfo" + Chat_SendVerifyCode_FullMethodName = "/openim.chat.chat/SendVerifyCode" + Chat_VerifyCode_FullMethodName = "/openim.chat.chat/VerifyCode" + Chat_GetCaptchaImage_FullMethodName = "/openim.chat.chat/GetCaptchaImage" + Chat_RegisterUser_FullMethodName = "/openim.chat.chat/RegisterUser" + Chat_Login_FullMethodName = "/openim.chat.chat/Login" + Chat_ResetPassword_FullMethodName = "/openim.chat.chat/ResetPassword" + Chat_ChangePassword_FullMethodName = "/openim.chat.chat/ChangePassword" + Chat_CheckUserExist_FullMethodName = "/openim.chat.chat/CheckUserExist" + Chat_DelUserAccount_FullMethodName = "/openim.chat.chat/DelUserAccount" + Chat_FindUserAccount_FullMethodName = "/openim.chat.chat/FindUserAccount" + Chat_FindAccountUser_FullMethodName = "/openim.chat.chat/FindAccountUser" + Chat_OpenIMCallback_FullMethodName = "/openim.chat.chat/OpenIMCallback" + Chat_UserLoginCount_FullMethodName = "/openim.chat.chat/UserLoginCount" + Chat_SearchUserInfo_FullMethodName = "/openim.chat.chat/SearchUserInfo" + Chat_GetTokenForVideoMeeting_FullMethodName = "/openim.chat.chat/GetTokenForVideoMeeting" + Chat_SetAllowRegister_FullMethodName = "/openim.chat.chat/SetAllowRegister" + Chat_GetAllowRegister_FullMethodName = "/openim.chat.chat/GetAllowRegister" + Chat_GetSensitiveWords_FullMethodName = "/openim.chat.chat/GetSensitiveWords" + Chat_CheckSensitiveWords_FullMethodName = "/openim.chat.chat/CheckSensitiveWords" + Chat_AddSensitiveWord_FullMethodName = "/openim.chat.chat/AddSensitiveWord" + Chat_UpdateSensitiveWord_FullMethodName = "/openim.chat.chat/UpdateSensitiveWord" + Chat_DeleteSensitiveWord_FullMethodName = "/openim.chat.chat/DeleteSensitiveWord" + Chat_GetSensitiveWord_FullMethodName = "/openim.chat.chat/GetSensitiveWord" + Chat_SearchSensitiveWords_FullMethodName = "/openim.chat.chat/SearchSensitiveWords" + Chat_BatchAddSensitiveWords_FullMethodName = "/openim.chat.chat/BatchAddSensitiveWords" + Chat_BatchUpdateSensitiveWords_FullMethodName = "/openim.chat.chat/BatchUpdateSensitiveWords" + Chat_BatchDeleteSensitiveWords_FullMethodName = "/openim.chat.chat/BatchDeleteSensitiveWords" + Chat_AddSensitiveWordGroup_FullMethodName = "/openim.chat.chat/AddSensitiveWordGroup" + Chat_UpdateSensitiveWordGroup_FullMethodName = "/openim.chat.chat/UpdateSensitiveWordGroup" + Chat_DeleteSensitiveWordGroup_FullMethodName = "/openim.chat.chat/DeleteSensitiveWordGroup" + Chat_GetSensitiveWordGroup_FullMethodName = "/openim.chat.chat/GetSensitiveWordGroup" + Chat_GetAllSensitiveWordGroups_FullMethodName = "/openim.chat.chat/GetAllSensitiveWordGroups" + Chat_GetSensitiveWordConfig_FullMethodName = "/openim.chat.chat/GetSensitiveWordConfig" + Chat_UpdateSensitiveWordConfig_FullMethodName = "/openim.chat.chat/UpdateSensitiveWordConfig" + Chat_GetSensitiveWordLogs_FullMethodName = "/openim.chat.chat/GetSensitiveWordLogs" + Chat_DeleteSensitiveWordLogs_FullMethodName = "/openim.chat.chat/DeleteSensitiveWordLogs" + Chat_GetUserLoginRecords_FullMethodName = "/openim.chat.chat/GetUserLoginRecords" + Chat_GetSensitiveWordStats_FullMethodName = "/openim.chat.chat/GetSensitiveWordStats" + Chat_GetSensitiveWordLogStats_FullMethodName = "/openim.chat.chat/GetSensitiveWordLogStats" + Chat_GetAppSystemConfigs_FullMethodName = "/openim.chat.chat/GetAppSystemConfigs" + Chat_GetWalletBalance_FullMethodName = "/openim.chat.chat/GetWalletBalance" + Chat_GetWalletInfo_FullMethodName = "/openim.chat.chat/GetWalletInfo" + Chat_GetWalletBalanceRecords_FullMethodName = "/openim.chat.chat/GetWalletBalanceRecords" + Chat_SetPaymentPassword_FullMethodName = "/openim.chat.chat/SetPaymentPassword" + Chat_SetWithdrawAccount_FullMethodName = "/openim.chat.chat/SetWithdrawAccount" + Chat_CreateWithdrawApplication_FullMethodName = "/openim.chat.chat/CreateWithdrawApplication" + Chat_GetWithdrawApplications_FullMethodName = "/openim.chat.chat/GetWithdrawApplications" + Chat_RealNameAuth_FullMethodName = "/openim.chat.chat/RealNameAuth" + Chat_CreateFavorite_FullMethodName = "/openim.chat.chat/CreateFavorite" + Chat_GetFavorite_FullMethodName = "/openim.chat.chat/GetFavorite" + Chat_GetFavorites_FullMethodName = "/openim.chat.chat/GetFavorites" + Chat_SearchFavorites_FullMethodName = "/openim.chat.chat/SearchFavorites" + Chat_UpdateFavorite_FullMethodName = "/openim.chat.chat/UpdateFavorite" + Chat_DeleteFavorite_FullMethodName = "/openim.chat.chat/DeleteFavorite" + Chat_GetFavoritesByTags_FullMethodName = "/openim.chat.chat/GetFavoritesByTags" + Chat_GetFavoriteCount_FullMethodName = "/openim.chat.chat/GetFavoriteCount" + Chat_CreateScheduledTask_FullMethodName = "/openim.chat.chat/CreateScheduledTask" + Chat_GetScheduledTask_FullMethodName = "/openim.chat.chat/GetScheduledTask" + Chat_GetScheduledTasks_FullMethodName = "/openim.chat.chat/GetScheduledTasks" + Chat_UpdateScheduledTask_FullMethodName = "/openim.chat.chat/UpdateScheduledTask" + Chat_DeleteScheduledTask_FullMethodName = "/openim.chat.chat/DeleteScheduledTask" +) + +// ChatClient is the client API for Chat service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ChatClient interface { + AddFriend(ctx context.Context, in *AddFriendReq, opts ...grpc.CallOption) (*AddFriendResp, error) + // Edit personal information - called by the user or an administrator + UpdateUserInfo(ctx context.Context, in *UpdateUserInfoReq, opts ...grpc.CallOption) (*UpdateUserInfoResp, error) + AddUserAccount(ctx context.Context, in *AddUserAccountReq, opts ...grpc.CallOption) (*AddUserAccountResp, error) + // Get user's public information - called by strangers + SearchUserPublicInfo(ctx context.Context, in *SearchUserPublicInfoReq, opts ...grpc.CallOption) (*SearchUserPublicInfoResp, error) + FindUserPublicInfo(ctx context.Context, in *FindUserPublicInfoReq, opts ...grpc.CallOption) (*FindUserPublicInfoResp, error) + // Search user information - called by administrators, other users get public fields + SearchUserFullInfo(ctx context.Context, in *SearchUserFullInfoReq, opts ...grpc.CallOption) (*SearchUserFullInfoResp, error) + FindUserFullInfo(ctx context.Context, in *FindUserFullInfoReq, opts ...grpc.CallOption) (*FindUserFullInfoResp, error) + SendVerifyCode(ctx context.Context, in *SendVerifyCodeReq, opts ...grpc.CallOption) (*SendVerifyCodeResp, error) + VerifyCode(ctx context.Context, in *VerifyCodeReq, opts ...grpc.CallOption) (*VerifyCodeResp, error) + GetCaptchaImage(ctx context.Context, in *GetCaptchaImageReq, opts ...grpc.CallOption) (*GetCaptchaImageResp, error) + RegisterUser(ctx context.Context, in *RegisterUserReq, opts ...grpc.CallOption) (*RegisterUserResp, error) + Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) + ResetPassword(ctx context.Context, in *ResetPasswordReq, opts ...grpc.CallOption) (*ResetPasswordResp, error) + ChangePassword(ctx context.Context, in *ChangePasswordReq, opts ...grpc.CallOption) (*ChangePasswordResp, error) + CheckUserExist(ctx context.Context, in *CheckUserExistReq, opts ...grpc.CallOption) (*CheckUserExistResp, error) + DelUserAccount(ctx context.Context, in *DelUserAccountReq, opts ...grpc.CallOption) (*DelUserAccountResp, error) + FindUserAccount(ctx context.Context, in *FindUserAccountReq, opts ...grpc.CallOption) (*FindUserAccountResp, error) + FindAccountUser(ctx context.Context, in *FindAccountUserReq, opts ...grpc.CallOption) (*FindAccountUserResp, error) + OpenIMCallback(ctx context.Context, in *OpenIMCallbackReq, opts ...grpc.CallOption) (*OpenIMCallbackResp, error) + // Statistics + UserLoginCount(ctx context.Context, in *UserLoginCountReq, opts ...grpc.CallOption) (*UserLoginCountResp, error) + SearchUserInfo(ctx context.Context, in *SearchUserInfoReq, opts ...grpc.CallOption) (*SearchUserInfoResp, error) + // Audio/video call and video meeting + GetTokenForVideoMeeting(ctx context.Context, in *GetTokenForVideoMeetingReq, opts ...grpc.CallOption) (*GetTokenForVideoMeetingResp, error) + SetAllowRegister(ctx context.Context, in *SetAllowRegisterReq, opts ...grpc.CallOption) (*SetAllowRegisterResp, error) + GetAllowRegister(ctx context.Context, in *GetAllowRegisterReq, opts ...grpc.CallOption) (*GetAllowRegisterResp, error) + // 获取敏感词列表(客户端启动时调用) + GetSensitiveWords(ctx context.Context, in *GetSensitiveWordsReq, opts ...grpc.CallOption) (*GetSensitiveWordsResp, error) + // 检测敏感词(用户发送消息时调用) + CheckSensitiveWords(ctx context.Context, in *CheckSensitiveWordsReq, opts ...grpc.CallOption) (*CheckSensitiveWordsResp, error) + // 敏感词管理 + AddSensitiveWord(ctx context.Context, in *AddSensitiveWordReq, opts ...grpc.CallOption) (*AddSensitiveWordResp, error) + UpdateSensitiveWord(ctx context.Context, in *UpdateSensitiveWordReq, opts ...grpc.CallOption) (*UpdateSensitiveWordResp, error) + DeleteSensitiveWord(ctx context.Context, in *DeleteSensitiveWordReq, opts ...grpc.CallOption) (*DeleteSensitiveWordResp, error) + GetSensitiveWord(ctx context.Context, in *GetSensitiveWordReq, opts ...grpc.CallOption) (*GetSensitiveWordResp, error) + SearchSensitiveWords(ctx context.Context, in *SearchSensitiveWordsReq, opts ...grpc.CallOption) (*SearchSensitiveWordsResp, error) + BatchAddSensitiveWords(ctx context.Context, in *BatchAddSensitiveWordsReq, opts ...grpc.CallOption) (*BatchAddSensitiveWordsResp, error) + BatchUpdateSensitiveWords(ctx context.Context, in *BatchUpdateSensitiveWordsReq, opts ...grpc.CallOption) (*BatchUpdateSensitiveWordsResp, error) + BatchDeleteSensitiveWords(ctx context.Context, in *BatchDeleteSensitiveWordsReq, opts ...grpc.CallOption) (*BatchDeleteSensitiveWordsResp, error) + // 敏感词分组管理 + AddSensitiveWordGroup(ctx context.Context, in *AddSensitiveWordGroupReq, opts ...grpc.CallOption) (*AddSensitiveWordGroupResp, error) + UpdateSensitiveWordGroup(ctx context.Context, in *UpdateSensitiveWordGroupReq, opts ...grpc.CallOption) (*UpdateSensitiveWordGroupResp, error) + DeleteSensitiveWordGroup(ctx context.Context, in *DeleteSensitiveWordGroupReq, opts ...grpc.CallOption) (*DeleteSensitiveWordGroupResp, error) + GetSensitiveWordGroup(ctx context.Context, in *GetSensitiveWordGroupReq, opts ...grpc.CallOption) (*GetSensitiveWordGroupResp, error) + GetAllSensitiveWordGroups(ctx context.Context, in *GetAllSensitiveWordGroupsReq, opts ...grpc.CallOption) (*GetAllSensitiveWordGroupsResp, error) + // 敏感词配置管理 + GetSensitiveWordConfig(ctx context.Context, in *GetSensitiveWordConfigReq, opts ...grpc.CallOption) (*GetSensitiveWordConfigResp, error) + UpdateSensitiveWordConfig(ctx context.Context, in *UpdateSensitiveWordConfigReq, opts ...grpc.CallOption) (*UpdateSensitiveWordConfigResp, error) + // 敏感词日志管理 + GetSensitiveWordLogs(ctx context.Context, in *GetSensitiveWordLogsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogsResp, error) + DeleteSensitiveWordLogs(ctx context.Context, in *DeleteSensitiveWordLogsReq, opts ...grpc.CallOption) (*DeleteSensitiveWordLogsResp, error) + // 用户登录记录管理 + GetUserLoginRecords(ctx context.Context, in *GetUserLoginRecordsReq, opts ...grpc.CallOption) (*GetUserLoginRecordsResp, error) + // 敏感词统计 + GetSensitiveWordStats(ctx context.Context, in *GetSensitiveWordStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordStatsResp, error) + GetSensitiveWordLogStats(ctx context.Context, in *GetSensitiveWordLogStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogStatsResp, error) + // 获取APP端配置(返回所有 show_in_app=true 且 enabled=true 的配置) + GetAppSystemConfigs(ctx context.Context, in *GetAppSystemConfigsReq, opts ...grpc.CallOption) (*GetAppSystemConfigsResp, error) + // 获取钱包余额 + GetWalletBalance(ctx context.Context, in *GetWalletBalanceReq, opts ...grpc.CallOption) (*GetWalletBalanceResp, error) + // 获取钱包详细信息(包括余额、提现账号、实名信息等) + GetWalletInfo(ctx context.Context, in *GetWalletInfoReq, opts ...grpc.CallOption) (*GetWalletInfoResp, error) + // 获取余额明细(余额变动记录) + GetWalletBalanceRecords(ctx context.Context, in *GetWalletBalanceRecordsReq, opts ...grpc.CallOption) (*GetWalletBalanceRecordsResp, error) + // 设置支付密码(首次设置或修改) + SetPaymentPassword(ctx context.Context, in *SetPaymentPasswordReq, opts ...grpc.CallOption) (*SetPaymentPasswordResp, error) + // 设置提现账号 + SetWithdrawAccount(ctx context.Context, in *SetWithdrawAccountReq, opts ...grpc.CallOption) (*SetWithdrawAccountResp, error) + // 申请提现 + CreateWithdrawApplication(ctx context.Context, in *CreateWithdrawApplicationReq, opts ...grpc.CallOption) (*CreateWithdrawApplicationResp, error) + // 获取用户的提现申请列表 + GetWithdrawApplications(ctx context.Context, in *GetWithdrawApplicationsReq, opts ...grpc.CallOption) (*GetWithdrawApplicationsResp, error) + // 实名认证 + RealNameAuth(ctx context.Context, in *RealNameAuthReq, opts ...grpc.CallOption) (*RealNameAuthResp, error) + // 创建收藏 + CreateFavorite(ctx context.Context, in *CreateFavoriteReq, opts ...grpc.CallOption) (*CreateFavoriteResp, error) + // 获取收藏详情 + GetFavorite(ctx context.Context, in *GetFavoriteReq, opts ...grpc.CallOption) (*GetFavoriteResp, error) + // 获取收藏列表 + GetFavorites(ctx context.Context, in *GetFavoritesReq, opts ...grpc.CallOption) (*GetFavoritesResp, error) + // 搜索收藏 + SearchFavorites(ctx context.Context, in *SearchFavoritesReq, opts ...grpc.CallOption) (*SearchFavoritesResp, error) + // 更新收藏 + UpdateFavorite(ctx context.Context, in *UpdateFavoriteReq, opts ...grpc.CallOption) (*UpdateFavoriteResp, error) + // 删除收藏 + DeleteFavorite(ctx context.Context, in *DeleteFavoriteReq, opts ...grpc.CallOption) (*DeleteFavoriteResp, error) + // 根据标签获取收藏 + GetFavoritesByTags(ctx context.Context, in *GetFavoritesByTagsReq, opts ...grpc.CallOption) (*GetFavoritesByTagsResp, error) + // 获取收藏数量 + GetFavoriteCount(ctx context.Context, in *GetFavoriteCountReq, opts ...grpc.CallOption) (*GetFavoriteCountResp, error) + // 创建定时任务 + CreateScheduledTask(ctx context.Context, in *CreateScheduledTaskReq, opts ...grpc.CallOption) (*CreateScheduledTaskResp, error) + // 获取定时任务详情 + GetScheduledTask(ctx context.Context, in *GetScheduledTaskReq, opts ...grpc.CallOption) (*GetScheduledTaskResp, error) + // 获取定时任务列表 + GetScheduledTasks(ctx context.Context, in *GetScheduledTasksReq, opts ...grpc.CallOption) (*GetScheduledTasksResp, error) + // 更新定时任务 + UpdateScheduledTask(ctx context.Context, in *UpdateScheduledTaskReq, opts ...grpc.CallOption) (*UpdateScheduledTaskResp, error) + // 删除定时任务 + DeleteScheduledTask(ctx context.Context, in *DeleteScheduledTaskReq, opts ...grpc.CallOption) (*DeleteScheduledTaskResp, error) +} + +type chatClient struct { + cc grpc.ClientConnInterface +} + +func NewChatClient(cc grpc.ClientConnInterface) ChatClient { + return &chatClient{cc} +} + +func (c *chatClient) AddFriend(ctx context.Context, in *AddFriendReq, opts ...grpc.CallOption) (*AddFriendResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddFriendResp) + err := c.cc.Invoke(ctx, Chat_AddFriend_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateUserInfo(ctx context.Context, in *UpdateUserInfoReq, opts ...grpc.CallOption) (*UpdateUserInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateUserInfoResp) + err := c.cc.Invoke(ctx, Chat_UpdateUserInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) AddUserAccount(ctx context.Context, in *AddUserAccountReq, opts ...grpc.CallOption) (*AddUserAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddUserAccountResp) + err := c.cc.Invoke(ctx, Chat_AddUserAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SearchUserPublicInfo(ctx context.Context, in *SearchUserPublicInfoReq, opts ...grpc.CallOption) (*SearchUserPublicInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchUserPublicInfoResp) + err := c.cc.Invoke(ctx, Chat_SearchUserPublicInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) FindUserPublicInfo(ctx context.Context, in *FindUserPublicInfoReq, opts ...grpc.CallOption) (*FindUserPublicInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindUserPublicInfoResp) + err := c.cc.Invoke(ctx, Chat_FindUserPublicInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SearchUserFullInfo(ctx context.Context, in *SearchUserFullInfoReq, opts ...grpc.CallOption) (*SearchUserFullInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchUserFullInfoResp) + err := c.cc.Invoke(ctx, Chat_SearchUserFullInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) FindUserFullInfo(ctx context.Context, in *FindUserFullInfoReq, opts ...grpc.CallOption) (*FindUserFullInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindUserFullInfoResp) + err := c.cc.Invoke(ctx, Chat_FindUserFullInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SendVerifyCode(ctx context.Context, in *SendVerifyCodeReq, opts ...grpc.CallOption) (*SendVerifyCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SendVerifyCodeResp) + err := c.cc.Invoke(ctx, Chat_SendVerifyCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) VerifyCode(ctx context.Context, in *VerifyCodeReq, opts ...grpc.CallOption) (*VerifyCodeResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(VerifyCodeResp) + err := c.cc.Invoke(ctx, Chat_VerifyCode_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetCaptchaImage(ctx context.Context, in *GetCaptchaImageReq, opts ...grpc.CallOption) (*GetCaptchaImageResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetCaptchaImageResp) + err := c.cc.Invoke(ctx, Chat_GetCaptchaImage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) RegisterUser(ctx context.Context, in *RegisterUserReq, opts ...grpc.CallOption) (*RegisterUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RegisterUserResp) + err := c.cc.Invoke(ctx, Chat_RegisterUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*LoginResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(LoginResp) + err := c.cc.Invoke(ctx, Chat_Login_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) ResetPassword(ctx context.Context, in *ResetPasswordReq, opts ...grpc.CallOption) (*ResetPasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ResetPasswordResp) + err := c.cc.Invoke(ctx, Chat_ResetPassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) ChangePassword(ctx context.Context, in *ChangePasswordReq, opts ...grpc.CallOption) (*ChangePasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ChangePasswordResp) + err := c.cc.Invoke(ctx, Chat_ChangePassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) CheckUserExist(ctx context.Context, in *CheckUserExistReq, opts ...grpc.CallOption) (*CheckUserExistResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckUserExistResp) + err := c.cc.Invoke(ctx, Chat_CheckUserExist_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DelUserAccount(ctx context.Context, in *DelUserAccountReq, opts ...grpc.CallOption) (*DelUserAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DelUserAccountResp) + err := c.cc.Invoke(ctx, Chat_DelUserAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) FindUserAccount(ctx context.Context, in *FindUserAccountReq, opts ...grpc.CallOption) (*FindUserAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindUserAccountResp) + err := c.cc.Invoke(ctx, Chat_FindUserAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) FindAccountUser(ctx context.Context, in *FindAccountUserReq, opts ...grpc.CallOption) (*FindAccountUserResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindAccountUserResp) + err := c.cc.Invoke(ctx, Chat_FindAccountUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) OpenIMCallback(ctx context.Context, in *OpenIMCallbackReq, opts ...grpc.CallOption) (*OpenIMCallbackResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(OpenIMCallbackResp) + err := c.cc.Invoke(ctx, Chat_OpenIMCallback_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UserLoginCount(ctx context.Context, in *UserLoginCountReq, opts ...grpc.CallOption) (*UserLoginCountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UserLoginCountResp) + err := c.cc.Invoke(ctx, Chat_UserLoginCount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SearchUserInfo(ctx context.Context, in *SearchUserInfoReq, opts ...grpc.CallOption) (*SearchUserInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchUserInfoResp) + err := c.cc.Invoke(ctx, Chat_SearchUserInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetTokenForVideoMeeting(ctx context.Context, in *GetTokenForVideoMeetingReq, opts ...grpc.CallOption) (*GetTokenForVideoMeetingResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTokenForVideoMeetingResp) + err := c.cc.Invoke(ctx, Chat_GetTokenForVideoMeeting_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SetAllowRegister(ctx context.Context, in *SetAllowRegisterReq, opts ...grpc.CallOption) (*SetAllowRegisterResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetAllowRegisterResp) + err := c.cc.Invoke(ctx, Chat_SetAllowRegister_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetAllowRegister(ctx context.Context, in *GetAllowRegisterReq, opts ...grpc.CallOption) (*GetAllowRegisterResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAllowRegisterResp) + err := c.cc.Invoke(ctx, Chat_GetAllowRegister_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWords(ctx context.Context, in *GetSensitiveWordsReq, opts ...grpc.CallOption) (*GetSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) CheckSensitiveWords(ctx context.Context, in *CheckSensitiveWordsReq, opts ...grpc.CallOption) (*CheckSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_CheckSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) AddSensitiveWord(ctx context.Context, in *AddSensitiveWordReq, opts ...grpc.CallOption) (*AddSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddSensitiveWordResp) + err := c.cc.Invoke(ctx, Chat_AddSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateSensitiveWord(ctx context.Context, in *UpdateSensitiveWordReq, opts ...grpc.CallOption) (*UpdateSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordResp) + err := c.cc.Invoke(ctx, Chat_UpdateSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DeleteSensitiveWord(ctx context.Context, in *DeleteSensitiveWordReq, opts ...grpc.CallOption) (*DeleteSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordResp) + err := c.cc.Invoke(ctx, Chat_DeleteSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWord(ctx context.Context, in *GetSensitiveWordReq, opts ...grpc.CallOption) (*GetSensitiveWordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWord_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SearchSensitiveWords(ctx context.Context, in *SearchSensitiveWordsReq, opts ...grpc.CallOption) (*SearchSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_SearchSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) BatchAddSensitiveWords(ctx context.Context, in *BatchAddSensitiveWordsReq, opts ...grpc.CallOption) (*BatchAddSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchAddSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_BatchAddSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) BatchUpdateSensitiveWords(ctx context.Context, in *BatchUpdateSensitiveWordsReq, opts ...grpc.CallOption) (*BatchUpdateSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchUpdateSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_BatchUpdateSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) BatchDeleteSensitiveWords(ctx context.Context, in *BatchDeleteSensitiveWordsReq, opts ...grpc.CallOption) (*BatchDeleteSensitiveWordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(BatchDeleteSensitiveWordsResp) + err := c.cc.Invoke(ctx, Chat_BatchDeleteSensitiveWords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) AddSensitiveWordGroup(ctx context.Context, in *AddSensitiveWordGroupReq, opts ...grpc.CallOption) (*AddSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Chat_AddSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateSensitiveWordGroup(ctx context.Context, in *UpdateSensitiveWordGroupReq, opts ...grpc.CallOption) (*UpdateSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Chat_UpdateSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DeleteSensitiveWordGroup(ctx context.Context, in *DeleteSensitiveWordGroupReq, opts ...grpc.CallOption) (*DeleteSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Chat_DeleteSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWordGroup(ctx context.Context, in *GetSensitiveWordGroupReq, opts ...grpc.CallOption) (*GetSensitiveWordGroupResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordGroupResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWordGroup_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetAllSensitiveWordGroups(ctx context.Context, in *GetAllSensitiveWordGroupsReq, opts ...grpc.CallOption) (*GetAllSensitiveWordGroupsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAllSensitiveWordGroupsResp) + err := c.cc.Invoke(ctx, Chat_GetAllSensitiveWordGroups_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWordConfig(ctx context.Context, in *GetSensitiveWordConfigReq, opts ...grpc.CallOption) (*GetSensitiveWordConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordConfigResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWordConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateSensitiveWordConfig(ctx context.Context, in *UpdateSensitiveWordConfigReq, opts ...grpc.CallOption) (*UpdateSensitiveWordConfigResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateSensitiveWordConfigResp) + err := c.cc.Invoke(ctx, Chat_UpdateSensitiveWordConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWordLogs(ctx context.Context, in *GetSensitiveWordLogsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordLogsResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWordLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DeleteSensitiveWordLogs(ctx context.Context, in *DeleteSensitiveWordLogsReq, opts ...grpc.CallOption) (*DeleteSensitiveWordLogsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSensitiveWordLogsResp) + err := c.cc.Invoke(ctx, Chat_DeleteSensitiveWordLogs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetUserLoginRecords(ctx context.Context, in *GetUserLoginRecordsReq, opts ...grpc.CallOption) (*GetUserLoginRecordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserLoginRecordsResp) + err := c.cc.Invoke(ctx, Chat_GetUserLoginRecords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWordStats(ctx context.Context, in *GetSensitiveWordStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordStatsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordStatsResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWordStats_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetSensitiveWordLogStats(ctx context.Context, in *GetSensitiveWordLogStatsReq, opts ...grpc.CallOption) (*GetSensitiveWordLogStatsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetSensitiveWordLogStatsResp) + err := c.cc.Invoke(ctx, Chat_GetSensitiveWordLogStats_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetAppSystemConfigs(ctx context.Context, in *GetAppSystemConfigsReq, opts ...grpc.CallOption) (*GetAppSystemConfigsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAppSystemConfigsResp) + err := c.cc.Invoke(ctx, Chat_GetAppSystemConfigs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetWalletBalance(ctx context.Context, in *GetWalletBalanceReq, opts ...grpc.CallOption) (*GetWalletBalanceResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWalletBalanceResp) + err := c.cc.Invoke(ctx, Chat_GetWalletBalance_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetWalletInfo(ctx context.Context, in *GetWalletInfoReq, opts ...grpc.CallOption) (*GetWalletInfoResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWalletInfoResp) + err := c.cc.Invoke(ctx, Chat_GetWalletInfo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetWalletBalanceRecords(ctx context.Context, in *GetWalletBalanceRecordsReq, opts ...grpc.CallOption) (*GetWalletBalanceRecordsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWalletBalanceRecordsResp) + err := c.cc.Invoke(ctx, Chat_GetWalletBalanceRecords_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SetPaymentPassword(ctx context.Context, in *SetPaymentPasswordReq, opts ...grpc.CallOption) (*SetPaymentPasswordResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetPaymentPasswordResp) + err := c.cc.Invoke(ctx, Chat_SetPaymentPassword_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SetWithdrawAccount(ctx context.Context, in *SetWithdrawAccountReq, opts ...grpc.CallOption) (*SetWithdrawAccountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetWithdrawAccountResp) + err := c.cc.Invoke(ctx, Chat_SetWithdrawAccount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) CreateWithdrawApplication(ctx context.Context, in *CreateWithdrawApplicationReq, opts ...grpc.CallOption) (*CreateWithdrawApplicationResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateWithdrawApplicationResp) + err := c.cc.Invoke(ctx, Chat_CreateWithdrawApplication_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetWithdrawApplications(ctx context.Context, in *GetWithdrawApplicationsReq, opts ...grpc.CallOption) (*GetWithdrawApplicationsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetWithdrawApplicationsResp) + err := c.cc.Invoke(ctx, Chat_GetWithdrawApplications_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) RealNameAuth(ctx context.Context, in *RealNameAuthReq, opts ...grpc.CallOption) (*RealNameAuthResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RealNameAuthResp) + err := c.cc.Invoke(ctx, Chat_RealNameAuth_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) CreateFavorite(ctx context.Context, in *CreateFavoriteReq, opts ...grpc.CallOption) (*CreateFavoriteResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateFavoriteResp) + err := c.cc.Invoke(ctx, Chat_CreateFavorite_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetFavorite(ctx context.Context, in *GetFavoriteReq, opts ...grpc.CallOption) (*GetFavoriteResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFavoriteResp) + err := c.cc.Invoke(ctx, Chat_GetFavorite_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetFavorites(ctx context.Context, in *GetFavoritesReq, opts ...grpc.CallOption) (*GetFavoritesResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFavoritesResp) + err := c.cc.Invoke(ctx, Chat_GetFavorites_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SearchFavorites(ctx context.Context, in *SearchFavoritesReq, opts ...grpc.CallOption) (*SearchFavoritesResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SearchFavoritesResp) + err := c.cc.Invoke(ctx, Chat_SearchFavorites_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateFavorite(ctx context.Context, in *UpdateFavoriteReq, opts ...grpc.CallOption) (*UpdateFavoriteResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateFavoriteResp) + err := c.cc.Invoke(ctx, Chat_UpdateFavorite_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DeleteFavorite(ctx context.Context, in *DeleteFavoriteReq, opts ...grpc.CallOption) (*DeleteFavoriteResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteFavoriteResp) + err := c.cc.Invoke(ctx, Chat_DeleteFavorite_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetFavoritesByTags(ctx context.Context, in *GetFavoritesByTagsReq, opts ...grpc.CallOption) (*GetFavoritesByTagsResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFavoritesByTagsResp) + err := c.cc.Invoke(ctx, Chat_GetFavoritesByTags_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetFavoriteCount(ctx context.Context, in *GetFavoriteCountReq, opts ...grpc.CallOption) (*GetFavoriteCountResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetFavoriteCountResp) + err := c.cc.Invoke(ctx, Chat_GetFavoriteCount_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) CreateScheduledTask(ctx context.Context, in *CreateScheduledTaskReq, opts ...grpc.CallOption) (*CreateScheduledTaskResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateScheduledTaskResp) + err := c.cc.Invoke(ctx, Chat_CreateScheduledTask_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetScheduledTask(ctx context.Context, in *GetScheduledTaskReq, opts ...grpc.CallOption) (*GetScheduledTaskResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetScheduledTaskResp) + err := c.cc.Invoke(ctx, Chat_GetScheduledTask_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetScheduledTasks(ctx context.Context, in *GetScheduledTasksReq, opts ...grpc.CallOption) (*GetScheduledTasksResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetScheduledTasksResp) + err := c.cc.Invoke(ctx, Chat_GetScheduledTasks_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) UpdateScheduledTask(ctx context.Context, in *UpdateScheduledTaskReq, opts ...grpc.CallOption) (*UpdateScheduledTaskResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateScheduledTaskResp) + err := c.cc.Invoke(ctx, Chat_UpdateScheduledTask_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DeleteScheduledTask(ctx context.Context, in *DeleteScheduledTaskReq, opts ...grpc.CallOption) (*DeleteScheduledTaskResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteScheduledTaskResp) + err := c.cc.Invoke(ctx, Chat_DeleteScheduledTask_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ChatServer is the server API for Chat service. +// All implementations must embed UnimplementedChatServer +// for forward compatibility. +type ChatServer interface { + AddFriend(context.Context, *AddFriendReq) (*AddFriendResp, error) + // Edit personal information - called by the user or an administrator + UpdateUserInfo(context.Context, *UpdateUserInfoReq) (*UpdateUserInfoResp, error) + AddUserAccount(context.Context, *AddUserAccountReq) (*AddUserAccountResp, error) + // Get user's public information - called by strangers + SearchUserPublicInfo(context.Context, *SearchUserPublicInfoReq) (*SearchUserPublicInfoResp, error) + FindUserPublicInfo(context.Context, *FindUserPublicInfoReq) (*FindUserPublicInfoResp, error) + // Search user information - called by administrators, other users get public fields + SearchUserFullInfo(context.Context, *SearchUserFullInfoReq) (*SearchUserFullInfoResp, error) + FindUserFullInfo(context.Context, *FindUserFullInfoReq) (*FindUserFullInfoResp, error) + SendVerifyCode(context.Context, *SendVerifyCodeReq) (*SendVerifyCodeResp, error) + VerifyCode(context.Context, *VerifyCodeReq) (*VerifyCodeResp, error) + GetCaptchaImage(context.Context, *GetCaptchaImageReq) (*GetCaptchaImageResp, error) + RegisterUser(context.Context, *RegisterUserReq) (*RegisterUserResp, error) + Login(context.Context, *LoginReq) (*LoginResp, error) + ResetPassword(context.Context, *ResetPasswordReq) (*ResetPasswordResp, error) + ChangePassword(context.Context, *ChangePasswordReq) (*ChangePasswordResp, error) + CheckUserExist(context.Context, *CheckUserExistReq) (*CheckUserExistResp, error) + DelUserAccount(context.Context, *DelUserAccountReq) (*DelUserAccountResp, error) + FindUserAccount(context.Context, *FindUserAccountReq) (*FindUserAccountResp, error) + FindAccountUser(context.Context, *FindAccountUserReq) (*FindAccountUserResp, error) + OpenIMCallback(context.Context, *OpenIMCallbackReq) (*OpenIMCallbackResp, error) + // Statistics + UserLoginCount(context.Context, *UserLoginCountReq) (*UserLoginCountResp, error) + SearchUserInfo(context.Context, *SearchUserInfoReq) (*SearchUserInfoResp, error) + // Audio/video call and video meeting + GetTokenForVideoMeeting(context.Context, *GetTokenForVideoMeetingReq) (*GetTokenForVideoMeetingResp, error) + SetAllowRegister(context.Context, *SetAllowRegisterReq) (*SetAllowRegisterResp, error) + GetAllowRegister(context.Context, *GetAllowRegisterReq) (*GetAllowRegisterResp, error) + // 获取敏感词列表(客户端启动时调用) + GetSensitiveWords(context.Context, *GetSensitiveWordsReq) (*GetSensitiveWordsResp, error) + // 检测敏感词(用户发送消息时调用) + CheckSensitiveWords(context.Context, *CheckSensitiveWordsReq) (*CheckSensitiveWordsResp, error) + // 敏感词管理 + AddSensitiveWord(context.Context, *AddSensitiveWordReq) (*AddSensitiveWordResp, error) + UpdateSensitiveWord(context.Context, *UpdateSensitiveWordReq) (*UpdateSensitiveWordResp, error) + DeleteSensitiveWord(context.Context, *DeleteSensitiveWordReq) (*DeleteSensitiveWordResp, error) + GetSensitiveWord(context.Context, *GetSensitiveWordReq) (*GetSensitiveWordResp, error) + SearchSensitiveWords(context.Context, *SearchSensitiveWordsReq) (*SearchSensitiveWordsResp, error) + BatchAddSensitiveWords(context.Context, *BatchAddSensitiveWordsReq) (*BatchAddSensitiveWordsResp, error) + BatchUpdateSensitiveWords(context.Context, *BatchUpdateSensitiveWordsReq) (*BatchUpdateSensitiveWordsResp, error) + BatchDeleteSensitiveWords(context.Context, *BatchDeleteSensitiveWordsReq) (*BatchDeleteSensitiveWordsResp, error) + // 敏感词分组管理 + AddSensitiveWordGroup(context.Context, *AddSensitiveWordGroupReq) (*AddSensitiveWordGroupResp, error) + UpdateSensitiveWordGroup(context.Context, *UpdateSensitiveWordGroupReq) (*UpdateSensitiveWordGroupResp, error) + DeleteSensitiveWordGroup(context.Context, *DeleteSensitiveWordGroupReq) (*DeleteSensitiveWordGroupResp, error) + GetSensitiveWordGroup(context.Context, *GetSensitiveWordGroupReq) (*GetSensitiveWordGroupResp, error) + GetAllSensitiveWordGroups(context.Context, *GetAllSensitiveWordGroupsReq) (*GetAllSensitiveWordGroupsResp, error) + // 敏感词配置管理 + GetSensitiveWordConfig(context.Context, *GetSensitiveWordConfigReq) (*GetSensitiveWordConfigResp, error) + UpdateSensitiveWordConfig(context.Context, *UpdateSensitiveWordConfigReq) (*UpdateSensitiveWordConfigResp, error) + // 敏感词日志管理 + GetSensitiveWordLogs(context.Context, *GetSensitiveWordLogsReq) (*GetSensitiveWordLogsResp, error) + DeleteSensitiveWordLogs(context.Context, *DeleteSensitiveWordLogsReq) (*DeleteSensitiveWordLogsResp, error) + // 用户登录记录管理 + GetUserLoginRecords(context.Context, *GetUserLoginRecordsReq) (*GetUserLoginRecordsResp, error) + // 敏感词统计 + GetSensitiveWordStats(context.Context, *GetSensitiveWordStatsReq) (*GetSensitiveWordStatsResp, error) + GetSensitiveWordLogStats(context.Context, *GetSensitiveWordLogStatsReq) (*GetSensitiveWordLogStatsResp, error) + // 获取APP端配置(返回所有 show_in_app=true 且 enabled=true 的配置) + GetAppSystemConfigs(context.Context, *GetAppSystemConfigsReq) (*GetAppSystemConfigsResp, error) + // 获取钱包余额 + GetWalletBalance(context.Context, *GetWalletBalanceReq) (*GetWalletBalanceResp, error) + // 获取钱包详细信息(包括余额、提现账号、实名信息等) + GetWalletInfo(context.Context, *GetWalletInfoReq) (*GetWalletInfoResp, error) + // 获取余额明细(余额变动记录) + GetWalletBalanceRecords(context.Context, *GetWalletBalanceRecordsReq) (*GetWalletBalanceRecordsResp, error) + // 设置支付密码(首次设置或修改) + SetPaymentPassword(context.Context, *SetPaymentPasswordReq) (*SetPaymentPasswordResp, error) + // 设置提现账号 + SetWithdrawAccount(context.Context, *SetWithdrawAccountReq) (*SetWithdrawAccountResp, error) + // 申请提现 + CreateWithdrawApplication(context.Context, *CreateWithdrawApplicationReq) (*CreateWithdrawApplicationResp, error) + // 获取用户的提现申请列表 + GetWithdrawApplications(context.Context, *GetWithdrawApplicationsReq) (*GetWithdrawApplicationsResp, error) + // 实名认证 + RealNameAuth(context.Context, *RealNameAuthReq) (*RealNameAuthResp, error) + // 创建收藏 + CreateFavorite(context.Context, *CreateFavoriteReq) (*CreateFavoriteResp, error) + // 获取收藏详情 + GetFavorite(context.Context, *GetFavoriteReq) (*GetFavoriteResp, error) + // 获取收藏列表 + GetFavorites(context.Context, *GetFavoritesReq) (*GetFavoritesResp, error) + // 搜索收藏 + SearchFavorites(context.Context, *SearchFavoritesReq) (*SearchFavoritesResp, error) + // 更新收藏 + UpdateFavorite(context.Context, *UpdateFavoriteReq) (*UpdateFavoriteResp, error) + // 删除收藏 + DeleteFavorite(context.Context, *DeleteFavoriteReq) (*DeleteFavoriteResp, error) + // 根据标签获取收藏 + GetFavoritesByTags(context.Context, *GetFavoritesByTagsReq) (*GetFavoritesByTagsResp, error) + // 获取收藏数量 + GetFavoriteCount(context.Context, *GetFavoriteCountReq) (*GetFavoriteCountResp, error) + // 创建定时任务 + CreateScheduledTask(context.Context, *CreateScheduledTaskReq) (*CreateScheduledTaskResp, error) + // 获取定时任务详情 + GetScheduledTask(context.Context, *GetScheduledTaskReq) (*GetScheduledTaskResp, error) + // 获取定时任务列表 + GetScheduledTasks(context.Context, *GetScheduledTasksReq) (*GetScheduledTasksResp, error) + // 更新定时任务 + UpdateScheduledTask(context.Context, *UpdateScheduledTaskReq) (*UpdateScheduledTaskResp, error) + // 删除定时任务 + DeleteScheduledTask(context.Context, *DeleteScheduledTaskReq) (*DeleteScheduledTaskResp, error) + mustEmbedUnimplementedChatServer() +} + +// UnimplementedChatServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedChatServer struct{} + +func (UnimplementedChatServer) AddFriend(context.Context, *AddFriendReq) (*AddFriendResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddFriend not implemented") +} +func (UnimplementedChatServer) UpdateUserInfo(context.Context, *UpdateUserInfoReq) (*UpdateUserInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserInfo not implemented") +} +func (UnimplementedChatServer) AddUserAccount(context.Context, *AddUserAccountReq) (*AddUserAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddUserAccount not implemented") +} +func (UnimplementedChatServer) SearchUserPublicInfo(context.Context, *SearchUserPublicInfoReq) (*SearchUserPublicInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchUserPublicInfo not implemented") +} +func (UnimplementedChatServer) FindUserPublicInfo(context.Context, *FindUserPublicInfoReq) (*FindUserPublicInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindUserPublicInfo not implemented") +} +func (UnimplementedChatServer) SearchUserFullInfo(context.Context, *SearchUserFullInfoReq) (*SearchUserFullInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchUserFullInfo not implemented") +} +func (UnimplementedChatServer) FindUserFullInfo(context.Context, *FindUserFullInfoReq) (*FindUserFullInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindUserFullInfo not implemented") +} +func (UnimplementedChatServer) SendVerifyCode(context.Context, *SendVerifyCodeReq) (*SendVerifyCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendVerifyCode not implemented") +} +func (UnimplementedChatServer) VerifyCode(context.Context, *VerifyCodeReq) (*VerifyCodeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyCode not implemented") +} +func (UnimplementedChatServer) GetCaptchaImage(context.Context, *GetCaptchaImageReq) (*GetCaptchaImageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCaptchaImage not implemented") +} +func (UnimplementedChatServer) RegisterUser(context.Context, *RegisterUserReq) (*RegisterUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterUser not implemented") +} +func (UnimplementedChatServer) Login(context.Context, *LoginReq) (*LoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") +} +func (UnimplementedChatServer) ResetPassword(context.Context, *ResetPasswordReq) (*ResetPasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResetPassword not implemented") +} +func (UnimplementedChatServer) ChangePassword(context.Context, *ChangePasswordReq) (*ChangePasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangePassword not implemented") +} +func (UnimplementedChatServer) CheckUserExist(context.Context, *CheckUserExistReq) (*CheckUserExistResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckUserExist not implemented") +} +func (UnimplementedChatServer) DelUserAccount(context.Context, *DelUserAccountReq) (*DelUserAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelUserAccount not implemented") +} +func (UnimplementedChatServer) FindUserAccount(context.Context, *FindUserAccountReq) (*FindUserAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindUserAccount not implemented") +} +func (UnimplementedChatServer) FindAccountUser(context.Context, *FindAccountUserReq) (*FindAccountUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindAccountUser not implemented") +} +func (UnimplementedChatServer) OpenIMCallback(context.Context, *OpenIMCallbackReq) (*OpenIMCallbackResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method OpenIMCallback not implemented") +} +func (UnimplementedChatServer) UserLoginCount(context.Context, *UserLoginCountReq) (*UserLoginCountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UserLoginCount not implemented") +} +func (UnimplementedChatServer) SearchUserInfo(context.Context, *SearchUserInfoReq) (*SearchUserInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchUserInfo not implemented") +} +func (UnimplementedChatServer) GetTokenForVideoMeeting(context.Context, *GetTokenForVideoMeetingReq) (*GetTokenForVideoMeetingResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTokenForVideoMeeting not implemented") +} +func (UnimplementedChatServer) SetAllowRegister(context.Context, *SetAllowRegisterReq) (*SetAllowRegisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetAllowRegister not implemented") +} +func (UnimplementedChatServer) GetAllowRegister(context.Context, *GetAllowRegisterReq) (*GetAllowRegisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAllowRegister not implemented") +} +func (UnimplementedChatServer) GetSensitiveWords(context.Context, *GetSensitiveWordsReq) (*GetSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWords not implemented") +} +func (UnimplementedChatServer) CheckSensitiveWords(context.Context, *CheckSensitiveWordsReq) (*CheckSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckSensitiveWords not implemented") +} +func (UnimplementedChatServer) AddSensitiveWord(context.Context, *AddSensitiveWordReq) (*AddSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSensitiveWord not implemented") +} +func (UnimplementedChatServer) UpdateSensitiveWord(context.Context, *UpdateSensitiveWordReq) (*UpdateSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWord not implemented") +} +func (UnimplementedChatServer) DeleteSensitiveWord(context.Context, *DeleteSensitiveWordReq) (*DeleteSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWord not implemented") +} +func (UnimplementedChatServer) GetSensitiveWord(context.Context, *GetSensitiveWordReq) (*GetSensitiveWordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWord not implemented") +} +func (UnimplementedChatServer) SearchSensitiveWords(context.Context, *SearchSensitiveWordsReq) (*SearchSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchSensitiveWords not implemented") +} +func (UnimplementedChatServer) BatchAddSensitiveWords(context.Context, *BatchAddSensitiveWordsReq) (*BatchAddSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchAddSensitiveWords not implemented") +} +func (UnimplementedChatServer) BatchUpdateSensitiveWords(context.Context, *BatchUpdateSensitiveWordsReq) (*BatchUpdateSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchUpdateSensitiveWords not implemented") +} +func (UnimplementedChatServer) BatchDeleteSensitiveWords(context.Context, *BatchDeleteSensitiveWordsReq) (*BatchDeleteSensitiveWordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchDeleteSensitiveWords not implemented") +} +func (UnimplementedChatServer) AddSensitiveWordGroup(context.Context, *AddSensitiveWordGroupReq) (*AddSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSensitiveWordGroup not implemented") +} +func (UnimplementedChatServer) UpdateSensitiveWordGroup(context.Context, *UpdateSensitiveWordGroupReq) (*UpdateSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWordGroup not implemented") +} +func (UnimplementedChatServer) DeleteSensitiveWordGroup(context.Context, *DeleteSensitiveWordGroupReq) (*DeleteSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWordGroup not implemented") +} +func (UnimplementedChatServer) GetSensitiveWordGroup(context.Context, *GetSensitiveWordGroupReq) (*GetSensitiveWordGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordGroup not implemented") +} +func (UnimplementedChatServer) GetAllSensitiveWordGroups(context.Context, *GetAllSensitiveWordGroupsReq) (*GetAllSensitiveWordGroupsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAllSensitiveWordGroups not implemented") +} +func (UnimplementedChatServer) GetSensitiveWordConfig(context.Context, *GetSensitiveWordConfigReq) (*GetSensitiveWordConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordConfig not implemented") +} +func (UnimplementedChatServer) UpdateSensitiveWordConfig(context.Context, *UpdateSensitiveWordConfigReq) (*UpdateSensitiveWordConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSensitiveWordConfig not implemented") +} +func (UnimplementedChatServer) GetSensitiveWordLogs(context.Context, *GetSensitiveWordLogsReq) (*GetSensitiveWordLogsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordLogs not implemented") +} +func (UnimplementedChatServer) DeleteSensitiveWordLogs(context.Context, *DeleteSensitiveWordLogsReq) (*DeleteSensitiveWordLogsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSensitiveWordLogs not implemented") +} +func (UnimplementedChatServer) GetUserLoginRecords(context.Context, *GetUserLoginRecordsReq) (*GetUserLoginRecordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserLoginRecords not implemented") +} +func (UnimplementedChatServer) GetSensitiveWordStats(context.Context, *GetSensitiveWordStatsReq) (*GetSensitiveWordStatsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordStats not implemented") +} +func (UnimplementedChatServer) GetSensitiveWordLogStats(context.Context, *GetSensitiveWordLogStatsReq) (*GetSensitiveWordLogStatsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSensitiveWordLogStats not implemented") +} +func (UnimplementedChatServer) GetAppSystemConfigs(context.Context, *GetAppSystemConfigsReq) (*GetAppSystemConfigsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAppSystemConfigs not implemented") +} +func (UnimplementedChatServer) GetWalletBalance(context.Context, *GetWalletBalanceReq) (*GetWalletBalanceResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWalletBalance not implemented") +} +func (UnimplementedChatServer) GetWalletInfo(context.Context, *GetWalletInfoReq) (*GetWalletInfoResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWalletInfo not implemented") +} +func (UnimplementedChatServer) GetWalletBalanceRecords(context.Context, *GetWalletBalanceRecordsReq) (*GetWalletBalanceRecordsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWalletBalanceRecords not implemented") +} +func (UnimplementedChatServer) SetPaymentPassword(context.Context, *SetPaymentPasswordReq) (*SetPaymentPasswordResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetPaymentPassword not implemented") +} +func (UnimplementedChatServer) SetWithdrawAccount(context.Context, *SetWithdrawAccountReq) (*SetWithdrawAccountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetWithdrawAccount not implemented") +} +func (UnimplementedChatServer) CreateWithdrawApplication(context.Context, *CreateWithdrawApplicationReq) (*CreateWithdrawApplicationResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateWithdrawApplication not implemented") +} +func (UnimplementedChatServer) GetWithdrawApplications(context.Context, *GetWithdrawApplicationsReq) (*GetWithdrawApplicationsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetWithdrawApplications not implemented") +} +func (UnimplementedChatServer) RealNameAuth(context.Context, *RealNameAuthReq) (*RealNameAuthResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method RealNameAuth not implemented") +} +func (UnimplementedChatServer) CreateFavorite(context.Context, *CreateFavoriteReq) (*CreateFavoriteResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateFavorite not implemented") +} +func (UnimplementedChatServer) GetFavorite(context.Context, *GetFavoriteReq) (*GetFavoriteResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFavorite not implemented") +} +func (UnimplementedChatServer) GetFavorites(context.Context, *GetFavoritesReq) (*GetFavoritesResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFavorites not implemented") +} +func (UnimplementedChatServer) SearchFavorites(context.Context, *SearchFavoritesReq) (*SearchFavoritesResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchFavorites not implemented") +} +func (UnimplementedChatServer) UpdateFavorite(context.Context, *UpdateFavoriteReq) (*UpdateFavoriteResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateFavorite not implemented") +} +func (UnimplementedChatServer) DeleteFavorite(context.Context, *DeleteFavoriteReq) (*DeleteFavoriteResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteFavorite not implemented") +} +func (UnimplementedChatServer) GetFavoritesByTags(context.Context, *GetFavoritesByTagsReq) (*GetFavoritesByTagsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFavoritesByTags not implemented") +} +func (UnimplementedChatServer) GetFavoriteCount(context.Context, *GetFavoriteCountReq) (*GetFavoriteCountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFavoriteCount not implemented") +} +func (UnimplementedChatServer) CreateScheduledTask(context.Context, *CreateScheduledTaskReq) (*CreateScheduledTaskResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateScheduledTask not implemented") +} +func (UnimplementedChatServer) GetScheduledTask(context.Context, *GetScheduledTaskReq) (*GetScheduledTaskResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetScheduledTask not implemented") +} +func (UnimplementedChatServer) GetScheduledTasks(context.Context, *GetScheduledTasksReq) (*GetScheduledTasksResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetScheduledTasks not implemented") +} +func (UnimplementedChatServer) UpdateScheduledTask(context.Context, *UpdateScheduledTaskReq) (*UpdateScheduledTaskResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateScheduledTask not implemented") +} +func (UnimplementedChatServer) DeleteScheduledTask(context.Context, *DeleteScheduledTaskReq) (*DeleteScheduledTaskResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteScheduledTask not implemented") +} +func (UnimplementedChatServer) mustEmbedUnimplementedChatServer() {} +func (UnimplementedChatServer) testEmbeddedByValue() {} + +// UnsafeChatServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ChatServer will +// result in compilation errors. +type UnsafeChatServer interface { + mustEmbedUnimplementedChatServer() +} + +func RegisterChatServer(s grpc.ServiceRegistrar, srv ChatServer) { + // If the following call pancis, it indicates UnimplementedChatServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Chat_ServiceDesc, srv) +} + +func _Chat_AddFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).AddFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_AddFriend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).AddFriend(ctx, req.(*AddFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateUserInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateUserInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateUserInfo(ctx, req.(*UpdateUserInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_AddUserAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddUserAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).AddUserAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_AddUserAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).AddUserAccount(ctx, req.(*AddUserAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SearchUserPublicInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchUserPublicInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SearchUserPublicInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SearchUserPublicInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SearchUserPublicInfo(ctx, req.(*SearchUserPublicInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_FindUserPublicInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindUserPublicInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).FindUserPublicInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_FindUserPublicInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).FindUserPublicInfo(ctx, req.(*FindUserPublicInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SearchUserFullInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchUserFullInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SearchUserFullInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SearchUserFullInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SearchUserFullInfo(ctx, req.(*SearchUserFullInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_FindUserFullInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindUserFullInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).FindUserFullInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_FindUserFullInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).FindUserFullInfo(ctx, req.(*FindUserFullInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SendVerifyCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendVerifyCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SendVerifyCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SendVerifyCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SendVerifyCode(ctx, req.(*SendVerifyCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_VerifyCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyCodeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).VerifyCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_VerifyCode_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).VerifyCode(ctx, req.(*VerifyCodeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetCaptchaImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCaptchaImageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetCaptchaImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetCaptchaImage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetCaptchaImage(ctx, req.(*GetCaptchaImageReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_RegisterUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).RegisterUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_RegisterUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).RegisterUser(ctx, req.(*RegisterUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).Login(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_Login_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).Login(ctx, req.(*LoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_ResetPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResetPasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).ResetPassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_ResetPassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).ResetPassword(ctx, req.(*ResetPasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_ChangePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ChangePasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).ChangePassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_ChangePassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).ChangePassword(ctx, req.(*ChangePasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_CheckUserExist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckUserExistReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).CheckUserExist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_CheckUserExist_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).CheckUserExist(ctx, req.(*CheckUserExistReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DelUserAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DelUserAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DelUserAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DelUserAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DelUserAccount(ctx, req.(*DelUserAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_FindUserAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindUserAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).FindUserAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_FindUserAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).FindUserAccount(ctx, req.(*FindUserAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_FindAccountUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindAccountUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).FindAccountUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_FindAccountUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).FindAccountUser(ctx, req.(*FindAccountUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_OpenIMCallback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OpenIMCallbackReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).OpenIMCallback(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_OpenIMCallback_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).OpenIMCallback(ctx, req.(*OpenIMCallbackReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UserLoginCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserLoginCountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UserLoginCount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UserLoginCount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UserLoginCount(ctx, req.(*UserLoginCountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SearchUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchUserInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SearchUserInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SearchUserInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SearchUserInfo(ctx, req.(*SearchUserInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetTokenForVideoMeeting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTokenForVideoMeetingReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetTokenForVideoMeeting(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetTokenForVideoMeeting_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetTokenForVideoMeeting(ctx, req.(*GetTokenForVideoMeetingReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SetAllowRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetAllowRegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SetAllowRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SetAllowRegister_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SetAllowRegister(ctx, req.(*SetAllowRegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetAllowRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllowRegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetAllowRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetAllowRegister_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetAllowRegister(ctx, req.(*GetAllowRegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWords(ctx, req.(*GetSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_CheckSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).CheckSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_CheckSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).CheckSensitiveWords(ctx, req.(*CheckSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_AddSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).AddSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_AddSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).AddSensitiveWord(ctx, req.(*AddSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateSensitiveWord(ctx, req.(*UpdateSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DeleteSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DeleteSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DeleteSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DeleteSensitiveWord(ctx, req.(*DeleteSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWord_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWord(ctx, req.(*GetSensitiveWordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SearchSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SearchSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SearchSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SearchSensitiveWords(ctx, req.(*SearchSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_BatchAddSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchAddSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).BatchAddSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_BatchAddSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).BatchAddSensitiveWords(ctx, req.(*BatchAddSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_BatchUpdateSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchUpdateSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).BatchUpdateSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_BatchUpdateSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).BatchUpdateSensitiveWords(ctx, req.(*BatchUpdateSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_BatchDeleteSensitiveWords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchDeleteSensitiveWordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).BatchDeleteSensitiveWords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_BatchDeleteSensitiveWords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).BatchDeleteSensitiveWords(ctx, req.(*BatchDeleteSensitiveWordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_AddSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).AddSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_AddSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).AddSensitiveWordGroup(ctx, req.(*AddSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateSensitiveWordGroup(ctx, req.(*UpdateSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DeleteSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DeleteSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DeleteSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DeleteSensitiveWordGroup(ctx, req.(*DeleteSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWordGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWordGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWordGroup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWordGroup(ctx, req.(*GetSensitiveWordGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetAllSensitiveWordGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllSensitiveWordGroupsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetAllSensitiveWordGroups(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetAllSensitiveWordGroups_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetAllSensitiveWordGroups(ctx, req.(*GetAllSensitiveWordGroupsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWordConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWordConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWordConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWordConfig(ctx, req.(*GetSensitiveWordConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateSensitiveWordConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSensitiveWordConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateSensitiveWordConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateSensitiveWordConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateSensitiveWordConfig(ctx, req.(*UpdateSensitiveWordConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWordLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWordLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWordLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWordLogs(ctx, req.(*GetSensitiveWordLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DeleteSensitiveWordLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSensitiveWordLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DeleteSensitiveWordLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DeleteSensitiveWordLogs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DeleteSensitiveWordLogs(ctx, req.(*DeleteSensitiveWordLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetUserLoginRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserLoginRecordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetUserLoginRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetUserLoginRecords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetUserLoginRecords(ctx, req.(*GetUserLoginRecordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWordStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordStatsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWordStats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWordStats_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWordStats(ctx, req.(*GetSensitiveWordStatsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetSensitiveWordLogStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSensitiveWordLogStatsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetSensitiveWordLogStats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetSensitiveWordLogStats_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetSensitiveWordLogStats(ctx, req.(*GetSensitiveWordLogStatsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetAppSystemConfigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAppSystemConfigsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetAppSystemConfigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetAppSystemConfigs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetAppSystemConfigs(ctx, req.(*GetAppSystemConfigsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetWalletBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWalletBalanceReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetWalletBalance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetWalletBalance_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetWalletBalance(ctx, req.(*GetWalletBalanceReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetWalletInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWalletInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetWalletInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetWalletInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetWalletInfo(ctx, req.(*GetWalletInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetWalletBalanceRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWalletBalanceRecordsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetWalletBalanceRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetWalletBalanceRecords_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetWalletBalanceRecords(ctx, req.(*GetWalletBalanceRecordsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SetPaymentPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetPaymentPasswordReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SetPaymentPassword(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SetPaymentPassword_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SetPaymentPassword(ctx, req.(*SetPaymentPasswordReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SetWithdrawAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetWithdrawAccountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SetWithdrawAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SetWithdrawAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SetWithdrawAccount(ctx, req.(*SetWithdrawAccountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_CreateWithdrawApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateWithdrawApplicationReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).CreateWithdrawApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_CreateWithdrawApplication_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).CreateWithdrawApplication(ctx, req.(*CreateWithdrawApplicationReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetWithdrawApplications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetWithdrawApplicationsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetWithdrawApplications(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetWithdrawApplications_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetWithdrawApplications(ctx, req.(*GetWithdrawApplicationsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_RealNameAuth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RealNameAuthReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).RealNameAuth(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_RealNameAuth_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).RealNameAuth(ctx, req.(*RealNameAuthReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_CreateFavorite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateFavoriteReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).CreateFavorite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_CreateFavorite_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).CreateFavorite(ctx, req.(*CreateFavoriteReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetFavorite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFavoriteReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetFavorite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetFavorite_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetFavorite(ctx, req.(*GetFavoriteReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetFavorites_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFavoritesReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetFavorites(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetFavorites_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetFavorites(ctx, req.(*GetFavoritesReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SearchFavorites_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchFavoritesReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SearchFavorites(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_SearchFavorites_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SearchFavorites(ctx, req.(*SearchFavoritesReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateFavorite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateFavoriteReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateFavorite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateFavorite_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateFavorite(ctx, req.(*UpdateFavoriteReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DeleteFavorite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteFavoriteReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DeleteFavorite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DeleteFavorite_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DeleteFavorite(ctx, req.(*DeleteFavoriteReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetFavoritesByTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFavoritesByTagsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetFavoritesByTags(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetFavoritesByTags_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetFavoritesByTags(ctx, req.(*GetFavoritesByTagsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetFavoriteCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFavoriteCountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetFavoriteCount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetFavoriteCount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetFavoriteCount(ctx, req.(*GetFavoriteCountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_CreateScheduledTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateScheduledTaskReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).CreateScheduledTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_CreateScheduledTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).CreateScheduledTask(ctx, req.(*CreateScheduledTaskReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetScheduledTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetScheduledTaskReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetScheduledTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetScheduledTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetScheduledTask(ctx, req.(*GetScheduledTaskReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetScheduledTasks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetScheduledTasksReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetScheduledTasks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_GetScheduledTasks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetScheduledTasks(ctx, req.(*GetScheduledTasksReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_UpdateScheduledTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateScheduledTaskReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).UpdateScheduledTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_UpdateScheduledTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).UpdateScheduledTask(ctx, req.(*UpdateScheduledTaskReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DeleteScheduledTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteScheduledTaskReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DeleteScheduledTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chat_DeleteScheduledTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DeleteScheduledTask(ctx, req.(*DeleteScheduledTaskReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Chat_ServiceDesc is the grpc.ServiceDesc for Chat service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Chat_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openim.chat.chat", + HandlerType: (*ChatServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddFriend", + Handler: _Chat_AddFriend_Handler, + }, + { + MethodName: "UpdateUserInfo", + Handler: _Chat_UpdateUserInfo_Handler, + }, + { + MethodName: "AddUserAccount", + Handler: _Chat_AddUserAccount_Handler, + }, + { + MethodName: "SearchUserPublicInfo", + Handler: _Chat_SearchUserPublicInfo_Handler, + }, + { + MethodName: "FindUserPublicInfo", + Handler: _Chat_FindUserPublicInfo_Handler, + }, + { + MethodName: "SearchUserFullInfo", + Handler: _Chat_SearchUserFullInfo_Handler, + }, + { + MethodName: "FindUserFullInfo", + Handler: _Chat_FindUserFullInfo_Handler, + }, + { + MethodName: "SendVerifyCode", + Handler: _Chat_SendVerifyCode_Handler, + }, + { + MethodName: "VerifyCode", + Handler: _Chat_VerifyCode_Handler, + }, + { + MethodName: "GetCaptchaImage", + Handler: _Chat_GetCaptchaImage_Handler, + }, + { + MethodName: "RegisterUser", + Handler: _Chat_RegisterUser_Handler, + }, + { + MethodName: "Login", + Handler: _Chat_Login_Handler, + }, + { + MethodName: "ResetPassword", + Handler: _Chat_ResetPassword_Handler, + }, + { + MethodName: "ChangePassword", + Handler: _Chat_ChangePassword_Handler, + }, + { + MethodName: "CheckUserExist", + Handler: _Chat_CheckUserExist_Handler, + }, + { + MethodName: "DelUserAccount", + Handler: _Chat_DelUserAccount_Handler, + }, + { + MethodName: "FindUserAccount", + Handler: _Chat_FindUserAccount_Handler, + }, + { + MethodName: "FindAccountUser", + Handler: _Chat_FindAccountUser_Handler, + }, + { + MethodName: "OpenIMCallback", + Handler: _Chat_OpenIMCallback_Handler, + }, + { + MethodName: "UserLoginCount", + Handler: _Chat_UserLoginCount_Handler, + }, + { + MethodName: "SearchUserInfo", + Handler: _Chat_SearchUserInfo_Handler, + }, + { + MethodName: "GetTokenForVideoMeeting", + Handler: _Chat_GetTokenForVideoMeeting_Handler, + }, + { + MethodName: "SetAllowRegister", + Handler: _Chat_SetAllowRegister_Handler, + }, + { + MethodName: "GetAllowRegister", + Handler: _Chat_GetAllowRegister_Handler, + }, + { + MethodName: "GetSensitiveWords", + Handler: _Chat_GetSensitiveWords_Handler, + }, + { + MethodName: "CheckSensitiveWords", + Handler: _Chat_CheckSensitiveWords_Handler, + }, + { + MethodName: "AddSensitiveWord", + Handler: _Chat_AddSensitiveWord_Handler, + }, + { + MethodName: "UpdateSensitiveWord", + Handler: _Chat_UpdateSensitiveWord_Handler, + }, + { + MethodName: "DeleteSensitiveWord", + Handler: _Chat_DeleteSensitiveWord_Handler, + }, + { + MethodName: "GetSensitiveWord", + Handler: _Chat_GetSensitiveWord_Handler, + }, + { + MethodName: "SearchSensitiveWords", + Handler: _Chat_SearchSensitiveWords_Handler, + }, + { + MethodName: "BatchAddSensitiveWords", + Handler: _Chat_BatchAddSensitiveWords_Handler, + }, + { + MethodName: "BatchUpdateSensitiveWords", + Handler: _Chat_BatchUpdateSensitiveWords_Handler, + }, + { + MethodName: "BatchDeleteSensitiveWords", + Handler: _Chat_BatchDeleteSensitiveWords_Handler, + }, + { + MethodName: "AddSensitiveWordGroup", + Handler: _Chat_AddSensitiveWordGroup_Handler, + }, + { + MethodName: "UpdateSensitiveWordGroup", + Handler: _Chat_UpdateSensitiveWordGroup_Handler, + }, + { + MethodName: "DeleteSensitiveWordGroup", + Handler: _Chat_DeleteSensitiveWordGroup_Handler, + }, + { + MethodName: "GetSensitiveWordGroup", + Handler: _Chat_GetSensitiveWordGroup_Handler, + }, + { + MethodName: "GetAllSensitiveWordGroups", + Handler: _Chat_GetAllSensitiveWordGroups_Handler, + }, + { + MethodName: "GetSensitiveWordConfig", + Handler: _Chat_GetSensitiveWordConfig_Handler, + }, + { + MethodName: "UpdateSensitiveWordConfig", + Handler: _Chat_UpdateSensitiveWordConfig_Handler, + }, + { + MethodName: "GetSensitiveWordLogs", + Handler: _Chat_GetSensitiveWordLogs_Handler, + }, + { + MethodName: "DeleteSensitiveWordLogs", + Handler: _Chat_DeleteSensitiveWordLogs_Handler, + }, + { + MethodName: "GetUserLoginRecords", + Handler: _Chat_GetUserLoginRecords_Handler, + }, + { + MethodName: "GetSensitiveWordStats", + Handler: _Chat_GetSensitiveWordStats_Handler, + }, + { + MethodName: "GetSensitiveWordLogStats", + Handler: _Chat_GetSensitiveWordLogStats_Handler, + }, + { + MethodName: "GetAppSystemConfigs", + Handler: _Chat_GetAppSystemConfigs_Handler, + }, + { + MethodName: "GetWalletBalance", + Handler: _Chat_GetWalletBalance_Handler, + }, + { + MethodName: "GetWalletInfo", + Handler: _Chat_GetWalletInfo_Handler, + }, + { + MethodName: "GetWalletBalanceRecords", + Handler: _Chat_GetWalletBalanceRecords_Handler, + }, + { + MethodName: "SetPaymentPassword", + Handler: _Chat_SetPaymentPassword_Handler, + }, + { + MethodName: "SetWithdrawAccount", + Handler: _Chat_SetWithdrawAccount_Handler, + }, + { + MethodName: "CreateWithdrawApplication", + Handler: _Chat_CreateWithdrawApplication_Handler, + }, + { + MethodName: "GetWithdrawApplications", + Handler: _Chat_GetWithdrawApplications_Handler, + }, + { + MethodName: "RealNameAuth", + Handler: _Chat_RealNameAuth_Handler, + }, + { + MethodName: "CreateFavorite", + Handler: _Chat_CreateFavorite_Handler, + }, + { + MethodName: "GetFavorite", + Handler: _Chat_GetFavorite_Handler, + }, + { + MethodName: "GetFavorites", + Handler: _Chat_GetFavorites_Handler, + }, + { + MethodName: "SearchFavorites", + Handler: _Chat_SearchFavorites_Handler, + }, + { + MethodName: "UpdateFavorite", + Handler: _Chat_UpdateFavorite_Handler, + }, + { + MethodName: "DeleteFavorite", + Handler: _Chat_DeleteFavorite_Handler, + }, + { + MethodName: "GetFavoritesByTags", + Handler: _Chat_GetFavoritesByTags_Handler, + }, + { + MethodName: "GetFavoriteCount", + Handler: _Chat_GetFavoriteCount_Handler, + }, + { + MethodName: "CreateScheduledTask", + Handler: _Chat_CreateScheduledTask_Handler, + }, + { + MethodName: "GetScheduledTask", + Handler: _Chat_GetScheduledTask_Handler, + }, + { + MethodName: "GetScheduledTasks", + Handler: _Chat_GetScheduledTasks_Handler, + }, + { + MethodName: "UpdateScheduledTask", + Handler: _Chat_UpdateScheduledTask_Handler, + }, + { + MethodName: "DeleteScheduledTask", + Handler: _Chat_DeleteScheduledTask_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "chat/chat.proto", +} diff --git a/pkg/protocol/common/common.pb.go b/pkg/protocol/common/common.pb.go new file mode 100644 index 0000000..82327fa --- /dev/null +++ b/pkg/protocol/common/common.pb.go @@ -0,0 +1,930 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v6.33.0 +// source: common/common.proto + +package common + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UserFullInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password"` + Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account"` + PhoneNumber string `protobuf:"bytes,4,opt,name=phoneNumber,proto3" json:"phoneNumber"` + AreaCode string `protobuf:"bytes,5,opt,name=areaCode,proto3" json:"areaCode"` + Email string `protobuf:"bytes,6,opt,name=email,proto3" json:"email"` + Nickname string `protobuf:"bytes,7,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,8,opt,name=faceURL,proto3" json:"faceURL"` + Gender int32 `protobuf:"varint,9,opt,name=gender,proto3" json:"gender"` + Level int32 `protobuf:"varint,10,opt,name=level,proto3" json:"level"` + Birth int64 `protobuf:"varint,11,opt,name=birth,proto3" json:"birth"` + AllowAddFriend int32 `protobuf:"varint,12,opt,name=allowAddFriend,proto3" json:"allowAddFriend"` + AllowBeep int32 `protobuf:"varint,13,opt,name=allowBeep,proto3" json:"allowBeep"` + AllowVibration int32 `protobuf:"varint,14,opt,name=allowVibration,proto3" json:"allowVibration"` + GlobalRecvMsgOpt int32 `protobuf:"varint,15,opt,name=globalRecvMsgOpt,proto3" json:"globalRecvMsgOpt"` + RegisterType int32 `protobuf:"varint,16,opt,name=registerType,proto3" json:"registerType"` + UserType int32 `protobuf:"varint,17,opt,name=userType,proto3" json:"userType"` // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + UserFlag string `protobuf:"bytes,18,opt,name=userFlag,proto3" json:"userFlag"` // 用户标签/标识 + CreateTime int64 `protobuf:"varint,19,opt,name=createTime,proto3" json:"createTime"` // 用户创建时间 + Ip string `protobuf:"bytes,20,opt,name=ip,proto3" json:"ip"` // 用户最新登录IP + // 实名认证信息 + IdCard string `protobuf:"bytes,21,opt,name=idCard,proto3" json:"idCard"` // 身份证号 + RealName string `protobuf:"bytes,22,opt,name=realName,proto3" json:"realName"` // 真实姓名 + IdCardPhotoFront string `protobuf:"bytes,23,opt,name=idCardPhotoFront,proto3" json:"idCardPhotoFront"` // 身份证正面照片URL + IdCardPhotoBack string `protobuf:"bytes,24,opt,name=idCardPhotoBack,proto3" json:"idCardPhotoBack"` // 身份证反面照片URL + AuditStatus int32 `protobuf:"varint,25,opt,name=auditStatus,proto3" json:"auditStatus"` // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +func (x *UserFullInfo) Reset() { + *x = UserFullInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_common_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserFullInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserFullInfo) ProtoMessage() {} + +func (x *UserFullInfo) ProtoReflect() protoreflect.Message { + mi := &file_common_common_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserFullInfo.ProtoReflect.Descriptor instead. +func (*UserFullInfo) Descriptor() ([]byte, []int) { + return file_common_common_proto_rawDescGZIP(), []int{0} +} + +func (x *UserFullInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UserFullInfo) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *UserFullInfo) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *UserFullInfo) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *UserFullInfo) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *UserFullInfo) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UserFullInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *UserFullInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *UserFullInfo) GetGender() int32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *UserFullInfo) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *UserFullInfo) GetBirth() int64 { + if x != nil { + return x.Birth + } + return 0 +} + +func (x *UserFullInfo) GetAllowAddFriend() int32 { + if x != nil { + return x.AllowAddFriend + } + return 0 +} + +func (x *UserFullInfo) GetAllowBeep() int32 { + if x != nil { + return x.AllowBeep + } + return 0 +} + +func (x *UserFullInfo) GetAllowVibration() int32 { + if x != nil { + return x.AllowVibration + } + return 0 +} + +func (x *UserFullInfo) GetGlobalRecvMsgOpt() int32 { + if x != nil { + return x.GlobalRecvMsgOpt + } + return 0 +} + +func (x *UserFullInfo) GetRegisterType() int32 { + if x != nil { + return x.RegisterType + } + return 0 +} + +func (x *UserFullInfo) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +func (x *UserFullInfo) GetUserFlag() string { + if x != nil { + return x.UserFlag + } + return "" +} + +func (x *UserFullInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *UserFullInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *UserFullInfo) GetIdCard() string { + if x != nil { + return x.IdCard + } + return "" +} + +func (x *UserFullInfo) GetRealName() string { + if x != nil { + return x.RealName + } + return "" +} + +func (x *UserFullInfo) GetIdCardPhotoFront() string { + if x != nil { + return x.IdCardPhotoFront + } + return "" +} + +func (x *UserFullInfo) GetIdCardPhotoBack() string { + if x != nil { + return x.IdCardPhotoBack + } + return "" +} + +func (x *UserFullInfo) GetAuditStatus() int32 { + if x != nil { + return x.AuditStatus + } + return 0 +} + +type UserPublicInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email"` + Nickname string `protobuf:"bytes,4,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,5,opt,name=faceURL,proto3" json:"faceURL"` + Gender int32 `protobuf:"varint,6,opt,name=gender,proto3" json:"gender"` + Level int32 `protobuf:"varint,7,opt,name=level,proto3" json:"level"` + UserType int32 `protobuf:"varint,8,opt,name=userType,proto3" json:"userType"` // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 +} + +func (x *UserPublicInfo) Reset() { + *x = UserPublicInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_common_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserPublicInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserPublicInfo) ProtoMessage() {} + +func (x *UserPublicInfo) ProtoReflect() protoreflect.Message { + mi := &file_common_common_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserPublicInfo.ProtoReflect.Descriptor instead. +func (*UserPublicInfo) Descriptor() ([]byte, []int) { + return file_common_common_proto_rawDescGZIP(), []int{1} +} + +func (x *UserPublicInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UserPublicInfo) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *UserPublicInfo) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UserPublicInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *UserPublicInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *UserPublicInfo) GetGender() int32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *UserPublicInfo) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *UserPublicInfo) GetUserType() int32 { + if x != nil { + return x.UserType + } + return 0 +} + +type UserIdentity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email"` + AreaCode string `protobuf:"bytes,2,opt,name=areaCode,proto3" json:"areaCode"` + PhoneNumber string `protobuf:"bytes,3,opt,name=phoneNumber,proto3" json:"phoneNumber"` + DeviceID string `protobuf:"bytes,4,opt,name=deviceID,proto3" json:"deviceID"` + Platform int32 `protobuf:"varint,5,opt,name=platform,proto3" json:"platform"` + Account string `protobuf:"bytes,6,opt,name=account,proto3" json:"account"` +} + +func (x *UserIdentity) Reset() { + *x = UserIdentity{} + if protoimpl.UnsafeEnabled { + mi := &file_common_common_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserIdentity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserIdentity) ProtoMessage() {} + +func (x *UserIdentity) ProtoReflect() protoreflect.Message { + mi := &file_common_common_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserIdentity.ProtoReflect.Descriptor instead. +func (*UserIdentity) Descriptor() ([]byte, []int) { + return file_common_common_proto_rawDescGZIP(), []int{2} +} + +func (x *UserIdentity) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UserIdentity) GetAreaCode() string { + if x != nil { + return x.AreaCode + } + return "" +} + +func (x *UserIdentity) GetPhoneNumber() string { + if x != nil { + return x.PhoneNumber + } + return "" +} + +func (x *UserIdentity) GetDeviceID() string { + if x != nil { + return x.DeviceID + } + return "" +} + +func (x *UserIdentity) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *UserIdentity) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +type AppletInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + AppID string `protobuf:"bytes,3,opt,name=appID,proto3" json:"appID"` + Icon string `protobuf:"bytes,4,opt,name=icon,proto3" json:"icon"` + Url string `protobuf:"bytes,5,opt,name=url,proto3" json:"url"` + Md5 string `protobuf:"bytes,6,opt,name=md5,proto3" json:"md5"` + Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size"` + Version string `protobuf:"bytes,8,opt,name=version,proto3" json:"version"` + Priority uint32 `protobuf:"varint,9,opt,name=priority,proto3" json:"priority"` + Status uint32 `protobuf:"varint,10,opt,name=status,proto3" json:"status"` + CreateTime int64 `protobuf:"varint,11,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *AppletInfo) Reset() { + *x = AppletInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_common_common_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AppletInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AppletInfo) ProtoMessage() {} + +func (x *AppletInfo) ProtoReflect() protoreflect.Message { + mi := &file_common_common_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AppletInfo.ProtoReflect.Descriptor instead. +func (*AppletInfo) Descriptor() ([]byte, []int) { + return file_common_common_proto_rawDescGZIP(), []int{3} +} + +func (x *AppletInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AppletInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AppletInfo) GetAppID() string { + if x != nil { + return x.AppID + } + return "" +} + +func (x *AppletInfo) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *AppletInfo) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *AppletInfo) GetMd5() string { + if x != nil { + return x.Md5 + } + return "" +} + +func (x *AppletInfo) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *AppletInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *AppletInfo) GetPriority() uint32 { + if x != nil { + return x.Priority + } + return 0 +} + +func (x *AppletInfo) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *AppletInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type LogInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Platform int32 `protobuf:"varint,2,opt,name=platform,proto3" json:"platform"` + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url"` + CreateTime int64 `protobuf:"varint,4,opt,name=createTime,proto3" json:"createTime"` + Nickname string `protobuf:"bytes,5,opt,name=nickname,proto3" json:"nickname"` + LogID string `protobuf:"bytes,6,opt,name=logID,proto3" json:"logID"` + Filename string `protobuf:"bytes,7,opt,name=filename,proto3" json:"filename"` + SystemType string `protobuf:"bytes,8,opt,name=systemType,proto3" json:"systemType"` + Ex string `protobuf:"bytes,9,opt,name=ex,proto3" json:"ex"` + Version string `protobuf:"bytes,10,opt,name=version,proto3" json:"version"` +} + +func (x *LogInfo) Reset() { + *x = LogInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_common_common_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LogInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogInfo) ProtoMessage() {} + +func (x *LogInfo) ProtoReflect() protoreflect.Message { + mi := &file_common_common_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogInfo.ProtoReflect.Descriptor instead. +func (*LogInfo) Descriptor() ([]byte, []int) { + return file_common_common_proto_rawDescGZIP(), []int{4} +} + +func (x *LogInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *LogInfo) GetPlatform() int32 { + if x != nil { + return x.Platform + } + return 0 +} + +func (x *LogInfo) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *LogInfo) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *LogInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *LogInfo) GetLogID() string { + if x != nil { + return x.LogID + } + return "" +} + +func (x *LogInfo) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *LogInfo) GetSystemType() string { + if x != nil { + return x.SystemType + } + return "" +} + +func (x *LogInfo) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +func (x *LogInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +var File_common_common_proto protoreflect.FileDescriptor + +var file_common_common_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xfc, 0x05, 0x0a, 0x0c, 0x55, 0x73, + 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, + 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, + 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, + 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x14, 0x0a, 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x62, 0x69, 0x72, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x41, + 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x42, 0x65, 0x65, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x42, 0x65, 0x65, 0x70, 0x12, 0x26, 0x0a, 0x0e, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x56, 0x69, 0x62, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x56, 0x69, 0x62, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x65, + 0x63, 0x76, 0x4d, 0x73, 0x67, 0x4f, 0x70, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x76, 0x4d, 0x73, 0x67, 0x4f, 0x70, 0x74, + 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x46, 0x6c, 0x61, 0x67, 0x18, 0x12, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, + 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x64, + 0x43, 0x61, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x43, 0x61, + 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, + 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x43, 0x61, 0x72, 0x64, 0x50, 0x68, 0x6f, + 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x75, 0x64, + 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xd8, 0x01, 0x0a, 0x0e, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, + 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, + 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x80, 0x02, 0x0a, 0x0a, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, + 0x70, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x64, 0x35, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x12, 0x0a, 0x04, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x87, 0x02, + 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x6f, 0x67, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x49, + 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x65, 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x2e, 0x69, + 0x6d, 0x61, 0x6c, 0x6c, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_common_common_proto_rawDescOnce sync.Once + file_common_common_proto_rawDescData = file_common_common_proto_rawDesc +) + +func file_common_common_proto_rawDescGZIP() []byte { + file_common_common_proto_rawDescOnce.Do(func() { + file_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_common_proto_rawDescData) + }) + return file_common_common_proto_rawDescData +} + +var file_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_common_common_proto_goTypes = []interface{}{ + (*UserFullInfo)(nil), // 0: openim.chat.common.UserFullInfo + (*UserPublicInfo)(nil), // 1: openim.chat.common.UserPublicInfo + (*UserIdentity)(nil), // 2: openim.chat.common.UserIdentity + (*AppletInfo)(nil), // 3: openim.chat.common.AppletInfo + (*LogInfo)(nil), // 4: openim.chat.common.LogInfo +} +var file_common_common_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_common_common_proto_init() } +func file_common_common_proto_init() { + if File_common_common_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_common_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserFullInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserPublicInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserIdentity); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AppletInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LogInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_common_common_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_common_common_proto_goTypes, + DependencyIndexes: file_common_common_proto_depIdxs, + MessageInfos: file_common_common_proto_msgTypes, + }.Build() + File_common_common_proto = out.File + file_common_common_proto_rawDesc = nil + file_common_common_proto_goTypes = nil + file_common_common_proto_depIdxs = nil +} diff --git a/pkg/protocol/common/common.proto b/pkg/protocol/common/common.proto new file mode 100644 index 0000000..6475cdb --- /dev/null +++ b/pkg/protocol/common/common.proto @@ -0,0 +1,81 @@ +syntax = "proto3"; +package openim.chat.common; +option go_package = "git.imall.cloud/openim/chat/pkg/protocol/common"; + + +message UserFullInfo{ + string userID = 1; + string password = 2; + string account = 3; + string phoneNumber = 4; + string areaCode = 5; + string email = 6; + string nickname = 7; + string faceURL = 8; + int32 gender = 9; + int32 level = 10; + int64 birth = 11; + int32 allowAddFriend = 12; + int32 allowBeep = 13; + int32 allowVibration = 14; + int32 globalRecvMsgOpt = 15; + int32 registerType = 16; + int32 userType = 17; // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 + string userFlag = 18; // 用户标签/标识 + int64 createTime = 19; // 用户创建时间 + string ip = 20; // 用户最新登录IP + // 实名认证信息 + string idCard = 21; // 身份证号 + string realName = 22; // 真实姓名 + string idCardPhotoFront = 23; // 身份证正面照片URL + string idCardPhotoBack = 24; // 身份证反面照片URL + int32 auditStatus = 25; // 审核状态:0-未审核,1-审核通过,2-审核拒绝 +} + +message UserPublicInfo{ + string userID = 1; + string account = 2; + string email = 3; + string nickname = 4; + string faceURL = 5; + int32 gender = 6; + int32 level = 7; + int32 userType = 8; // 用户类型: 0=普通用户, 1=企业用户, 2=机器人, 3=管理员 +} + +message UserIdentity { + string email = 1; + string areaCode = 2; + string phoneNumber = 3; + string deviceID = 4; + int32 platform = 5; + string account = 6; +} + + +message AppletInfo { + string id = 1; + string name = 2; + string appID = 3; + string icon = 4; + string url = 5; + string md5 = 6; + int64 size = 7; + string version = 8; + uint32 priority = 9; + uint32 status = 10; + int64 createTime = 11; +} + +message LogInfo{ + string userID=1; + int32 platform=2; + string url=3; + int64 createTime=4; + string nickname=5; + string logID=6; + string filename=7; + string systemType=8; + string ex=9; + string version=10; +} \ No newline at end of file diff --git a/pkg/protocol/gen.cmd b/pkg/protocol/gen.cmd new file mode 100644 index 0000000..4248d4c --- /dev/null +++ b/pkg/protocol/gen.cmd @@ -0,0 +1,32 @@ +@echo off +setlocal + +rem Define array elements +set "PROTO_NAMES=admin chat common bot" + +rem Loop through each element in the array +for %%i in (%PROTO_NAMES%) do ( + protoc --go_out=./%%i --go_opt=module=git.imall.cloud/openim/chat/pkg/protocol/%%i %%i/%%i.proto + if ERRORLEVEL 1 ( + echo error processing %%i.proto + exit /b %ERRORLEVEL% + ) +) + +rem Generate Go-grpc code + +for %%i in (%PROTO_NAMES%) do ( + protoc --go-grpc_out=./%%i --go-grpc_opt=module=git.imall.cloud/openim/chat/pkg/protocol/%%i %%i/%%i.proto + if ERRORLEVEL 1 ( + echo error processing %%i.proto + exit /b %ERRORLEVEL% + ) + ) + + +rem Replace "omitempty" in *.pb.go files with UTF-8 encoding +for /r %%f in (*.pb.go) do ( + powershell -Command "(Get-Content -Path '%%f' -Encoding UTF8) -replace ',omitempty', '' | Set-Content -Path '%%f' -Encoding UTF8" +) + +endlocal diff --git a/pkg/protocol/gen.sh b/pkg/protocol/gen.sh new file mode 100755 index 0000000..5e5c6c8 --- /dev/null +++ b/pkg/protocol/gen.sh @@ -0,0 +1,29 @@ +PROTO_NAMES=( + "admin" + "chat" + "common" +) + +for name in "${PROTO_NAMES[@]}"; do + protoc --go_out=./${name} --go_opt=module=git.imall.cloud/openim/chat/pkg/protocol/${name} ${name}/${name}.proto + if [ $? -ne 0 ]; then + echo "error processing ${name}.proto (go_out)" + exit $? + fi +done + +# generate go-grpc + +for name in "${PROTO_NAMES[@]}"; do + protoc --go-grpc_out=./${name} --go-grpc_opt=module=git.imall.cloud/openim/chat/pkg/protocol/${name} ${name}/${name}.proto + if [ $? -ne 0 ]; then + echo "error processing ${name}.proto (go-grpc_out)" + exit $? + fi +done + +if [ "$(uname -s)" == "Darwin" ]; then + find . -type f -name '*.pb.go' -exec sed -i '' 's/,omitempty"`/\"\`/g' {} + +else + find . -type f -name '*.pb.go' -exec sed -i 's/,omitempty"`/\"\`/g' {} + +fi \ No newline at end of file diff --git a/pkg/protocol/sdkws/sdkws.proto b/pkg/protocol/sdkws/sdkws.proto new file mode 100644 index 0000000..f2d02d2 --- /dev/null +++ b/pkg/protocol/sdkws/sdkws.proto @@ -0,0 +1,525 @@ +syntax = "proto3"; +package openim.sdkws; + +import "wrapperspb/wrapperspb.proto"; + +option go_package = "git.imall.cloud/openim/protocol/sdkws"; + +////////////////////////////////base/////////////////////////////// + +message GroupInfo { + string groupID = 1; + string groupName = 2; + string notification = 3; + string introduction = 4; + string faceURL = 5; + string ownerUserID = 6; + int64 createTime = 7; + uint32 memberCount = 8; + string ex = 9; + int32 status = 10; + string creatorUserID = 11; + int32 groupType = 12; + int32 needVerification = 13; + int32 lookMemberInfo = 14; + int32 applyMemberFriend = 15; + int64 notificationUpdateTime = 16; + string notificationUserID = 17; +} + +message GroupInfoForSet { + string groupID = 1; + string groupName = 2; + string notification = 3; + string introduction = 4; + string faceURL = 5; + openim.protobuf.StringValue ex = 6; + openim.protobuf.Int32Value needVerification = 7; + openim.protobuf.Int32Value lookMemberInfo = 8; + openim.protobuf.Int32Value applyMemberFriend = 9; +} + +message GroupMemberFullInfo { + string groupID = 1; + string userID = 2; + int32 roleLevel = 3; + int64 joinTime = 4; + string nickname = 5; + string faceURL = 6; + int32 appMangerLevel = 7; //if >0 + int32 joinSource = 8; + string operatorUserID = 9; + string ex = 10; + int64 muteEndTime = 11; + string inviterUserID = 12; +} + +message PublicUserInfo { + string userID = 1; + string nickname = 2; + string faceURL = 3; + string ex = 4; +} + +message UserInfo { + string userID = 1; + string nickname = 2; + string faceURL = 3; + string ex = 4; + int64 createTime = 5; + int32 appMangerLevel = 6; + int32 globalRecvMsgOpt = 7; +} + +message UserInfoWithEx { + string userID = 1; + openim.protobuf.StringValue nickname = 2; + openim.protobuf.StringValue faceURL = 3; + openim.protobuf.StringValue ex = 4; + openim.protobuf.Int32Value globalRecvMsgOpt = 7; +} + +message FriendInfo { + string ownerUserID = 1; + string remark = 2; + int64 createTime = 3; + UserInfo friendUser = 4; + int32 addSource = 5; + string operatorUserID = 6; + string ex = 7; + bool isPinned = 8; +} + +message BlackInfo { + string ownerUserID = 1; + int64 createTime = 2; + PublicUserInfo blackUserInfo = 3; + int32 addSource = 4; + string operatorUserID = 5; + string ex = 6; +} + +message GroupRequest { + PublicUserInfo userInfo = 1; + GroupInfo groupInfo = 2; + int32 handleResult = 3; + string reqMsg = 4; + string handleMsg = 5; + int64 reqTime = 6; + string handleUserID = 7; + int64 handleTime = 8; + string ex = 9; + int32 joinSource = 10; + string inviterUserID = 11; +} + +message FriendRequest { + string fromUserID = 1; + string fromNickname = 2; + string fromFaceURL = 3; + string toUserID = 4; + string toNickname = 5; + string toFaceURL = 6; + int32 handleResult = 7; + string reqMsg = 8; + int64 createTime = 9; + string handlerUserID = 10; + string handleMsg = 11; + int64 handleTime = 12; + string ex = 13; +} + +///////////////////////////////////base end///////////////////////////////////// +enum PullOrder { + PullOrderAsc = 0; + PullOrderDesc = 1; +} +message PullMessageBySeqsReq { + string userID = 1; + repeated SeqRange seqRanges = 2; + PullOrder order = 3; +} + +message SeqRange { + string conversationID = 1; + int64 begin = 2; + int64 end = 3; + int64 num = 4; +} + +message PullMsgs { + repeated MsgData Msgs = 1; + bool isEnd = 2; +} + +message PullMessageBySeqsResp { + map msgs = 1; + map notificationMsgs = 2; +} + +message GetMaxSeqReq { + string userID = 1; +} + +message GetMaxSeqResp { + map maxSeqs = 1; + map minSeqs = 2; +} + +message UserSendMsgResp { + string serverMsgID = 1; + string clientMsgID = 2; + int64 sendTime = 3; +} + +message MsgData { + string sendID = 1; + string recvID = 2; + string groupID = 3; + string clientMsgID = 4; + string serverMsgID = 5; + int32 senderPlatformID = 6; + string senderNickname = 7; + string senderFaceURL = 8; + int32 sessionType = 9; + int32 msgFrom = 10; + int32 contentType = 11; + bytes content = 12; + int64 seq = 14; + int64 sendTime = 15; + int64 createTime = 16; + int32 status = 17; + bool isRead = 18; + map options = 19; + OfflinePushInfo offlinePushInfo = 20; + repeated string atUserIDList = 21; + string attachedInfo = 22; + string ex = 23; +} +message PushMessages { + map msgs = 1; + map notificationMsgs = 2; +} +message OfflinePushInfo { + string title = 1; + string desc = 2; + string ex = 3; + string iOSPushSound = 4; + bool iOSBadgeCount = 5; + string signalInfo = 6; +} + +message TipsComm { + bytes detail = 1; + string defaultTips = 2; + string jsonDetail = 3; +} + +//////////////////////group///////////////////// + +// OnGroupCreated() +message GroupCreatedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo memberList = 3; + int64 operationTime = 4; + GroupMemberFullInfo groupOwnerUser = 5; +} + +// OnGroupInfoSet() +message GroupInfoSetTips { + GroupMemberFullInfo opUser = 1; //who do this + int64 muteTime = 2; + GroupInfo group = 3; +} + +message GroupInfoSetNameTips { + GroupMemberFullInfo opUser = 1; //who do this + GroupInfo group = 2; +} + +message GroupInfoSetAnnouncementTips { + GroupMemberFullInfo opUser = 1; //who do this + GroupInfo group = 2; +} + +// OnJoinGroupApplication() +message JoinGroupApplicationTips { + GroupInfo group = 1; + PublicUserInfo applicant = 2; + string reqMsg = 3; +} + +// OnQuitGroup() +//Actively leave the group +message MemberQuitTips { + GroupInfo group = 1; + GroupMemberFullInfo quitUser = 2; + int64 operationTime = 3; +} + +// OnApplicationGroupAccepted() +message GroupApplicationAcceptedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + string handleMsg = 4; + int32 receiverAs = 5; // admin(==1) or applicant(==0) +} + +// OnApplicationGroupRejected() +message GroupApplicationRejectedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + string handleMsg = 4; + int32 receiverAs = 5; // admin(==1) or applicant(==0) +} + +// OnTransferGroupOwner() +message GroupOwnerTransferredTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + GroupMemberFullInfo newGroupOwner = 3; + string oldGroupOwner = 4; + int64 operationTime = 5; +} + +// OnMemberKicked() +message MemberKickedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo kickedUserList = 3; + int64 operationTime = 4; +} + +// OnMemberInvited() +message MemberInvitedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo invitedUserList = 3; + int64 operationTime = 4; +} + +//Actively join the group +message MemberEnterTips { + GroupInfo group = 1; + GroupMemberFullInfo entrantUser = 2; + int64 operationTime = 3; +} + +message GroupDismissedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + +message GroupMemberMutedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; + GroupMemberFullInfo mutedUser = 4; + uint32 mutedSeconds = 5; +} + +message GroupMemberCancelMutedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; + GroupMemberFullInfo mutedUser = 4; +} + +message GroupMutedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + +message GroupCancelMutedTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + +message GroupMemberInfoSetTips { + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; + GroupMemberFullInfo changedUser = 4; +} + +//////////////////////friend///////////////////// + +message FriendApplication { + int64 addTime = 1; + string addSource = 2; + string addWording = 3; +} + +message FromToUserID { + string fromUserID = 1; + string toUserID = 2; +} + +//FromUserID apply to add ToUserID +message FriendApplicationTips { + FromToUserID fromToUserID = 1; //from:sender; to:receiver +} + +//FromUserID accept or reject ToUserID +message FriendApplicationApprovedTips { + FromToUserID fromToUserID = 1; //from: approver; to: requester + string handleMsg = 2; +} + +//FromUserID accept or reject ToUserID +message FriendApplicationRejectedTips { + FromToUserID fromToUserID = 1; //from: rejecter; to: requester + string handleMsg = 2; +} + +// FromUserID Added a friend ToUserID +message FriendAddedTips { + FriendInfo friend = 1; + int64 operationTime = 2; + PublicUserInfo opUser = 3; //who do this +} + +// FromUserID deleted a friend ToUserID +message FriendDeletedTips { + FromToUserID fromToUserID = 1; //from:owner; to:friend +} + +message BlackAddedTips { + FromToUserID fromToUserID = 1; //from:owner; to:black +} + +message BlackDeletedTips { + FromToUserID fromToUserID = 1; //from:owner; to:black +} + +message FriendInfoChangedTips { + FromToUserID fromToUserID = 1; //from:changed; to:friend +} + +//////////////////////user///////////////////// +message UserInfoUpdatedTips { + string userID = 1; +} + +message UserStatusChangeTips { + string fromUserID = 1; + string toUserID = 2; + int32 status = 3; + int32 platformID = 4; +} +message UserCommandAddTips { + string fromUserID = 1; + string toUserID = 2; +} +message UserCommandUpdateTips { + string fromUserID = 1; + string toUserID = 2; +} +message UserCommandDeleteTips { + string fromUserID = 1; + string toUserID = 2; +} + +//////////////////////conversation///////////////////// +message ConversationUpdateTips { + string userID = 1; + repeated string conversationIDList = 2; +} + +message ConversationSetPrivateTips { + string recvID = 1; + string sendID = 2; + bool isPrivate = 3; + string conversationID = 4; +} + +message ConversationHasReadTips { + string userID = 1; + string conversationID = 2; + int64 hasReadSeq = 3; + int64 unreadCountTime = 4; +} + +message NotificationElem { + string detail = 1; +} + +////////////////////message/////////////////////// +message seqs { + repeated int64 seqs = 1; +} + +message DeleteMessageTips { + string opUserID = 1; + string userID = 2; + repeated int64 seqs = 3; +} + +message RevokeMsgTips { + string revokerUserID = 1; + string clientMsgID = 2; + int64 revokeTime = 3; + int32 sesstionType = 5; + int64 seq = 6; + string conversationID = 7; + bool isAdminRevoke = 8; +} + +message MessageRevokedContent { + string revokerID = 1; + int32 revokerRole = 2; + string clientMsgID = 3; + string revokerNickname = 4; + int64 revokeTime = 5; + int64 sourceMessageSendTime = 6; + string sourceMessageSendID = 7; + string sourceMessageSenderNickname = 8; + int32 sessionType = 10; + int64 seq = 11; + string ex = 12; +} + +message ClearConversationTips { + string userID = 1; + repeated string conversationIDs = 2; +} + +message DeleteMsgsTips { + string userID = 1; + string conversationID = 2; + repeated int64 seqs = 3; +} + +message MarkAsReadTips { + string markAsReadUserID = 1; + string conversationID = 2; + repeated int64 seqs = 3; + int64 hasReadSeq = 4; +} + +message SetAppBackgroundStatusReq { + string userID = 1; + bool isBackground = 2; +} + +message SetAppBackgroundStatusResp {} +message ProcessUserCommand { + string userID = 1; + int32 type = 2; + int64 createTime = 3; + string uuid = 4; + string value = 5; +} + +message RequestPagination { + int32 pageNumber = 1; + int32 showNumber = 2; +} +message FriendsInfoUpdateTips { + FromToUserID fromToUserID = 1; + repeated string friendIDs = 2; +} diff --git a/pkg/protocol/wrapperspb/wrapperspb.proto b/pkg/protocol/wrapperspb/wrapperspb.proto new file mode 100644 index 0000000..85b8b28 --- /dev/null +++ b/pkg/protocol/wrapperspb/wrapperspb.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +package openim.protobuf; + +option go_package = "git.imall.cloud/openim/protocol/wrapperspb"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +message BytesValue { + // The bytes value. + bytes value = 1; +} \ No newline at end of file diff --git a/pkg/rpclient/chat/admin.go b/pkg/rpclient/chat/admin.go new file mode 100644 index 0000000..9d6504b --- /dev/null +++ b/pkg/rpclient/chat/admin.go @@ -0,0 +1,109 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/common/mctx" + "git.imall.cloud/openim/chat/pkg/eerrs" + "git.imall.cloud/openim/chat/pkg/protocol/admin" +) + +func NewAdminClient(client admin.AdminClient) *AdminClient { + return &AdminClient{ + client: client, + } +} + +type AdminClient struct { + client admin.AdminClient +} + +func (o *AdminClient) GetConfig(ctx context.Context) (map[string]string, error) { + conf, err := o.client.GetClientConfig(ctx, &admin.GetClientConfigReq{}) + if err != nil { + return nil, err + } + if conf.Config == nil { + return map[string]string{}, nil + } + return conf.Config, nil +} + +func (o *AdminClient) CheckInvitationCode(ctx context.Context, invitationCode string) error { + resp, err := o.client.FindInvitationCode(ctx, &admin.FindInvitationCodeReq{Codes: []string{invitationCode}}) + if err != nil { + return err + } + if len(resp.Codes) == 0 { + return eerrs.ErrInvitationNotFound.Wrap() + } + if resp.Codes[0].UsedUserID != "" { + return eerrs.ErrInvitationCodeUsed.Wrap() + } + return nil +} + +func (o *AdminClient) CheckRegister(ctx context.Context, ip string) error { + _, err := o.client.CheckRegisterForbidden(ctx, &admin.CheckRegisterForbiddenReq{Ip: ip}) + return err +} + +func (o *AdminClient) CheckLogin(ctx context.Context, userID string, ip string) error { + _, err := o.client.CheckLoginForbidden(ctx, &admin.CheckLoginForbiddenReq{Ip: ip, UserID: userID}) + return err +} + +func (o *AdminClient) UseInvitationCode(ctx context.Context, userID string, invitationCode string) error { + _, err := o.client.UseInvitationCode(ctx, &admin.UseInvitationCodeReq{UserID: userID, Code: invitationCode}) + return err +} + +func (o *AdminClient) CheckNilOrAdmin(ctx context.Context) (bool, error) { + if !mctx.HaveOpUser(ctx) { + return false, nil + } + _, err := mctx.CheckAdmin(ctx) + if err != nil { + return false, err + } + return true, nil +} + +func (o *AdminClient) CreateToken(ctx context.Context, userID string, userType int32) (*admin.CreateTokenResp, error) { + return o.client.CreateToken(ctx, &admin.CreateTokenReq{UserID: userID, UserType: userType}) +} + +func (o *AdminClient) GetDefaultFriendUserID(ctx context.Context) ([]string, error) { + resp, err := o.client.FindDefaultFriend(ctx, &admin.FindDefaultFriendReq{}) + if err != nil { + return nil, err + } + return resp.UserIDs, nil +} + +func (o *AdminClient) GetDefaultGroupID(ctx context.Context) ([]string, error) { + resp, err := o.client.FindDefaultGroup(ctx, &admin.FindDefaultGroupReq{}) + if err != nil { + return nil, err + } + return resp.GroupIDs, nil +} + +func (o *AdminClient) InvalidateToken(ctx context.Context, userID string) error { + _, err := o.client.InvalidateToken(ctx, &admin.InvalidateTokenReq{UserID: userID}) + return err +} diff --git a/pkg/rpclient/chat/chat.go b/pkg/rpclient/chat/chat.go new file mode 100644 index 0000000..bf306cf --- /dev/null +++ b/pkg/rpclient/chat/chat.go @@ -0,0 +1,197 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package chat + +import ( + "context" + + "git.imall.cloud/openim/chat/pkg/protocol/chat" + "git.imall.cloud/openim/chat/pkg/protocol/common" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" +) + +func NewChatClient(client chat.ChatClient) *ChatClient { + return &ChatClient{ + client: client, + } +} + +type ChatClient struct { + client chat.ChatClient +} + +func (o *ChatClient) FindUserPublicInfo(ctx context.Context, userIDs []string) ([]*common.UserPublicInfo, error) { + if len(userIDs) == 0 { + return []*common.UserPublicInfo{}, nil + } + resp, err := o.client.FindUserPublicInfo(ctx, &chat.FindUserPublicInfoReq{UserIDs: userIDs}) + if err != nil { + return nil, err + } + return resp.Users, nil +} + +func (o *ChatClient) MapUserPublicInfo(ctx context.Context, userIDs []string) (map[string]*common.UserPublicInfo, error) { + users, err := o.FindUserPublicInfo(ctx, userIDs) + if err != nil { + return nil, err + } + return datautil.SliceToMap(users, func(user *common.UserPublicInfo) string { + return user.UserID + }), nil +} + +func (o *ChatClient) FindUserFullInfo(ctx context.Context, userIDs []string) ([]*common.UserFullInfo, error) { + if len(userIDs) == 0 { + return []*common.UserFullInfo{}, nil + } + resp, err := o.client.FindUserFullInfo(ctx, &chat.FindUserFullInfoReq{UserIDs: userIDs}) + if err != nil { + return nil, err + } + return resp.Users, nil +} + +func (o *ChatClient) MapUserFullInfo(ctx context.Context, userIDs []string) (map[string]*common.UserFullInfo, error) { + users, err := o.FindUserFullInfo(ctx, userIDs) + if err != nil { + return nil, err + } + userMap := make(map[string]*common.UserFullInfo) + for i, user := range users { + userMap[user.UserID] = users[i] + } + return userMap, nil +} + +func (o *ChatClient) GetUserFullInfo(ctx context.Context, userID string) (*common.UserFullInfo, error) { + users, err := o.FindUserFullInfo(ctx, []string{userID}) + if err != nil { + return nil, err + } + if len(users) == 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("user id not found") + } + return users[0], nil +} + +func (o *ChatClient) GetUserPublicInfo(ctx context.Context, userID string) (*common.UserPublicInfo, error) { + users, err := o.FindUserPublicInfo(ctx, []string{userID}) + if err != nil { + return nil, err + } + if len(users) == 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("user id not found", "userID", userID) + } + return users[0], nil +} + +func (o *ChatClient) UpdateUser(ctx context.Context, req *chat.UpdateUserInfoReq) error { + _, err := o.client.UpdateUserInfo(ctx, req) + return err +} + +func (o *ChatClient) CheckUserExist(ctx context.Context, req *chat.CheckUserExistReq) (resp *chat.CheckUserExistResp, err error) { + resp, err = o.client.CheckUserExist(ctx, req) + return resp, err +} + +func (o *ChatClient) DelUserAccount(ctx context.Context, req *chat.DelUserAccountReq) (resp *chat.DelUserAccountResp, err error) { + resp, err = o.client.DelUserAccount(ctx, req) + return resp, err +} + +// ==================== 敏感词管理相关方法 ==================== + +func (o *ChatClient) AddSensitiveWord(ctx context.Context, req *chat.AddSensitiveWordReq) (*chat.AddSensitiveWordResp, error) { + return o.client.AddSensitiveWord(ctx, req) +} + +func (o *ChatClient) UpdateSensitiveWord(ctx context.Context, req *chat.UpdateSensitiveWordReq) (*chat.UpdateSensitiveWordResp, error) { + return o.client.UpdateSensitiveWord(ctx, req) +} + +func (o *ChatClient) DeleteSensitiveWord(ctx context.Context, req *chat.DeleteSensitiveWordReq) (*chat.DeleteSensitiveWordResp, error) { + return o.client.DeleteSensitiveWord(ctx, req) +} + +func (o *ChatClient) GetSensitiveWord(ctx context.Context, req *chat.GetSensitiveWordReq) (*chat.GetSensitiveWordResp, error) { + return o.client.GetSensitiveWord(ctx, req) +} + +func (o *ChatClient) SearchSensitiveWords(ctx context.Context, req *chat.SearchSensitiveWordsReq) (*chat.SearchSensitiveWordsResp, error) { + return o.client.SearchSensitiveWords(ctx, req) +} + +func (o *ChatClient) BatchAddSensitiveWords(ctx context.Context, req *chat.BatchAddSensitiveWordsReq) (*chat.BatchAddSensitiveWordsResp, error) { + return o.client.BatchAddSensitiveWords(ctx, req) +} + +func (o *ChatClient) BatchUpdateSensitiveWords(ctx context.Context, req *chat.BatchUpdateSensitiveWordsReq) (*chat.BatchUpdateSensitiveWordsResp, error) { + return o.client.BatchUpdateSensitiveWords(ctx, req) +} + +func (o *ChatClient) BatchDeleteSensitiveWords(ctx context.Context, req *chat.BatchDeleteSensitiveWordsReq) (*chat.BatchDeleteSensitiveWordsResp, error) { + return o.client.BatchDeleteSensitiveWords(ctx, req) +} + +func (o *ChatClient) AddSensitiveWordGroup(ctx context.Context, req *chat.AddSensitiveWordGroupReq) (*chat.AddSensitiveWordGroupResp, error) { + return o.client.AddSensitiveWordGroup(ctx, req) +} + +func (o *ChatClient) UpdateSensitiveWordGroup(ctx context.Context, req *chat.UpdateSensitiveWordGroupReq) (*chat.UpdateSensitiveWordGroupResp, error) { + return o.client.UpdateSensitiveWordGroup(ctx, req) +} + +func (o *ChatClient) DeleteSensitiveWordGroup(ctx context.Context, req *chat.DeleteSensitiveWordGroupReq) (*chat.DeleteSensitiveWordGroupResp, error) { + return o.client.DeleteSensitiveWordGroup(ctx, req) +} + +func (o *ChatClient) GetSensitiveWordGroup(ctx context.Context, req *chat.GetSensitiveWordGroupReq) (*chat.GetSensitiveWordGroupResp, error) { + return o.client.GetSensitiveWordGroup(ctx, req) +} + +func (o *ChatClient) GetAllSensitiveWordGroups(ctx context.Context, req *chat.GetAllSensitiveWordGroupsReq) (*chat.GetAllSensitiveWordGroupsResp, error) { + return o.client.GetAllSensitiveWordGroups(ctx, req) +} + +func (o *ChatClient) GetSensitiveWordConfig(ctx context.Context, req *chat.GetSensitiveWordConfigReq) (*chat.GetSensitiveWordConfigResp, error) { + return o.client.GetSensitiveWordConfig(ctx, req) +} + +func (o *ChatClient) UpdateSensitiveWordConfig(ctx context.Context, req *chat.UpdateSensitiveWordConfigReq) (*chat.UpdateSensitiveWordConfigResp, error) { + return o.client.UpdateSensitiveWordConfig(ctx, req) +} + +func (o *ChatClient) GetSensitiveWordLogs(ctx context.Context, req *chat.GetSensitiveWordLogsReq) (*chat.GetSensitiveWordLogsResp, error) { + return o.client.GetSensitiveWordLogs(ctx, req) +} + +func (o *ChatClient) DeleteSensitiveWordLogs(ctx context.Context, req *chat.DeleteSensitiveWordLogsReq) (*chat.DeleteSensitiveWordLogsResp, error) { + return o.client.DeleteSensitiveWordLogs(ctx, req) +} + +func (o *ChatClient) GetSensitiveWordStats(ctx context.Context, req *chat.GetSensitiveWordStatsReq) (*chat.GetSensitiveWordStatsResp, error) { + return o.client.GetSensitiveWordStats(ctx, req) +} + +func (o *ChatClient) GetSensitiveWordLogStats(ctx context.Context, req *chat.GetSensitiveWordLogStatsReq) (*chat.GetSensitiveWordLogStatsResp, error) { + return o.client.GetSensitiveWordLogStats(ctx, req) +} + +func (o *ChatClient) GetUserLoginRecords(ctx context.Context, req *chat.GetUserLoginRecordsReq) (*chat.GetUserLoginRecordsResp, error) { + return o.client.GetUserLoginRecords(ctx, req) +} diff --git a/pkg/sms/ali.go b/pkg/sms/ali.go new file mode 100644 index 0000000..c02b885 --- /dev/null +++ b/pkg/sms/ali.go @@ -0,0 +1,69 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sms + +import ( + "context" + "encoding/json" + + aliconf "github.com/alibabacloud-go/darabonba-openapi/client" + dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v2/client" + "github.com/alibabacloud-go/tea/tea" + "github.com/openimsdk/tools/errs" +) + +func NewAli(endpoint, accessKeyId, accessKeySecret, signName, verificationCodeTemplateCode string) (SMS, error) { + conf := &aliconf.Config{ + Endpoint: tea.String(endpoint), + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + } + client, err := dysmsapi.NewClient(conf) + if err != nil { + return nil, err + } + return &ali{ + signName: signName, + verificationCodeTemplateCode: verificationCodeTemplateCode, + client: client, + }, nil +} + +type ali struct { + signName string + verificationCodeTemplateCode string + client *dysmsapi.Client +} + +func (a *ali) Name() string { + return "ali-sms" +} + +func (a *ali) SendCode(ctx context.Context, areaCode string, phoneNumber string, verifyCode string) error { + data, err := json.Marshal(&struct { + Code string `json:"code"` + }{Code: verifyCode}) + if err != nil { + return errs.Wrap(err) + } + req := &dysmsapi.SendSmsRequest{ + PhoneNumbers: tea.String(areaCode + phoneNumber), + SignName: tea.String(a.signName), + TemplateCode: tea.String(a.verificationCodeTemplateCode), + TemplateParam: tea.String(string(data)), + } + _, err = a.client.SendSms(req) + return errs.Wrap(err) +} diff --git a/pkg/sms/bao.go b/pkg/sms/bao.go new file mode 100644 index 0000000..a1ba8fd --- /dev/null +++ b/pkg/sms/bao.go @@ -0,0 +1,159 @@ +// Copyright © 2023 OpenIM open source community. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sms + +import ( + "context" + "crypto/md5" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" +) + +func NewBao(endpoint, accessKeyId, accessKeySecret, signName, verificationCodeTemplateCode string) (SMS, error) { + return &bao{ + endpoint: endpoint, + accessKeyId: accessKeyId, + accessKeySecret: accessKeySecret, + signName: signName, + verificationCodeTemplateCode: verificationCodeTemplateCode, + statusMap: map[string]string{ + "0": "短信发送成功", + "-1": "参数不全", + "-2": "服务器空间不支持,请确认支持curl或者fsocket", + "30": "密码错误", + "40": "账号不存在", + "41": "余额不足", + "42": "帐户已过期", + "43": "IP地址限制", + "50": "内容含有敏感词", + "51": "手机号码格式错误", + "52": "短信内容为空", + }, + }, nil +} + +type bao struct { + endpoint string + accessKeyId string + accessKeySecret string + signName string + verificationCodeTemplateCode string + statusMap map[string]string +} + +func (b *bao) Name() string { + return "bao-sms" +} + +func (b *bao) SendCode(ctx context.Context, areaCode string, phoneNumber string, verifyCode string) error { + // 去除国家码中的+号 + areaCode = strings.TrimPrefix(areaCode, "+") + + // 构建完整手机号 + var fullPhoneNumber string + // 对于中国手机号,短信宝只需要11位数字 + if areaCode == "86" || areaCode == "086" { + fullPhoneNumber = phoneNumber // 只发送手机号,不加国家码 + } else { + fullPhoneNumber = areaCode + phoneNumber + } + + log.ZInfo(ctx, "SMSBao Build Phone", "areaCode", areaCode, "phoneNumber", phoneNumber, "fullPhoneNumber", fullPhoneNumber) + + // 密码处理:如果已经是MD5格式(32位十六进制),直接使用;否则进行MD5加密 + password := b.accessKeySecret + // 检查是否是MD5格式(32位十六进制小写字符串) + if len(b.accessKeySecret) != 32 || !isHexString(b.accessKeySecret) { + password = fmt.Sprintf("%x", md5.Sum([]byte(b.accessKeySecret))) + } + + // 构建短信内容 + content := fmt.Sprintf("您的验证码是%s。如非本人操作,请忽略本短信", verifyCode) + if b.signName != "" { + content = fmt.Sprintf("【%s】%s", b.signName, content) + } + + log.ZInfo(ctx, "SMSBao Content", "content", content) + + // 构建请求URL - 短信宝API: https://api.smsbao.com/sms?u=用户名&p=MD5密码&m=手机号&c=内容 + // 如果endpoint已包含完整路径,直接使用;否则追加/sms + smsURL := b.endpoint + if !strings.Contains(smsURL, "/sms") { + if !strings.HasSuffix(smsURL, "/") { + smsURL += "/" + } + smsURL += "sms" + } + + apiURL := fmt.Sprintf("%s?u=%s&p=%s&m=%s&c=%s", + smsURL, + url.QueryEscape(b.accessKeyId), + url.QueryEscape(password), + url.QueryEscape(fullPhoneNumber), + url.QueryEscape(content), + ) + + log.ZInfo(ctx, "SMSBao Request", "url", apiURL, "phone", fullPhoneNumber, "areaCode", areaCode, "phoneNumber", phoneNumber) + + req, err := http.NewRequestWithContext(ctx, "GET", apiURL, nil) + if err != nil { + return errs.Wrap(err) + } + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + log.ZError(ctx, "SMSBao Request Failed", err, "phone", fullPhoneNumber) + return errs.Wrap(err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.ZError(ctx, "SMSBao Read Response Failed", err, "phone", fullPhoneNumber) + return errs.Wrap(err) + } + + result := strings.TrimSpace(string(body)) + log.ZInfo(ctx, "SMSBao Response", "phone", fullPhoneNumber, "status", resp.StatusCode, "result", result, "rawBody", string(body)) + + // 返回0表示成功 + if result != "0" { + errMsg := b.statusMap[result] + if errMsg == "" { + errMsg = fmt.Sprintf("未知错误代码: %s", result) + } + log.ZError(ctx, "SMSBao Failed", fmt.Errorf("%s", errMsg), "code", result, "phone", fullPhoneNumber) + return errs.New(errMsg) + } + + return nil +} + +// isHexString 检查字符串是否是纯十六进制字符 +func isHexString(s string) bool { + for _, c := range s { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { + return false + } + } + return true +} diff --git a/pkg/sms/sms.go b/pkg/sms/sms.go new file mode 100644 index 0000000..a3c95b2 --- /dev/null +++ b/pkg/sms/sms.go @@ -0,0 +1,8 @@ +package sms + +import "context" + +type SMS interface { + Name() string + SendCode(ctx context.Context, areaCode string, phoneNumber string, verifyCode string) error +} diff --git a/pkg/util/genutil.go b/pkg/util/genutil.go new file mode 100644 index 0000000..399e782 --- /dev/null +++ b/pkg/util/genutil.go @@ -0,0 +1,52 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "fmt" + "os" + "path/filepath" +) + +// OutDir creates the absolute path name from path and checks path exists. +// Returns absolute path including trailing '/' or error if path does not exist. +func OutDir(path string) (string, error) { + outDir, err := filepath.Abs(path) + if err != nil { + return "", err + } + + stat, err := os.Stat(outDir) + if err != nil { + return "", err + } + + if !stat.IsDir() { + return "", fmt.Errorf("output directory %s is not a directory", outDir) + } + outDir += "/" + return outDir, nil +} + +func ExitWithError(err error) { + programName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "%s exit -1: %+v\n\n", programName, err) + os.Exit(-1) +} + +func SIGTERMExit() { + programName := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "Warning %s receive process terminal SIGTERM exit 0\n", programName) +} diff --git a/start-config.yml b/start-config.yml new file mode 100644 index 0000000..1fb653b --- /dev/null +++ b/start-config.yml @@ -0,0 +1,11 @@ +serviceBinaries: + chat-api: 1 + chat-rpc: 1 + admin-api: 1 + admin-rpc: 1 + bot-api: 1 + bot-rpc: 1 +toolBinaries: + - check-component + - attribute-to-credential +maxFileDescriptors: 10000 diff --git a/tools/attribute-to-credential/main.go b/tools/attribute-to-credential/main.go new file mode 100644 index 0000000..59afb11 --- /dev/null +++ b/tools/attribute-to-credential/main.go @@ -0,0 +1,157 @@ +package main + +import ( + "context" + "flag" + "fmt" + "path/filepath" + + "git.imall.cloud/openim/chat/internal/rpc/chat" + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/constant" + table "git.imall.cloud/openim/chat/pkg/common/db/table/chat" + "git.imall.cloud/openim/chat/tools/dataversion" + "git.imall.cloud/openim/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/runtimeenv" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const ( + credentialKey = "credential" + credentialVersion = 1 + + attributeCollection = "attribute" + credentialCollection = "credential" + pageNum = 1000 +) + +func initConfig(configDir string) (*config.Mongo, error) { + var ( + mongoConfig = &config.Mongo{} + ) + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + err := config.Load(configDir, config.MongodbConfigFileName, config.EnvPrefixMap[config.MongodbConfigFileName], runtimeEnv, mongoConfig) + if err != nil { + return nil, err + } + + return mongoConfig, nil +} + +func pageGetAttribute(ctx context.Context, coll *mongo.Collection, pagination *sdkws.RequestPagination) (int64, []*table.Attribute, error) { + return mongoutil.FindPage[*table.Attribute](ctx, coll, bson.M{}, pagination) +} + +func doAttributeToCredential() error { + var index int + var configDir string + flag.IntVar(&index, "i", 0, "Index number") + defaultConfigDir := filepath.Join("..", "..", "..", "..", "..", "config") + flag.StringVar(&configDir, "c", defaultConfigDir, "Configuration dir") + flag.Parse() + + fmt.Printf("Index: %d, Config Path: %s\n", index, configDir) + + mongoConfig, err := initConfig(configDir) + if err != nil { + return err + } + + ctx := context.Background() + + mgocli, err := mongoutil.NewMongoDB(ctx, mongoConfig.Build()) + if err != nil { + return err + } + + versionColl := mgocli.GetDB().Collection(dataversion.Collection) + converted, err := dataversion.CheckVersion(versionColl, credentialKey, credentialVersion) + if err != nil { + return err + } + if converted { + fmt.Println("[credential] credential data has been converted") + return nil + } + + attrColl := mgocli.GetDB().Collection(attributeCollection) + credColl := mgocli.GetDB().Collection(credentialCollection) + + pagination := &sdkws.RequestPagination{ + PageNumber: 1, + ShowNumber: pageNum, + } + tx := mgocli.GetTx() + if err = tx.Transaction(ctx, func(ctx context.Context) error { + for { + _, attrs, err := pageGetAttribute(ctx, attrColl, pagination) + if err != nil { + return err + } + credentials := make([]*table.Credential, 0, pageNum*3) + for _, attr := range attrs { + if attr.Email != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: attr.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) + } + if attr.Account != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: attr.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + } + if attr.PhoneNumber != "" && attr.AreaCode != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: chat.BuildCredentialPhone(attr.AreaCode, attr.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) + } + + } + for _, credential := range credentials { + err = mongoutil.UpdateOne(ctx, credColl, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }, bson.M{ + "$set": credential, + }, false, options.Update().SetUpsert(true)) + if err != nil { + return err + } + } + + pagination.PageNumber++ + if len(attrs) < pageNum { + break + } + } + return nil + }); err != nil { + return err + } + if err := dataversion.SetVersion(versionColl, credentialKey, credentialVersion); err != nil { + return fmt.Errorf("set mongodb credential version %w", err) + } + fmt.Println("[credential] update old data to credential success") + return nil +} + +func main() { + if err := doAttributeToCredential(); err != nil { + program.ExitWithError(err) + } +} diff --git a/tools/check-component/main.go b/tools/check-component/main.go new file mode 100644 index 0000000..9ffefe0 --- /dev/null +++ b/tools/check-component/main.go @@ -0,0 +1,161 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "flag" + "fmt" + "path/filepath" + "time" + + "git.imall.cloud/openim/chat/pkg/common/config" + "git.imall.cloud/openim/chat/pkg/common/imapi" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/runtimeenv" +) + +const maxRetry = 180 + +func CheckEtcd(ctx context.Context, config *config.Etcd) error { + return etcd.Check(ctx, config.Address, "/check_chat_component", + true, + etcd.WithDialTimeout(10*time.Second), + etcd.WithMaxCallSendMsgSize(20*1024*1024), + etcd.WithUsernameAndPassword(config.Username, config.Password)) +} + +func CheckMongo(ctx context.Context, config *config.Mongo) error { + return mongoutil.Check(ctx, config.Build()) +} + +func CheckRedis(ctx context.Context, config *config.Redis) error { + return redisutil.Check(ctx, config.Build()) +} + +func CheckOpenIM(ctx context.Context, apiURL, secret, adminUserID string, redisConf *config.Redis, interval int) error { + imAPI := imapi.New(apiURL, secret, adminUserID) + _, err := imAPI.GetAdminTokenServer(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) + return err +} + +func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Discovery, *config.Share, error) { + var ( + mongoConfig = &config.Mongo{} + redisConfig = &config.Redis{} + discoveryConfig = &config.Discovery{} + shareConfig = &config.Share{} + ) + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + err := config.Load(configDir, config.MongodbConfigFileName, config.EnvPrefixMap[config.MongodbConfigFileName], runtimeEnv, mongoConfig) + if err != nil { + return nil, nil, nil, nil, err + } + + err = config.Load(configDir, config.RedisConfigFileName, config.EnvPrefixMap[config.RedisConfigFileName], runtimeEnv, redisConfig) + if err != nil { + return nil, nil, nil, nil, err + } + + err = config.Load(configDir, config.DiscoveryConfigFileName, config.EnvPrefixMap[config.DiscoveryConfigFileName], runtimeEnv, discoveryConfig) + if err != nil { + return nil, nil, nil, nil, err + } + err = config.Load(configDir, config.ShareFileName, config.EnvPrefixMap[config.ShareFileName], runtimeEnv, shareConfig) + if err != nil { + return nil, nil, nil, nil, err + } + + return mongoConfig, redisConfig, discoveryConfig, shareConfig, nil +} + +func main() { + var index int + var configDir string + flag.IntVar(&index, "i", 0, "Index number") + defaultConfigDir := filepath.Join("..", "..", "..", "..", "..", "config") + flag.StringVar(&configDir, "c", defaultConfigDir, "Configuration dir") + flag.Parse() + + fmt.Printf("Index: %d, Config Path: %s\n", index, configDir) + + mongoConfig, redisConfig, zookeeperConfig, shareConfig, err := initConfig(configDir) + if err != nil { + program.ExitWithError(err) + } + + ctx := context.Background() + err = performChecks(ctx, mongoConfig, redisConfig, zookeeperConfig, shareConfig, maxRetry) + if err != nil { + // Assume program.ExitWithError logs the error and exits. + // Replace with your error handling logic as necessary. + program.ExitWithError(err) + } +} + +func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig *config.Redis, discovery *config.Discovery, shareConfig *config.Share, maxRetry int) error { + checksDone := make(map[string]bool) + + checks := map[string]func(ctx context.Context) error{ + "Mongo": func(ctx context.Context) error { + return CheckMongo(ctx, mongoConfig) + }, + "Redis": func(ctx context.Context) error { + return CheckRedis(ctx, redisConfig) + }, + "OpenIM": func(ctx context.Context) error { + return CheckOpenIM(ctx, shareConfig.OpenIM.ApiURL, shareConfig.OpenIM.Secret, shareConfig.OpenIM.AdminUserID, redisConfig, shareConfig.OpenIM.TokenRefreshInterval) + }, + } + + if discovery.Enable == "etcd" { + checks["Etcd"] = func(ctx context.Context) error { + return CheckEtcd(ctx, &discovery.Etcd) + } + } + + for i := 0; i < maxRetry; i++ { + allSuccess := true + for name, check := range checks { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + if !checksDone[name] { + if err := check(ctx); err != nil { + fmt.Printf("%s check failed: %v\n", name, err) + allSuccess = false + } else { + fmt.Printf("%s check succeeded.\n", name) + checksDone[name] = true + } + } + cancel() + } + + if allSuccess { + fmt.Println("All components checks passed successfully.") + return nil + } + + time.Sleep(1 * time.Second) + } + + return fmt.Errorf("not all components checks passed successfully after %d attempts", maxRetry) +} diff --git a/tools/dataversion/data_version.go b/tools/dataversion/data_version.go new file mode 100644 index 0000000..b7525cb --- /dev/null +++ b/tools/dataversion/data_version.go @@ -0,0 +1,51 @@ +package dataversion + +import ( + "context" + "errors" + "fmt" + "strconv" + "time" + + "github.com/openimsdk/tools/db/mongoutil" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const ( + Collection = "data_version" +) + +func CheckVersion(coll *mongo.Collection, key string, currentVersion int) (converted bool, err error) { + type VersionTable struct { + Key string `bson:"key"` + Value string `bson:"value"` + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + res, err := mongoutil.FindOne[VersionTable](ctx, coll, bson.M{"key": key}) + if err == nil { + ver, err := strconv.Atoi(res.Value) + if err != nil { + return false, fmt.Errorf("version %s parse error %w", res.Value, err) + } + if ver >= currentVersion { + return true, nil + } + return false, nil + } else if errors.Is(err, mongo.ErrNoDocuments) { + return false, nil + } else { + return false, err + } +} + +func SetVersion(coll *mongo.Collection, key string, version int) error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + option := options.Update().SetUpsert(true) + filter := bson.M{"key": key} + update := bson.M{"$set": bson.M{"key": key, "value": strconv.Itoa(version)}} + return mongoutil.UpdateOne(ctx, coll, filter, update, false, option) +} diff --git a/version/version b/version/version new file mode 100644 index 0000000..b9268da --- /dev/null +++ b/version/version @@ -0,0 +1 @@ +1.8.1 \ No newline at end of file diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000..23b3a82 --- /dev/null +++ b/version/version.go @@ -0,0 +1,6 @@ +package version + +import _ "embed" + +//go:embed version +var Version string