github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/common/mux/writer.go (about)

     1  package mux
     2  
     3  import (
     4  	"github.com/xmplusdev/xmcore/common"
     5  	"github.com/xmplusdev/xmcore/common/buf"
     6  	"github.com/xmplusdev/xmcore/common/net"
     7  	"github.com/xmplusdev/xmcore/common/protocol"
     8  	"github.com/xmplusdev/xmcore/common/serial"
     9  )
    10  
    11  type Writer struct {
    12  	dest         net.Destination
    13  	writer       buf.Writer
    14  	id           uint16
    15  	followup     bool
    16  	hasError     bool
    17  	transferType protocol.TransferType
    18  	globalID     [8]byte
    19  }
    20  
    21  func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte) *Writer {
    22  	return &Writer{
    23  		id:           id,
    24  		dest:         dest,
    25  		writer:       writer,
    26  		followup:     false,
    27  		transferType: transferType,
    28  		globalID:     globalID,
    29  	}
    30  }
    31  
    32  func NewResponseWriter(id uint16, writer buf.Writer, transferType protocol.TransferType) *Writer {
    33  	return &Writer{
    34  		id:           id,
    35  		writer:       writer,
    36  		followup:     true,
    37  		transferType: transferType,
    38  	}
    39  }
    40  
    41  func (w *Writer) getNextFrameMeta() FrameMetadata {
    42  	meta := FrameMetadata{
    43  		SessionID: w.id,
    44  		Target:    w.dest,
    45  		GlobalID:  w.globalID,
    46  	}
    47  
    48  	if w.followup {
    49  		meta.SessionStatus = SessionStatusKeep
    50  	} else {
    51  		w.followup = true
    52  		meta.SessionStatus = SessionStatusNew
    53  	}
    54  
    55  	return meta
    56  }
    57  
    58  func (w *Writer) writeMetaOnly() error {
    59  	meta := w.getNextFrameMeta()
    60  	b := buf.New()
    61  	if err := meta.WriteTo(b); err != nil {
    62  		return err
    63  	}
    64  	return w.writer.WriteMultiBuffer(buf.MultiBuffer{b})
    65  }
    66  
    67  func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
    68  	frame := buf.New()
    69  	if len(data) == 1 {
    70  		frame.UDP = data[0].UDP
    71  	}
    72  	if err := meta.WriteTo(frame); err != nil {
    73  		return err
    74  	}
    75  	if _, err := serial.WriteUint16(frame, uint16(data.Len())); err != nil {
    76  		return err
    77  	}
    78  
    79  	mb2 := make(buf.MultiBuffer, 0, len(data)+1)
    80  	mb2 = append(mb2, frame)
    81  	mb2 = append(mb2, data...)
    82  	return writer.WriteMultiBuffer(mb2)
    83  }
    84  
    85  func (w *Writer) writeData(mb buf.MultiBuffer) error {
    86  	meta := w.getNextFrameMeta()
    87  	meta.Option.Set(OptionData)
    88  
    89  	return writeMetaWithFrame(w.writer, meta, mb)
    90  }
    91  
    92  // WriteMultiBuffer implements buf.Writer.
    93  func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
    94  	defer buf.ReleaseMulti(mb)
    95  
    96  	if mb.IsEmpty() {
    97  		return w.writeMetaOnly()
    98  	}
    99  
   100  	for !mb.IsEmpty() {
   101  		var chunk buf.MultiBuffer
   102  		if w.transferType == protocol.TransferTypeStream {
   103  			mb, chunk = buf.SplitSize(mb, 8*1024)
   104  		} else {
   105  			mb2, b := buf.SplitFirst(mb)
   106  			mb = mb2
   107  			chunk = buf.MultiBuffer{b}
   108  		}
   109  		if err := w.writeData(chunk); err != nil {
   110  			return err
   111  		}
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // Close implements common.Closable.
   118  func (w *Writer) Close() error {
   119  	meta := FrameMetadata{
   120  		SessionID:     w.id,
   121  		SessionStatus: SessionStatusEnd,
   122  	}
   123  	if w.hasError {
   124  		meta.Option.Set(OptionError)
   125  	}
   126  
   127  	frame := buf.New()
   128  	common.Must(meta.WriteTo(frame))
   129  
   130  	w.writer.WriteMultiBuffer(buf.MultiBuffer{frame})
   131  	return nil
   132  }