recvLineAsync for non-blocking sockets implemented, as well as recvLine for asyncio async sockets. Fixed removeDir on windows.
This commit is contained in:
parent
7ec9b042e4
commit
9aeecaa4cf
5 changed files with 83 additions and 10 deletions
|
|
@ -61,6 +61,8 @@ type
|
||||||
|
|
||||||
handleAccept*: proc (s: PAsyncSocket, arg: PObject)
|
handleAccept*: proc (s: PAsyncSocket, arg: PObject)
|
||||||
|
|
||||||
|
lineBuffer: TaintedString ## Temporary storage for ``recvLine``
|
||||||
|
|
||||||
TInfo* = enum
|
TInfo* = enum
|
||||||
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed
|
SockIdle, SockConnecting, SockConnected, SockListening, SockClosed
|
||||||
|
|
||||||
|
|
@ -88,6 +90,8 @@ proc newAsyncSocket(userArg: PObject = nil): PAsyncSocket =
|
||||||
result.handleConnect = (proc (s: PAsyncSocket, arg: PObject) = nil)
|
result.handleConnect = (proc (s: PAsyncSocket, arg: PObject) = nil)
|
||||||
result.handleAccept = (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,
|
proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP,
|
protocol: TProtocol = IPPROTO_TCP,
|
||||||
userArg: PObject = nil): PAsyncSocket =
|
userArg: PObject = nil): PAsyncSocket =
|
||||||
|
|
@ -193,6 +197,31 @@ proc isConnecting*(s: PAsyncSocket): bool =
|
||||||
## Determines whether ``s`` is connecting.
|
## Determines whether ``s`` is connecting.
|
||||||
return s.info == SockConnecting
|
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 =
|
proc poll*(d: PDispatcher, timeout: int = 500): bool =
|
||||||
## This function checks for events on all the sockets in the `PDispatcher`.
|
## This function checks for events on all the sockets in the `PDispatcher`.
|
||||||
## It then proceeds to call the correct event handler.
|
## It then proceeds to call the correct event handler.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
## It doesn't if `async` is true, because it doesn't check for 226 then.
|
||||||
if ftp.dsockStatus == SockConnected:
|
if ftp.dsockStatus == SockConnected:
|
||||||
var r = TaintedString""
|
var r = TaintedString""
|
||||||
if ftp.dsock.recvLine(r):
|
if ftp.dsock.recvAsync(r):
|
||||||
if r.string != "":
|
if r.string != "":
|
||||||
ftp.job.lines.add(r.string & "\n")
|
ftp.job.lines.add(r.string)
|
||||||
else:
|
else:
|
||||||
ftp.dsockStatus = SockClosed
|
ftp.dsockStatus = SockClosed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ type
|
||||||
TAsyncIRC* = object of TIRC
|
TAsyncIRC* = object of TIRC
|
||||||
userArg: PObject
|
userArg: PObject
|
||||||
handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, userArg: PObject)
|
handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, userArg: PObject)
|
||||||
|
lineBuffer: TaintedString
|
||||||
|
|
||||||
TIRCMType* = enum
|
TIRCMType* = enum
|
||||||
MUnknown,
|
MUnknown,
|
||||||
|
|
@ -281,7 +282,7 @@ proc poll*(irc: var TIRC, ev: var TIRCEvent,
|
||||||
var ret = socks.select(timeout)
|
var ret = socks.select(timeout)
|
||||||
if socks.len() == 0 and ret != 0:
|
if socks.len() == 0 and ret != 0:
|
||||||
if irc.sock.recvLine(line):
|
if irc.sock.recvLine(line):
|
||||||
ev = irc.processLine(line)
|
ev = irc.processLine(line.string)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
if processOther(irc, ev): result = true
|
if processOther(irc, ev): result = true
|
||||||
|
|
@ -320,10 +321,21 @@ proc handleConnect(h: PObject) =
|
||||||
|
|
||||||
proc handleRead(h: PObject) =
|
proc handleRead(h: PObject) =
|
||||||
var irc = PAsyncIRC(h)
|
var irc = PAsyncIRC(h)
|
||||||
var line = ""
|
var line = "".TaintedString
|
||||||
if irc.sock.recvLine(line):
|
var ret = irc.sock.recvLineAsync(line)
|
||||||
var ev = irc[].processLine(line)
|
case ret
|
||||||
|
of RecvFullLine:
|
||||||
|
var ev = irc[].processLine(irc.lineBuffer.string & line.string)
|
||||||
irc.handleEvent(irc[], ev, irc.userArg)
|
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) =
|
proc handleTask(h: PObject) =
|
||||||
var irc = PAsyncIRC(h)
|
var irc = PAsyncIRC(h)
|
||||||
|
|
|
||||||
|
|
@ -929,7 +929,7 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string =
|
||||||
|
|
||||||
proc rawRemoveDir(dir: string) =
|
proc rawRemoveDir(dir: string) =
|
||||||
when defined(windows):
|
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()
|
GetLastError() != 18'i32: OSError()
|
||||||
else:
|
else:
|
||||||
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
|
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ type
|
||||||
length*: int
|
length*: int
|
||||||
addrList*: seq[string]
|
addrList*: seq[string]
|
||||||
|
|
||||||
|
TRecvLineResult* = enum ## result for recvLineAsync
|
||||||
|
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||||
|
|
||||||
const
|
const
|
||||||
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
|
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 =
|
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||||
## returns false if no further data is available. `Line` must be initialized
|
## returns false if no further data is available. `Line` must be initialized
|
||||||
## and not nil! This does not throw an EOS exception, therefore
|
## and not nil! This does not throw an EOS exception.
|
||||||
## it can be used in both blocking and non-blocking sockets.
|
|
||||||
## If ``socket`` is disconnected, ``true`` will be returned and line will be
|
## If ``socket`` is disconnected, ``true`` will be returned and line will be
|
||||||
## set to ``""``.
|
## set to ``""``.
|
||||||
setLen(line.string, 0)
|
setLen(line.string, 0)
|
||||||
|
|
@ -565,6 +567,31 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||||
elif c == '\L': return true
|
elif c == '\L': return true
|
||||||
add(line.string, c)
|
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 =
|
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||||
## receives data from a socket
|
## receives data from a socket
|
||||||
result = recv(cint(socket), data, size, 0'i32)
|
result = recv(cint(socket), data, size, 0'i32)
|
||||||
|
|
@ -664,6 +691,11 @@ proc sendAsync*(socket: TSocket, data: string): bool =
|
||||||
return false
|
return false
|
||||||
else: OSError()
|
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):
|
when defined(Windows):
|
||||||
const
|
const
|
||||||
SOCKET_ERROR = -1
|
SOCKET_ERROR = -1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue