-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprinter.go
More file actions
125 lines (104 loc) · 3.28 KB
/
printer.go
File metadata and controls
125 lines (104 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package telnet
import (
"bufio"
"context"
"errors"
"io"
"net"
)
// TelnetPrinter is a Terminal subsidiary that parses text sent by the remote peer.
// This object is largely not used by consumers. It has a few methods that are consumed
// by telopts, but received text is largely handled through the Terminal itself.
type TelnetPrinter struct {
scanner *TelnetScanner
complete chan error
eventPump *terminalEventPump
promptCommands atomicPromptCommands
middlewares *MiddlewareStack
}
func newTelnetPrinter(charset *Charset, inputStream io.Reader, eventPump *terminalEventPump) *TelnetPrinter {
scanner := NewTelnetScanner(charset, inputStream)
printer := &TelnetPrinter{
scanner: scanner,
complete: make(chan error, 1),
eventPump: eventPump,
}
printer.promptCommands.Init()
return printer
}
func (p *TelnetPrinter) isSuppressedPromptCommand(t PromptCommands) bool {
promptCommands := p.promptCommands.Get()
return (t == PromptCommandGA && promptCommands&PromptCommandGA == 0) ||
(t == PromptCommandEOR && promptCommands&PromptCommandEOR == 0)
}
func (p *TelnetPrinter) printerLoop(ctx context.Context, terminal *Terminal) {
for ctx.Err() == nil && p.scanner.Scan(ctx) {
if p.scanner.Err() != nil {
// Don't worry about temporary errors
var netErr net.Error
if errors.As(p.scanner.Err(), &netErr) {
if netErr.Timeout() {
continue
}
}
p.eventPump.EncounteredError(p.scanner.Err())
} else if ctx.Err() != nil {
break
}
output := p.scanner.Output()
if output == nil {
continue
}
switch o := output.(type) {
case PromptData:
if p.isSuppressedPromptCommand(PromptCommands(o)) {
continue
}
case CommandData:
if o.Command.OpCode == 0 || o.Command.OpCode == NOP {
continue
}
terminal.processTelOptCommand(o.Command)
}
p.eventPump.EncounteredPrinterOutput(p.scanner.Output())
}
if ctx.Err() != nil && !errors.Is(ctx.Err(), context.Canceled) {
p.complete <- ctx.Err()
} else if p.scanner.Err() != nil && !errors.Is(p.scanner.Err(), net.ErrClosed) {
p.complete <- p.scanner.Err()
} else {
p.complete <- nil
}
}
// waitForExit will block until the printer is disposed of
func (p *TelnetPrinter) waitForExit() error {
err := <-p.complete
p.complete <- err
return err
}
// SetPromptCommand will activate a particular prompt command and permit
// it to be received by the printer. Prompt commands are IAC GA/IAC EOR, commands
// that indicate to the consumer where to place a prompt
func (p *TelnetPrinter) SetPromptCommand(flag PromptCommands) {
p.promptCommands.SetPromptCommand(flag)
}
// ClearPromptCommand will deactivate a particular prompt command and cause it
// to be ignored by the printer. Prompt commands are IAC GA/IAC EOR, commands
// that indicate to the consumer where to place a prompt
func (p *TelnetPrinter) ClearPromptCommand(flag PromptCommands) {
p.promptCommands.ClearPromptCommand(flag)
}
func (p *TelnetPrinter) WrapReader(wrap func(reader io.Reader) (io.Reader, error)) error {
wrapped, err := wrap(p.scanner.baseStream)
if err != nil {
return err
}
p.scanner.inputStream = wrapped
scan := bufio.NewScanner(wrapped)
scan.Split(p.scanner.ScanTelnet)
p.scanner.scanner = scan
return nil
}
func (p *TelnetPrinter) Middlewares() *MiddlewareStack {
return p.middlewares
}