From 5c8b8eb94bd764e074b7a3ca72ca550fbfcd1990 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Thu, 6 Jan 2022 04:11:28 +0100 Subject: [PATCH] Implement backend.Stdout that can be subscribed/unsubscribed. --- Commands.go | 3 ++- Filter.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ Peernet.go | 4 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Commands.go b/Commands.go index 1613fb5..9a7b413 100644 --- a/Commands.go +++ b/Commands.go @@ -8,6 +8,7 @@ package core import ( "bytes" + "encoding/hex" "fmt" "github.com/PeernetOfficial/core/dht" @@ -214,7 +215,7 @@ func (peer *PeerInfo) cmdPong(msg *protocol.MessageRaw, connection *Connection) // cmdChat handles a chat message [debug] func (peer *PeerInfo) cmdChat(msg *protocol.MessageRaw, connection *Connection) { - fmt.Printf("Chat from '%s': %s\n", connection.Address.String(), string(msg.PacketRaw.Payload)) + fmt.Fprintf(peer.Backend.Stdout, "Chat from %s '%s': %s\n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()), connection.Address.String(), string(msg.PacketRaw.Payload)) } // cmdLocalDiscovery handles an incoming announcement via local discovery diff --git a/Filter.go b/Filter.go index c782746..cd69e85 100644 --- a/Filter.go +++ b/Filter.go @@ -9,12 +9,15 @@ Filters allow the caller to intercept events. The filter functions must not modi package core import ( + "io" "log" + "sync" "github.com/PeernetOfficial/core/blockchain" "github.com/PeernetOfficial/core/btcec" "github.com/PeernetOfficial/core/dht" "github.com/PeernetOfficial/core/protocol" + "github.com/google/uuid" ) // Filters contains all functions to install the hook. Use nil for unused. @@ -123,3 +126,45 @@ func (backend *Backend) initFilters() { func DefaultLogError(function, format string, v ...interface{}) { log.Printf("["+function+"] "+format, v...) } + +// MultiWriter code that allows to subscribe/unsubscribe. +type multiWriter struct { + writers map[uuid.UUID]io.Writer + sync.Mutex +} + +// Creates a new writer that duplicates its writes to all the subscribed writers. +// Each write is written to each subscribed writer, one at a time. If any writer returns an error, the entire write operation continues. +func newMultiWriter() *multiWriter { + return &multiWriter{writers: make(map[uuid.UUID]io.Writer)} +} + +// Subscribe a new writer to the list of writers +func (m *multiWriter) Subscribe(writer io.Writer) (id uuid.UUID) { + m.Lock() + defer m.Unlock() + + id = uuid.New() + m.writers[id] = writer + + return id +} + +// Unsubscribe a writer from the list of writers +func (m *multiWriter) Unsubscribe(id uuid.UUID) { + m.Lock() + defer m.Unlock() + + delete(m.writers, id) +} + +// Write a slice of byte to each of the subscribed writers. It will not return any errors. +func (m *multiWriter) Write(p []byte) (n int, err error) { + m.Lock() + defer m.Unlock() + + for _, w := range m.writers { + w.Write(p) + } + return len(p), nil +} diff --git a/Peernet.go b/Peernet.go index db28a03..8f9c8d6 100644 --- a/Peernet.go +++ b/Peernet.go @@ -29,6 +29,7 @@ func Init(UserAgent string, ConfigFilename string, Filters *Filters) (backend *B backend = &Backend{ ConfigFilename: ConfigFilename, userAgent: UserAgent, + Stdout: newMultiWriter(), } if Filters != nil { @@ -108,4 +109,7 @@ type Backend struct { // peerMonitor is a list of channels receiving information about new peers peerMonitor []chan<- *PeerInfo + + // Stdout bundles any output for the end-user. Writers may subscribe/unsubscribe. + Stdout *multiWriter }