85 lines
2.6 KiB
Go
85 lines
2.6 KiB
Go
//go:build commercial
|
|
|
|
// Package edition - Commercial replication implementation.
|
|
// This file is built ONLY when the "commercial" build tag is specified.
|
|
//
|
|
// Real-time replication to backup POPs (Calgary/Zurich).
|
|
// Community Edition does not have replication functionality.
|
|
//
|
|
// This is PROPRIETARY code - part of Commercial Edition licensing.
|
|
package edition
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
// startReplication begins the background replication goroutine.
|
|
// Called at startup in commercial edition via StartReplication variable.
|
|
func startReplication(ctx context.Context, dataDir string) {
|
|
if globalConfig == nil || globalConfig.ReplicationConfig == nil || globalConfig.ReplicationConfig.PrimaryPOP == "" {
|
|
log.Printf("Commercial edition: replication disabled (no backup POP configured)")
|
|
return
|
|
}
|
|
|
|
log.Printf("Commercial edition: replication enabled to %s", globalConfig.ReplicationConfig.PrimaryPOP)
|
|
|
|
go func() {
|
|
ticker := time.NewTicker(time.Duration(globalConfig.ReplicationConfig.PollInterval) * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
if err := replicateBatch(ctx, dataDir); err != nil {
|
|
log.Printf("replication error: %v", err)
|
|
// Alert operator on repeated failures
|
|
// TODO: Track consecutive failures, alert after threshold
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
// replicateBatch sends unreplicated entries to backup POP.
|
|
func replicateBatch(ctx context.Context, dataDir string) error {
|
|
// Implementation TBD - stub for now
|
|
// 1. Open DB
|
|
// 2. Call lib.EntryListUnreplicated()
|
|
// 3. Encrypt/encode entries
|
|
// 4. POST to backup POP
|
|
// 5. Mark replicated with lib.EntryMarkReplicated()
|
|
return nil
|
|
}
|
|
|
|
// ReplicatedEntry represents an entry being sent to backup POP.
|
|
type ReplicatedEntry struct {
|
|
EntryID string `json:"entry_id"`
|
|
Type string `json:"type"`
|
|
Title string `json:"title"`
|
|
TitleIdx string `json:"title_idx"`
|
|
Data []byte `json:"data"` // Encrypted blob
|
|
DataLevel int `json:"data_level"`
|
|
Scopes string `json:"scopes"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
UpdatedAt int64 `json:"updated_at"`
|
|
Version int `json:"version"`
|
|
}
|
|
|
|
// ReplicationRequest is sent to backup POP.
|
|
type ReplicationRequest struct {
|
|
SourcePOP string `json:"source_pop"`
|
|
Entries []ReplicatedEntry `json:"entries"`
|
|
Timestamp int64 `json:"timestamp"`
|
|
}
|
|
|
|
// ReplicationResponse from backup POP.
|
|
type ReplicationResponse struct {
|
|
Accepted []string `json:"accepted"` // EntryIDs successfully stored
|
|
Rejected []string `json:"rejected"` // EntryIDs failed validation
|
|
Duplicate []string `json:"duplicate"` // EntryIDs already present (version conflict)
|
|
}
|