tractor.dev/toolkit-go@v0.0.0-20241010005851-214d91207d07/duplex/mux/frame/decoder.go (about) 1 package frame 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 "sync" 10 ) 11 12 // Decoder decodes messages given an io.Reader 13 type Decoder struct { 14 r io.Reader 15 sync.Mutex 16 } 17 18 func NewDecoder(r io.Reader) *Decoder { 19 return &Decoder{r: r} 20 } 21 22 func (dec *Decoder) Decode() (Message, error) { 23 dec.Lock() 24 defer dec.Unlock() 25 26 var msgNum [1]byte 27 _, err := io.ReadFull(dec.r, msgNum[:]) 28 if err != nil { 29 var syscallErr *os.SyscallError 30 if errors.As(err, &syscallErr) { //&& syscallErr.Err == syscall.ECONNRESET { // syscall.ECONNRESET not supported by tinygo 0.28.1 31 return nil, io.EOF 32 } 33 return nil, err 34 } 35 36 var msg Message 37 msg, err = messageFrom(msgNum) 38 if err != nil { 39 return nil, err 40 } 41 42 if msgNum[0] == msgChannelData { 43 var data struct { 44 ChannelID uint32 45 Length uint32 46 } 47 if err := binary.Read(dec.r, binary.BigEndian, &data); err != nil { 48 return nil, err 49 } 50 dataMsg := msg.(*DataMessage) 51 dataMsg.ChannelID = data.ChannelID 52 dataMsg.Length = data.Length 53 dataMsg.Data = make([]byte, data.Length) 54 _, err := io.ReadFull(dec.r, dataMsg.Data) 55 if err != nil { 56 return nil, err 57 } 58 } else { 59 if err := binary.Read(dec.r, binary.BigEndian, msg); err != nil { 60 return nil, err 61 } 62 } 63 64 if Debug != nil { 65 fmt.Fprintln(Debug, ">>DEC", msg) 66 } 67 68 return msg, nil 69 } 70 71 func messageFrom(num [1]byte) (Message, error) { 72 switch num[0] { 73 case msgChannelOpen: 74 return new(OpenMessage), nil 75 case msgChannelData: 76 return new(DataMessage), nil 77 case msgChannelOpenConfirm: 78 return new(OpenConfirmMessage), nil 79 case msgChannelOpenFailure: 80 return new(OpenFailureMessage), nil 81 case msgChannelWindowAdjust: 82 return new(WindowAdjustMessage), nil 83 case msgChannelEOF: 84 return new(EOFMessage), nil 85 case msgChannelClose: 86 return new(CloseMessage), nil 87 default: 88 return nil, fmt.Errorf("qtalk: unexpected message type %d", num[0]) 89 } 90 }