mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
Merge branch 'bigbreak' of https://github.com/Araq/Nimrod into bigbreak
This commit is contained in:
@@ -449,6 +449,8 @@ when defined(windows) or defined(nimdoc):
|
||||
## complete once all the data requested is read, a part of the data has been
|
||||
## read, or the socket has disconnected in which case the future will
|
||||
## complete with a value of ``""``.
|
||||
##
|
||||
## **Warning**: The ``Peek`` socket flag is not supported on Windows.
|
||||
|
||||
|
||||
# Things to note:
|
||||
@@ -458,6 +460,8 @@ when defined(windows) or defined(nimdoc):
|
||||
# '\0' in the message currently signifies a socket disconnect. Who
|
||||
# knows what will happen when someone sends that to our socket.
|
||||
verifyPresence(socket)
|
||||
assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
|
||||
|
||||
var retFuture = newFuture[string]("recv")
|
||||
var dataBuf: TWSABuf
|
||||
dataBuf.buf = cast[cstring](alloc0(size))
|
||||
|
||||
@@ -34,7 +34,26 @@ type
|
||||
fd: TAsyncFd
|
||||
offset: int64
|
||||
|
||||
# TODO: These will be nil in other threads?
|
||||
var
|
||||
asyncStdin* {.threadvar.}: AsyncFile ## Asynchronous stdin handle
|
||||
asyncStdout* {.threadvar.}: AsyncFile ## Asynchronous stdout handle
|
||||
asyncStderr* {.threadvar.}: AsyncFile ## Asynchronous stderr handle
|
||||
|
||||
when defined(windows):
|
||||
asyncStdin = AsyncFile(
|
||||
fd: getStdHandle(STD_INPUT_HANDLE).TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
asyncStdout = AsyncFile(
|
||||
fd: getStdHandle(STD_OUTPUT_HANDLE).TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
asyncStderr = AsyncFile(
|
||||
fd: getStdHandle(STD_ERROR_HANDLE).TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
|
||||
proc getDesiredAccess(mode: TFileMode): int32 =
|
||||
case mode
|
||||
of fmRead:
|
||||
@@ -54,6 +73,19 @@ when defined(windows):
|
||||
else:
|
||||
CREATE_NEW
|
||||
else:
|
||||
asyncStdin = AsyncFile(
|
||||
fd: STDIN_FILENO.TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
asyncStdout = AsyncFile(
|
||||
fd: STDOUT_FILENO.TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
asyncStderr = AsyncFile(
|
||||
fd: STDERR_FILENO.TAsyncFd,
|
||||
offset: 0
|
||||
)
|
||||
|
||||
proc getPosixFlags(mode: TFileMode): cint =
|
||||
case mode
|
||||
of fmRead:
|
||||
@@ -201,6 +233,19 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
||||
|
||||
return retFuture
|
||||
|
||||
proc readLine*(f: AsyncFile): Future[string] {.async.} =
|
||||
## Reads a single line from the specified file asynchronously.
|
||||
result = ""
|
||||
while true:
|
||||
var c = await read(f, 1)
|
||||
if c[0] == '\c':
|
||||
c = await read(f, 1)
|
||||
break
|
||||
if c[0] == '\L' or c == "":
|
||||
break
|
||||
else:
|
||||
result.add(c)
|
||||
|
||||
proc getFilePos*(f: AsyncFile): int64 =
|
||||
## Retrieves the current position of the file pointer that is
|
||||
## used to read from the specified file. The file's first byte has the
|
||||
|
||||
@@ -157,34 +157,43 @@ proc connect*(socket: PAsyncSocket, address: string, port: TPort,
|
||||
sslSetConnectState(socket.sslHandle)
|
||||
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
|
||||
|
||||
proc readIntoBuf(socket: PAsyncSocket,
|
||||
flags: set[TSocketFlags]): Future[int] {.async.} =
|
||||
var data = await recv(socket.fd.TAsyncFD, BufferSize, flags)
|
||||
if data.len != 0:
|
||||
copyMem(addr socket.buffer[0], addr data[0], data.len)
|
||||
proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
|
||||
flags: set[TSocketFlags]): Future[int] {.async.} =
|
||||
if socket.isSsl:
|
||||
when defined(ssl):
|
||||
# SSL mode.
|
||||
let ret = bioWrite(socket.bioIn, addr socket.buffer[0], data.len.cint)
|
||||
if ret < 0:
|
||||
raiseSSLError()
|
||||
sslLoop(socket, flags,
|
||||
sslRead(socket.sslHandle, addr socket.buffer[0], BufferSize.cint))
|
||||
socket.currPos = 0
|
||||
socket.bufLen = opResult # Injected from sslLoop template.
|
||||
sslRead(socket.sslHandle, buf, size.cint))
|
||||
result = opResult
|
||||
else:
|
||||
var data = await recv(socket.fd.TAsyncFD, size, flags)
|
||||
if data.len != 0:
|
||||
copyMem(buf, addr data[0], data.len)
|
||||
# Not in SSL mode.
|
||||
socket.bufLen = data.len
|
||||
socket.currPos = 0
|
||||
result = data.len
|
||||
|
||||
proc readIntoBuf(socket: PAsyncSocket,
|
||||
flags: set[TSocketFlags]): Future[int] {.async.} =
|
||||
result = await readInto(addr socket.buffer[0], BufferSize, socket, flags)
|
||||
socket.currPos = 0
|
||||
socket.bufLen = result
|
||||
|
||||
proc recv*(socket: PAsyncSocket, size: int,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
|
||||
## Reads ``size`` bytes from ``socket``. Returned future will complete once
|
||||
## all of the requested data is read. If socket is disconnected during the
|
||||
## Reads **up to** ``size`` bytes from ``socket``.
|
||||
##
|
||||
## For buffered sockets this function will attempt to read all the requested
|
||||
## data. It will read this data in ``BufferSize`` chunks.
|
||||
##
|
||||
## For unbuffered sockets this function makes no effort to read
|
||||
## all the data requested. It will return as much data as the operating system
|
||||
## gives it.
|
||||
##
|
||||
## If socket is disconnected during the
|
||||
## recv operation then the future may complete with only a part of the
|
||||
## requested data read. If socket is disconnected and no data is available
|
||||
## requested data.
|
||||
##
|
||||
## If socket is disconnected and no data is available
|
||||
## to be read then the future will complete with a value of ``""``.
|
||||
if socket.isBuffered:
|
||||
result = newString(size)
|
||||
@@ -216,7 +225,9 @@ proc recv*(socket: PAsyncSocket, size: int,
|
||||
socket.currPos = originalBufPos
|
||||
result.setLen(read)
|
||||
else:
|
||||
result = await recv(socket.fd.TAsyncFD, size, flags)
|
||||
result = newString(size)
|
||||
let read = await readInto(addr result[0], size, socket, flags)
|
||||
result.setLen(read)
|
||||
|
||||
proc send*(socket: PAsyncSocket, data: string,
|
||||
flags = {TSocketFlags.SafeDisconn}) {.async.} =
|
||||
@@ -282,6 +293,9 @@ proc recvLine*(socket: PAsyncSocket,
|
||||
## The partial line **will be lost**.
|
||||
##
|
||||
## **Warning**: The ``Peek`` flag is not yet implemented.
|
||||
##
|
||||
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
|
||||
## uses ``\r\L`` to delimit a new line.
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
@@ -324,10 +338,8 @@ proc recvLine*(socket: PAsyncSocket,
|
||||
if c.len == 0:
|
||||
return ""
|
||||
if c == "\r":
|
||||
c = await recv(socket, 1, flags + {TSocketFlags.Peek})
|
||||
if c.len > 0 and c == "\L":
|
||||
let dummy = await recv(socket, 1, flags)
|
||||
assert dummy == "\L"
|
||||
c = await recv(socket, 1, flags) # Skip \L
|
||||
assert c == "\L"
|
||||
addNLIfEmpty()
|
||||
return
|
||||
elif c == "\L":
|
||||
|
||||
@@ -466,7 +466,8 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
|
||||
result.headers = newStringTable(modeCaseInsensitive)
|
||||
result.userAgent = defUserAgent
|
||||
result.maxRedirects = maxRedirects
|
||||
result.sslContext = net.SslContext(sslContext)
|
||||
when defined(ssl):
|
||||
result.sslContext = net.SslContext(sslContext)
|
||||
|
||||
proc close*(client: AsyncHttpClient) =
|
||||
## Closes any connections held by the HTTP client.
|
||||
|
||||
@@ -330,7 +330,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
var s = PFileHandleStream(s)
|
||||
if s.atTheEnd: return 0
|
||||
var br: int32
|
||||
var a = winlean.readFile(s.handle, buffer, bufLen.cint, br, nil)
|
||||
var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil)
|
||||
# TRUE and zero bytes returned (EOF).
|
||||
# TRUE and n (>0) bytes returned (good data).
|
||||
# FALSE and bytes returned undefined (system error).
|
||||
@@ -341,7 +341,8 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||
var s = PFileHandleStream(s)
|
||||
var bytesWritten: int32
|
||||
var a = winlean.writeFile(s.handle, buffer, bufLen.cint, bytesWritten, nil)
|
||||
var a = winlean.writeFile(s.handle, buffer, bufLen.cint,
|
||||
addr bytesWritten, nil)
|
||||
if a == 0: raiseOSError(osLastError())
|
||||
|
||||
proc newFileHandleStream(handle: THandle): PFileHandleStream =
|
||||
|
||||
Reference in New Issue
Block a user