Merge branch 'bigbreak' of https://github.com/Araq/Nimrod into bigbreak

This commit is contained in:
Araq 2014-09-07 00:58:49 +02:00
commit 0e5078429f
5 changed files with 87 additions and 24 deletions

View file

@ -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 ## 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 ## read, or the socket has disconnected in which case the future will
## complete with a value of ``""``. ## complete with a value of ``""``.
##
## **Warning**: The ``Peek`` socket flag is not supported on Windows.
# Things to note: # Things to note:
@ -458,6 +460,8 @@ when defined(windows) or defined(nimdoc):
# '\0' in the message currently signifies a socket disconnect. Who # '\0' in the message currently signifies a socket disconnect. Who
# knows what will happen when someone sends that to our socket. # knows what will happen when someone sends that to our socket.
verifyPresence(socket) verifyPresence(socket)
assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
var retFuture = newFuture[string]("recv") var retFuture = newFuture[string]("recv")
var dataBuf: TWSABuf var dataBuf: TWSABuf
dataBuf.buf = cast[cstring](alloc0(size)) dataBuf.buf = cast[cstring](alloc0(size))

View file

@ -34,7 +34,26 @@ type
fd: TAsyncFd fd: TAsyncFd
offset: int64 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): 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 = proc getDesiredAccess(mode: TFileMode): int32 =
case mode case mode
of fmRead: of fmRead:
@ -54,6 +73,19 @@ when defined(windows):
else: else:
CREATE_NEW CREATE_NEW
else: 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 = proc getPosixFlags(mode: TFileMode): cint =
case mode case mode
of fmRead: of fmRead:
@ -201,6 +233,19 @@ proc read*(f: AsyncFile, size: int): Future[string] =
return retFuture 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 = proc getFilePos*(f: AsyncFile): int64 =
## Retrieves the current position of the file pointer that is ## Retrieves the current position of the file pointer that is
## used to read from the specified file. The file's first byte has the ## used to read from the specified file. The file's first byte has the

View file

@ -157,34 +157,43 @@ proc connect*(socket: PAsyncSocket, address: string, port: TPort,
sslSetConnectState(socket.sslHandle) sslSetConnectState(socket.sslHandle)
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle)) sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
proc readIntoBuf(socket: PAsyncSocket, proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
flags: set[TSocketFlags]): Future[int] {.async.} = 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)
if socket.isSsl: if socket.isSsl:
when defined(ssl): when defined(ssl):
# SSL mode. # SSL mode.
let ret = bioWrite(socket.bioIn, addr socket.buffer[0], data.len.cint)
if ret < 0:
raiseSSLError()
sslLoop(socket, flags, sslLoop(socket, flags,
sslRead(socket.sslHandle, addr socket.buffer[0], BufferSize.cint)) sslRead(socket.sslHandle, buf, size.cint))
socket.currPos = 0
socket.bufLen = opResult # Injected from sslLoop template.
result = opResult result = opResult
else: 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. # Not in SSL mode.
socket.bufLen = data.len
socket.currPos = 0
result = data.len 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, proc recv*(socket: PAsyncSocket, size: int,
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} = flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
## Reads ``size`` bytes from ``socket``. Returned future will complete once ## Reads **up to** ``size`` bytes from ``socket``.
## all of the requested data is read. If socket is disconnected during the ##
## 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 ## 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 ``""``. ## to be read then the future will complete with a value of ``""``.
if socket.isBuffered: if socket.isBuffered:
result = newString(size) result = newString(size)
@ -216,7 +225,9 @@ proc recv*(socket: PAsyncSocket, size: int,
socket.currPos = originalBufPos socket.currPos = originalBufPos
result.setLen(read) result.setLen(read)
else: 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, proc send*(socket: PAsyncSocket, data: string,
flags = {TSocketFlags.SafeDisconn}) {.async.} = flags = {TSocketFlags.SafeDisconn}) {.async.} =
@ -282,6 +293,9 @@ proc recvLine*(socket: PAsyncSocket,
## The partial line **will be lost**. ## The partial line **will be lost**.
## ##
## **Warning**: The ``Peek`` flag is not yet implemented. ## **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 = template addNLIfEmpty(): stmt =
if result.len == 0: if result.len == 0:
result.add("\c\L") result.add("\c\L")
@ -324,10 +338,8 @@ proc recvLine*(socket: PAsyncSocket,
if c.len == 0: if c.len == 0:
return "" return ""
if c == "\r": if c == "\r":
c = await recv(socket, 1, flags + {TSocketFlags.Peek}) c = await recv(socket, 1, flags) # Skip \L
if c.len > 0 and c == "\L": assert c == "\L"
let dummy = await recv(socket, 1, flags)
assert dummy == "\L"
addNLIfEmpty() addNLIfEmpty()
return return
elif c == "\L": elif c == "\L":

View file

@ -466,7 +466,8 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
result.headers = newStringTable(modeCaseInsensitive) result.headers = newStringTable(modeCaseInsensitive)
result.userAgent = defUserAgent result.userAgent = defUserAgent
result.maxRedirects = maxRedirects result.maxRedirects = maxRedirects
result.sslContext = net.SslContext(sslContext) when defined(ssl):
result.sslContext = net.SslContext(sslContext)
proc close*(client: AsyncHttpClient) = proc close*(client: AsyncHttpClient) =
## Closes any connections held by the HTTP client. ## Closes any connections held by the HTTP client.

View file

@ -330,7 +330,7 @@ when defined(Windows) and not defined(useNimRtl):
var s = PFileHandleStream(s) var s = PFileHandleStream(s)
if s.atTheEnd: return 0 if s.atTheEnd: return 0
var br: int32 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 zero bytes returned (EOF).
# TRUE and n (>0) bytes returned (good data). # TRUE and n (>0) bytes returned (good data).
# FALSE and bytes returned undefined (system error). # 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) = proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) =
var s = PFileHandleStream(s) var s = PFileHandleStream(s)
var bytesWritten: int32 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()) if a == 0: raiseOSError(osLastError())
proc newFileHandleStream(handle: THandle): PFileHandleStream = proc newFileHandleStream(handle: THandle): PFileHandleStream =