204 lines
7.4 KiB
Go
204 lines
7.4 KiB
Go
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
|
||
}
|