From 5260dc354e55e9c91a8c2100413ded9821c32ee2 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Wed, 12 Jan 2022 16:51:18 +0100 Subject: [PATCH] Pipe the output of debug commands into the right target writer. This fixes hidden responses in the debug terminal via websocket. --- Block Transfer.go | 67 ++++++++++++++++++++++++----------------------- Command Debug.go | 33 ++++++++++++----------- Command Line.go | 19 ++++++++------ File Transfer.go | 55 +++++++++++++++++++------------------- Main.go | 3 +++ 5 files changed, 93 insertions(+), 84 deletions(-) diff --git a/Block Transfer.go b/Block Transfer.go index 2aa11b7..234f94f 100644 --- a/Block Transfer.go +++ b/Block Transfer.go @@ -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)) } } diff --git a/Command Debug.go b/Command Debug.go index 824c91f..8e0b79e 100644 --- a/Command Debug.go +++ b/Command Debug.go @@ -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 ---- diff --git a/Command Line.go b/Command Line.go index 0eb6213..67dbef3 100644 --- a/Command Line.go +++ b/Command Line.go @@ -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") } } } diff --git a/File Transfer.go b/File Transfer.go index 5c1dc9b..ea1a0b9 100644 --- a/File Transfer.go +++ b/File Transfer.go @@ -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 } diff --git a/Main.go b/Main.go index 4e2d46d..e7b8fec 100644 --- a/Main.go +++ b/Main.go @@ -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.