Răsfoiți Sursa

dev: automated commit - 2026-03-08 13:11:39

Mariano Z. 2 săptămâni în urmă
părinte
comite
d8deb05308
2 a modificat fișierele cu 76 adăugiri și 24 ștergeri
  1. 37 0
      internal/cloudflare/client.go
  2. 39 24
      internal/cron/cron.go

+ 37 - 0
internal/cloudflare/client.go

@@ -109,6 +109,43 @@ func UpdateDNSRecord(ctx context.Context, apiKey, zoneID, recordID string, rec D
 	return err
 }
 
+type batchPutRecord struct {
+	ID      string `json:"id"`
+	Type    string `json:"type"`
+	Name    string `json:"name"`
+	Content string `json:"content"`
+	Proxied bool   `json:"proxied"`
+	TTL     int    `json:"ttl"`
+}
+
+type batchRequest struct {
+	Puts []batchPutRecord `json:"puts"`
+}
+
+func BatchUpdateDNSRecords(ctx context.Context, apiKey, zoneID string, records []DNSRecord) error {
+	url := fmt.Sprintf("%s/zones/%s/dns_records/batch", baseURL, zoneID)
+
+	puts := make([]batchPutRecord, len(records))
+	for i, rec := range records {
+		puts[i] = batchPutRecord{
+			ID:      rec.ID,
+			Type:    rec.Type,
+			Name:    rec.Name,
+			Content: rec.Content,
+			Proxied: rec.Proxied,
+			TTL:     rec.TTL,
+		}
+	}
+
+	data, err := json.Marshal(batchRequest{Puts: puts})
+	if err != nil {
+		return fmt.Errorf("marshal batch payload: %w", err)
+	}
+
+	_, err = doRequest(ctx, http.MethodPost, url, apiKey, bytes.NewReader(data))
+	return err
+}
+
 func doRequest(ctx context.Context, method, rawURL, apiKey string, body io.Reader) (json.RawMessage, error) {
 	parsed, _ := url.Parse(rawURL)
 	path := parsed.Path

+ 39 - 24
internal/cron/cron.go

@@ -139,39 +139,54 @@ func (u *DDNSUpdater) run() {
 		return
 	}
 
-	allOK := true
+	type zoneKey struct {
+		apiKey string
+		zoneID string
+	}
+	byZone := make(map[zoneKey][]queries.ListNonStaticRecordsRow)
 	for _, rec := range records {
-		err := cf.UpdateDNSRecord(ctx, rec.ZoneApiKey, rec.CfZoneID, rec.CfRecordID, cf.DNSRecord{
-			Type:    rec.Type,
-			Name:    rec.Name,
-			Content: ip,
-			Proxied: rec.Proxied == 1,
-			TTL:     1, // auto
-		})
-		if err != nil {
-			slog.Error("failed to update DNS record",
-				"record", rec.Name,
-				"zone", rec.CfZoneID,
-				"error", err,
-			)
-			allOK = false
-			continue
+		k := zoneKey{apiKey: rec.ZoneApiKey, zoneID: rec.CfZoneID}
+		byZone[k] = append(byZone[k], rec)
+	}
+
+	allOK := true
+	for k, zoneRecs := range byZone {
+		cfRecords := make([]cf.DNSRecord, len(zoneRecs))
+		for i, rec := range zoneRecs {
+			cfRecords[i] = cf.DNSRecord{
+				ID:      rec.CfRecordID,
+				Type:    rec.Type,
+				Name:    rec.Name,
+				Content: ip,
+				Proxied: rec.Proxied == 1,
+				TTL:     1, // auto
+			}
 		}
 
-		err = u.q.UpdateRecordContent(ctx, queries.UpdateRecordContentParams{
-			ID:      rec.ID,
-			Content: ip,
-		})
-		if err != nil {
-			slog.Error("failed to update local record content",
-				"record", rec.Name,
+		if err := cf.BatchUpdateDNSRecords(ctx, k.apiKey, k.zoneID, cfRecords); err != nil {
+			slog.Error("failed to batch update DNS records",
+				"zone", k.zoneID,
+				"count", len(zoneRecs),
 				"error", err,
 			)
 			allOK = false
 			continue
 		}
 
-		slog.Info("updated DNS record", "record", rec.Name, "ip", ip)
+		for _, rec := range zoneRecs {
+			if err := u.q.UpdateRecordContent(ctx, queries.UpdateRecordContentParams{
+				ID:      rec.ID,
+				Content: ip,
+			}); err != nil {
+				slog.Error("failed to update local record content",
+					"record", rec.Name,
+					"error", err,
+				)
+				allOK = false
+				continue
+			}
+			slog.Info("updated DNS record", "record", rec.Name, "ip", ip)
+		}
 	}
 
 	if allOK {