wdcli: Use progress writer instead of IOStream
This commit is contained in:
parent
890022ae64
commit
3b78b06fff
49 changed files with 396 additions and 393 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue