Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windyUseStdHttp, gzip, headers #75

Merged
merged 1 commit into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ nimcache
*.dll
__pycache__
bindings/generated
cacert.pem
183 changes: 150 additions & 33 deletions src/windy/http.nim
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import common, internal, std/asyncdispatch, std/httpclient, std/random, std/strutils, std/tables, ws, std/times
import common, internal, std/asyncdispatch, std/httpclient, std/random, std/strutils, std/tables, ws, std/times, zippy

type
HttpRequestState* = ref object
url*, verb*: string
headers*: seq[HttpHeader]
requestBody*: string
deadline*: float64
canceled*: bool

onError*: HttpErrorCallback
onResponse*: HttpResponseCallback
onUploadProgress*: HttpProgressCallback
onDownloadProgress*: HttpProgressCallback
HttpRequestState = ref object
url, verb: string
headers: seq[HttpHeader]
requestBody: string
deadline: float64
canceled: bool

onError: HttpErrorCallback
onResponse: HttpResponseCallback
onUploadProgress: HttpProgressCallback
onDownloadProgress: HttpProgressCallback

client: AsyncHttpClient

WebSocketState* = ref object
url*: string
deadline*: float64
closed*: bool
WebSocketState = ref object
url: string
deadline: float64
closed: bool

onError*: HttpErrorCallback
onOpen*, onClose*: common.Callback
onMessage*: WebSocketMessageCallback
onError: HttpErrorCallback
onOpen, onClose: common.Callback
onMessage: WebSocketMessageCallback

webSocket: WebSocket

Expand All @@ -40,7 +40,7 @@ template usingHttpDispatcher(body: untyped) =
finally:
setGlobalDispatcher(prevDispatcher)

proc newHttpRequestHandle*(): HttpRequestHandle =
proc newHttpRequestHandle(): HttpRequestHandle =
let state = HttpRequestState()

while true:
Expand All @@ -49,7 +49,7 @@ proc newHttpRequestHandle*(): HttpRequestHandle =
httpRequests[result] = state
break

proc newWebSocketHandle*(): WebSocketHandle =
proc newWebSocketHandle(): WebSocketHandle =
let state = WebSocketState()

while true:
Expand All @@ -58,21 +58,15 @@ proc newWebSocketHandle*(): WebSocketHandle =
webSockets[result] = state
break

proc getState*(handle: HttpRequestHandle): HttpRequestState =
httpRequests.getOrDefault(handle, nil)

proc getState*(handle: WebSocketHandle): WebSocketState =
webSockets.getOrDefault(handle, nil)

proc cancel*(handle: HttpRequestHandle) =
let state = handle.getState()
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.canceled = true
state.client.close()

proc close*(handle: WebSocketHandle) =
let state = handle.getState()
let state = webSockets.getOrDefault(handle, nil)
if state == nil:
return
state.closed = true
Expand All @@ -85,7 +79,7 @@ proc close*(handle: WebSocketHandle) =
proc httpRequestTasklet(handle: HttpRequestHandle) {.async.} =
await sleepAsync(0) # Sleep until next poll

let state = handle.getState()
let state = httpRequests.getOrDefault(handle, nil)
if state.canceled:
return

Expand Down Expand Up @@ -118,6 +112,12 @@ proc httpRequestTasklet(handle: HttpRequestHandle) {.async.} =
else:
httpResponse.code = response.code.int
httpResponse.body = await response.body

for key, value in response.headers:
httpResponse.headers[key] = value

if httpResponse.headers["content-encoding"].toLowerAscii() == "gzip":
httpResponse.body = uncompress(httpResponse.body, dfGzip)
except:
if not state.canceled and state.onError != nil:
state.onError(getCurrentExceptionMsg())
Expand All @@ -134,7 +134,7 @@ proc httpRequestTasklet(handle: HttpRequestHandle) {.async.} =
proc webSocketTasklet(handle: WebSocketHandle) {.async.} =
await sleepAsync(0) # Sleep until next poll

let state = handle.getState()
let state = webSockets.getOrDefault(handle, nil)
if state.closed:
return

Expand Down Expand Up @@ -180,14 +180,14 @@ proc webSocketTasklet(handle: WebSocketHandle) {.async.} =

webSockets.del(handle)

proc startTasklet*(handle: HttpRequestHandle) =
proc startTasklet(handle: HttpRequestHandle) =
try:
usingHttpDispatcher:
asyncCheck handle.httpRequestTasklet()
except:
quit("Failed to start HTTP request tasklet")

proc startTasklet*(handle: WebSocketHandle) =
proc startTasklet(handle: WebSocketHandle) =
try:
usingHttpDispatcher:
asyncCheck handle.webSocketTasklet()
Expand All @@ -214,3 +214,120 @@ proc pollHttp*() =
handle.close()
if state.onError != nil:
state.onError(msg)

proc startHttpRequest*(
url: string,
verb = "GET",
headers = newSeq[HttpHeader](),
body = "",
deadline = defaultHttpDeadline
): HttpRequestHandle {.raises: [].} =
result = newHttpRequestHandle()

var headers = headers
headers.addDefaultHeaders()

let state = httpRequests.getOrDefault(result, nil)
state.url = url
state.verb = verb
state.headers = headers
state.requestBody = body
state.deadline = deadline

result.startTasklet()

proc deadline*(handle: HttpRequestHandle): float64 =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.deadline

proc `deadline=`*(handle: HttpRequestHandle, deadline: float64) =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.deadline = deadline

proc `onError=`*(
handle: HttpRequestHandle,
callback: HttpErrorCallback
) =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.onError = callback

proc `onResponse=`*(
handle: HttpRequestHandle,
callback: HttpResponseCallback
) =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.onResponse = callback

proc `onUploadProgress=`*(
handle: HttpRequestHandle,
callback: HttpProgressCallback
) =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.onUploadProgress = callback

proc `onDownloadProgress=`*(
handle: HttpRequestHandle,
callback: HttpProgressCallback
) =
let state = httpRequests.getOrDefault(handle, nil)
if state == nil:
return
state.onDownloadProgress = callback

proc openWebSocket*(
url: string,
deadline = defaultHttpDeadline
): WebSocketHandle {.raises: [].} =
result = newWebSocketHandle()

let state = webSockets.getOrDefault(result, nil)
state.url = url
state.deadline = deadline

result.startTasklet()

proc `onError=`*(
handle: WebSocketHandle,
callback: HttpErrorCallback
) =
let state = webSockets.getOrDefault(handle, nil)
if state == nil:
return
state.onError = callback

proc `onOpen=`*(
handle: WebSocketHandle,
callback: common.Callback
) =
let state = webSockets.getOrDefault(handle, nil)
if state == nil:
return
state.onOpen = callback

proc `onMessage=`*(
handle: WebSocketHandle,
callback: WebSocketMessageCallback
) =
let state = webSockets.getOrDefault(handle, nil)
if state == nil:
return
state.onMessage = callback

proc `onClose=`*(
handle: WebSocketHandle,
callback: common.Callback
) =
let state = webSockets.getOrDefault(handle, nil)
if state == nil:
return
state.onClose = callback
Loading