Files
data-engine/controller/sync/platform_sync_controller.go
T
2026-07-16 14:34:06 +08:00

204 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package sync
import (
"context"
svc "dataengine/service/sync"
"fmt"
"gitea.redpowerfuture.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g"
"github.com/sirupsen/logrus"
)
var PlatformSyncController = new(syncCtrl)
type syncCtrl struct{}
// RefreshTokenReq 刷新 Token 请求
type RefreshTokenReq struct {
g.Meta `path:"/refreshToken" method:"post" tags:"平台同步" summary:"刷新Token" dc:"刷新指定平台的认证Token(如腾讯OAuth2"`
PlatformCode string `json:"platformCode" v:"required" dc:"平台编码"`
}
// RefreshTokenRes 刷新 Token 响应
type RefreshTokenRes struct {
Success bool `json:"success"`
Message string `json:"message"`
}
// RefreshToken 手动触发 Token 刷新
// 由 PPGo_Job 定时调度,定期刷新平台 Token(如腾讯 OAuth2 access_token
func (c *syncCtrl) RefreshToken(ctx context.Context, req *RefreshTokenReq) (*RefreshTokenRes, error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
logrus.Infof("[HTTP] 触发 Token 刷新: platform=%s", req.PlatformCode)
pm := &svc.PlatformManager{}
platform, _, err := pm.GetPlatformWithInterfaces(ctx, req.PlatformCode)
if err != nil {
return nil, fmt.Errorf("读取平台配置失败: %w", err)
}
if err := svc.RefreshTencentToken(ctx, platform); err != nil {
return &RefreshTokenRes{Success: false, Message: err.Error()}, nil
}
return &RefreshTokenRes{Success: true, Message: "Token 刷新成功"}, nil
}
// TriggerSyncReq 触发同步请求
type TriggerSyncReq struct {
g.Meta `path:"/trigger" method:"post" tags:"平台同步" summary:"触发同步" dc:"根据平台编码和接口编码触发数据同步"`
PlatformCode string `json:"platformCode" v:"required" dc:"平台编码"`
InterfaceCode string `json:"interfaceCode" v:"required" dc:"接口编码"`
FullSync bool `json:"fullSync" dc:"是否全量同步,true=全量 false=增量"`
}
// TriggerSyncRes 触发同步响应
type TriggerSyncRes struct {
Success bool `json:"success"`
TableName string `json:"tableName"`
TotalRows int `json:"totalRows"`
InsertedRows int `json:"insertedRows"`
Duration string `json:"duration"`
}
// TriggerSync 触发同步
func (c *syncCtrl) TriggerSync(ctx context.Context, req *TriggerSyncReq) (*TriggerSyncRes, error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
logrus.Infof("触发同步: platform=%s, interface=%s, fullSync=%v", req.PlatformCode, req.InterfaceCode, req.FullSync)
result, err := svc.SyncByConfig(ctx, req.PlatformCode, req.InterfaceCode, req.FullSync)
if err != nil {
return nil, err
}
return &TriggerSyncRes{
Success: true, TableName: result.TableName,
TotalRows: result.TotalRows, InsertedRows: result.InsertedRows,
Duration: result.Duration,
}, nil
}
// QueryPlatformConfigReq 查询平台配置请求
type QueryPlatformConfigReq struct {
g.Meta `path:"/config" method:"get" tags:"平台同步" summary:"查询平台配置" dc:"查看平台和接口配置"`
PlatformCode string `json:"platformCode" v:"required" dc:"平台编码"`
}
// QueryPlatformConfigRes 查询平台配置响应
type QueryPlatformConfigRes struct {
PlatformName string `json:"platformName"`
PlatformCode string `json:"platformCode"`
ApiBaseUrl string `json:"apiBaseUrl"`
AuthType string `json:"authType"`
HasToken bool `json:"hasToken"`
InterfaceCount int `json:"interfaceCount"`
Interfaces []struct {
Code string `json:"code"`
Name string `json:"name"`
Url string `json:"url"`
HasTableDef bool `json:"hasTableDef"`
} `json:"interfaces"`
}
// ============================================================
// 批量操作(供 PPGo_Job 调度)
// ============================================================
// TriggerAllSyncReq 触发全平台同步请求
type TriggerAllSyncReq struct {
g.Meta `path:"/triggerAll" method:"post" tags:"平台同步" summary:"触发全平台同步" dc:"遍历所有ACTIVE平台/接口执行同步"`
FullSync bool `json:"fullSync" dc:"true=强制全量同步,false=自动判断增量/全量"`
}
// TriggerAllSyncRes 触发全平台同步响应
type TriggerAllSyncRes struct {
Success bool `json:"success"`
Message string `json:"message"`
Results []svc.SyncRunItemResult `json:"results,omitempty"`
}
// TriggerAllSync 触发全平台同步(等价于内部自动同步的一次完整执行)
func (c *syncCtrl) TriggerAllSync(ctx context.Context, req *TriggerAllSyncReq) (*TriggerAllSyncRes, error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
logrus.Infof("[HTTP] 触发全平台同步, fullSync=%v", req.FullSync)
results := svc.TriggerAllSync(ctx, req.FullSync)
hasError := false
for _, r := range results {
if !r.Success {
hasError = true
break
}
}
res := &TriggerAllSyncRes{Results: results}
if hasError {
res.Success = false
res.Message = "全平台同步完成,部分失败"
} else {
res.Success = true
res.Message = "全平台同步完成"
}
return res, nil
}
// CompensateReq 触发补偿扫描请求
type CompensateReq struct {
g.Meta `path:"/compensate" method:"post" tags:"平台同步" summary:"触发补偿扫描" dc:"扫描失败任务并重试"`
}
// CompensateRes 触发补偿扫描响应
type CompensateRes struct {
Success bool `json:"success"`
Message string `json:"message"`
Result *svc.CompensateResult `json:"result,omitempty"`
}
// Compensate 触发补偿扫描(等价于内部补偿调度的一次完整执行)
func (c *syncCtrl) Compensate(ctx context.Context, req *CompensateReq) (*CompensateRes, error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
logrus.Info("[HTTP] 触发补偿扫描")
result := svc.TriggerCompensation(ctx)
res := &CompensateRes{Result: result}
if result.TotalFailed == 0 {
res.Success = true
res.Message = "补偿扫描完成,没有待补偿任务"
} else if result.Failed > 0 {
res.Success = false
res.Message = fmt.Sprintf("补偿扫描完成,共 %d 个失败任务,成功补偿 %d 个,失败 %d 个,已达最大重试 %d 个",
result.TotalFailed, result.Succeeded, result.Failed, result.MaxRetryReached)
} else {
res.Success = true
res.Message = fmt.Sprintf("补偿扫描完成,共 %d 个失败任务,成功补偿 %d 个",
result.TotalFailed, result.Succeeded)
}
return res, nil
}
// QueryConfig 查询配置
func (c *syncCtrl) QueryConfig(ctx context.Context, req *QueryPlatformConfigReq) (*QueryPlatformConfigRes, error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
pm := &svc.PlatformManager{}
platform, interfaces, err := pm.GetPlatformWithInterfaces(ctx, req.PlatformCode)
if err != nil {
return nil, err
}
res := &QueryPlatformConfigRes{
PlatformName: platform.PlatformName, PlatformCode: platform.PlatformCode,
ApiBaseUrl: platform.ApiBaseUrl, AuthType: platform.AuthType,
HasToken: platform.AccessToken != "", InterfaceCount: len(interfaces),
}
for _, iface := range interfaces {
res.Interfaces = append(res.Interfaces, struct {
Code string `json:"code"`
Name string `json:"name"`
Url string `json:"url"`
HasTableDef bool `json:"hasTableDef"`
}{
Code: iface.Code, Name: iface.Name, Url: iface.Url,
HasTableDef: iface.TableDefinition != nil && len(iface.TableDefinition) > 0,
})
}
return res, nil
}