diff options
author | Araq <rumpf_a@web.de> | 2011-09-20 00:57:06 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-09-20 00:57:06 +0200 |
commit | daa2c8732d0f4feef20f68e75e9c491e95b95a0d (patch) | |
tree | 9554e9e80e16b733c0c708349a822936b8126832 /lib | |
parent | fd62116f6eb80d1dd3d6cc745d80629ad32dca1a (diff) | |
parent | c2d9e27f7da098183bed738f76e5dd7fd6fb9303 (diff) | |
download | Nim-daa2c8732d0f4feef20f68e75e9c491e95b95a0d.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/irc.nim | 256 | ||||
-rwxr-xr-x | lib/wrappers/sphinx.nim | 126 |
2 files changed, 319 insertions, 63 deletions
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim new file mode 100644 index 000000000..5a4c815f6 --- /dev/null +++ b/lib/pure/irc.nim @@ -0,0 +1,256 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2011 Dominik Picheta +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements an asynchronous IRC client. +## +## Currently this module requires at least some knowledge of the IRC protocol. +## It provides a function for sending raw messages to the IRC server, together +## with some basic functions like sending a message to a channel. +## It automizes the process of keeping the connection alive, so you don't +## need to reply to PING messages. In fact, the server is also PING'ed to check +## the amount of lag. +## +## .. code-block:: Nimrod +## var client = irc("irc.server.net", joinChans = @["#channel"]) +## client.connect() +## while True: +## var event: TIRCEvent +## if client.poll(event): +## case event.typ +## of EvDisconnected: break +## of EvMsg: +## # Where all the magic happens. + +import sockets, strutils, parseutils, times + +type + TIRC* = object + address: string + port: TPort + nick, user, realname, serverPass: string + sock: TSocket + connected: bool + lastPing: float + lastPong: float + lag: float + channelsToJoin: seq[string] + + TIRCMType* = enum + MUnknown, + MNumeric, + MPrivMsg, + MJoin, + MPart, + MMode, + MTopic, + MInvite, + MKick, + MQuit, + MNick, + MNotice, + MPing, + MPong + + TIRCEventType* = enum + EvMsg, EvDisconnected + TIRCEvent* = object + case typ*: TIRCEventType + of EvDisconnected: nil + of EvMsg: + cmd*: TIRCMType + nick*, user*, host*, servername*: string + numeric*: string + params*: seq[string] + raw*: string + +proc send*(irc: var TIRC, message: string) = + ## Sends ``message`` as a raw command. It adds ``\c\L`` for you. + irc.sock.send(message & "\c\L") + +proc privmsg*(irc: var TIRC, 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) = + ## 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 = "") = + ## Joins ``channel``. + ## + ## If key is not ``""``, then channel is assumed to be key protected and this + ## function will join the channel using ``key``. + if key == "": + irc.send("JOIN " & channel) + else: + irc.send("JOIN " & channel & " " & key) + +proc part*(irc: var TIRC, channel, message: string) = + ## Leaves ``channel`` with ``message``. + irc.send("PART " & channel & " :" & message) + +proc isNumber(s: string): bool = + ## Checks if `s` contains only numbers. + var i = 0 + while s[i] in {'0'..'9'}: inc(i) + result = i == s.len and s.len > 0 + +proc parseMessage(msg: string): TIRCEvent = + result.typ = EvMsg + result.cmd = MUnknown + result.raw = msg + var i = 0 + # Process the prefix + if msg[i] == ':': + inc(i) # Skip `:` + var nick = "" + i.inc msg.parseUntil(nick, {'!', ' '}, i) + if msg[i] == '!': + result.nick = nick + inc(i) # Skip `!` + i.inc msg.parseUntil(result.user, {'@'}, i) + inc(i) # Skip `@` + i.inc msg.parseUntil(result.host, {' '}, i) + inc(i) # Skip ` ` + else: + result.serverName = nick + inc(i) # Skip ` ` + + # Process command + var cmd = "" + i.inc msg.parseUntil(cmd, {' '}, i) + + if cmd.isNumber: + result.cmd = MNumeric + result.numeric = cmd + else: + case cmd + of "PRIVMSG": result.cmd = MPrivMsg + of "JOIN": result.cmd = MJoin + of "PART": result.cmd = MPart + of "PONG": result.cmd = MPong + of "PING": result.cmd = MPing + of "MODE": result.cmd = MMode + of "TOPIC": result.cmd = MTopic + of "INVITE": result.cmd = MInvite + of "KICK": result.cmd = MKick + of "QUIT": result.cmd = MQuit + of "NICK": result.cmd = MNick + of "NOTICE": result.cmd = MNotice + else: result.cmd = MUnknown + + # Don't skip space here. It is skipped in the following While loop. + + # Params + result.params = @[] + var param = "" + while msg[i] != '\0' and msg[i] != ':': + inc(i) # Skip ` `. + i.inc msg.parseUntil(param, {' ', ':', '\0'}, i) + if param != "": + result.params.add(param) + param.setlen(0) + + if msg[i] == ':': + inc(i) # Skip `:`. + result.params.add(msg[i..msg.len-1]) + +proc connect*(irc: var TIRC) = + ## 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) + + # Greet the server :) + if irc.serverPass != "": irc.send("PASS " & irc.serverPass) + irc.send("NICK " & irc.nick) + irc.send("USER $1 * 0 :$2" % [irc.user, irc.realname]) + +proc irc*(address: string, port: TPort = 6667.TPort, + nick = "NimrodBot", + user = "NimrodBot", + realname = "NimrodBot", serverPass = "", + joinChans: seq[string] = @[]): TIRC = + ## This function calls `connect`, so you don't need to. + result.address = address + result.port = port + result.nick = nick + result.user = user + result.realname = realname + result.serverPass = serverPass + result.lastPing = epochTime() + result.lastPong = -1.0 + result.lag = -1.0 + result.channelsToJoin = joinChans + + result.connect() + +proc poll*(irc: var TIRC, ev: var TIRCEvent, + timeout: int = 500): bool = + ## This function parses a single message from the IRC server and returns + ## a TIRCEvent. + ## + ## This function should be called often as it also handles pinging + ## the server. + var line = "" + var socks = @[irc.sock] + var ret = socks.select(timeout) + if socks.len() == 0 and ret == 1: + if irc.sock.recvLine(line): + if line == "": + ev.typ = EvDisconnected + else: + ev = parseMessage(line) + if ev.cmd == MPing: + irc.send("PONG " & ev.params[0]) + if ev.cmd == MPong: + irc.lag = epochTime() - parseFloat(ev.params[ev.params.high]) + irc.lastPong = epochTime() + if ev.cmd == MNumeric: + if ev.numeric == "001": + for chan in items(irc.channelsToJoin): + irc.join(chan) + result = true + + if epochTime() - irc.lastPing >= 20.0: + irc.lastPing = epochTime() + irc.send("PING :" & formatFloat(irc.lastPing)) + +proc getLag*(irc: var TIRC): float = + ## Returns the latency between this client and the IRC server in seconds. + ## + ## If latency is unknown, returns -1.0. + return irc.lag + +proc getLastPong*(irc: var TIRC): float = + ## Returns the last time the server has responded to a PING message. + ## + ## This is useful if you want to detect whether your + ## connection has timed out. + ## + ## If a PONG has never been received, returns -1.0. + return irc.lastPong + +when isMainModule: + var client = irc("irc.freenode.net", nick="TestBot", joinChans = @["#nimrod"]) + while True: + var event: TIRCEvent + if client.poll(event): + case event.typ + of EvDisconnected: + break + of EvMsg: + if event.cmd == MPrivMsg: + var msg = event.params[event.params.high] + if msg == "|test": client.privmsg(event.params[0], "hello") + + echo( repr(event) ) + echo("Lag: ", formatFloat(client.getLag())) + echo("Last pong: ", formatFloat(client.getLastPong())) diff --git a/lib/wrappers/sphinx.nim b/lib/wrappers/sphinx.nim index a4fce0205..b4e127c65 100755 --- a/lib/wrappers/sphinx.nim +++ b/lib/wrappers/sphinx.nim @@ -12,7 +12,7 @@ # did not, you can find it at http://www.gnu.org/ # -## Nimrod wrapper for ``shpinx``. +## Nimrod wrapper for ``sphinx``. {.deadCodeElim: on.} when defined(windows): @@ -26,7 +26,7 @@ else: sphinxDll* = "libspinxclient.so" #/ known searchd status codes: -const +const SEARCHD_OK* = 0 SEARCHD_ERROR* = 1 SEARCHD_RETRY* = 2 @@ -34,7 +34,7 @@ const #/ known match modes -const +const SPH_MATCH_ALL* = 0 SPH_MATCH_ANY* = 1 SPH_MATCH_PHRASE* = 2 @@ -45,7 +45,7 @@ const #/ known ranking modes (ext2 only) -const +const SPH_RANK_PROXIMITY_BM25* = 0 SPH_RANK_BM25* = 1 SPH_RANK_NONE* = 2 @@ -58,7 +58,7 @@ const #/ known sort modes -const +const SPH_SORT_RELEVANCE* = 0 SPH_SORT_ATTR_DESC* = 1 SPH_SORT_ATTR_ASC* = 2 @@ -68,14 +68,14 @@ const #/ known filter types -const +const SPH_FILTER_VALUES* = 0 SPH_FILTER_RANGE* = 1 SPH_FILTER_FLOATRANGE* = 2 #/ known attribute types -const +const SPH_ATTR_INTEGER* = 1 SPH_ATTR_TIMESTAMP* = 2 SPH_ATTR_ORDINAL* = 3 @@ -87,7 +87,7 @@ const #/ known grouping functions -const +const SPH_GROUPBY_DAY* = 0 SPH_GROUPBY_WEEK* = 1 SPH_GROUPBY_MONTH* = 2 @@ -95,19 +95,19 @@ const SPH_GROUPBY_ATTR* = 4 SPH_GROUPBY_ATTRPAIR* = 5 -type +type TSphinxBool* {.size: sizeof(cint).} = enum SPH_FALSE = 0, SPH_TRUE = 1 Tclient {.pure, final.} = object PClient* = ptr TClient - Twordinfo*{.pure, final.} = object + Twordinfo*{.pure, final.} = object word*: cstring docs*: cint hits*: cint - Tresult*{.pure, final.} = object + Tresult*{.pure, final.} = object error*: cstring warning*: cstring status*: cint @@ -124,7 +124,7 @@ type num_words*: cint words*: ptr array [0..100_000, TWordinfo] - Texcerpt_options*{.pure, final.} = object + Texcerpt_options*{.pure, final.} = object before_match*: cstring after_match*: cstring chunk_separator*: cstring @@ -145,114 +145,114 @@ type allow_empty*: TSphinxBool emit_zones*: TSphinxBool - Tkeyword_info*{.pure, final.} = object + Tkeyword_info*{.pure, final.} = object tokenized*: cstring normalized*: cstring num_docs*: cint num_hits*: cint -proc create*(copy_args: TSphinxBool): PClient{.cdecl, importc: "sphinx_create", +proc create*(copy_args: TSphinxBool): PClient{.cdecl, importc: "sphinx_create", dynlib: sphinxDll.} -proc cleanup*(client: PClient){.cdecl, importc: "sphinx_cleanup", +proc cleanup*(client: PClient){.cdecl, importc: "sphinx_cleanup", dynlib: sphinxDll.} -proc destroy*(client: PClient){.cdecl, importc: "sphinx_destroy", +proc destroy*(client: PClient){.cdecl, importc: "sphinx_destroy", dynlib: sphinxDll.} -proc error*(client: PClient): cstring{.cdecl, importc: "sphinx_error", +proc error*(client: PClient): cstring{.cdecl, importc: "sphinx_error", dynlib: sphinxDll.} -proc warning*(client: PClient): cstring{.cdecl, importc: "sphinx_warning", +proc warning*(client: PClient): cstring{.cdecl, importc: "sphinx_warning", dynlib: sphinxDll.} -proc set_server*(client: PClient, host: cstring, port: cint): TSphinxBool{.cdecl, +proc set_server*(client: PClient, host: cstring, port: cint): TSphinxBool{.cdecl, importc: "sphinx_set_server", dynlib: sphinxDll.} -proc set_connect_timeout*(client: PClient, seconds: float32): TSphinxBool{.cdecl, +proc set_connect_timeout*(client: PClient, seconds: float32): TSphinxBool{.cdecl, importc: "sphinx_set_connect_timeout", dynlib: sphinxDll.} -proc open*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_open", +proc open*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_open", dynlib: sphinxDll.} -proc close*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_close", +proc close*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_close", dynlib: sphinxDll.} -proc set_limits*(client: PClient, offset: cint, limit: cint, - max_matches: cint, cutoff: cint): TSphinxBool{.cdecl, +proc set_limits*(client: PClient, offset: cint, limit: cint, + max_matches: cint, cutoff: cint): TSphinxBool{.cdecl, importc: "sphinx_set_limits", dynlib: sphinxDll.} proc set_max_query_time*(client: PClient, max_query_time: cint): TSphinxBool{. cdecl, importc: "sphinx_set_max_query_time", dynlib: sphinxDll.} -proc set_match_mode*(client: PClient, mode: cint): TSphinxBool{.cdecl, +proc set_match_mode*(client: PClient, mode: cint): TSphinxBool{.cdecl, importc: "sphinx_set_match_mode", dynlib: sphinxDll.} -proc set_ranking_mode*(client: PClient, ranker: cint): TSphinxBool{.cdecl, +proc set_ranking_mode*(client: PClient, ranker: cint): TSphinxBool{.cdecl, importc: "sphinx_set_ranking_mode", dynlib: sphinxDll.} proc set_sort_mode*(client: PClient, mode: cint, sortby: cstring): TSphinxBool{. cdecl, importc: "sphinx_set_sort_mode", dynlib: sphinxDll.} -proc set_field_weights*(client: PClient, num_weights: cint, +proc set_field_weights*(client: PClient, num_weights: cint, field_names: cstringArray, field_weights: ptr cint): TSphinxBool{. cdecl, importc: "sphinx_set_field_weights", dynlib: sphinxDll.} -proc set_index_weights*(client: PClient, num_weights: cint, +proc set_index_weights*(client: PClient, num_weights: cint, index_names: cstringArray, index_weights: ptr cint): TSphinxBool{. cdecl, importc: "sphinx_set_index_weights", dynlib: sphinxDll.} proc set_id_range*(client: PClient, minid: int64, maxid: int64): TSphinxBool{. cdecl, importc: "sphinx_set_id_range", dynlib: sphinxDll.} -proc add_filter*(client: PClient, attr: cstring, num_values: cint, - values: ptr int64, exclude: TSphinxBool): TSphinxBool{.cdecl, +proc add_filter*(client: PClient, attr: cstring, num_values: cint, + values: ptr int64, exclude: TSphinxBool): TSphinxBool{.cdecl, importc: "sphinx_add_filter", dynlib: sphinxDll.} -proc add_filter_range*(client: PClient, attr: cstring, umin: int64, - umax: int64, exclude: TSphinxBool): TSphinxBool{.cdecl, +proc add_filter_range*(client: PClient, attr: cstring, umin: int64, + umax: int64, exclude: TSphinxBool): TSphinxBool{.cdecl, importc: "sphinx_add_filter_range", dynlib: sphinxDll.} -proc add_filter_float_range*(client: PClient, attr: cstring, fmin: float32, - fmax: float32, exclude: TSphinxBool): TSphinxBool{.cdecl, +proc add_filter_float_range*(client: PClient, attr: cstring, fmin: float32, + fmax: float32, exclude: TSphinxBool): TSphinxBool{.cdecl, importc: "sphinx_add_filter_float_range", dynlib: sphinxDll.} -proc set_geoanchor*(client: PClient, attr_latitude: cstring, +proc set_geoanchor*(client: PClient, attr_latitude: cstring, attr_longitude: cstring, latitude: float32, longitude: float32): TSphinxBool{. cdecl, importc: "sphinx_set_geoanchor", dynlib: sphinxDll.} -proc set_groupby*(client: PClient, attr: cstring, groupby_func: cint, - group_sort: cstring): TSphinxBool{.cdecl, +proc set_groupby*(client: PClient, attr: cstring, groupby_func: cint, + group_sort: cstring): TSphinxBool{.cdecl, importc: "sphinx_set_groupby", dynlib: sphinxDll.} -proc set_groupby_distinct*(client: PClient, attr: cstring): TSphinxBool{.cdecl, +proc set_groupby_distinct*(client: PClient, attr: cstring): TSphinxBool{.cdecl, importc: "sphinx_set_groupby_distinct", dynlib: sphinxDll.} -proc set_retries*(client: PClient, count: cint, delay: cint): TSphinxBool{.cdecl, +proc set_retries*(client: PClient, count: cint, delay: cint): TSphinxBool{.cdecl, importc: "sphinx_set_retries", dynlib: sphinxDll.} -proc add_override*(client: PClient, attr: cstring, docids: ptr int64, - num_values: cint, values: ptr cint): TSphinxBool{.cdecl, +proc add_override*(client: PClient, attr: cstring, docids: ptr int64, + num_values: cint, values: ptr cint): TSphinxBool{.cdecl, importc: "sphinx_add_override", dynlib: sphinxDll.} -proc set_select*(client: PClient, select_list: cstring): TSphinxBool{.cdecl, +proc set_select*(client: PClient, select_list: cstring): TSphinxBool{.cdecl, importc: "sphinx_set_select", dynlib: sphinxDll.} -proc reset_filters*(client: PClient){.cdecl, +proc reset_filters*(client: PClient){.cdecl, importc: "sphinx_reset_filters", dynlib: sphinxDll.} -proc reset_groupby*(client: PClient){.cdecl, +proc reset_groupby*(client: PClient){.cdecl, importc: "sphinx_reset_groupby", dynlib: sphinxDll.} -proc query*(client: PClient, query: cstring, index_list: cstring, - comment: cstring): ptr Tresult{.cdecl, importc: "sphinx_query", +proc query*(client: PClient, query: cstring, index_list: cstring, + comment: cstring): ptr Tresult{.cdecl, importc: "sphinx_query", dynlib: sphinxDll.} -proc add_query*(client: PClient, query: cstring, index_list: cstring, - comment: cstring): cint{.cdecl, importc: "sphinx_add_query", +proc add_query*(client: PClient, query: cstring, index_list: cstring, + comment: cstring): cint{.cdecl, importc: "sphinx_add_query", dynlib: sphinxDll.} -proc run_queries*(client: PClient): ptr Tresult{.cdecl, +proc run_queries*(client: PClient): ptr Tresult{.cdecl, importc: "sphinx_run_queries", dynlib: sphinxDll.} -proc get_num_results*(client: PClient): cint{.cdecl, +proc get_num_results*(client: PClient): cint{.cdecl, importc: "sphinx_get_num_results", dynlib: sphinxDll.} -proc get_id*(result: ptr Tresult, match: cint): int64{.cdecl, +proc get_id*(result: ptr Tresult, match: cint): int64{.cdecl, importc: "sphinx_get_id", dynlib: sphinxDll.} -proc get_weight*(result: ptr Tresult, match: cint): cint{.cdecl, +proc get_weight*(result: ptr Tresult, match: cint): cint{.cdecl, importc: "sphinx_get_weight", dynlib: sphinxDll.} -proc get_int*(result: ptr Tresult, match: cint, attr: cint): int64{.cdecl, +proc get_int*(result: ptr Tresult, match: cint, attr: cint): int64{.cdecl, importc: "sphinx_get_int", dynlib: sphinxDll.} -proc get_float*(result: ptr Tresult, match: cint, attr: cint): float32{.cdecl, +proc get_float*(result: ptr Tresult, match: cint, attr: cint): float32{.cdecl, importc: "sphinx_get_float", dynlib: sphinxDll.} proc get_mva*(result: ptr Tresult, match: cint, attr: cint): ptr cint{. cdecl, importc: "sphinx_get_mva", dynlib: sphinxDll.} -proc get_string*(result: ptr Tresult, match: cint, attr: cint): cstring{.cdecl, +proc get_string*(result: ptr Tresult, match: cint, attr: cint): cstring{.cdecl, importc: "sphinx_get_string", dynlib: sphinxDll.} -proc init_excerpt_options*(opts: ptr Texcerpt_options){.cdecl, +proc init_excerpt_options*(opts: ptr Texcerpt_options){.cdecl, importc: "sphinx_init_excerpt_options", dynlib: sphinxDll.} -proc build_excerpts*(client: PClient, num_docs: cint, docs: cstringArray, +proc build_excerpts*(client: PClient, num_docs: cint, docs: cstringArray, index: cstring, words: cstring, opts: ptr Texcerpt_options): cstringArray{. cdecl, importc: "sphinx_build_excerpts", dynlib: sphinxDll.} -proc update_attributes*(client: PClient, index: cstring, num_attrs: cint, - attrs: cstringArray, num_docs: cint, +proc update_attributes*(client: PClient, index: cstring, num_attrs: cint, + attrs: cstringArray, num_docs: cint, docids: ptr int64, values: ptr int64): cint{. cdecl, importc: "sphinx_update_attributes", dynlib: sphinxDll.} -proc update_attributes_mva*(client: PClient, index: cstring, attr: cstring, - docid: int64, num_values: cint, - values: ptr cint): cint{.cdecl, +proc update_attributes_mva*(client: PClient, index: cstring, attr: cstring, + docid: int64, num_values: cint, + values: ptr cint): cint{.cdecl, importc: "sphinx_update_attributes_mva", dynlib: sphinxDll.} -proc build_keywords*(client: PClient, query: cstring, index: cstring, +proc build_keywords*(client: PClient, query: cstring, index: cstring, hits: TSphinxBool, out_num_keywords: ptr cint): ptr Tkeyword_info{. cdecl, importc: "sphinx_build_keywords", dynlib: sphinxDll.} proc status*(client: PClient, num_rows: ptr cint, num_cols: ptr cint): cstringArray{. |