diff options
author | Araq <rumpf_a@web.de> | 2012-02-18 10:48:06 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-02-18 10:48:06 +0100 |
commit | b88d98c17a00171ddc1a9d8059ad713d174b800c (patch) | |
tree | 28e2f416e6a6fc6df9ad292ab30ed260d564712b | |
parent | 330d0a92fb3e5732edba90791ee2409d61269af1 (diff) | |
parent | 9aeecaa4cf9fdc46d80ce5dd6bbcc0a9486903fb (diff) | |
download | Nim-b88d98c17a00171ddc1a9d8059ad713d174b800c.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
-rw-r--r-- | lib/pure/asyncio.nim | 29 | ||||
-rw-r--r-- | lib/pure/ftpclient.nim | 4 | ||||
-rw-r--r-- | lib/pure/irc.nim | 22 | ||||
-rwxr-xr-x | lib/pure/os.nim | 2 | ||||
-rwxr-xr-x | lib/pure/sockets.nim | 36 |
5 files changed, 83 insertions, 10 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 1c366e4d9..417a220f9 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -61,6 +61,8 @@ type handleAccept*: proc (s: PAsyncSocket, arg: PObject) + lineBuffer: TaintedString ## Temporary storage for ``recvLine`` + TInfo* = enum SockIdle, SockConnecting, SockConnected, SockListening, SockClosed @@ -88,6 +90,8 @@ proc newAsyncSocket(userArg: PObject = nil): PAsyncSocket = result.handleConnect = (proc (s: PAsyncSocket, arg: PObject) = nil) result.handleAccept = (proc (s: PAsyncSocket, arg: PObject) = nil) + result.lineBuffer = "".TaintedString + proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, protocol: TProtocol = IPPROTO_TCP, userArg: PObject = nil): PAsyncSocket = @@ -193,6 +197,31 @@ proc isConnecting*(s: PAsyncSocket): bool = ## Determines whether ``s`` is connecting. return s.info == SockConnecting +proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool = + ## Behaves similar to ``sockets.recvLine``, however it handles non-blocking + ## sockets properly. This function guarantees that ``line`` is a full line, + ## if this function can only retrieve some data; it will save this data and + ## add it to the result when a full line is retrieved. + setLen(line.string, 0) + var dataReceived = "".TaintedString + var ret = s.socket.recvLineAsync(dataReceived) + case ret + of RecvFullLine: + if s.lineBuffer.len > 0: + string(line).add(s.lineBuffer.string) + setLen(s.lineBuffer.string, 0) + + string(line).add(dataReceived.string) + result = true + of RecvPartialLine: + string(s.lineBuffer).add(dataReceived.string) + result = false + of RecvDisconnected: + result = true + of RecvFail: + result = false + + proc poll*(d: PDispatcher, timeout: int = 500): bool = ## This function checks for events on all the sockets in the `PDispatcher`. ## It then proceeds to call the correct event handler. diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 6d207b98f..669499342 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -196,9 +196,9 @@ proc getLines(ftp: var TFTPClient, async: bool = false): bool = ## It doesn't if `async` is true, because it doesn't check for 226 then. if ftp.dsockStatus == SockConnected: var r = TaintedString"" - if ftp.dsock.recvLine(r): + if ftp.dsock.recvAsync(r): if r.string != "": - ftp.job.lines.add(r.string & "\n") + ftp.job.lines.add(r.string) else: ftp.dsockStatus = SockClosed diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 09e85f234..6e9e30281 100644 --- a/lib/pure/irc.nim +++ b/lib/pure/irc.nim @@ -46,6 +46,7 @@ type TAsyncIRC* = object of TIRC userArg: PObject handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, userArg: PObject) + lineBuffer: TaintedString TIRCMType* = enum MUnknown, @@ -281,7 +282,7 @@ proc poll*(irc: var TIRC, ev: var TIRCEvent, var ret = socks.select(timeout) if socks.len() == 0 and ret != 0: if irc.sock.recvLine(line): - ev = irc.processLine(line) + ev = irc.processLine(line.string) result = true if processOther(irc, ev): result = true @@ -320,11 +321,22 @@ proc handleConnect(h: PObject) = proc handleRead(h: PObject) = var irc = PAsyncIRC(h) - var line = "" - if irc.sock.recvLine(line): - var ev = irc[].processLine(line) + var line = "".TaintedString + var ret = irc.sock.recvLineAsync(line) + case ret + of RecvFullLine: + var ev = irc[].processLine(irc.lineBuffer.string & line.string) irc.handleEvent(irc[], ev, irc.userArg) - + irc.lineBuffer = "".TaintedString + of RecvPartialLine: + if line.string != "": + string(irc.lineBuffer).add(line.string) + of RecvDisconnected: + var ev: TIRCEvent + ev.typ = EvDisconnected + irc.handleEvent(irc[], ev, irc.userArg) + of RecvFail: nil + proc handleTask(h: PObject) = var irc = PAsyncIRC(h) var ev: TIRCEvent diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 6b8176dde..5b3859bd2 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -929,7 +929,7 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string = proc rawRemoveDir(dir: string) = when defined(windows): - if RemoveDirectoryA(dir) != 0'i32 and GetLastError() != 3'i32 and + if RemoveDirectoryA(dir) == 0'i32 and GetLastError() != 3'i32 and GetLastError() != 18'i32: OSError() else: if rmdir(dir) != 0'i32 and errno != ENOENT: OSError() diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 564b76343..5721d79fe 100755 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -56,6 +56,9 @@ type length*: int addrList*: seq[string] + TRecvLineResult* = enum ## result for recvLineAsync + RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail + const InvalidSocket* = TSocket(-1'i32) ## invalid socket number @@ -546,8 +549,7 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int = proc recvLine*(socket: TSocket, line: var TaintedString): bool = ## returns false if no further data is available. `Line` must be initialized - ## and not nil! This does not throw an EOS exception, therefore - ## it can be used in both blocking and non-blocking sockets. + ## and not nil! This does not throw an EOS exception. ## If ``socket`` is disconnected, ``true`` will be returned and line will be ## set to ``""``. setLen(line.string, 0) @@ -565,6 +567,31 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool = elif c == '\L': return true add(line.string, c) +proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult = + ## similar to ``recvLine`` but for non-blocking sockets. + ## The values of the returned enum should be pretty self explanatory: + ## If a full line has been retrieved; ``RecvFullLine`` is returned. + ## If some data has been retrieved; ``RecvPartialLine`` is returned. + ## If the socket has been disconnected; ``RecvDisconncted`` is returned. + ## If call to ``recv`` failed; ``RecvFail`` is returned. + setLen(line.string, 0) + while true: + var c: char + var n = recv(cint(socket), addr(c), 1, 0'i32) + if n < 0: + return (if line.len == 0: RecvFail else: RecvPartialLine) + elif n == 0: + return (if line.len == 0: RecvDisconnected else: RecvPartialLine) + if c == '\r': + n = recv(cint(socket), addr(c), 1, MSG_PEEK) + if n > 0 and c == '\L': + discard recv(cint(socket), addr(c), 1, 0'i32) + elif n <= 0: + return (if line.len == 0: RecvFail else: RecvPartialLine) + return RecvFullLine + elif c == '\L': return RecvFullLine + add(line.string, c) + proc recv*(socket: TSocket, data: pointer, size: int): int = ## receives data from a socket result = recv(cint(socket), data, size, 0'i32) @@ -664,6 +691,11 @@ proc sendAsync*(socket: TSocket, data: string): bool = return false else: OSError() +proc trySend*(socket: TSocket, data: string): bool = + ## safe alternative to ``send``. Does not raise an EOS when an error occurs, + ## and instead returns ``false`` on failure. + result = send(socket, cstring(data), data.len) == data.len + when defined(Windows): const SOCKET_ERROR = -1 |