Fixes IRC module.

This commit is contained in:
Dominik Picheta 2012-09-12 23:50:23 +01:00
commit 254bc714dd
2 changed files with 61 additions and 35 deletions

View file

@ -119,6 +119,8 @@ type
handleAccept*: proc (s: PAsyncSocket) {.closure.} handleAccept*: proc (s: PAsyncSocket) {.closure.}
handleTask*: proc (s: PAsyncSocket) {.closure.}
lineBuffer: TaintedString ## Temporary storage for ``recvLine`` lineBuffer: TaintedString ## Temporary storage for ``recvLine``
sslNeedAccept: bool sslNeedAccept: bool
proto: TProtocol proto: TProtocol
@ -145,6 +147,7 @@ proc newAsyncSocket(): PAsyncSocket =
result.handleRead = (proc (s: PAsyncSocket) = nil) result.handleRead = (proc (s: PAsyncSocket) = nil)
result.handleConnect = (proc (s: PAsyncSocket) = nil) result.handleConnect = (proc (s: PAsyncSocket) = nil)
result.handleAccept = (proc (s: PAsyncSocket) = nil) result.handleAccept = (proc (s: PAsyncSocket) = nil)
result.handleTask = (proc (s: PAsyncSocket) = nil)
result.lineBuffer = "".TaintedString result.lineBuffer = "".TaintedString
@ -196,6 +199,13 @@ when defined(ssl):
# handshake will set socket's ``sslNoHandshake`` field. # handshake will set socket's ``sslNoHandshake`` field.
discard PAsyncSocket(h).socket.handshake() discard PAsyncSocket(h).socket.handshake()
proc asyncSockTask(h: PObject) =
when defined(ssl):
h.asyncSockDoHandshake()
PAsyncSocket(h).handleTask(PAsyncSocket(h))
proc toDelegate(sock: PAsyncSocket): PDelegate = proc toDelegate(sock: PAsyncSocket): PDelegate =
result = newDelegate() result = newDelegate()
result.deleVal = sock result.deleVal = sock
@ -204,6 +214,7 @@ proc toDelegate(sock: PAsyncSocket): PDelegate =
result.mode = fmReadWrite result.mode = fmReadWrite
result.handleRead = asyncSockHandleRead result.handleRead = asyncSockHandleRead
result.handleWrite = asyncSockHandleWrite result.handleWrite = asyncSockHandleWrite
result.task = asyncSockTask
# TODO: Errors? # TODO: Errors?
#result.handleError = (proc (h: PObject) = assert(false)) #result.handleError = (proc (h: PObject) = assert(false))
@ -217,9 +228,6 @@ proc toDelegate(sock: PAsyncSocket): PDelegate =
else: else:
sock.deleg.open = false sock.deleg.open = false
when defined(ssl):
result.task = asyncSockDoHandshake
proc connect*(sock: PAsyncSocket, name: string, port = TPort(0), proc connect*(sock: PAsyncSocket, name: string, port = TPort(0),
af: TDomain = AF_INET) = af: TDomain = AF_INET) =
## Begins connecting ``sock`` to ``name``:``port``. ## Begins connecting ``sock`` to ``name``:``port``.
@ -257,6 +265,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
## ##
## **Note**: ``client`` needs to be initialised. ## **Note**: ``client`` needs to be initialised.
assert(client != nil) assert(client != nil)
client = newAsyncSocket()
var c: TSocket var c: TSocket
new(c) new(c)
when defined(ssl): when defined(ssl):

View file

