package rep import ( "crypto/subtle" "git.crumpington.com/public/jldb/lib/httpconn" "log" "net/http" "time" ) const ( cmdGetInfo = 10 cmdSendState = 20 cmdStreamWAL = 30 ) // --------------------------------------------------------------------------- func (rep *Replicator) Handle(w http.ResponseWriter, r *http.Request) { logf := func(pattern string, args ...any) { log.Printf("[HTTP-HANDLER] "+pattern, args...) } conn, err := httpconn.Accept(w, r) if err != nil { logf("Failed to accept connection: %s", err) return } defer conn.Close() psk := make([]byte, 256) conn.SetReadDeadline(time.Now().Add(rep.conf.NetTimeout)) if _, err := conn.Read(psk); err != nil { logf("Failed to read PSK: %v", err) return } expected := rep.pskBytes if subtle.ConstantTimeCompare(expected, psk) != 1 { logf("PSK mismatch.") return } cmd := make([]byte, 1) for { conn.SetReadDeadline(time.Now().Add(rep.conf.NetTimeout)) if _, err := conn.Read(cmd); err != nil { logf("Read failed: %v", err) return } switch cmd[0] { case cmdGetInfo: if err := sendJSON(rep.Info(), conn, rep.conf.NetTimeout); err != nil { logf("Failed to send info: %s", err) return } case cmdSendState: if err := rep.sendState(conn); err != nil { if !rep.stopped() { logf("Failed to send state: %s", err) } return } case cmdStreamWAL: err := rep.wal.Send(conn, rep.conf.NetTimeout) if !rep.stopped() { logf("Failed when sending WAL: %s", err) } return } } }