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  }