@ -44,10 +44,8 @@ type
PAsyncIRC* = ref TAsyncIRC PAsyncIRC* = ref TAsyncIRC
TAsyncIRC* = object of TIRC TAsyncIRC* = object of TIRC
userArg: PObject handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, asyncSock: PAsyncSocket
userArg: PObject) {.nimcall.}
lineBuffer: TaintedString
TIRCMType* = enum TIRCMType* = enum
MUnknown, MUnknown,
@ -320,12 +318,16 @@ proc connect*(irc: PAsyncIRC) =
assert(irc.address != "") assert(irc.address != "")
assert(irc.port != TPort(0)) assert(irc.port != TPort(0))
irc.sock = socket() irc.asyncSock = AsyncSocket()
irc.sock.setBlocking(false) irc.asyncSock.connect(irc.address, irc.port)
irc.sock.connectAsync(irc.address, irc.port)
irc.status = SockConnecting
proc handleConnect(h: PObject) = 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) var irc = PAsyncIRC(h)
# Greet the server :) # Greet the server :)
@ -334,8 +336,22 @@ proc handleConnect(h: PObject) =
irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true) irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
irc.status = SockConnected irc.status = SockConnected
"""
proc handleRead(h: PObject) = proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) =
var line = "".TaintedString
var ret = s.recvLine(line)
if ret:
if line == "":
var ev: TIRCEvent
irc[].close()
ev.typ = EvDisconnected
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 irc = PAsyncIRC(h)
var line = "".TaintedString var line = "".TaintedString
var ret = irc.sock.recvLineAsync(line) var ret = irc.sock.recvLineAsync(line)
@ -352,13 +368,18 @@ proc handleRead(h: PObject) =
irc[].close() irc[].close()
ev.typ = EvDisconnected ev.typ = EvDisconnected
irc.handleEvent(irc[], ev, irc.userArg) irc.handleEvent(irc[], ev, irc.userArg)
of RecvFail: nil of RecvFail: nil"""
proc handleTask(h: PObject) = proc handleTask(s: PAsyncSocket, irc: PAsyncIRC) =
var ev: TIRCEvent
if irc[].processOther(ev):
irc.handleEvent(irc[], ev)
discard """proc handleTask(h: PObject) =
var irc = PAsyncIRC(h) var irc = PAsyncIRC(h)
var ev: TIRCEvent var ev: TIRCEvent
if PAsyncIRC(h)[].processOther(ev): if PAsyncIRC(h)[].processOther(ev):
irc.handleEvent(irc[], ev, irc.userArg) irc.handleEvent(irc[], ev, irc.userArg)"""
proc asyncIRC*(address: string, port: TPort = 6667.TPort, proc asyncIRC*(address: string, port: TPort = 6667.TPort,
nick = "NimrodBot", nick = "NimrodBot",
@ -366,9 +387,8 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
realname = "NimrodBot", serverPass = "", realname = "NimrodBot", serverPass = "",
joinChans: seq[string] = @[], joinChans: seq[string] = @[],
msgLimit: bool = true, msgLimit: bool = true,
ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
userArg: PObject) {.nimcall.}, ): PAsyncIRC =
userArg: PObject = nil): PAsyncIRC =
## Use this function if you want to use asyncio's dispatcher. ## Use this function if you want to use asyncio's dispatcher.
## ##
## **Note:** Do **NOT** use this if you're writing a simple IRC bot which only ## **Note:** Do **NOT** use this if you're writing a simple IRC bot which only
@ -389,28 +409,25 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
result.msgLimit = msgLimit result.msgLimit = msgLimit
result.messageBuffer = @[] result.messageBuffer = @[]
result.handleEvent = ircEvent result.handleEvent = ircEvent
result.userArg = userArg
result.lineBuffer = ""
proc register*(d: PDispatcher, irc: PAsyncIRC) = proc register*(d: PDispatcher, irc: PAsyncIRC) =
## Registers ``irc`` with dispatcher ``d``. ## Registers ``irc`` with dispatcher ``d``.
var dele = newDelegate() irc.asyncSock.handleConnect =
dele.deleVal = irc proc (s: PAsyncSocket) =
dele.getSocket = (proc (h: PObject): tuple[info: TInfo, sock: TSocket] = handleConnect(s, irc)
if PAsyncIRC(h).status == SockConnecting or irc.asyncSock.handleRead =
PAsyncIRC(h).status == SockConnected: proc (s: PAsyncSocket) =
return (PAsyncIRC(h).status, PAsyncIRC(h).sock) handleRead(s, irc)
else: return (SockIdle, PAsyncIRC(h).sock)) irc.asyncSock.handleTask =
dele.handleConnect = handleConnect proc (s: PAsyncSocket) =
dele.handleRead = handleRead handleTask(s, irc)
dele.task = handleTask d.register(irc.asyncSock)
d.register(dele)
when isMainModule: when isMainModule:
#var m = parseMessage("ERROR :Closing Link: dom96.co.cc (Ping timeout: 252 seconds)") #var m = parseMessage("ERROR :Closing Link: dom96.co.cc (Ping timeout: 252 seconds)")
#echo(repr(m)) #echo(repr(m))
#discard """
var client = irc("amber.tenthbit.net", nick="TestBot1234", var client = irc("amber.tenthbit.net", nick="TestBot1234",
joinChans = @["#flood"]) joinChans = @["#flood"])
@ -431,5 +448,5 @@ when isMainModule:
#echo( repr(event) ) #echo( repr(event) )
#echo("Lag: ", formatFloat(client.getLag())) #echo("Lag: ", formatFloat(client.getLag()))
#"""