Frame-by-frame IMQ with an outgoing filter; HTTP interceptor hook
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
2551888ed6
commit
2190230f81
6 files changed
+485
-24
No files matched your search
@@ -0,0 +1,120 @@
|
||||
package imq
|
||||
|
||||
import "errors"
|
||||
|
||||
// Message types the proxy reads or writes.
|
||||
const (
|
||||
C2gSendMessage = 1304
|
||||
G2cResult = 3102
|
||||
)
|
||||
|
||||
// SendMessage is a C2gSendMessage: a message the client sends to a queue's mount.
|
||||
type SendMessage struct {
|
||||
OpID uint64
|
||||
Queue string
|
||||
Mount string
|
||||
Message []byte
|
||||
}
|
||||
|
||||
// field is one protobuf field: its number and either a varint or bytes.
|
||||
type field struct {
|
||||
num uint64
|
||||
varint uint64
|
||||
bytes []byte
|
||||
isLen bool
|
||||
}
|
||||
|
||||
func fields(b []byte) ([]field, error) {
|
||||
var out []field
|
||||
for i := 0; i < len(b); {
|
||||
key, n := varint(b[i:])
|
||||
if n <= 0 {
|
||||
return nil, ErrMalformed
|
||||
}
|
||||
i += n
|
||||
f := field{num: key >> 3}
|
||||
switch key & 7 {
|
||||
case 0:
|
||||
v, n := varint(b[i:])
|
||||
if n <= 0 {
|
||||
return nil, ErrMalformed
|
||||
}
|
||||
f.varint, i = v, i+n
|
||||
case 2:
|
||||
l, n := varint(b[i:])
|
||||
if n <= 0 || l > uint64(len(b)-i-n) {
|
||||
return nil, ErrMalformed
|
||||
}
|
||||
i += n
|
||||
f.bytes, f.isLen, i = b[i:i+int(l)], true, i+int(l)
|
||||
default:
|
||||
return nil, ErrMalformed
|
||||
}
|
||||
out = append(out, f)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ParseSendMessage reads a C2gSendMessage's data.
|
||||
func ParseSendMessage(data []byte) (SendMessage, error) {
|
||||
fs, err := fields(data)
|
||||
if err != nil {
|
||||
return SendMessage{}, err
|
||||
}
|
||||
var m SendMessage
|
||||
seen := 0
|
||||
for _, f := range fs {
|
||||
switch {
|
||||
case f.num == 1 && !f.isLen:
|
||||
m.OpID, seen = f.varint, seen|1
|
||||
case f.num == 2 && f.isLen:
|
||||
m.Queue, seen = string(f.bytes), seen|2
|
||||
case f.num == 3 && f.isLen:
|
||||
m.Mount, seen = string(f.bytes), seen|4
|
||||
case f.num == 4 && f.isLen:
|
||||
m.Message, seen = f.bytes, seen|8
|
||||
default:
|
||||
return SendMessage{}, errors.New("imq: unexpected field in C2gSendMessage")
|
||||
}
|
||||
}
|
||||
if seen != 15 {
|
||||
return SendMessage{}, errors.New("imq: C2gSendMessage is missing fields")
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Marshal encodes the message's data, fields in the client's order.
|
||||
func (m SendMessage) Marshal() []byte {
|
||||
var b []byte
|
||||
b = appendVarintField(b, 1, m.OpID)
|
||||
b = appendBytesField(b, 2, []byte(m.Queue))
|
||||
b = appendBytesField(b, 3, []byte(m.Mount))
|
||||
return appendBytesField(b, 4, m.Message)
|
||||
}
|
||||
|
||||
// Result encodes a G2cResult's data: the answer to the operation opID (status 0 is success).
|
||||
func Result(opID, status uint64) []byte {
|
||||
return appendVarintField(appendVarintField(nil, 1, opID), 2, status)
|
||||
}
|
||||
|
||||
// EncodeFrame wraps a message's data in a frame of the given type.
|
||||
func EncodeFrame(t uint64, data []byte) []byte {
|
||||
return appendBytesField(appendVarintField(nil, 1, t), 2, data)
|
||||
}
|
||||
|
||||
func appendVarint(b []byte, v uint64) []byte {
|
||||
for v >= 0x80 {
|
||||
b = append(b, byte(v)|0x80)
|
||||
v >>= 7
|
||||
}
|
||||
return append(b, byte(v))
|
||||
}
|
||||
|
||||
func appendVarintField(b []byte, num, v uint64) []byte {
|
||||
return appendVarint(appendVarint(b, num<<3), v)
|
||||
}
|
||||
|
||||
func appendBytesField(b []byte, num uint64, v []byte) []byte {
|
||||
b = appendVarint(appendVarint(b, num<<3|2), uint64(len(v)))
|
||||
return append(b, v...)
|
||||
}
|
||||
Reference in new issue
Block a user