github.com/diamondburned/arikawa/v2@v2.1.0/internal/zlib/zlib.go (about) 1 // Package zlib provides abstractions on top of compress/zlib to work with 2 // Discord's method of compressing websocket packets. 3 package zlib 4 5 import ( 6 "bytes" 7 "log" 8 9 "github.com/pkg/errors" 10 ) 11 12 var Suffix = [4]byte{'\x00', '\x00', '\xff', '\xff'} 13 14 var ErrPartial = errors.New("only partial payload in buffer") 15 16 type Inflator struct { 17 zlib Reader 18 wbuf bytes.Buffer // write buffer for writing compressed bytes 19 rbuf bytes.Buffer // read buffer for writing uncompressed bytes 20 } 21 22 func NewInflator() *Inflator { 23 return &Inflator{ 24 wbuf: bytes.Buffer{}, 25 rbuf: bytes.Buffer{}, 26 } 27 } 28 29 func (i *Inflator) Write(p []byte) (n int, err error) { 30 log.Println(p) 31 // Write to buffer normally. 32 return i.wbuf.Write(p) 33 } 34 35 // CanFlush returns if Flush() should be called. 36 func (i *Inflator) CanFlush() bool { 37 if i.wbuf.Len() < 4 { 38 return false 39 } 40 p := i.wbuf.Bytes() 41 return bytes.Equal(p[len(p)-4:], Suffix[:]) 42 } 43 44 func (i *Inflator) Flush() ([]byte, error) { 45 // Check if close frames are there: 46 // if !i.CanFlush() { 47 // return nil, ErrPartial 48 // } 49 50 // log.Println(i.wbuf.Bytes()) 51 52 // We should reset the write buffer after flushing. 53 // defer i.wbuf.Reset() 54 55 // We can reset the read buffer while returning its byte slice. This works 56 // as long as we copy the byte slice before resetting. 57 defer i.rbuf.Reset() 58 59 // Guarantee there's a zlib writer. Since Discord streams zlib, we have to 60 // reuse the same Reader. Only the first packet has the zlib header. 61 if i.zlib == nil { 62 r, err := zlibStreamer(&i.wbuf) 63 if err != nil { 64 return nil, errors.Wrap(err, "failed to make a FLATE reader") 65 } 66 // safe assertion 67 i.zlib = r 68 // } else { 69 // // Reset the FLATE reader for future use: 70 // if err := i.zlib.Reset(&i.wbuf, nil); err != nil { 71 // return nil, errors.Wrap(err, "failed to reset zlib reader") 72 // } 73 } 74 75 // We can ignore zlib.Read's error, as zlib.Close would return them. 76 _, err := i.rbuf.ReadFrom(i.zlib) 77 78 // ErrUnexpectedEOF happens because zlib tries to find the last 4 bytes 79 // to verify checksum. Discord doesn't send this. 80 if err != nil { 81 // Unexpected error, try and close. 82 return nil, errors.Wrap(err, "failed to read from FLATE reader") 83 } 84 85 // if err := i.zlib.Close(); err != nil && err != io.ErrUnexpectedEOF { 86 // // Try and close anyway. 87 // return nil, errors.Wrap(err, "failed to read from zlib reader") 88 // } 89 90 // Copy the bytes. 91 return bytecopy(i.rbuf.Bytes()), nil 92 } 93 94 // func (d *Deflator) TryFlush() ([]byte, error) { 95 // // Check if the buffer ends with the zlib close suffix. 96 // if d.wbuf.Len() < 4 { 97 // return nil, nil 98 // } 99 // if p := d.wbuf.Bytes(); !bytes.Equal(p[len(p)-4:], Suffix[:]) { 100 // return nil, nil 101 // } 102 103 // // Guarantee there's a zlib writer. Since Discord streams zlib, we have to 104 // // reuse the same Reader. Only the first packet has the zlib header. 105 // if d.zlib == nil { 106 // r, err := zlib.NewReader(&d.wbuf) 107 // if err != nil { 108 // return nil, errors.Wrap(err, "failed to make a zlib reader") 109 // } 110 // // safe assertion 111 // d.zlib = r 112 // } 113 114 // // We can reset the read buffer while returning its byte slice. This works 115 // // as long as we copy the byte slice before resetting. 116 // defer d.rbuf.Reset() 117 118 // defer d.wbuf.Reset() 119 120 // // We can ignore zlib.Read's error, as zlib.Close would return them. 121 // _, err := d.rbuf.ReadFrom(d.zlib) 122 // log.Println("Read:", err, d.rbuf.String()) 123 124 // // ErrUnexpectedEOF happens because zlib tries to find the last 4 bytes 125 // // to verify checksum. Discord doesn't send this. 126 // // if err != nil && err != io.ErrUnexpectedEOF { 127 // // // Unexpected error, try and close. 128 // // return nil, errors.Wrap(err, "failed to read from zlib reader") 129 // // } 130 131 // if err := d.zlib.Close(); err != nil && err != io.ErrUnexpectedEOF { 132 // // Try and close anyway. 133 // return nil, errors.Wrap(err, "failed to read from zlib reader") 134 // } 135 136 // // Copy the bytes. 137 // return bytecopy(d.rbuf.Bytes()), nil 138 // } 139 140 func bytecopy(p []byte) []byte { 141 cpy := make([]byte, len(p)) 142 copy(cpy, p) 143 return cpy 144 }