## Nim-LibP2P ## Copyright (c) 2019 Status Research & Development GmbH ## Licensed under either of ## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) ## * MIT license ([LICENSE-MIT](LICENSE-MIT)) ## at your option. ## This file may not be copied, modified, or distributed except according to ## those terms. import chronos import nimcrypto/utils, chronicles import types, ../../connection, ../../varint, ../../vbuffer, ../../stream/lpstream logScope: topic = "MplexCoder" const DefaultChannelSize* = 1 shl 20 type Msg* = tuple id: uint64 msgType: MessageType data: seq[byte] InvalidMplexMsgType = object of CatchableError proc newInvalidMplexMsgType*(): ref InvalidMplexMsgType = newException(InvalidMplexMsgType, "invalid message type") proc readMplexVarint(conn: Connection): Future[uint64] {.async, gcsafe.} = var varint: uint length: int res: VarintStatus buffer = newSeq[byte](10) try: for i in 0.. DefaultReadSize: raise newInvalidVarintSizeException() var data: seq[byte] = newSeq[byte](dataLenVarint.int) if dataLenVarint.int > 0: await conn.readExactly(addr data[0], dataLenVarint.int) trace "read data", data = data.len let msgType = header and 0x7 if msgType.int > ord(MessageType.ResetOut): raise newInvalidMplexMsgType() result = (uint64(header shr 3), MessageType(msgType), data) proc writeMsg*(conn: Connection, id: uint64, msgType: MessageType, data: seq[byte] = @[]) {.async, gcsafe.} = trace "seding data over mplex", id, msgType, data = data.len ## write lenght prefixed var buf = initVBuffer() buf.writePBVarint(id shl 3 or ord(msgType).uint) buf.writePBVarint(data.len().uint) # size should be always sent buf.finish() try: await conn.write(buf.buffer & data) except LPStreamIncompleteError as exc: trace "unable to send message", exc = exc.msg proc writeMsg*(conn: Connection, id: uint64, msgType: MessageType, data: string) {.async, gcsafe.} = result = conn.writeMsg(id, msgType, cast[seq[byte]](data))