IRCサーバに指定ユーザのログイン状況が知りたい
netcat(The GNU Netcat -- Official homepage)越しにirc語は話したことがあったけど,なにもないとこから書くのも面倒なのと,どうせクライアントのスケルトンがあると思ったらあったのでPython でシンプルな IRC クライアントを作成するを参考にircクライアントをpython3のunicode文字とbytearrayの使い方を理解するために書いてみた.あとircクライアントのpythonライブラリは探してもいない.
# -*- coding: utf-8 -*- """ refer: http://www.codereading.com/codereading/python/python-irc-client.html @date: 2010/02/23 @author: karronoli Python3.1.1 irc client test for WIDE server """ import socket import difflib import sys SERVER = 'irc.tokyo.wide.ad.jp' PORT = 6667 NICKNAME = 'your_nickname' CHARCODE = 'iso2022_jp' #CHANNEL = '#test_py' #open a socket to handle the connection IRC = socket.socket(socket.AF_INET, socket.SOCK_STREAM) IRC.settimeout(3.0) #open a connection with the server def irc_conn(): IRC.connect((SERVER, PORT)) #simple function to send data through the socket def send_data(command): status = IRC.send((command + "\r\n").encode(CHARCODE)) # unicode -> iso2022_jp if status == -1 : raise Exception('send_data error', status) #join the channel def join(channel): send_data('JOIN ' + channel) #send login data (customizable) def login(nickname, username='yourname', password = None, realname='yourname', hostname='hoge', servername='hoge'): send_data('USER %s %s %s %s' % (username, hostname, servername, realname)) send_data("NICK " + nickname) def get_motd(): buffer = bytearray() """ # 内包表記で書きたかったけど失敗した残骸 # motd size(WIDE):about 4650bytes, append method is bad for only 1bytes append [buffer.append(tmp) for tmp in IRC.recv(1024) if buffer.find(b"End of MOTD command") < 0] time.sleep(3) [buffer.append(tmp) for tmp in IRC.recv(4096) if buffer.find(b"End of MOTD command") < 0] """ #[buffer.append(tmp) for tmp in IRC.recv(8192) if buffer.find(b"End of MOTD command") < 0] #appendは1byte単位しか追加できないけど原因はrecvが途中で止まるせいだと思う #[buffer.append(tmp) for tmp in IRC.recv(1) if buffer.find(b"End of MOTD command") < 0] while buffer.find(b"End of MOTD command") < 0 and len(buffer) < 5120: buffer += IRC.recv(1024) return buffer.decode(CHARCODE) # iso2022_jp -> unicode #return IRC.recv(8192).decode(CHARCODE) #一回で読み込むことはできない def is_present(user): """ #下のと同じだけどなんとなく残してる send_data('ISON ' + user) search_user = IRC.recv(1024).decode(CHARCODE) # iso2022_jp -> unicode if len(search_user.split(':')[1]) == 0: return False else: return True """ print('Search user ' + user) send_data("ISON " + user) #search_user = IRC.recv(1024).decode(CHARCODE).split(':') # iso2022_jp -> unicode #search_user = [] #[search_user.append(tmp.strip()) for tmp in IRC.recv(1024).decode('iso2022_jp').split(':') if tmp.strip() != ''] search_user = [tmp.strip() for tmp in IRC.recv(1024).decode('iso2022_jp').split(':') if tmp.strip() != ''] print(search_user) if (len(search_user) > 1): return True else: return False """ # この場合現実的じゃないけどdiffを使ってみた. # 自分がログインしたときのISONの返り値と探したいユーザのを:区切りの単語単位でdiffる send_data('ISON ' + NICKNAME) my = IRC.recv(1024).decode(CHARCODE).split(":") #diff = difflib.ndiff(search_user, my) for buf in difflib.ndiff(search_user, my): #print(buf) diff_status = buf[0:2] if (diff_status == "- " or diff_status == "+ "): _user = buf.split(":")[1] if len(_user) == 0: print("%s is absent" % user) return False else: print("%s is present" % _user) return True #print(buf.split(":")[1], ) """ if __name__ == '__main__': irc_conn() login(NICKNAME) #join(CHANNEL) motd = get_motd() print(motd) # windowsで動かしてたのでcp932とか使った open('motd.txt', 'wb').write(motd.encode('cp932')) print('motd ended.') print(is_present('ison_test_no_user_expected')) print(is_present(NICKNAME)) send_data('WHOIS karronoli') # 自分が普段使うユーザ名 print(IRC.recv(1024).decode(CHARCODE)) send_data('WHOIS ' + NICKNAME) print(IRC.recv(1024).decode(CHARCODE)) send_data('EXIT') IRC.close()
ちょっと気に食わないけど土台としてはほぼお決まりな感じなので備忘録がてら貼り付けた.やっぱpythonで新規に何か書くときはpython3だな.文字コードをちゃんと意識してますよ感が結構好き.あと内包表記のスコープとか.encode/decodeはどっちがどっちか良く分からなくなるので必ずコメントを足すようにしてる.
ところでpidginのユーザ情報の取得が異様に遅い気がするんだけど生ソケット越しのWHOISの応答はすぐに返ってくる.どうしてなんだろ?