package httpdns import ( "encoding/json" "log" "github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/iwind/TeaGo/dbs" ) func toPBCluster(cluster *models.HTTPDNSCluster) *pb.HTTPDNSCluster { if cluster == nil { return nil } return &pb.HTTPDNSCluster{ Id: int64(cluster.Id), IsOn: cluster.IsOn > 0, IsDefault: cluster.IsDefault > 0, Name: cluster.Name, ServiceDomain: cluster.ServiceDomain, DefaultTTL: cluster.DefaultTTL, FallbackTimeoutMs: cluster.FallbackTimeoutMs, InstallDir: cluster.InstallDir, TlsPolicyJSON: cluster.TLSPolicy, CreatedAt: int64(cluster.CreatedAt), UpdatedAt: int64(cluster.UpdatedAt), AutoRemoteStart: cluster.AutoRemoteStart > 0, AccessLogIsOn: cluster.AccessLogIsOn > 0, TimeZone: cluster.TimeZone, } } // toPBClusterWithResolvedCerts 转换集群并解析证书引用为实际 PEM 数据 // 供节点调用的 RPC 使用,确保节点能拿到完整的证书内容 func toPBClusterWithResolvedCerts(tx *dbs.Tx, cluster *models.HTTPDNSCluster) *pb.HTTPDNSCluster { pbCluster := toPBCluster(cluster) if pbCluster == nil { return nil } resolved := resolveTLSPolicyCerts(tx, cluster.TLSPolicy) if resolved != nil { pbCluster.TlsPolicyJSON = resolved } return pbCluster } // resolveTLSPolicyCerts 将 tlsPolicyJSON 中的 certRefs 解析为带实际 PEM 数据的 certs func resolveTLSPolicyCerts(tx *dbs.Tx, tlsPolicyJSON []byte) []byte { if len(tlsPolicyJSON) == 0 { return nil } // 解析外层结构: {"listen": [...], "sslPolicy": {...}} var tlsConfig map[string]json.RawMessage if err := json.Unmarshal(tlsPolicyJSON, &tlsConfig); err != nil { return nil } sslPolicyData, ok := tlsConfig["sslPolicy"] if !ok || len(sslPolicyData) == 0 { return nil } var sslPolicy sslconfigs.SSLPolicy if err := json.Unmarshal(sslPolicyData, &sslPolicy); err != nil { return nil } // 检查 certs 是否已经有实际数据 for _, cert := range sslPolicy.Certs { if cert != nil && len(cert.CertData) > 128 && len(cert.KeyData) > 128 { return nil // 已有完整 PEM 数据,无需处理 } } // 从 certRefs 解析实际证书数据 if len(sslPolicy.CertRefs) == 0 { return nil } var resolvedCerts []*sslconfigs.SSLCertConfig for _, ref := range sslPolicy.CertRefs { if ref == nil || ref.CertId <= 0 { continue } certConfig, err := models.SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, false, nil, nil) if err != nil { log.Println("[HTTPDNS]resolve cert", ref.CertId, "failed:", err.Error()) continue } if certConfig == nil || len(certConfig.CertData) == 0 || len(certConfig.KeyData) == 0 { continue } resolvedCerts = append(resolvedCerts, certConfig) } if len(resolvedCerts) == 0 { return nil } // 把解析后的证书写回 sslPolicy.Certs sslPolicy.Certs = resolvedCerts newPolicyData, err := json.Marshal(&sslPolicy) if err != nil { return nil } tlsConfig["sslPolicy"] = newPolicyData result, err := json.Marshal(tlsConfig) if err != nil { return nil } return result } func toPBNode(node *models.HTTPDNSNode) *pb.HTTPDNSNode { if node == nil { return nil } return &pb.HTTPDNSNode{ Id: int64(node.Id), ClusterId: int64(node.ClusterId), Name: node.Name, IsOn: node.IsOn, IsUp: node.IsUp, IsInstalled: node.IsInstalled, IsActive: node.IsActive, UniqueId: node.UniqueId, Secret: node.Secret, InstallDir: node.InstallDir, StatusJSON: node.Status, InstallStatusJSON: node.InstallStatus, CreatedAt: int64(node.CreatedAt), UpdatedAt: int64(node.UpdatedAt), } } func toPBApp(app *models.HTTPDNSApp, secret *models.HTTPDNSAppSecret) *pb.HTTPDNSApp { if app == nil { return nil } var signEnabled bool var signSecret string var signUpdatedAt int64 if secret != nil { signEnabled = secret.SignEnabled signSecret = secret.SignSecret signUpdatedAt = int64(secret.SignUpdatedAt) } // 构建 clusterIdsJSON clusterIds := models.SharedHTTPDNSAppDAO.ReadAppClusterIds(app) clusterIdsJSON, _ := json.Marshal(clusterIds) return &pb.HTTPDNSApp{ Id: int64(app.Id), Name: app.Name, AppId: app.AppId, IsOn: app.IsOn, SniMode: app.SNIMode, SignEnabled: signEnabled, SignSecret: signSecret, SignUpdatedAt: signUpdatedAt, CreatedAt: int64(app.CreatedAt), UpdatedAt: int64(app.UpdatedAt), UserId: int64(app.UserId), ClusterIdsJSON: clusterIdsJSON, } } func toPBDomain(domain *models.HTTPDNSDomain, ruleCount int64) *pb.HTTPDNSDomain { if domain == nil { return nil } return &pb.HTTPDNSDomain{ Id: int64(domain.Id), AppId: int64(domain.AppId), Domain: domain.Domain, IsOn: domain.IsOn, CreatedAt: int64(domain.CreatedAt), UpdatedAt: int64(domain.UpdatedAt), RuleCount: ruleCount, } } func toPBRule(rule *models.HTTPDNSCustomRule, records []*models.HTTPDNSCustomRuleRecord) *pb.HTTPDNSCustomRule { if rule == nil { return nil } var pbRecords []*pb.HTTPDNSRuleRecord for _, record := range records { pbRecords = append(pbRecords, &pb.HTTPDNSRuleRecord{ Id: int64(record.Id), RuleId: int64(record.RuleId), RecordType: record.RecordType, RecordValue: record.RecordValue, Weight: record.Weight, Sort: record.Sort, }) } return &pb.HTTPDNSCustomRule{ Id: int64(rule.Id), AppId: int64(rule.AppId), DomainId: int64(rule.DomainId), RuleName: rule.RuleName, LineScope: rule.LineScope, LineCarrier: rule.LineCarrier, LineRegion: rule.LineRegion, LineProvince: rule.LineProvince, LineContinent: rule.LineContinent, LineCountry: rule.LineCountry, Ttl: rule.TTL, IsOn: rule.IsOn, Priority: rule.Priority, UpdatedAt: int64(rule.UpdatedAt), Records: pbRecords, } }