wdcli: Use progress writer instead of IOStream

This commit is contained in:
Tom Wiesing 2022-11-30 11:39:29 +01:00
parent 890022ae64
commit 3b78b06fff
No known key found for this signature in database
49 changed files with 396 additions and 393 deletions

View file

@ -89,20 +89,21 @@ func (h *WebSocket) serveWebsocket(w http.ResponseWriter, r *http.Request) {
h.pool.Get(nil).Put(socket)
}
// WebSocketConnection represents a connected Websocket
// WebSocketConnection represents a connected WebSocket.
type WebSocketConnection interface {
// Context returns a context that is closed once this websocket is closed.
// Context returns a context that is closed once the connection is terminated.
Context() context.Context
// Read returns a channel that receives message.
// The channel is closed once no more messags are available.
// The channel is closed if no more messags are available (for instance because the server closed).
Read() <-chan WebSocketMessage
// Write queues the provided message for sending
// and returns a channel that is closed once the message has been sent.
// Write queues the provided message for sending.
// The returned channel is closed once the message has been sent.
Write(WebSocketMessage) <-chan struct{}
// WriteText is a convenience method to send a TextMessage
// WriteText is a convenience method to send a TextMessage.
// The returned channel is closed once the message has been sent.
WriteText(text string) <-chan struct{}
// Close closes the underlying connection

View file

@ -1,57 +1,108 @@
package logging
import (
"io"
"sync"
"github.com/tkw1536/goprogram/stream"
)
var logLevelMutex sync.Mutex
var logLevelMap = make(map[uintptr]int)
type writerIndent struct{}
func getIndent(io stream.IOStream) int {
logLevelMutex.Lock()
defer logLevelMutex.Unlock()
var indentKey = writerIndent{}
id, ok := logID(io)
func getIndent(writer io.Writer) int {
value, ok := getKey(writer, indentKey)
if !ok {
value = 0
}
return value.(int)
}
func incIndent(writer io.Writer) int {
value, ok := upsetKey(writer, indentKey, func(value any, fresh bool) any {
if fresh {
return 0
}
return value.(int) + 1
})
if !ok {
return 0
}
return logLevelMap[id]
return value.(int)
}
func incIndent(io stream.IOStream) int {
logLevelMutex.Lock()
defer logLevelMutex.Unlock()
id, ok := logID(io)
if !ok { // if we don't have an id, then inc statically returns 1
return 1
}
logLevelMap[id]++
return logLevelMap[id]
}
func decIndent(io stream.IOStream) int {
logLevelMutex.Lock()
defer logLevelMutex.Unlock()
id, ok := logID(io)
if !ok { // if we don't have an id, then dec statically returns 0
func decIndent(writer io.Writer) int {
value, ok := upsetKey(writer, indentKey, func(value any, fresh bool) any {
if fresh {
return 0
}
level := value.(int) - 1
if level < 0 {
level = 0
}
return level
})
if !ok {
return 0
}
logLevelMap[id]--
if logLevelMap[id] < 0 {
panic("DecLogIdent: decrease below 0")
}
return logLevelMap[id]
return value.(int)
}
func logID(io stream.IOStream) (uintptr, bool) {
file, ok := io.Stdin.(interface{ Fd() uintptr })
// KEY-VALUE STORE for writers
var writerDataMutex sync.RWMutex
var writerDataData = make(map[uintptr]map[any]any)
func getKey(writer io.Writer, key any) (value any, ok bool) {
uid, ok := id(writer)
if !ok {
return nil, false
}
writerDataMutex.RLock()
defer writerDataMutex.RUnlock()
value, ok = writerDataData[uid][key]
return
}
func setKey(writer io.Writer, key, value any) bool {
uid, ok := id(writer)
if !ok {
return false
}
writerDataMutex.Lock()
defer writerDataMutex.Unlock()
values, ok := writerDataData[uid]
if !ok {
values = make(map[any]any)
writerDataData[uid] = values
}
values[key] = value
return true
}
func upsetKey(writer io.Writer, key any, update func(value any, fresh bool) any) (any, bool) {
uid, ok := id(writer)
if !ok {
return nil, false
}
writerDataMutex.Lock()
defer writerDataMutex.Unlock()
values, ok := writerDataData[uid]
if !ok {
values = make(map[any]any)
writerDataData[uid] = values
}
values[key] = update(values[key], !ok)
return values[key], true
}
func id(writer io.Writer) (uintptr, bool) {
file, ok := writer.(interface{ Fd() uintptr })
if !ok {
return 0, false
}

View file

@ -1,30 +1,38 @@
package logging
import (
"fmt"
"io"
"strings"
"github.com/tkw1536/goprogram/stream"
"golang.org/x/term"
)
// LogOperation logs a message that is displayed to the user, and then increases the log indent level.
func LogOperation(operation func() error, io stream.IOStream, format string, args ...interface{}) error {
logOperation(io, getIndent(io), format, args...)
incIndent(io)
defer decIndent(io)
func LogOperation(operation func() error, progress io.Writer, format string, args ...interface{}) error {
logOperation(progress, getIndent(progress), format, args...)
incIndent(progress)
defer decIndent(progress)
return operation()
}
// LogMessage logs a message that is displayed to the user
func LogMessage(io stream.IOStream, format string, args ...interface{}) (int, error) {
return logOperation(io, getIndent(io), format, args...)
func LogMessage(progress io.Writer, format string, args ...interface{}) (int, error) {
return logOperation(progress, getIndent(progress), format, args...)
}
func logOperation(io stream.IOStream, indent int, format string, args ...interface{}) (int, error) {
func logOperation(progress io.Writer, indent int, format string, args ...interface{}) (int, error) {
message := "\033[1m" + strings.Repeat(" ", indent+1) + "=> " + format + "\033[0m\n"
if !io.StdoutIsATerminal() {
if !streamIsTerminal(progress) {
message = " => " + format + "\n"
}
return io.Printf(message, args...)
return fmt.Fprintf(progress, message, args...)
}
// streamIsTerminal checks if stream is a terminal
func streamIsTerminal(stream any) bool {
file, ok := stream.(interface{ Fd() uintptr })
return ok && term.IsTerminal(int(file.Fd()))
}