feat: import services and standardize Go 1.26.5

This commit is contained in:
2026-08-09 10:43:45 +08:00
parent 689c74b28f
commit 86024fa81d
1456 changed files with 220765 additions and 2 deletions

525
apps/base/ads/README.md Normal file
View File

@@ -0,0 +1,525 @@
# Ads Service
[![Go Version](https://img.shields.io/badge/Go-1.25.1-blue.svg)](https://golang.org/)
[![License](https://img.shields.io/badge/License-Internal-red.svg)](LICENSE)
[![Build Status](https://img.shields.io/badge/Build-Passing-green.svg)](https://git.apinb.com/bsm-apps/ads)
一个高性能、可扩展的广告管理微服务,基于 gRPC 和 HTTP Gateway 架构,提供广告位管理、广告内容分发等核心功能。
## 🚀 特性
- **📢 广告管理**: 多类型广告内容管理(文本、图片、视频、音频、链接、附件)
- **📍 广告位管理**: 灵活的广告位配置和分类管理
- **⚡ 高性能**: Redis缓存 + 数据库优化,支持高并发访问
- **🔄 智能缓存**: 10分钟缓存策略提升响应速度
- **🐳 容器化**: 完整的Docker支持
- **📊 监控**: 健康检查和APM集成
- **🔒 安全**: 完善的错误处理和输入验证
- **🌐 多协议**: 支持gRPC和HTTP Gateway双重访问方式
## 📋 目录
- [快速开始](#-快速开始)
- [项目结构](#-项目结构)
- [核心功能](#-核心功能)
- [API文档](#-api文档)
- [开发指南](#-开发指南)
- [部署说明](#-部署说明)
- [性能优化](#-性能优化)
- [故障排除](#-故障排除)
## 🚀 快速开始
### 环境要求
- **Go**: 1.25.1+
- **PostgreSQL**: 12+
- **Redis**: 6+
- **Docker**: 20.10+ (可选)
- **Protocol Buffers**: 3.15+ (开发需要)
### 快速安装
```bash
# 克隆项目
git clone git.apinb.com/bsm-apps/ads.git
cd ads
# 安装依赖
go mod tidy
# 生成代码
make proto
# 构建应用
go build -o bin/ads cmd/main/main.go
# 运行服务
./bin/ads
```
### Docker 快速启动
```bash
# 构建镜像
docker build -t ads-service .
# 运行容器
docker run -d --name ads-service \
-p 12216:12216 \
-p 12102:12102 \
-e SERVICE_ENV=development \
ads-service
```
## 📁 项目结构
```
ads/
├── 📁 cmd/ # 应用程序入口
│ ├── 📁 main/ # 主服务入口
│ └── 📁 cli/ # 命令行工具
├── 📁 internal/ # 内部包
│ ├── 📁 config/ # 配置管理
│ ├── 📁 impl/ # 实现层
│ ├── 📁 logic/ # 业务逻辑
│ │ └── 📁 fetch/ # 广告获取逻辑
│ ├── 📁 models/ # 数据模型
│ └── 📁 server/ # 服务器实现
├── 📁 pb/ # Protocol Buffers 生成代码
├── 📁 proto/ # Protocol Buffers 定义文件
├── 📁 swagger/ # API 文档
├── 📁 scripts/ # 脚本文件
├── 📁 etc/ # 配置文件
├── 🐳 Dockerfile # Docker 镜像构建
├── 🔧 Makefile # 构建脚本
└── 📖 README.md # 项目文档
```
## 🔧 核心功能
### 1. 广告获取服务 (Fetch Service)
#### 📍 按广告位获取广告 (ByPos)
```protobuf
rpc ByPos(ByPosRequest) returns (ByPosReply)
```
- **功能**: 根据广告位标识获取对应的广告内容
- **特性**:
- 支持多种广告类型(文本、图片、视频、音频、链接、附件)
- Redis缓存加速缓存时间10分钟
- 只返回启用状态的广告
- 完整的错误处理和日志记录
- **用途**: 前端页面广告展示、移动端广告投放
### 2. 广告类型支持
| 类型 | 值 | 描述 | 用途 |
|------|----|----|----|
| 文本 | 1 | 纯文本广告 | 文字推广、通知公告 |
| 图片 | 2 | 图片广告 | 横幅广告、图片推广 |
| 视频 | 3 | 视频广告 | 视频推广、宣传片 |
| 音频 | 4 | 音频广告 | 音频推广、语音广告 |
| 链接 | 5 | 链接广告 | 跳转链接、外部推广 |
| 附件 | 6 | 附件广告 | 文件下载、文档推广 |
## 📚 API文档
### gRPC 服务
| 服务 | 方法 | 描述 | 端口 |
|------|------|------|------|
| Fetch | ByPos | 按广告位获取广告 | 12216 |
### HTTP Gateway
| 端点 | 方法 | 描述 |
|------|------|------|
| `/ads.Fetch/ByPos` | POST | 按广告位获取广告 |
### Swagger 文档
- **本地**: http://localhost:12102/ads.swagger.json
- **在线**: 通过 HTTP Gateway 访问完整的 API 文档
### 请求示例
#### gRPC 请求
```protobuf
// 请求
{
"key": "homepage_banner"
}
// 响应
{
"data": [
{
"id": 1,
"title": "首页横幅广告",
"content": "欢迎使用我们的服务",
"type": 2,
"toUrl": "https://example.com",
"created": "2024-01-01 12:00:00"
}
]
}
```
#### HTTP 请求
```bash
curl -X POST http://localhost:12102/ads.Fetch/ByPos \
-H "Content-Type: application/json" \
-d '{"key": "homepage_banner"}'
```
## 🛠️ 开发指南
### 开发环境设置
```bash
# 安装开发工具
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
# 启动开发模式
go run cmd/main/main.go
```
### 代码生成
```bash
# 生成 protobuf 代码
protoc --go_out=. --go-grpc_out=. proto/ads.proto
# 生成 Swagger 文档
protoc --grpc-gateway_out=. --openapiv2_out=swagger proto/ads.proto
```
### 测试
```bash
# 运行所有测试
go test ./...
# 测试覆盖率
go test -cover ./...
# 代码检查
go vet ./...
gofmt -s -w .
```
### 数据库管理
```bash
# 初始化数据库表
go run cmd/main/main.go --init-db
# 数据库迁移
gorm migrate
```
## 🚀 部署说明
### Docker 部署
```bash
# 构建镜像
docker build -t ads-service:latest .
# 启动服务栈
docker run -d --name ads-service \
-p 12216:12216 \
-p 12102:12102 \
-e SERVICE_ENV=production \
-e CONFIG_FILE=etc/ads_prod.yaml \
ads-service:latest
```
### 生产环境部署
1. **环境准备**
```bash
# 创建生产配置
cp etc/ads_dev.yaml etc/ads_prod.yaml
# 编辑生产配置...
```
2. **数据库初始化**
```bash
# 创建数据库表
psql -h your-db-host -U postgres -d ads_db -c "
CREATE TABLE IF NOT EXISTS ads_pos (
id SERIAL PRIMARY KEY,
key VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS ads_item (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
pos_key VARCHAR(255) NOT NULL,
content VARCHAR(255) DEFAULT '',
type INTEGER DEFAULT 0,
to_url VARCHAR(255) DEFAULT '',
status INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"
```
3. **服务启动**
```bash
# 构建生产版本
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/ads-linux cmd/main/main.go
# 启动服务
./bin/ads-linux
```
### Kubernetes 部署
```yaml
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ads-service
spec:
replicas: 3
selector:
matchLabels:
app: ads-service
template:
metadata:
labels:
app: ads-service
spec:
containers:
- name: ads-service
image: ads-service:latest
ports:
- containerPort: 12216
- containerPort: 12102
env:
- name: SERVICE_ENV
value: "production"
- name: CONFIG_FILE
value: "etc/ads_prod.yaml"
```
## ⚡ 性能优化
### 缓存策略
| 数据类型 | 缓存时间 | 策略 | 说明 |
|----------|----------|------|------|
| 广告数据 | 10分钟 | 按广告位缓存 | 提升查询性能 |
| 广告位信息 | 30分钟 | 全量缓存 | 减少数据库查询 |
### 数据库优化
- **索引优化**: 在 `pos_key` 和 `status` 字段建立复合索引
- **查询优化**: 只查询启用状态的广告
- **连接池**: 配置合适的连接池大小
- **读写分离**: 支持主从数据库配置
### 监控指标
```bash
# 服务健康检查
curl http://localhost:12102/health
# 性能指标
curl http://localhost:12102/metrics
```
## 🔧 配置说明
### 环境配置文件
```yaml
# etc/ads_prod.yaml
Service: ads
Port: 12216
# 数据库配置
Databases:
Driver: postgres
Source:
- host=db-host user=postgres password=*** dbname=ads_db port=5432 sslmode=require
# 缓存配置
Cache: redis://username:password@redis-host:6379/0
# 网关配置
Gateway:
Enable: true
Port: 12102
# 微服务配置
MicroService:
Enable: true
Registry: etcd://etcd-cluster:2379
# APM监控
APM:
Platform: elasticAPM
Endpoint: http://apm-server:8200
```
### 环境变量
| 变量名 | 描述 | 默认值 |
|--------|------|--------|
| `SERVICE_ENV` | 运行环境 | `development` |
| `CONFIG_FILE` | 配置文件路径 | `etc/ads_dev.yaml` |
| `LOG_LEVEL` | 日志级别 | `info` |
| `TZ` | 时区设置 | `Asia/Shanghai` |
## 🐛 故障排除
### 常见问题
1. **服务启动失败**
```bash
# 检查端口占用
netstat -tlnp | grep :12216
# 检查配置文件
go run cmd/main/main.go --check-config
```
2. **数据库连接失败**
```bash
# 测试数据库连接
psql -h your-db-host -U postgres -d ads_db -c "SELECT 1;"
```
3. **Redis连接失败**
```bash
# 测试Redis连接
redis-cli -h your-redis-host ping
```
### 日志分析
```bash
# 查看服务日志
tail -f logs/ads.log
# 查看错误日志
grep ERROR logs/ads.log
# 查看性能日志
grep "slow query" logs/ads.log
```
### 性能调优
1. **内存优化**
```bash
# 监控内存使用
go tool pprof http://localhost:6060/debug/pprof/heap
```
2. **CPU优化**
```bash
# CPU性能分析
go tool pprof http://localhost:6060/debug/pprof/profile
```
## 📊 数据模型
### 核心表结构
#### ads_pos - 广告位表
```sql
CREATE TABLE ads_pos (
id SERIAL PRIMARY KEY,
key VARCHAR(255) NOT NULL, -- 广告位标识
name VARCHAR(255) NOT NULL, -- 广告位名称
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
#### ads_item - 广告内容表
```sql
CREATE TABLE ads_item (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL, -- 广告标题
pos_key VARCHAR(255) NOT NULL, -- 广告位标识
content VARCHAR(255) DEFAULT '', -- 广告内容
type INTEGER DEFAULT 0, -- 广告类型
to_url VARCHAR(255) DEFAULT '', -- 跳转链接
status INTEGER DEFAULT 1, -- 状态1:启用 0:禁用)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
## 🤝 贡献指南
### 开发流程
1. **Fork 项目**
2. **创建特性分支**: `git checkout -b feature/amazing-feature`
3. **提交更改**: `git commit -m 'Add amazing feature'`
4. **推送分支**: `git push origin feature/amazing-feature`
5. **创建 Pull Request**
### 代码规范
- 遵循 Go 官方代码规范
- 使用 `gofmt` 格式化代码
- 添加必要的注释和文档
- 编写单元测试
### 提交规范
```
type(scope): description
[optional body]
[optional footer]
```
类型:
- `feat`: 新功能
- `fix`: 修复bug
- `docs`: 文档更新
- `style`: 代码格式
- `refactor`: 重构
- `test`: 测试
- `chore`: 构建过程或辅助工具的变动
## 📄 许可证
本项目采用内部许可证,仅供 BSM 内部使用。
## 👥 团队
- **作者**: David Yan (david.yan@qq.com)
- **维护者**: BSM 开发团队
- **项目地址**: [git.apinb.com/bsm-apps/ads](https://git.apinb.com/bsm-apps/ads)
## 🔗 相关链接
- [BSM SDK](https://git.apinb.com/bsm-sdk)
- [API 文档](https://docs.apinb.com/ads)
- [问题反馈](https://git.apinb.com/bsm-apps/ads/issues)
---
<div align="center">
**⭐ 如果这个项目对你有帮助,请给它一个星标!**
Made with ❤️ by BSM Team
</div>

View File

@@ -0,0 +1,50 @@
version: v2
plugins:
- local: protoc-gen-go
out: pb
opt:
- paths=source_relative
- local: protoc-gen-go
out: ../../bsm-sdk/client/golang/ads
opt:
- paths=source_relative
- local: protoc-gen-go-grpc
out: pb
opt:
- paths=source_relative
- local: protoc-gen-go-grpc
out: ../../bsm-sdk/client/golang/ads
opt:
- paths=source_relative
- local: protoc-gen-grpc-gateway
out: pb
opt:
- paths=source_relative
- generate_unbound_methods=True
- local: protoc-gen-slc
out: ./
- local: protoc-gen-ts
out: ../../bsm-sdk/client/typescript
- local: protoc-gen-dart
out: ../../bsm-sdk/client/dart/ads
opt:
- grpc
- local: protoc-gen-openapiv2
out: swagger
opt: allow_merge=true,merge_file_name=ads
- local: protoc-gen-openapiv2
out: ../../bsm-sdk/client/docs/ads
opt: allow_merge=true,merge_file_name=ads
- local: protoc-gen-markdown
out: ../../bsm-sdk/client/docs/ads

10
apps/base/ads/buf.yaml Normal file
View File

@@ -0,0 +1,10 @@
# For details on buf.yaml configuration, visit https://buf.build/docs/configuration/v2/buf-yaml
version: v2
lint:
use:
- STANDARD
modules:
- path: proto
breaking:
use:
- FILE

View File

@@ -0,0 +1,8 @@
package main
import "log"
// main 命令行工具入口函数
func main() {
log.Println("广告服务命令行工具")
}

View File

@@ -0,0 +1,46 @@
/**
* @Author: david.yan(david.yan@qq.com)
* @Date: 2021-11-26 15:25:03
* @Description: 广告服务主程序入口
*/
package service
import (
"git.apinb.com/bsm-apps/ads/internal/config"
"git.apinb.com/bsm-apps/ads/internal/impl"
"git.apinb.com/bsm-apps/ads/internal/server"
"git.apinb.com/bsm-sdk/core/service"
)
var (
ServiceKey = "ads" // 服务标识符
)
// main 广告服务主函数
func Run() {
// 初始化服务配置
config.New(ServiceKey)
// 初始化各类服务实例数据库、缓存、etcd等
impl.NewImpl()
// 创建gRPC服务器实例
s := server.New(config.Spec.Addr)
// 创建微服务实例
srv := service.New(
s.Grpc,
&service.Options{
Addr: config.Spec.Addr, // 服务监听地址
MsConf: config.Spec.MicroService, // 微服务配置
EtcdClient: impl.EtcdService, // Etcd客户端
GatewayCtx: s.Ctx, // 网关上下文
GatewayConf: config.Spec.Gateway, // 网关配置
GatewayMux: s.Mux, // 网关路由
},
)
// 优雅关闭服务
defer srv.Stop()
// 启动服务
srv.Start()
}

View File

@@ -0,0 +1,35 @@
Service: ads
Port: 12216
Databases:
Driver: postgres
Source:
- host=47.109.77.183 user=postgres password=CHANGE_ME dbname=rst_dev port=5432 sslmode=disable TimeZone=Asia/Shanghai
# cache DB的选择请在后面直接带参数不带会自动HASH计算选择DB库。
Cache: redis://null:CHANGE_ME@47.109.77.183:6379/
# 微服务设置
MicroService:
Enable: false
Anonymous:
- ads.Fetch.ByPos
# Gateway 设置
Gateway:
Enable: true
Port: 12102
# 微服务调用密钥
SecretKey: 6ad9529688041483f458f8de11ed16ff
# Rpc:
# fts:
# Endpoint: https://api-v2.traingo.cn/fts/v2
# SecretKey: 4ef05311358cd1c8f787281f08b38b1c
# 链路追踪,性能监控,日志收集
# APM:
# Platform: elasticAPM
# Endpoint: http://127.0.0.1:14268/api/traces

View File

@@ -0,0 +1,35 @@
Service: ads
Port: 12216
Databases:
Driver: postgres
Source:
- host=47.109.77.183 user=postgres password=CHANGE_ME dbname=rst_dev port=5432 sslmode=disable TimeZone=Asia/Shanghai
# cache DB的选择请在后面直接带参数不带会自动HASH计算选择DB库。
Cache: redis://null:CHANGE_ME@47.109.77.183:6379/
# 微服务设置
MicroService:
Enable: false
Anonymous:
- ads.Fetch.ByPos
# Gateway 设置
Gateway:
Enable: true
Port: 12102
# 微服务调用密钥
SecretKey: 6ad9529688041483f458f8de11ed16ff
# Rpc:
# fts:
# Endpoint: https://api-v2.traingo.cn/fts/v2
# SecretKey: 4ef05311358cd1c8f787281f08b38b1c
# 链路追踪,性能监控,日志收集
# APM:
# Platform: elasticAPM
# Endpoint: http://127.0.0.1:14268/api/traces

View File

@@ -0,0 +1,35 @@
Service: ads
Port: 12216
Databases:
Driver: postgres
Source:
- host=47.109.77.183 user=postgres password=CHANGE_ME dbname=rst_dev port=5432 sslmode=disable TimeZone=Asia/Shanghai
# cache DB的选择请在后面直接带参数不带会自动HASH计算选择DB库。
Cache: redis://null:CHANGE_ME@47.109.77.183:6379/
# 微服务设置
MicroService:
Enable: false
Anonymous:
- ads.Fetch.ByPos
# Gateway 设置
Gateway:
Enable: true
Port: 12102
# 微服务调用密钥
SecretKey: 6ad9529688041483f458f8de11ed16ff
# Rpc:
# fts:
# Endpoint: https://api-v2.traingo.cn/fts/v2
# SecretKey: 4ef05311358cd1c8f787281f08b38b1c
# 链路追踪,性能监控,日志收集
# APM:
# Platform: elasticAPM
# Endpoint: http://127.0.0.1:14268/api/traces

View File

@@ -0,0 +1,8 @@
[program:bsm-apps-ads]
command=/data/app/bsm-apps-ads
directory=/data/app
autostart=true
autorestart=true
user=root
redirect_stderr=true
stdout_logfile=/data/app/logs/apps-ads.log

70
apps/base/ads/go.mod Normal file
View File

@@ -0,0 +1,70 @@
module git.apinb.com/bsm-apps/ads
go 1.26.5
tool (
git.apinb.com/bsm-tools/protoc-gen-markdown
git.apinb.com/bsm-tools/protoc-gen-slc
git.apinb.com/bsm-tools/protoc-gen-ts
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
github.com/pepabo/protoc-gen-go-client
google.golang.org/grpc/cmd/protoc-gen-go-grpc
google.golang.org/protobuf/cmd/protoc-gen-go
)
require (
git.apinb.com/bsm-sdk/core v0.2.0
git.apinb.com/bsm-sdk/engine v1.3.2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
github.com/patrickmn/go-cache v2.1.0+incompatible
go.etcd.io/etcd/client/v3 v3.6.12
google.golang.org/grpc v1.81.1
google.golang.org/protobuf v1.36.11
gorm.io/gorm v1.31.1
)
require (
filippo.io/edwards25519 v1.2.0 // indirect
git.apinb.com/bsm-tools/protoc-gen-markdown v0.0.0-20250907131213-6c1694ce6bcb // indirect
git.apinb.com/bsm-tools/protoc-gen-slc v0.0.13 // indirect
git.apinb.com/bsm-tools/protoc-gen-ts v0.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c // indirect
github.com/go-sql-driver/mysql v1.10.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.10.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
github.com/pepabo/protoc-gen-go-client v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/redis/go-redis/v9 v9.20.0 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
go.etcd.io/etcd/api/v3 v3.6.12 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.12 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.28.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.36.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.6.0 // indirect
gorm.io/driver/postgres v1.6.0 // indirect
)

179
apps/base/ads/go.sum Normal file
View File

@@ -0,0 +1,179 @@
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
git.apinb.com/bsm-sdk/core v0.2.0 h1:/e9yqpsbKBrRgMiGpS3KX2O4qDLxo5V5GpPSLNGxEKw=
git.apinb.com/bsm-sdk/core v0.2.0/go.mod h1:E9T6Eboo/0Zb36BjkKbIgvFzq4fQ2Q8P/7y5zmYTI6Y=
git.apinb.com/bsm-sdk/engine v1.3.2 h1:QJ20jveUIHcn3Tu0ktrkZI9zGRaPuJRZ+YTbSa1Zj1w=
git.apinb.com/bsm-sdk/engine v1.3.2/go.mod h1:OXRlO6Cdidqagw+LJjCngvpuuX1rwhxDwZlL/MhwiKQ=
git.apinb.com/bsm-tools/protoc-gen-markdown v0.0.0-20250907131213-6c1694ce6bcb h1:GoXhkGzI5vZ9JMXCVsSRw/AGsJY0tM2aEv76YaUg2wM=
git.apinb.com/bsm-tools/protoc-gen-markdown v0.0.0-20250907131213-6c1694ce6bcb/go.mod h1:l+84zWPM4F40Ppar+jLapgjRNt6XWDsr+l0vN4Jjlm4=
git.apinb.com/bsm-tools/protoc-gen-slc v0.0.13 h1:RGg2R2kHz6IAD7scH6So2FlZYctFUDxqWR8i/+fMfOU=
git.apinb.com/bsm-tools/protoc-gen-slc v0.0.13/go.mod h1:NpJaupVAxmyBleRMAug4mGS6BQV2E32rtuiqQzj1b+A=
git.apinb.com/bsm-tools/protoc-gen-ts v0.0.2 h1:T9C1kY6iIHl5cZ7xyNgV2xlPNWxXmaWfTbD8AzpBB9M=
git.apinb.com/bsm-tools/protoc-gen-ts v0.0.2/go.mod h1:5kAPyKSSLL7HcdZvyJa+ICnOiit/O/Z963nQpGJRrao=
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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/davecgh/go-spew v1.1.0/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/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354=
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
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/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
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/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/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pepabo/protoc-gen-go-client v0.3.0 h1:BUlzqqgMXWaEYzGXw1vqLIShP18JV7BMDm45OSLr/AU=
github.com/pepabo/protoc-gen-go-client v0.3.0/go.mod h1:NvHW7/gsmZUK2UxafqzUzWD8zEMY0lMmm+2kLVxx8Jc=
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/redis/go-redis/v9 v9.20.0 h1:WnQYxLkgO2xiXTCJY0ldIiI8dNqCDlQAG+AtaH7a2a0=
github.com/redis/go-redis/v9 v9.20.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
go.etcd.io/etcd/api/v3 v3.6.12 h1:OLOZUKEuAA36TR48F0cIaa8FdzrWygjyfrJxXg4iDgs=
go.etcd.io/etcd/api/v3 v3.6.12/go.mod h1:p14EIQXHbuOQbVvL/WEes5uqKnxP9AgKJgpjbMVvzvE=
go.etcd.io/etcd/client/pkg/v3 v3.6.12 h1:36zzB+pQOdHbhN+kH2iJz/K8bJn0ZLtLfPPO7jozTDo=
go.etcd.io/etcd/client/pkg/v3 v3.6.12/go.mod h1:hh2+ZXtfLzs3o6mn92ntgNPBrTJJOvXqICM5g3L3DMY=
go.etcd.io/etcd/client/v3 v3.6.12 h1:kMSP6JcPZMqSJiX+TXdUIBU/4eXEZWBAaui4VihMbIc=
go.etcd.io/etcd/client/v3 v3.6.12/go.mod h1:CMs6fJWYiZQk4ytFjd4lE1diOvvRMmtbbn/alZXd3dQ=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
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.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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/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=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2 h1:rgSNvqscFZ1JgV/4wH5GOsZFSFkR2Eua9As3KIr2LlM=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2/go.mod h1:iMEtFwDlAhjDU9L5mY6U1XLwlIId/G3h+QcBHDIvrJ8=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/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/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

View File

@@ -0,0 +1,43 @@
package config
import (
"net"
"git.apinb.com/bsm-sdk/core/conf"
"git.apinb.com/bsm-sdk/core/crypto/encipher"
"git.apinb.com/bsm-sdk/core/env"
)
var (
Spec SrvConfig // 全局服务配置实例
)
// SrvConfig 服务配置结构体
type SrvConfig struct {
conf.Base `yaml:",inline"` // 基础配置(服务名、端口、缓存等)
Databases *conf.DBConf `yaml:"Databases"` // 数据库配置
MicroService *conf.MicroServiceConf `yaml:"MicroService"` // 微服务配置
Rpc map[string]conf.RpcConf `yaml:"Rpc"` // RPC服务配置
Gateway *conf.GatewayConf `yaml:"Gateway"` // 网关配置
Apm *conf.ApmConf `yaml:"APM"` // APM监控配置
Etcd *conf.EtcdConf `yaml:"Etcd"` // Etcd配置
}
// New 初始化服务配置
func New(srvKey string) {
// 初始化配置 创建一个新的配置实例,用于服务配置
conf.New(srvKey, &Spec)
// 配置校验 服务IP,端口; 端口如果不合规,则随机分配端口
Spec.Port = conf.CheckPort(Spec.Port)
Spec.BindIP = conf.CheckIP(Spec.BindIP)
Spec.Addr = net.JoinHostPort(Spec.BindIP, Spec.Port)
// 配置校验 服务名称地址及监听地址不能为空
conf.NotNil(Spec.Service, Spec.Cache)
// 初始化加密SecretKey
encipher.New(env.Runtime.JwtSecretKey)
conf.PrintInfo(Spec.Addr)
}

View File

@@ -0,0 +1,29 @@
package impl
import (
"git.apinb.com/bsm-apps/ads/internal/config"
"git.apinb.com/bsm-sdk/core/cache/redis"
"git.apinb.com/bsm-sdk/core/with"
cache "github.com/patrickmn/go-cache"
clientv3 "go.etcd.io/etcd/client/v3"
"gorm.io/gorm"
)
var (
RedisService *redis.RedisClient // Redis缓存服务客户端
EtcdService *clientv3.Client // Etcd服务发现客户端
DBService *gorm.DB // 数据库服务客户端
MemorySerice *cache.Cache // 内存缓存服务
)
// NewImpl 初始化各类服务实例
func NewImpl() {
// 初始化内存缓存服务
MemorySerice = with.Memory(nil)
// 初始化Redis缓存服务
RedisService = with.RedisCache(config.Spec.Cache)
// 初始化数据库服务
DBService = with.Databases(config.Spec.Databases, nil)
// 初始化Etcd服务发现
EtcdService = with.Etcd(config.Spec.Etcd)
}

View File

@@ -0,0 +1,40 @@
package fetch
import (
"context"
"git.apinb.com/bsm-apps/ads/internal/impl"
"git.apinb.com/bsm-apps/ads/internal/models"
pb "git.apinb.com/bsm-apps/ads/pb"
"git.apinb.com/bsm-sdk/core/errcode"
)
// 通过广告位获取广告信息
func ByPos(ctx context.Context, in *pb.ByPosRequest) (reply *pb.ByPosReply, err error) {
// 参数验证
if in.Key == "" {
return nil, errcode.ErrInvalidArgument
}
// 从数据库查询
var adsItems []models.AdsItem
err = impl.DBService.Where("pos_key = ? AND status = ?", in.Key, 1).Find(&adsItems).Error
if err != nil {
return nil, errcode.ErrDB
}
// 转换为protobuf格式
result := make([]*pb.AdsItem, 0, len(adsItems))
for _, item := range adsItems {
result = append(result, &pb.AdsItem{
Id: int64(item.ID),
Title: item.Title,
Content: item.Content,
Type: int32(item.Type),
ToUrl: item.ToUrl,
Created: item.CreatedAt.Format("2006-01-02 15:04:05"),
})
}
return &pb.ByPosReply{Data: result}, nil
}

View File

@@ -0,0 +1,44 @@
/**
* @Author: ZhaoYadong
* @Date: 2021-12-13 14:28:49
* @LastEditors: ZhaoYadong
* @LastEditTime: 2022-01-18 17:57:50
* @FilePath: /src/git.buka.tv/cloud-disk/internal/models/file.go
*/
package models
import (
"git.apinb.com/bsm-sdk/core/database"
"git.apinb.com/bsm-sdk/engine/types"
"gorm.io/gorm"
)
type ContentType int32
const (
CONTENT_TYPE_TEXT ContentType = iota + 1 // 1.文本
CONTENT_TYPE_IMAGE // 2.图片
CONTENT_TYPE_VIDEO // 3.视频
CONTENT_TYPE_AUDIO // 4.音频
CONTENT_TYPE_LINK // 5.连接
CONTENT_TYPE_ATTACHMENT // 6.附件
)
type AdsItem struct {
gorm.Model
Title string `gorm:"column:title;type:varchar(255);not null;" json:"title"` // 广告名称
PosKey string `gorm:"column:pos_key;type:varchar(255);not null;" json:"pos_key"` // 广告位key
Content string `gorm:"column:content;type:varchar(255);default:'';" json:"content"` // 广告内容
Type ContentType `gorm:"column:type;default:0;" json:"type"` // 广告类型
ToUrl string `gorm:"column:to_url;type:varchar(255);default:'';" json:"to_url"`
types.Std_Status
}
func init() {
database.AppendMigrate(&AdsItem{})
}
// TableName .
func (table *AdsItem) TableName() string {
return "ads_item" //对应数据库表名
}

View File

@@ -0,0 +1,28 @@
/**
* @Author: ZhaoYadong
* @Date: 2021-12-13 14:28:49
* @LastEditors: ZhaoYadong
* @LastEditTime: 2022-01-18 16:55:00
* @FilePath: /src/git.buka.tv/cloud-disk/internal/models/share.go
*/
package models
import (
"git.apinb.com/bsm-sdk/core/database"
"git.apinb.com/bsm-sdk/engine/types"
)
type AdsPos struct {
types.Std_IdCreated
Key string `gorm:"column:key;type:varchar(255);not null;" json:"key"` // 广告位的标记
Name string `gorm:"column:name;type:varchar(255);not null;" json:"name"` // 广告位的名称
}
func init() {
database.AppendMigrate(&AdsPos{})
}
// TableName .
func (table *AdsPos) TableName() string {
return "ads_pos" //对应数据库表名
}

View File

@@ -0,0 +1,21 @@
// Code generated by protoc-gen-slc. DO NOT EDIT.
package server
import (
"context"
"git.apinb.com/bsm-apps/ads/internal/logic/fetch"
pb "git.apinb.com/bsm-apps/ads/pb"
)
type FetchServer struct {
pb.UnimplementedFetchServer
}
func NewFetchServer() *FetchServer {
return &FetchServer{}
}
// 通过广告位获取广告信息
func (s *FetchServer) ByPos(ctx context.Context, in *pb.ByPosRequest) (*pb.ByPosReply, error) {
return fetch.ByPos(ctx, in)
}

View File

@@ -0,0 +1,91 @@
// Code generated by protoc-gen-slc. DO NOT EDIT.
package server
import (
"context"
pb "git.apinb.com/bsm-apps/ads/pb"
"git.apinb.com/bsm-sdk/core/vars"
gwRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
"google.golang.org/protobuf/proto"
"net/http"
"os"
"strings"
"time"
)
type Server struct {
Grpc *grpc.Server
Ctx context.Context
Mux *gwRuntime.ServeMux
grpcConns map[string]*grpc.ClientConn // 连接池
}
func New(addr string) *Server {
srv := &Server{
Ctx: context.Background(),
Grpc: grpc.NewServer(),
Mux: gwRuntime.NewServeMux(gwRuntime.WithForwardResponseRewriter(responseEnvelope)),
grpcConns: make(map[string]*grpc.ClientConn),
}
// register service to grpc.Server
pb.RegisterFetchServer(srv.Grpc, NewFetchServer())
reflection.Register(srv.Grpc)
// 连接池: 只创建一次连接并复用
conn, ok := srv.grpcConns[addr]
if !ok {
var err error
conn, err = grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
panic("failed to dial grpc server: " + err.Error())
}
srv.grpcConns[addr] = conn
}
// 将服务注册到Gateway
if err := pb.RegisterFetchHandler(srv.Ctx, srv.Mux, conn); err != nil {
panic("Failed to register Fetch handler: " + err.Error())
}
// Register services swagger
srv.RegisterSwagger()
return srv
}
// RegisterSwagger 注册swagger
func (s *Server) RegisterSwagger() {
srvKey := strings.ToLower(vars.ServiceKey)
s.Mux.HandlePath("GET", "/"+srvKey+".swagger.json", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
w.Header().Set("Content-Type", "application/json")
bytes, err := os.ReadFile("./swagger/" + srvKey + ".swagger.json")
if err != nil {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
}
w.Write(bytes)
return
})
}
// response envelope
func responseEnvelope(_ context.Context, response proto.Message) (interface{}, error) {
name := string(response.ProtoReflect().Descriptor().Name())
if name == "Status" || name == "Error" || name == "StatusReply" {
return response, nil
}
return map[string]any{
"code": 0,
"message": vars.OK,
"details": response,
"timeseq": time.Now().Unix(),
}, nil
}

267
apps/base/ads/pb/ads.pb.go Normal file
View File

@@ -0,0 +1,267 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc (unknown)
// source: ads.proto
package ads
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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 ByPosRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ByPosRequest) Reset() {
*x = ByPosRequest{}
mi := &file_ads_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ByPosRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ByPosRequest) ProtoMessage() {}
func (x *ByPosRequest) ProtoReflect() protoreflect.Message {
mi := &file_ads_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 ByPosRequest.ProtoReflect.Descriptor instead.
func (*ByPosRequest) Descriptor() ([]byte, []int) {
return file_ads_proto_rawDescGZIP(), []int{0}
}
func (x *ByPosRequest) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
type ByPosReply struct {
state protoimpl.MessageState `protogen:"open.v1"`
Data []*AdsItem `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ByPosReply) Reset() {
*x = ByPosReply{}
mi := &file_ads_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ByPosReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ByPosReply) ProtoMessage() {}
func (x *ByPosReply) ProtoReflect() protoreflect.Message {
mi := &file_ads_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 ByPosReply.ProtoReflect.Descriptor instead.
func (*ByPosReply) Descriptor() ([]byte, []int) {
return file_ads_proto_rawDescGZIP(), []int{1}
}
func (x *ByPosReply) GetData() []*AdsItem {
if x != nil {
return x.Data
}
return nil
}
type AdsItem struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` //广告名称
Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` //广告内容
Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type,omitempty"` //广告类型 1.文本 2.图片 3.视频
ToUrl string `protobuf:"bytes,5,opt,name=toUrl,proto3" json:"toUrl,omitempty"`
Created string `protobuf:"bytes,6,opt,name=created,proto3" json:"created,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AdsItem) Reset() {
*x = AdsItem{}
mi := &file_ads_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AdsItem) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AdsItem) ProtoMessage() {}
func (x *AdsItem) ProtoReflect() protoreflect.Message {
mi := &file_ads_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 AdsItem.ProtoReflect.Descriptor instead.
func (*AdsItem) Descriptor() ([]byte, []int) {
return file_ads_proto_rawDescGZIP(), []int{2}
}
func (x *AdsItem) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *AdsItem) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *AdsItem) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *AdsItem) GetType() int32 {
if x != nil {
return x.Type
}
return 0
}
func (x *AdsItem) GetToUrl() string {
if x != nil {
return x.ToUrl
}
return ""
}
func (x *AdsItem) GetCreated() string {
if x != nil {
return x.Created
}
return ""
}
var File_ads_proto protoreflect.FileDescriptor
const file_ads_proto_rawDesc = "" +
"\n" +
"\x12base/ads/ads.proto\x12\x03ads\" \n" +
"\fByPosRequest\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\".\n" +
"\n" +
"ByPosReply\x12 \n" +
"\x04data\x18\x01 \x03(\v2\f.ads.AdsItemR\x04data\"\x8d\x01\n" +
"\aAdsItem\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x14\n" +
"\x05title\x18\x02 \x01(\tR\x05title\x12\x18\n" +
"\acontent\x18\x03 \x01(\tR\acontent\x12\x12\n" +
"\x04type\x18\x04 \x01(\x05R\x04type\x12\x14\n" +
"\x05toUrl\x18\x05 \x01(\tR\x05toUrl\x12\x18\n" +
"\acreated\x18\x06 \x01(\tR\acreated26\n" +
"\x05Fetch\x12-\n" +
"\x05ByPos\x12\x11.ads.ByPosRequest\x1a\x0f.ads.ByPosReply\"\x00B\aZ\x05.;adsb\x06proto3"
var (
file_ads_proto_rawDescOnce sync.Once
file_ads_proto_rawDescData []byte
)
func file_ads_proto_rawDescGZIP() []byte {
file_ads_proto_rawDescOnce.Do(func() {
file_ads_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ads_proto_rawDesc), len(file_ads_proto_rawDesc)))
})
return file_ads_proto_rawDescData
}
var file_ads_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_ads_proto_goTypes = []any{
(*ByPosRequest)(nil), // 0: ads.ByPosRequest
(*ByPosReply)(nil), // 1: ads.ByPosReply
(*AdsItem)(nil), // 2: ads.AdsItem
}
var file_ads_proto_depIdxs = []int32{
2, // 0: ads.ByPosReply.data:type_name -> ads.AdsItem
0, // 1: ads.Fetch.ByPos:input_type -> ads.ByPosRequest
1, // 2: ads.Fetch.ByPos:output_type -> ads.ByPosReply
2, // [2:3] is the sub-list for method output_type
1, // [1:2] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_ads_proto_init() }
func file_ads_proto_init() {
if File_ads_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ads_proto_rawDesc), len(file_ads_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_ads_proto_goTypes,
DependencyIndexes: file_ads_proto_depIdxs,
MessageInfos: file_ads_proto_msgTypes,
}.Build()
File_ads_proto = out.File
file_ads_proto_goTypes = nil
file_ads_proto_depIdxs = nil
}

View File

@@ -0,0 +1,157 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: ads.proto
/*
Package ads is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package ads
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
func request_Fetch_ByPos_0(ctx context.Context, marshaler runtime.Marshaler, client FetchClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq ByPosRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.ByPos(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Fetch_ByPos_0(ctx context.Context, marshaler runtime.Marshaler, server FetchServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq ByPosRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ByPos(ctx, &protoReq)
return msg, metadata, err
}
// RegisterFetchHandlerServer registers the http handlers for service Fetch to "mux".
// UnaryRPC :call FetchServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterFetchHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterFetchHandlerServer(ctx context.Context, mux *runtime.ServeMux, server FetchServer) error {
mux.Handle(http.MethodPost, pattern_Fetch_ByPos_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/ads.Fetch/ByPos", runtime.WithHTTPPathPattern("/ads.Fetch/ByPos"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Fetch_ByPos_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Fetch_ByPos_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterFetchHandlerFromEndpoint is same as RegisterFetchHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterFetchHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterFetchHandler(ctx, mux, conn)
}
// RegisterFetchHandler registers the http handlers for service Fetch to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterFetchHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterFetchHandlerClient(ctx, mux, NewFetchClient(conn))
}
// RegisterFetchHandlerClient registers the http handlers for service Fetch
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "FetchClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "FetchClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "FetchClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterFetchHandlerClient(ctx context.Context, mux *runtime.ServeMux, client FetchClient) error {
mux.Handle(http.MethodPost, pattern_Fetch_ByPos_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/ads.Fetch/ByPos", runtime.WithHTTPPathPattern("/ads.Fetch/ByPos"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Fetch_ByPos_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Fetch_ByPos_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Fetch_ByPos_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"ads.Fetch", "ByPos"}, ""))
)
var (
forward_Fetch_ByPos_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,127 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: ads.proto
package ads
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 (
Fetch_ByPos_FullMethodName = "/ads.Fetch/ByPos"
)
// FetchClient is the client API for Fetch 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 FetchClient interface {
//通过广告位获取广告信息
ByPos(ctx context.Context, in *ByPosRequest, opts ...grpc.CallOption) (*ByPosReply, error)
}
type fetchClient struct {
cc grpc.ClientConnInterface
}
func NewFetchClient(cc grpc.ClientConnInterface) FetchClient {
return &fetchClient{cc}
}
func (c *fetchClient) ByPos(ctx context.Context, in *ByPosRequest, opts ...grpc.CallOption) (*ByPosReply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ByPosReply)
err := c.cc.Invoke(ctx, Fetch_ByPos_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// FetchServer is the server API for Fetch service.
// All implementations must embed UnimplementedFetchServer
// for forward compatibility.
//
// 广告子系统
type FetchServer interface {
//通过广告位获取广告信息
ByPos(context.Context, *ByPosRequest) (*ByPosReply, error)
mustEmbedUnimplementedFetchServer()
}
// UnimplementedFetchServer 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 UnimplementedFetchServer struct{}
func (UnimplementedFetchServer) ByPos(context.Context, *ByPosRequest) (*ByPosReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ByPos not implemented")
}
func (UnimplementedFetchServer) mustEmbedUnimplementedFetchServer() {}
func (UnimplementedFetchServer) testEmbeddedByValue() {}
// UnsafeFetchServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to FetchServer will
// result in compilation errors.
type UnsafeFetchServer interface {
mustEmbedUnimplementedFetchServer()
}
func RegisterFetchServer(s grpc.ServiceRegistrar, srv FetchServer) {
// If the following call pancis, it indicates UnimplementedFetchServer 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(&Fetch_ServiceDesc, srv)
}
func _Fetch_ByPos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ByPosRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(FetchServer).ByPos(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Fetch_ByPos_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(FetchServer).ByPos(ctx, req.(*ByPosRequest))
}
return interceptor(ctx, in, info, handler)
}
// Fetch_ServiceDesc is the grpc.ServiceDesc for Fetch service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Fetch_ServiceDesc = grpc.ServiceDesc{
ServiceName: "ads.Fetch",
HandlerType: (*FetchServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ByPos",
Handler: _Fetch_ByPos_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "ads.proto",
}

View File

@@ -0,0 +1,25 @@
syntax = "proto3";
package ads;
option go_package = ".;ads";
//广告子系统
service Fetch{
//通过广告位获取广告信息
rpc ByPos(ByPosRequest) returns (ByPosReply) {}
}
message ByPosRequest{
string key = 1;
}
message ByPosReply{
repeated AdsItem data =1;
}
message AdsItem{
int64 id = 1;
string title = 2;//广告名称
string content = 3;//广告内容
int32 type = 4;//广告类型 1.文本 2.图片 3.视频
string toUrl = 5;
string created = 6;
}

View File

@@ -0,0 +1,32 @@
filebeat.inputs:
- type: log
enabled: true
# 开启json解析
json.keys_under_root: true
json.add_error_key: true
# 日志文件路径
paths:
- ./logs/cloud/error.log
- ./logs/cloud/slow.log
setup.template.settings:
index.number_of_shards: 1
# 定义kafka topic field
fields:
log_topic: scf.cloud.dev
# 输出到kafka
output.kafka:
hosts: ["127.0.0.1:9092"]
topic: '%{[fields.log_topic]}'
partition.round_robin:
reachable_only: false
required_acks: 1
keep_alive: 10s
# ================================= Processors =================================
processors:
- decode_json_fields:
fields: ['@timestamp','level','content','trace','span','duration']
target: ""

View File

@@ -0,0 +1,5 @@
#install
go install github.com/securego/gosec/v2/cmd/gosec@latest
#run
gosec -fmt=json -out=./test/lint/gosec.json ./...

View File

@@ -0,0 +1,10 @@
# 由于goctl 不能编译多个proto文件所以先要安装合并工具
# go install git.apinb.com/bsm-tools/proto-merge@v0.0.3
# 1. 先合并
proto-merge ./proto/*.proto ./proto/passport.mproto
# 2. goctl 生成代码至/gen
goctl rpc protoc ./proto/passport.mproto --go_out=./pb --go-grpc_out=./pb --zrpc_out=./gen/ -m --style go_zero
#protoc --go_out=./pb/ --go_opt=paths=source_relative --go-grpc_out=./pb/ --go-grpc_opt=require_unimplemented_servers=false --go-grpc_opt=paths=source_relative ./proto/*.proto --proto_path=./proto/

View File

@@ -0,0 +1,7 @@
git pull
go get all
go get -u ./...
go mod tidy
git add .
git commit -m 'run ./script/update.sh'
git push

View File

@@ -0,0 +1,89 @@
{
"swagger": "2.0",
"info": {
"title": "ads.proto",
"version": "version not set"
},
"tags": [
{
"name": "Fetch"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"adsAdsItem": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "int64"
},
"title": {
"type": "string",
"title": "广告名称"
},
"content": {
"type": "string",
"title": "广告内容"
},
"type": {
"type": "integer",
"format": "int32",
"title": "广告类型 1.文本 2.图片 3.视频"
},
"toUrl": {
"type": "string"
},
"created": {
"type": "string"
}
}
},
"adsByPosReply": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/adsAdsItem"
}
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
{
"Golang errors": {},
"Issues": [],
"Stats": {
"files": 24,
"lines": 2377,
"nosec": 0,
"found": 0
},
"GosecVersion": "dev"
}

View File

@@ -0,0 +1,23 @@
package main
func main() {
/*
md := metadata.New(map[string]string{"request_id": utils.UUID(), "workspace": "scf"})
ctx := metadata.NewOutgoingContext(context.Background(), md)
// 建立GRPC连接
conn, err := grpc.Dial("127.0.0.1:12201", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
panic(err)
}
defer conn.Close()
c := pb.NewMethodClient(conn)
r, err := c.List()(ctx, &pb.Crc{
Code: "david",
})
if err != nil {
panic(err)
}
fmt.Printf("返回的消息: %s", r.Message)
*/
}