Pipe the output of debug commands into the right target writer. This fixes hidden responses in the debug terminal via websocket.

This commit is contained in:
Kleissner
2022-01-12 16:51:18 +01:00
parent 0bc0d007a4
commit 5260dc354e
5 changed files with 93 additions and 84 deletions

View File

@@ -9,6 +9,7 @@ package main
import (
"encoding/hex"
"fmt"
"io"
"github.com/PeernetOfficial/core"
"github.com/PeernetOfficial/core/blockchain"
@@ -17,10 +18,10 @@ import (
const maxBlockSize = 1 * 1024 * 1024
func blockTransfer(peer *core.PeerInfo, blockNumber uint64) {
func blockTransfer(peer *core.PeerInfo, blockNumber uint64, output io.Writer) {
conn, _, err := peer.BlockTransferRequest(peer.PublicKey, 1, maxBlockSize, []protocol.BlockRange{{Offset: uint64(blockNumber), Limit: 1}})
if err != nil {
fmt.Printf("Error starting block transfer: %s\n", err.Error())
fmt.Fprintf(output, "Error starting block transfer: %s\n", err.Error())
return
}
@@ -28,92 +29,92 @@ func blockTransfer(peer *core.PeerInfo, blockNumber uint64) {
conn.Close()
if err != nil {
fmt.Printf("Error reading block (indicated block size %d) from remote: %s\n", blockSize, err.Error())
fmt.Fprintf(output, "Error reading block (indicated block size %d) from remote: %s\n", blockSize, err.Error())
return
} else if targetBlock.Limit != 1 || targetBlock.Offset != blockNumber {
fmt.Printf("Error mismatch requested block %d with returned block %d (count %d)\n", blockNumber, targetBlock.Offset, targetBlock.Limit)
fmt.Fprintf(output, "Error mismatch requested block %d with returned block %d (count %d)\n", blockNumber, targetBlock.Offset, targetBlock.Limit)
return
} else if availability == protocol.GetBlockStatusNotAvailable { // Block range not available
fmt.Printf("Error requested block %d not available\n", blockNumber)
fmt.Fprintf(output, "Error requested block %d not available\n", blockNumber)
return
} else if availability == protocol.GetBlockStatusSizeExceed { // Block range exceeds size limit
fmt.Printf("Error block %d reported by remote as exceeding size %d (limit %d)\n", blockNumber, blockSize, maxBlockSize)
fmt.Fprintf(output, "Error block %d reported by remote as exceeding size %d (limit %d)\n", blockNumber, blockSize, maxBlockSize)
return
} else if availability != protocol.GetBlockStatusAvailable {
fmt.Printf("Error requested block %d unknown availability indicator %d\n", blockNumber, availability)
fmt.Fprintf(output, "Error requested block %d unknown availability indicator %d\n", blockNumber, availability)
return
}
decoded, status, err := blockchain.DecodeBlockRaw(data)
if err != nil {
fmt.Printf("Error decoding block: %s\n", err.Error())
fmt.Fprintf(output, "Error decoding block: %s\n", err.Error())
return
} else if status != blockchain.StatusOK {
fmt.Printf("Error decoding block status is %d\n", status)
fmt.Fprintf(output, "Error decoding block status is %d\n", status)
return
}
fmt.Printf("Block %d from %s: version %d, number %d, block size %d, decoded %d records\n", blockNumber, hex.EncodeToString(peer.PublicKey.SerializeCompressed()), decoded.BlockchainVersion, decoded.Number, len(data), len(decoded.RecordsDecoded))
fmt.Fprintf(output, "Block %d from %s: version %d, number %d, block size %d, decoded %d records\n", blockNumber, hex.EncodeToString(peer.PublicKey.SerializeCompressed()), decoded.BlockchainVersion, decoded.Number, len(data), len(decoded.RecordsDecoded))
for _, decodedR := range decoded.RecordsDecoded {
if file, ok := decodedR.(blockchain.BlockRecordFile); ok {
blockPrintFile(file)
blockPrintFile(file, output)
} else if recordsProfile, ok := decodedR.([]blockchain.BlockRecordProfile); ok {
for _, recordP := range recordsProfile {
blockPrintProfileField(recordP)
blockPrintProfileField(recordP, output)
}
} else {
fmt.Printf("* Unknown record.\n")
fmt.Fprintf(output, "* Unknown record.\n")
}
}
}
func blockPrintFile(file blockchain.BlockRecordFile) {
fmt.Printf("* File %s\n", file.ID.String())
fmt.Printf(" Size %d\n", file.Size)
fmt.Printf(" Type %d\n", file.Type)
fmt.Printf(" Format %d\n", file.Format)
fmt.Printf(" Hash %s\n", hex.EncodeToString(file.Hash))
fmt.Printf(" Merkle Root Hash %s\n", hex.EncodeToString(file.MerkleRootHash))
fmt.Printf(" Fragment Size %d\n", file.FragmentSize)
func blockPrintFile(file blockchain.BlockRecordFile, output io.Writer) {
fmt.Fprintf(output, "* File %s\n", file.ID.String())
fmt.Fprintf(output, " Size %d\n", file.Size)
fmt.Fprintf(output, " Type %d\n", file.Type)
fmt.Fprintf(output, " Format %d\n", file.Format)
fmt.Fprintf(output, " Hash %s\n", hex.EncodeToString(file.Hash))
fmt.Fprintf(output, " Merkle Root Hash %s\n", hex.EncodeToString(file.MerkleRootHash))
fmt.Fprintf(output, " Fragment Size %d\n", file.FragmentSize)
for _, tag := range file.Tags {
switch tag.Type {
case blockchain.TagName:
fmt.Printf(" Name %s\n", tag.Text())
fmt.Fprintf(output, " Name %s\n", tag.Text())
case blockchain.TagFolder:
fmt.Printf(" Folder %s\n", tag.Text())
fmt.Fprintf(output, " Folder %s\n", tag.Text())
case blockchain.TagDescription:
fmt.Printf(" Description %s\n", tag.Text())
fmt.Fprintf(output, " Description %s\n", tag.Text())
}
}
}
func blockPrintProfileField(field blockchain.BlockRecordProfile) {
func blockPrintProfileField(field blockchain.BlockRecordProfile, output io.Writer) {
switch field.Type {
case blockchain.ProfileName:
fmt.Printf("* Profile Name = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile Name = %s\n", string(field.Data))
case blockchain.ProfileEmail:
fmt.Printf("* Profile Email = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile Email = %s\n", string(field.Data))
case blockchain.ProfileWebsite:
fmt.Printf("* Profile Website = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile Website = %s\n", string(field.Data))
case blockchain.ProfileTwitter:
fmt.Printf("* Profile Twitter = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile Twitter = %s\n", string(field.Data))
case blockchain.ProfileYouTube:
fmt.Printf("* Profile YouTube = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile YouTube = %s\n", string(field.Data))
case blockchain.ProfileAddress:
fmt.Printf("* Profile Address = %s\n", string(field.Data))
fmt.Fprintf(output, "* Profile Address = %s\n", string(field.Data))
case blockchain.ProfilePicture:
fmt.Printf("* Profile Picture. Size %d\n", len(field.Data))
fmt.Fprintf(output, "* Profile Picture. Size %d\n", len(field.Data))
default:
fmt.Printf("* Field %d = %s\n", field.Type, hex.EncodeToString(field.Data))
fmt.Fprintf(output, "* Field %d = %s\n", field.Type, hex.EncodeToString(field.Data))
}
}

View File

@@ -10,6 +10,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
"io"
"sync"
"time"
@@ -20,16 +21,16 @@ import (
)
// debugCmdConnect connects to the node ID
func debugCmdConnect(backend *core.Backend, nodeID []byte) {
fmt.Printf("---------------- Connect to node %s ----------------\n", hex.EncodeToString(nodeID))
defer fmt.Printf("---------------- done node %s ----------------\n", hex.EncodeToString(nodeID))
func debugCmdConnect(backend *core.Backend, nodeID []byte, output io.Writer) {
fmt.Fprintf(output, "---------------- Connect to node %s ----------------\n", hex.EncodeToString(nodeID))
defer fmt.Fprintf(output, "---------------- done node %s ----------------\n", hex.EncodeToString(nodeID))
// in local DHT list?
_, peer := backend.IsNodeContact(nodeID)
if peer != nil {
fmt.Printf("* In local routing table: Yes.\n")
fmt.Fprintf(output, "* In local routing table: Yes.\n")
} else {
fmt.Printf("* In local routing table: No. Lookup via DHT. Timeout = 10 seconds.\n")
fmt.Fprintf(output, "* In local routing table: No. Lookup via DHT. Timeout = 10 seconds.\n")
hashMonitorControl(nodeID, 0)
defer hashMonitorControl(nodeID, 1)
@@ -37,30 +38,30 @@ func debugCmdConnect(backend *core.Backend, nodeID []byte) {
// Discovery via DHT.
_, peer, _ = backend.FindNode(nodeID, time.Second*10)
if peer == nil {
fmt.Printf("* Not found via DHT :(\n")
fmt.Fprintf(output, "* Not found via DHT :(\n")
return
}
fmt.Printf("* Successfully discovered via DHT.\n")
fmt.Fprintf(output, "* Successfully discovered via DHT.\n")
}
fmt.Printf("* Peer details:\n")
fmt.Printf(" Uncontacted: %t\n", peer.IsVirtual())
fmt.Printf(" Root peer: %t\n", peer.IsRootPeer)
fmt.Printf(" User Agent: %s\n", peer.UserAgent)
fmt.Printf(" Firewall: %t\n", peer.IsFirewallReported())
fmt.Fprintf(output, "* Peer details:\n")
fmt.Fprintf(output, " Uncontacted: %t\n", peer.IsVirtual())
fmt.Fprintf(output, " Root peer: %t\n", peer.IsRootPeer)
fmt.Fprintf(output, " User Agent: %s\n", peer.UserAgent)
fmt.Fprintf(output, " Firewall: %t\n", peer.IsFirewallReported())
// virtual peer?
if peer.IsVirtual() {
fmt.Printf("* Peer is virtual and was not contacted before. Sending out ping.\n")
fmt.Fprintf(output, "* Peer is virtual and was not contacted before. Sending out ping.\n")
peer.Ping()
} else {
fmt.Printf("* Connections:\n")
fmt.Printf("%s", textPeerConnections(peer))
fmt.Fprintf(output, "* Connections:\n")
fmt.Fprintf(output, "%s", textPeerConnections(peer))
}
// ping via all connections TODO
//fmt.Printf("* Sending ping:\n")
//fmt.Fprintf(output, "* Sending ping:\n")
}
// ---- filter for outgoing DHT searches ----

View File

@@ -314,7 +314,7 @@ func userCommands(backend *core.Backend, input io.Reader, output io.Writer, term
break
}
debugCmdConnect(backend, nodeID)
debugCmdConnect(backend, nodeID, output)
case "debug watch searches":
fmt.Fprintf(output, "Enable (1) or disable (0) watching of all outgoing DHT searches? (current setting: %t)\n", enableMonitorAll)
@@ -403,7 +403,7 @@ func userCommands(backend *core.Backend, input io.Reader, output io.Writer, term
break
}
go transferCompareFile(peer, fileHash)
go transferCompareFile(peer, fileHash, output)
case "get block":
fmt.Fprintf(output, "Enter peer ID or node ID:\n")
@@ -441,7 +441,7 @@ func userCommands(backend *core.Backend, input io.Reader, output io.Writer, term
break
}
go blockTransfer(peer, uint64(blockNumber))
go blockTransfer(peer, uint64(blockNumber), output)
case "exit":
backend.Filters.LogError("userCommands", "graceful exit via user terminal command\n")
@@ -455,14 +455,14 @@ func userCommands(backend *core.Backend, input io.Reader, output io.Writer, term
results := backend.SearchIndex.Search(text)
if len(results) == 0 {
fmt.Printf("No results found.\n")
fmt.Fprintf(output, "No results found.\n")
break
}
for _, result := range results {
fmt.Printf("- File ID %s\n", result.FileID.String())
fmt.Printf(" Public Key %s\n", hex.EncodeToString(result.PublicKey.SerializeCompressed()))
fmt.Printf(" Block Number %d\n", result.BlockNumber)
fmt.Fprintf(output, "- File ID %s\n", result.FileID.String())
fmt.Fprintf(output, " Public Key %s\n", hex.EncodeToString(result.PublicKey.SerializeCompressed()))
fmt.Fprintf(output, " Block Number %d\n", result.BlockNumber)
keywords := ""
for n, selector := range result.Selectors {
if n > 0 {
@@ -470,8 +470,11 @@ func userCommands(backend *core.Backend, input io.Reader, output io.Writer, term
}
keywords += selector.Word
}
fmt.Printf(" Found via keywords %s\n", keywords)
fmt.Fprintf(output, " Found via keywords %s\n", keywords)
}
default:
fmt.Fprintf(output, "Unknown command.\n")
}
}
}

View File

@@ -10,6 +10,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
"io"
"time"
"github.com/PeernetOfficial/core"
@@ -21,48 +22,48 @@ import (
// transferCompareFile downloads a file from a remote peer and compares it with the same file in the local warehouse.
// This function exists to test a file transfer.
// Note: The file MUST be stored locally, otherwise this function fails.
func transferCompareFile(peer *core.PeerInfo, fileHash []byte) {
func transferCompareFile(peer *core.PeerInfo, fileHash []byte, output io.Writer) {
// check if the file exists locally
_, fileInfo, status, _ := peer.Backend.UserWarehouse.FileExists(fileHash)
if status != warehouse.StatusOK {
fmt.Printf("File does not exist in local warehouse: %s\n", hex.EncodeToString(fileHash))
fmt.Fprintf(output, "File does not exist in local warehouse: %s\n", hex.EncodeToString(fileHash))
return
}
expectedSize := fileInfo.Size()
// peer must be connected
if !peer.IsConnectionActive() {
fmt.Printf("Peer has no active connection: %s\n", hex.EncodeToString(peer.NodeID))
fmt.Fprintf(output, "Peer has no active connection: %s\n", hex.EncodeToString(peer.NodeID))
return
}
fmt.Printf("1. Peer connected: %s\n", hex.EncodeToString(peer.NodeID))
fmt.Fprintf(output, "1. Peer connected: %s\n", hex.EncodeToString(peer.NodeID))
// request file transfer
udtConn, virtualConn, err := peer.FileTransferRequestUDT(fileHash, 0, 0)
if err != nil {
fmt.Printf("Error opening UDT connection: %s\n", err)
fmt.Fprintf(output, "Error opening UDT connection: %s\n", err)
return
}
defer udtConn.Close()
fmt.Printf("2. Opened UDT connection for file: %s\n", hex.EncodeToString(fileHash))
fmt.Fprintf(output, "2. Opened UDT connection for file: %s\n", hex.EncodeToString(fileHash))
fileSize, transferSize, err := protocol.FileTransferReadHeader(udtConn)
if err != nil {
fmt.Printf("Error reading file transfer header: %s\n", err)
fmt.Fprintf(output, "Error reading file transfer header: %s\n", err)
return
}
if fileSize != uint64(expectedSize) {
fmt.Printf("Error expected local file size %d mismatch with remote file size %d\n", expectedSize, fileSize)
fmt.Fprintf(output, "Error expected local file size %d mismatch with remote file size %d\n", expectedSize, fileSize)
return
} else if fileSize != transferSize {
fmt.Printf("Error remote peer only offering %d of total file size %d\n", transferSize, fileSize)
fmt.Fprintf(output, "Error remote peer only offering %d of total file size %d\n", transferSize, fileSize)
return
}
fmt.Printf("3. Matching transfer size %d and file size %d\n", transferSize, expectedSize)
fmt.Fprintf(output, "3. Matching transfer size %d and file size %d\n", transferSize, expectedSize)
// Previous: Loop in explicitly 512 bytes (which is the same buffer as io.Copy apparently) and compare with what is expected.
// Now use 4 KB buffer.
@@ -86,13 +87,13 @@ func transferCompareFile(peer *core.PeerInfo, fileHash []byte) {
data = data[:n]
if err != nil {
fmt.Printf("-- TERMINATE: ERROR READING. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
fmt.Fprintf(output, "-- TERMINATE: ERROR READING. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
break
} else if n == 0 {
fmt.Printf("-- TERMINATE: EMPTY READ but no error indicated. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
fmt.Fprintf(output, "-- TERMINATE: EMPTY READ but no error indicated. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
break
} else if dataRemaining <= 0 {
fmt.Printf("-- TERMINATE: EVERYTHING READ. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
fmt.Fprintf(output, "-- TERMINATE: EVERYTHING READ. Read %d bytes. Total read %d : %v\n", n, fileOffset+n, err)
break
}
@@ -101,46 +102,46 @@ func transferCompareFile(peer *core.PeerInfo, fileHash []byte) {
compareBuffer := bytes.NewBuffer(dataCompare)
_, bytesRead, err := peer.Backend.UserWarehouse.ReadFile(fileHash, int64(fileOffset), int64(n), compareBuffer)
if err != nil {
fmt.Printf("Warehouse error reading at offset %d length %d: %v\n", fileOffset, n, err)
fmt.Fprintf(output, "Warehouse error reading at offset %d length %d: %v\n", fileOffset, n, err)
break
} else if int(bytesRead) != n {
fmt.Printf("Warehouse did not read full data. Requested %d, provided %d.\n", n, bytesRead)
fmt.Fprintf(output, "Warehouse did not read full data. Requested %d, provided %d.\n", n, bytesRead)
break
}
dataCompare = compareBuffer.Bytes()
// make the comparison
if !bytes.Equal(data, dataCompare) {
fmt.Printf("Offset %08X read %d DATA MISMATCH:\n", fileOffset, n)
fmt.Printf("---- DATA FROM REMOTE:\n%s\n", hex.Dump(data))
fmt.Printf("---- DATA FROM LOCAL WAREHOUSE:\n%s\n", hex.Dump(dataCompare))
fmt.Fprintf(output, "Offset %08X read %d DATA MISMATCH:\n", fileOffset, n)
fmt.Fprintf(output, "---- DATA FROM REMOTE:\n%s\n", hex.Dump(data))
fmt.Fprintf(output, "---- DATA FROM LOCAL WAREHOUSE:\n%s\n", hex.Dump(dataCompare))
break
}
// status update every few seconds
//fmt.Printf("Offset %08X read %d SUCCESS\n", fileOffset, n)
//fmt.Fprintf(output, "Offset %08X read %d SUCCESS\n", fileOffset, n)
if time.Now().After(timeUpdateLast.Add(time.Second)) {
speed := float64(totalRead) / time.Since(timeStart).Seconds() / 1024
fmt.Printf("Offset %08X progress %.2f %% MATCHING. Speed: %.2f KB/s\n", fileOffset, float64((fileOffset+n)*100)/float64(fileSize), speed)
fmt.Fprintf(output, "Offset %08X progress %.2f %% MATCHING. Speed: %.2f KB/s\n", fileOffset, float64((fileOffset+n)*100)/float64(fileSize), speed)
timeUpdateLast = time.Now()
}
fileOffset += n
}
fmt.Printf("Terminate reason %d: %s\n", virtualConn.GetTerminateReason(), translateTerminateReason(virtualConn.GetTerminateReason()))
fmt.Fprintf(output, "Terminate reason %d: %s\n", virtualConn.GetTerminateReason(), translateTerminateReason(virtualConn.GetTerminateReason()))
speed := float64(totalRead) / time.Since(timeStart).Seconds() / 1024
fmt.Printf("Transfer took %s. Speed is %.2f KB/s\n", time.Since(timeStart).String(), speed)
fmt.Fprintf(output, "Transfer took %s. Speed is %.2f KB/s\n", time.Since(timeStart).String(), speed)
if totalRead != int(expectedSize) {
fmt.Printf("Error transferred data %d mismatch with reported file size %d\n", totalRead, fileSize)
fmt.Fprintf(output, "Error transferred data %d mismatch with reported file size %d\n", totalRead, fileSize)
return
}
fmt.Printf("Finished reading total of %d bytes. Expected %d bytes.\n", totalRead, fileSize)
fmt.Fprintf(output, "Finished reading total of %d bytes. Expected %d bytes.\n", totalRead, fileSize)
}
func translateTerminateReason(reason int) string {
@@ -179,7 +180,7 @@ func translateTerminateReason(reason int) string {
/*
// downloadFile downloads the file from the target peer
func downloadFile(publicKey *btcec.PublicKey, hash []byte) (data []byte, err error) {
func downloadFile(output io.Writer, publicKey *btcec.PublicKey, hash []byte) (data []byte, err error) {
peer := core.PeerlistLookup(publicKey)
if peer == nil {
return nil, errors.New("peer not connected")
@@ -196,13 +197,13 @@ func downloadFile(publicKey *btcec.PublicKey, hash []byte) (data []byte, err err
return nil, err
}
fmt.Printf("* Indicated file size = %d. Target transfer size = %d\n", fileSize, transferSize)
fmt.Fprintf(output, "* Indicated file size = %d. Target transfer size = %d\n", fileSize, transferSize)
// read all data
data = make([]byte, transferSize)
n, err := udtConn.Read(data)
fmt.Printf("* Read %d bytes (target %d), error: %v\n", n, transferSize, err)
fmt.Fprintf(output, "* Read %d bytes (target %d), error: %v\n", n, transferSize, err)
return data, err
}

View File

@@ -18,6 +18,9 @@ const configFile = "Config.yaml"
const appName = "Peernet Cmd"
var config struct {
// Warning: These settings are currently overwritten (deleted) when the config file is updated by core.
// In the future the core package will consider custom config fields.
// Log settings
ErrorOutput int `yaml:"ErrorOutput"` // 0 = Log file (default), 1 = Command line, 2 = Log file + command line, 3 = None
DebugAPI bool `yaml:"DebugAPI"` // Enables the debug API which allows profiling. Do not enable in production. Only available if compiled with debug tag.