diff options
-rw-r--r-- | lib/pure/asyncio.nim | 3 | ||||
-rw-r--r-- | lib/pure/ftpclient.nim | 4 | ||||
-rwxr-xr-x | lib/pure/httpserver.nim | 2 | ||||
-rw-r--r-- | lib/pure/irc.nim | 193 | ||||
-rwxr-xr-x | lib/pure/scgi.nim | 2 |
5 files changed, 111 insertions, 93 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 5ecc16de7..0f5197792 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -35,6 +35,9 @@ import sockets, os ## that in the future this type's fields will not be exported therefore breaking ## your code. ## +## **Warning:** The API of this module is unstable, and therefore is subject +## to change. +## ## Asynchronous sockets ## ==================== ## diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 410c5e8bc..78c96c3f1 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -26,6 +26,10 @@ import sockets, strutils, parseutils, times, os, asyncio ## var ftp = FTPClient("example.org", user = "user", pass = "pass") ## ftp.connect() ## ftp.retrFile("file.ext", "file.ext") +## +## **Warning:** The API of this module is unstable, and therefore is subject +## to change. + type TFTPClient* = object of TObject diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 9d9ea2012..ce816b7d4 100755 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -22,6 +22,8 @@ ## ## run(handleRequest, TPort(80)) ## +## **Warning:** The API of this module is unstable, and therefore is subject +## to change. import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 81a1befb5..11808ca33 100644 --- a/lib/pure/irc.nim +++ b/lib/pure/irc.nim @@ -16,15 +16,21 @@ ## the amount of lag. ## ## .. code-block:: Nimrod -## var client = irc("irc.server.net", joinChans = @["#channel"]) +## +## var client = irc("picheta.me", joinChans = @["#bots"]) ## client.connect() ## while True: ## var event: TIRCEvent ## if client.poll(event): ## case event.typ -## of EvDisconnected: break +## of EvConnected: nil +## of EvDisconnected: +## client.reconnect() ## of EvMsg: -## # Where all the magic happens. +## # Write your message reading code here. +## +## **Warning:** The API of this module is unstable, and therefore is subject +## to change. import sockets, strutils, parseutils, times, asyncio @@ -34,11 +40,15 @@ type port: TPort nick, user, realname, serverPass: string case isAsync: bool - of false: - sock: TSocket of true: - handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.} + handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.} asyncSock: PAsyncSocket + myDispatcher: PDispatcher + of false: + dummyA: pointer + dummyB: pointer # workaround a Nimrod API issue + dummyC: pointer + sock: TSocket status: TInfo lastPing: float lastPong: float @@ -47,6 +57,8 @@ type msgLimit: bool messageBuffer: seq[tuple[timeToSend: float, m: string]] + PIRC* = ref TIRC + PAsyncIRC* = ref TAsyncIRC TAsyncIRC* = object of TIRC @@ -68,9 +80,13 @@ type MError TIRCEventType* = enum - EvMsg, EvDisconnected + EvMsg, EvConnected, EvDisconnected TIRCEvent* = object ## IRC Event case typ*: TIRCEventType + of EvConnected: + ## Connected to server. + ## Only occurs with AsyncIRC. + nil of EvDisconnected: ## Disconnected from the server nil @@ -82,7 +98,7 @@ type origin*: string ## The channel/user that this msg originated from raw*: string ## Raw IRC message -proc send*(irc: var TIRC, message: string, sendImmediately = false) = +proc send*(irc: PIRC, message: string, sendImmediately = false) = ## Sends ``message`` as a raw command. It adds ``\c\L`` for you. var sendMsg = true if irc.msgLimit and not sendImmediately: @@ -104,15 +120,15 @@ proc send*(irc: var TIRC, message: string, sendImmediately = false) = # but I can't exactly check for EBrokenPipe. irc.status = SockClosed -proc privmsg*(irc: var TIRC, target, message: string) = +proc privmsg*(irc: PIRC, target, message: string) = ## Sends ``message`` to ``target``. ``Target`` can be a channel, or a user. irc.send("PRIVMSG $1 :$2" % [target, message]) -proc notice*(irc: var TIRC, target, message: string) = +proc notice*(irc: PIRC, target, message: string) = ## Sends ``notice`` to ``target``. ``Target`` can be a channel, or a user. irc.send("NOTICE $1 :$2" % [target, message]) -proc join*(irc: var TIRC, channel: string, key = "") = +proc join*(irc: PIRC, channel: string, key = "") = ## Joins ``channel``. ## ## If key is not ``""``, then channel is assumed to be key protected and this @@ -122,16 +138,19 @@ proc join*(irc: var TIRC, channel: string, key = "") = else: irc.send("JOIN " & channel & " " & key) -proc part*(irc: var TIRC, channel, message: string) = +proc part*(irc: PIRC, channel, message: string) = ## Leaves ``channel`` with ``message``. irc.send("PART " & channel & " :" & message) -proc close*(irc: var TIRC) = +proc close*(irc: PIRC) = ## Closes connection to an IRC server. ## ## **Warning:** This procedure does not send a ``QUIT`` message to the server. irc.status = SockClosed - irc.sock.close() + if irc.isAsync: + irc.asyncSock.close() + else: + irc.sock.close() proc isNumber(s: string): bool = ## Checks if `s` contains only numbers. @@ -202,12 +221,11 @@ proc parseMessage(msg: string): TIRCEvent = inc(i) # Skip `:`. result.params.add(msg[i..msg.len-1]) -proc connect*(irc: var TIRC) = +proc connect*(irc: PIRC) = ## Connects to an IRC server as specified by ``irc``. assert(irc.address != "") assert(irc.port != TPort(0)) - irc.sock = socket() irc.sock.connect(irc.address, irc.port) irc.status = SockConnected @@ -217,13 +235,21 @@ proc connect*(irc: var TIRC) = irc.send("NICK " & irc.nick, true) irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) +proc reconnect*(irc: PIRC) = + ## Reconnects to an IRC server. + ## + ## This should be used when an ``EvDisconnected`` event occurs. + irc.sock = socket() + irc.connect() + proc irc*(address: string, port: TPort = 6667.TPort, nick = "NimrodBot", user = "NimrodBot", realname = "NimrodBot", serverPass = "", joinChans: seq[string] = @[], - msgLimit: bool = true): TIRC = + msgLimit: bool = true): PIRC = ## Creates a ``TIRC`` object. + new(result) result.address = address result.port = port result.nick = nick @@ -237,8 +263,9 @@ proc irc*(address: string, port: TPort = 6667.TPort, result.msgLimit = msgLimit result.messageBuffer = @[] result.status = SockIdle + result.sock = socket() -proc processLine(irc: var TIRC, line: string): TIRCEvent = +proc processLine(irc: PIRC, line: string): TIRCEvent = if line.len == 0: irc.close() result.typ = EvDisconnected @@ -254,8 +281,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent = result.typ = EvDisconnected return - if result.cmd == MPing: - irc.send("PONG " & result.params[0]) + #if result.cmd == MPing: + # irc.send("PONG " & result.params[0]) if result.cmd == MPong: irc.lag = epochTime() - parseFloat(result.params[result.params.high]) irc.lastPong = epochTime() @@ -271,11 +298,11 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent = if result.nick == irc.nick: irc.nick = result.params[0] -proc processOther(irc: var TIRC, ev: var TIRCEvent): bool = +proc processOther(irc: PIRC, ev: var TIRCEvent): bool = result = false - if epochTime() - irc.lastPing >= 20.0: - irc.lastPing = epochTime() - irc.send("PING :" & formatFloat(irc.lastPing), true) + #if epochTime() - irc.lastPing >= 20.0: + # irc.lastPing = epochTime() + # irc.send("PING :" & formatFloat(irc.lastPing), true) if epochTime() - irc.lastPong >= 120.0 and irc.lastPong != -1.0: irc.close() @@ -290,7 +317,7 @@ proc processOther(irc: var TIRC, ev: var TIRCEvent): bool = break # messageBuffer is guaranteed to be from the quickest to the # later-est. -proc poll*(irc: var TIRC, ev: var TIRCEvent, +proc poll*(irc: PIRC, ev: var TIRCEvent, timeout: int = 500): bool = ## This function parses a single message from the IRC server and returns ## a TIRCEvent. @@ -316,46 +343,32 @@ proc poll*(irc: var TIRC, ev: var TIRCEvent, if processOther(irc, ev): result = true -proc getLag*(irc: var TIRC): float = +proc getLag*(irc: PIRC): float = ## Returns the latency between this client and the IRC server in seconds. ## ## If latency is unknown, returns -1.0. return irc.lag -proc isConnected*(irc: var TIRC): bool = +proc isConnected*(irc: PIRC): bool = ## Returns whether this IRC client is connected to an IRC server. return irc.status == SockConnected -proc getNick*(irc: var TIRC): string = +proc getNick*(irc: PIRC): string = ## Returns the current nickname of the client. return irc.nick # -- Asyncio dispatcher -proc connect*(irc: PAsyncIRC) = - ## Equivalent of connect for ``TIRC`` but specifically created for asyncio. - assert(irc.address != "") - assert(irc.port != TPort(0)) - - irc.asyncSock = AsyncSocket() - irc.asyncSock.connect(irc.address, irc.port) - proc handleConnect(s: PAsyncSocket, irc: PAsyncIRC) = # Greet the server :) - if irc.serverPass != "": irc[].send("PASS " & irc.serverPass, true) - irc[].send("NICK " & irc.nick, true) - irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) - -discard """proc handleConnect(h: PObject) = - var irc = PAsyncIRC(h) - - # Greet the server :) - if irc.serverPass != "": irc[].send("PASS " & irc.serverPass, true) - irc[].send("NICK " & irc.nick, true) - irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) - + if irc.serverPass != "": irc.send("PASS " & irc.serverPass, true) + irc.send("NICK " & irc.nick, true) + irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) irc.status = SockConnected -""" + + var ev: TIRCEvent + ev.typ = EvConnected + irc.handleEvent(irc, ev) proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) = var line = "".TaintedString @@ -363,42 +376,48 @@ proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) = if ret: if line == "": var ev: TIRCEvent - irc[].close() + irc.close() ev.typ = EvDisconnected - irc[].handleEvent(irc[], ev) + irc.handleEvent(irc, ev) else: - var ev = irc[].processLine(line.string) - irc[].handleEvent(irc[], ev) - -discard """proc handleRead(h: PObject) = - var irc = PAsyncIRC(h) - 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 - irc[].close() - ev.typ = EvDisconnected - irc.handleEvent(irc[], ev, irc.userArg) - of RecvFail: nil""" + var ev = irc.processLine(line.string) + irc.handleEvent(irc, ev) proc handleTask(s: PAsyncSocket, irc: PAsyncIRC) = var ev: TIRCEvent - if irc[].processOther(ev): - irc.handleEvent(irc[], ev) + if irc.processOther(ev): + irc.handleEvent(irc, ev) + +proc register*(d: PDispatcher, irc: PAsyncIRC) = + ## Registers ``irc`` with dispatcher ``d``. + irc.asyncSock.handleConnect = + proc (s: PAsyncSocket) = + handleConnect(s, irc) + irc.asyncSock.handleRead = + proc (s: PAsyncSocket) = + handleRead(s, irc) + irc.asyncSock.handleTask = + proc (s: PAsyncSocket) = + handleTask(s, irc) + d.register(irc.asyncSock) + irc.myDispatcher = d + +proc connect*(irc: PAsyncIRC) = + ## Equivalent of connect for ``TIRC`` but specifically created for asyncio. + assert(irc.address != "") + assert(irc.port != TPort(0)) -discard """proc handleTask(h: PObject) = - var irc = PAsyncIRC(h) - var ev: TIRCEvent - if PAsyncIRC(h)[].processOther(ev): - irc.handleEvent(irc[], ev, irc.userArg)""" + irc.asyncSock.connect(irc.address, irc.port) + +proc reconnect*(irc: PAsyncIRC) = + ## Reconnects to an IRC server. + ## + ## This should be used when an ``EvDisconnected`` event occurs. + ## + ## When successfully reconnected an ``EvConnected`` event will occur. + irc.asyncSock = AsyncSocket() + irc.myDispatcher.register(irc) + irc.connect() proc asyncIRC*(address: string, port: TPort = 6667.TPort, nick = "NimrodBot", @@ -406,7 +425,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort, realname = "NimrodBot", serverPass = "", joinChans: seq[string] = @[], msgLimit: bool = true, - ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.} + ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.} ): PAsyncIRC = ## Use this function if you want to use asyncio's dispatcher. ## @@ -429,19 +448,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort, result.msgLimit = msgLimit result.messageBuffer = @[] result.handleEvent = ircEvent - -proc register*(d: PDispatcher, irc: PAsyncIRC) = - ## Registers ``irc`` with dispatcher ``d``. - irc.asyncSock.handleConnect = - proc (s: PAsyncSocket) = - handleConnect(s, irc) - irc.asyncSock.handleRead = - proc (s: PAsyncSocket) = - handleRead(s, irc) - irc.asyncSock.handleTask = - proc (s: PAsyncSocket) = - handleTask(s, irc) - d.register(irc.asyncSock) + result.asyncSock = AsyncSocket() when isMainModule: #var m = parseMessage("ERROR :Closing Link: dom96.co.cc (Ping timeout: 252 seconds)") diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 44a579a7d..0f3b44e00 100755 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -23,6 +23,8 @@ ## ## run(handleRequest) ## +## **Warning:** The API of this module is unstable, and therefore is subject +## to change. import sockets, strutils, os, strtabs, asyncio |