Skip to content

Commit

Permalink
Improve typing (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
nitely authored Dec 18, 2024
1 parent 77e77d2 commit 058f1ef
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 326 deletions.
4 changes: 2 additions & 2 deletions src/hyperx/client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ when not defined(hyperxTest):
except CatchableError as err:
debugInfo err.getStackTrace()
debugInfo err.msg
raise newHyperxConnError(err.msg)
raise newConnError(err.msg)

proc newClient*(
hostname: string,
Expand Down Expand Up @@ -99,7 +99,7 @@ proc sendHeaders*(
template client: untyped = strm.client
template stream: untyped = strm.stream
check stream.state in strmStateHeaderSendAllowed,
newErrorOrDefault(stream.error, newStrmError errStreamClosed)
newErrorOrDefault(stream.error, newStrmError hyxStreamClosed)
var headers = newSeq[byte]()
client.hpackEncode(headers, ":method", $httpMethod)
client.hpackEncode(headers, ":scheme", "https")
Expand Down
254 changes: 123 additions & 131 deletions src/hyperx/clientserver.nim

Large diffs are not rendered by default.

138 changes: 74 additions & 64 deletions src/hyperx/errors.nim
Original file line number Diff line number Diff line change
@@ -1,103 +1,113 @@
## Exception types

import ./frame

# https://httpwg.org/specs/rfc9113.html#ErrorCodes
# XXX HyperxErrCode
type
ErrorCode* = distinct uint8
HyperxErrCode* = FrmErrCode
const
errNoError* = 0x00.ErrorCode
errProtocolError* = 0x01.ErrorCode
errInternalError* = 0x02.ErrorCode
errFlowControlError* = 0x03.ErrorCode
errSettingsTimeout* = 0x04.ErrorCode
errStreamClosed* = 0x05.ErrorCode
errFrameSizeError* = 0x06.ErrorCode
errRefusedStream* = 0x07.ErrorCode
errCancel* = 0x08.ErrorCode
errCompressionError* = 0x09.ErrorCode
errConnectError* = 0x0a.ErrorCode
errEnhanceYourCalm* = 0x0b.ErrorCode
errInadequateSecurity* = 0x0c.ErrorCode
errHttp11Required* = 0x0d.ErrorCode
errUnknown = 0xff.ErrorCode # not in the spec

proc `==`*(a, b: ErrorCode): bool {.borrow.}

func `$`(errCode: ErrorCode): string {.raises: [].} =
hyxNoError* = frmeNoError
hyxProtocolError* = frmeProtocolError
hyxInternalError* = frmeInternalError
hyxFlowControlError* = frmeFlowControlError
hyxSettingsTimeout* = frmeSettingsTimeout
hyxStreamClosed* = frmeStreamClosed
hyxFrameSizeError* = frmeFrameSizeError
hyxRefusedStream* = frmeRefusedStream
hyxCancel* = frmeCancel
hyxCompressionError* = frmeCompressionError
hyxConnectError* = frmeConnectError
hyxEnhanceYourCalm* = frmeEnhanceYourCalm
hyxInadequateSecurity* = frmeInadequateSecurity
hyxHttp11Required* = frmeHttp11Required
hyxUnknown = 0xff.HyperxErrCode # not in the spec

proc `==`*(a, b: HyperxErrCode): bool {.borrow.}

func `$`(errCode: HyperxErrCode): string {.raises: [].} =
case errCode
of errNoError: "NO_ERROR"
of errProtocolError: "PROTOCOL_ERROR"
of errInternalError: "INTERNAL_ERROR"
of errFlowControlError: "FLOW_CONTROL_ERROR"
of errSettingsTimeout: "SETTINGS_TIMEOUT"
of errStreamClosed: "STREAM_CLOSED"
of errFrameSizeError: "FRAME_SIZE_ERROR"
of errRefusedStream: "REFUSED_STREAM"
of errCancel: "CANCEL"
of errCompressionError: "COMPRESSION_ERROR"
of errConnectError: "CONNECT_ERROR"
of errEnhanceYourCalm: "ENHANCE_YOUR_CALM"
of errInadequateSecurity: "INADEQUATE_SECURITY"
of errHttp11Required: "HTTP_1_1_REQUIRED"
of hyxNoError: "NO_ERROR"
of hyxProtocolError: "PROTOCOL_ERROR"
of hyxInternalError: "INTERNAL_ERROR"
of hyxFlowControlError: "FLOW_CONTROL_ERROR"
of hyxSettingsTimeout: "SETTINGS_TIMEOUT"
of hyxStreamClosed: "STREAM_CLOSED"
of hyxFrameSizeError: "FRAME_SIZE_ERROR"
of hyxRefusedStream: "REFUSED_STREAM"
of hyxCancel: "CANCEL"
of hyxCompressionError: "COMPRESSION_ERROR"
of hyxConnectError: "CONNECT_ERROR"
of hyxEnhanceYourCalm: "ENHANCE_YOUR_CALM"
of hyxInadequateSecurity: "INADEQUATE_SECURITY"
of hyxHttp11Required: "HTTP_1_1_REQUIRED"
else: "UNKNOWN ERROR CODE"

func toErrorCode(e: uint32): ErrorCode {.raises: [].} =
if e in errNoError.uint32 .. errHttp11Required.uint32:
return e.ErrorCode
return errUnknown
func toErrorCode(e: uint32): HyperxErrCode {.raises: [].} =
if e in hyxNoError.uint32 .. hyxHttp11Required.uint32:
return e.HyperxErrCode
return hyxUnknown

# XXX remove ConnError and StrmError; expose code in Hyperx*
type
HyperxErrTyp* = enum
hxLocalErr, hxRemoteErr
hyxLocalErr, hyxRemoteErr
HyperxError* = object of CatchableError
#typ*: HyperxErrTyp
#code*: HyperxErrCode
HyperxConnError* = object of HyperxError
code*: HyperxErrCode
HyperxStrmError* = object of HyperxError
ConnClosedError* = object of HyperxConnError
ConnError* = object of HyperxConnError
code*: ErrorCode
GracefulShutdownError* = ConnError
StrmError* = object of HyperxStrmError
typ*: HyperxErrTyp
code*: ErrorCode
code*: HyperxErrCode
ConnClosedError* = object of HyperxConnError
GracefulShutdownError* = HyperxConnError
QueueClosedError* = object of HyperxError

func newHyperxConnError*(msg: string): ref HyperxConnError {.raises: [].} =
result = (ref HyperxConnError)(msg: msg)

func newConnClosedError*: ref ConnClosedError {.raises: [].} =
result = (ref ConnClosedError)(msg: "Connection Closed")
result = (ref ConnClosedError)(code: hyxUnknown, msg: "Connection Closed")

func newConnError*(errCode: ErrorCode): ref ConnError {.raises: [].} =
result = (ref ConnError)(code: errCode, msg: "Connection Error: " & $errCode)
func newConnError*(msg: string): ref HyperxConnError {.raises: [].} =
result = (ref HyperxConnError)(code: hyxInternalError, msg: msg)

func newConnError*(errCode: uint32): ref ConnError {.raises: [].} =
result = (ref ConnError)(
func newConnError*(errCode: HyperxErrCode): ref HyperxConnError {.raises: [].} =
result = (ref HyperxConnError)(code: errCode, msg: "Connection Error: " & $errCode)

func newConnError*(errCode: uint32): ref HyperxConnError {.raises: [].} =
result = (ref HyperxConnError)(
code: errCode.toErrorCode,
msg: "Connection Error: " & $errCode.toErrorCode
)

func newStrmError*(errCode: ErrorCode, typ = hxLocalErr): ref StrmError {.raises: [].} =
# XXX fix
func newError*(err: ref HyperxError): ref HyperxConnError {.raises: [].} =
result = (ref HyperxConnError)(code: hyxUnknown, msg: err.msg)

func newStrmError*(
errCode: HyperxErrCode, typ = hyxLocalErr
): ref HyperxStrmError {.raises: [].} =
let msg = case typ
of hxLocalErr: "Stream Error: " & $errCode
of hxRemoteErr: "Got Rst Error: " & $errCode
result = (ref StrmError)(typ: typ, code: errCode, msg: msg)
of hyxLocalErr: "Stream Error: " & $errCode
of hyxRemoteErr: "Got Rst Error: " & $errCode
result = (ref HyperxStrmError)(typ: typ, code: errCode, msg: msg)

func newStrmError*(errCode: uint32, typ = hxLocalErr): ref StrmError {.raises: [].} =
func newStrmError*(
errCode: uint32, typ = hyxLocalErr
): ref HyperxStrmError {.raises: [].} =
result = newStrmError(errCode.toErrorCode, typ)

func newError*(err: ref StrmError): ref StrmError {.raises: [].} =
result = (ref StrmError)(
func newError*(err: ref HyperxStrmError): ref HyperxStrmError {.raises: [].} =
result = (ref HyperxStrmError)(
typ: err.typ, code: err.code, msg: err.msg
)

func newErrorOrDefault*(err, default: ref StrmError): ref StrmError {.raises: [].} =
func newErrorOrDefault*(
err, default: ref HyperxStrmError
): ref HyperxStrmError {.raises: [].} =
if err != nil:
return newError(err)
else:
return default

func newGracefulShutdownError*(): ref GracefulShutdownError {.raises: [].} =
result = (ref GracefulShutdownError)(
code: errNoError, msg: "Connection Error: " & $errNoError
code: hyxNoError, msg: "Connection Error: " & $hyxNoError
)
132 changes: 65 additions & 67 deletions src/hyperx/frame.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import std/strutils
import std/strformat
import ./utils

template ones(n: untyped): uint = (1.uint shl n) - 1

Expand Down Expand Up @@ -113,9 +112,11 @@ type
FrmSid* = distinct uint32 #range[0 .. 31.ones.int]

proc `==`*(a, b: FrmSid): bool {.borrow.}
proc `+=`*(a: var FrmSid, b: FrmSid) {.borrow.}
proc `<`*(a, b: FrmSid): bool {.borrow.}

func `+=`*(a: var FrmSid, b: uint) {.raises: [].} =
a = (a.uint + b).FrmSid
#func `+=`*(a: var FrmSid, b: uint) {.raises: [].} =
# a = (a.uint + b).FrmSid

const
frmSidMain* = 0x00'u32.FrmSid
Expand Down Expand Up @@ -231,7 +232,7 @@ func hasPrio*(frm: Frame): bool {.raises: [].} =
frmfPriority in frm.flags and frm.typ == frmtHeaders

func newGoAwayFrame*(
lastSid, errorCode: int
lastSid: FrmSid, errorCode: FrmErrCode
): Frame {.raises: [].} =
result = newFrame(frmGoAwaySize)
result.setTyp frmtGoAway
Expand All @@ -241,7 +242,7 @@ func newGoAwayFrame*(

func newRstStreamFrame*(
sid: FrmSid,
errorCode: int
errorCode: FrmErrCode
): Frame {.raises: [].} =
result = newFrame(frmRstStreamSize)
result.setTyp frmtRstStream
Expand Down Expand Up @@ -347,7 +348,7 @@ func windowSizeInc*(frm: Frame): uint32 {.raises: [].} =
u32At(frm.s, frmHeaderSize, result)
result.clearBit 31 # clear reserved byte

func errorCode*(frm: Frame): uint32 {.raises: [].} =
func errCode*(frm: Frame): uint32 {.raises: [].} =
result = 0
case frm.typ
of frmtRstStream:
Expand All @@ -368,70 +369,67 @@ func lastStreamId*(frm: Frame): uint32 =
result.clearBit 31

func `$`*(frm: Frame): string {.raises: [].} =
result = ""
untrackExceptions:
result = fmt"""
===Frame===
sid: {$frm.sid.int}
typ: {$frm.typ.int}
ack: {$(frmfAck in frm.flags)}
endStrm: {$(frmfEndStream in frm.flags)}
payload len: {$frm.payloadLen.int}
===========""".unindent
result = fmt"""
===Frame===
sid: {$frm.sid.int}
typ: {$frm.typ.int}
ack: {$(frmfAck in frm.flags)}
endStrm: {$(frmfEndStream in frm.flags)}
payload len: {$frm.payloadLen.int}
===========""".unindent

func debugPayload*(frm: Frame): string {.raises: [].} =
result = ""
untrackExceptions:
var i = frmHeaderSize
result.add "===Payload==="
case frm.typ
of frmtRstStream:
var errCode = 0'u32
u32At(frm.s, i, errCode)
result.add fmt("\nError Code {$errCode}")
of frmtGoAway:
var lastStreamId = 0'u32
u32At(frm.s, i, lastStreamId)
result.add fmt("\nLast-Stream-ID {$lastStreamId}")
var errCode = 0'u32
u32At(frm.s, i+4, errCode)
result.add fmt("\nError Code {$errCode}")
of frmtWindowUpdate:
var wsIncrement = 0'u32
u32At(frm.s, i, wsIncrement)
result.add fmt("\nWindow Size Increment {$wsIncrement}")
of frmtSettings:
if frm.payloadLen.int mod 6 != 0:
result.add "\nbad payload"
return
for _ in 0 .. int(frm.payloadLen.int div 6)-1:
var iden = 0.uint
iden += frm.s[i].uint shl 8
iden += frm.s[i+1].uint
result.add fmt("\nIdentifier {$iden}")
var value = 0'u32
u32At(frm.s, i+2, value)
result.add fmt("\nValue {$value}")
i += 6
of frmtPing:
var value = 0
for x in frm.payload:
value += x.int
result.add fmt("\nPing {$value}")
of frmtData:
if frm.payload.len > 0:
result.add "\n"
var x = 0
for byt in frm.payload:
result.add byt.char
inc x
if x == 10:
break
if frm.payload.len > 10:
result.add "[truncated]"
else:
result.add "\nUnimplemented debug"
result.add "\n============="
var i = frmHeaderSize
result.add "===Payload==="
case frm.typ
of frmtRstStream:
var errCode = 0'u32
u32At(frm.s, i, errCode)
result.add fmt("\nError Code {$errCode}")
of frmtGoAway:
var lastStreamId = 0'u32
u32At(frm.s, i, lastStreamId)
result.add fmt("\nLast-Stream-ID {$lastStreamId}")
var errCode = 0'u32
u32At(frm.s, i+4, errCode)
result.add fmt("\nError Code {$errCode}")
of frmtWindowUpdate:
var wsIncrement = 0'u32
u32At(frm.s, i, wsIncrement)
result.add fmt("\nWindow Size Increment {$wsIncrement}")
of frmtSettings:
if frm.payloadLen.int mod 6 != 0:
result.add "\nbad payload"
return
for _ in 0 .. int(frm.payloadLen.int div 6)-1:
var iden = 0.uint
iden += frm.s[i].uint shl 8
iden += frm.s[i+1].uint
result.add fmt("\nIdentifier {$iden}")
var value = 0'u32
u32At(frm.s, i+2, value)
result.add fmt("\nValue {$value}")
i += 6
of frmtPing:
var value = 0
for x in frm.payload:
value += x.int
result.add fmt("\nPing {$value}")
of frmtData:
if frm.payload.len > 0:
result.add "\n"
var x = 0
for byt in frm.payload:
result.add byt.char
inc x
if x == 10:
break
if frm.payload.len > 10:
result.add "[truncated]"
else:
result.add "\nUnimplemented debug"
result.add "\n============="

when isMainModule:
block:
Expand Down
Loading

0 comments on commit 058f1ef

Please sign in to comment.