GOTO M.

趣味のコーディングとか、勉強とか、読書とか

Hastter(Twitterの投稿をHaskellで解釈して返すBOT) ver0.1 ←現在は稼動していません

状況

    • とりあえず 一 度 動 い た
    • 『例外処理については、意識していませんが。』
    • いくつかバグ(仕様)あり
      • ASCIIに無い文字が入ってくると落ちる。(日本語化してないUbuntuを使ってるからだろうか)
      • サニタイジングしていないので、嫌な事が起こるかも。(EC2だし、ダメージは無いけど)
      • よく分からないがたまに落ちる。
      • よく分からないがレスポンスを返さない時がある。(主処理に致命的なバグがある気がする)
      • maxId、もっと賢い処理方法が有る気がする。(memcacheとか?)

simple_bot.py

import twitter           # TwitterAPI
import time              # 時刻処理用
import re                # 正規表現処理用
import subprocess        # 外部プロセス呼び出し用
import xml.sax.saxutils  # HTMLエスケープ系処理用

USER="YOUR_TWITTER_USER"
PASS="YOUR_TWITTER_PASS"
BASEDIR="/home/ubuntu/scripts/python"

api=twitter.Api(username=USER, password=PASS)

#############################################
# 1つのつぶやき(tweet)を解析し、返信する #
#############################################
def reply_tweet(tweet):
  # "@YOUR_TWITTER_USER" のような返信シンボルを削除
  command = re.compile('@' + USER + ' *', re.I).sub('', xml.sax.saxutils.unescae(tweet.text))
  # バックスラッシュをエスケープしない(やや怪しい処理)
  command = re.compile('\\\\').sub('\\\\', command)
  # tweet本文をHaskell文とみなし評価する
  result = execute_haskell(command)
  # 返信シンボルを付加し、返信をTwitterに投稿
  replyStr = "@" + tweet.GetUser().screen_name + " " + result
  api.PostUpdate(replyStr)

#########################################################
# 文字列をHaskell文として評価し、結果を文字列として返す #
#########################################################
def execute_haskell(command):
  quitStr = ":quit\n" # Haskell処理系(ghci)から抜けるためのコマンド
  # Haskell処理系(ghci)プロセスを呼び出す
  p = subprocess.Popen("ghci", shell=True, cwd="/", stdin=subprocess.PIPE,
                       stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
  p.stdin.write(command + "\n" + quitStr)
  # 処理結果3行目のみ取得したいので、先頭2行はスキップ
  p.stdout.readline()
  p.stdout.readline()
  # Haskell処理系のプロンプト部分を削除
  return re.compile(r'Prelude> *').sub('', p.stdout.readline()).rstrip()

##########
# 主処理 #
##########
# 同じtweetを2度処理しないよう、これまで処理した最大IDを控えておく。
f_in = open(BASEDIR + '/maxId.txt', 'r')
maxId = int(f_in.readline())
f_in.close()
# 90秒ごとに返信を取得し、それぞれを解析し、返信する。
while(1):
  # 返信は投稿日時(降順)で返されるので、昇順にした後に順次処理。
  for i in reversed(api.GetReplies(since_id=str(maxId))):
    if maxId < i.GetId():
      maxId = i.GetId()
      f_out = open(BASEDIR + '/maxId.txt', 'w')
      f_out.write(str(maxId))
      f_out.close()
      reply_tweet(i) # change if the function changed
  time.sleep(90)


上のスクリプトが落ちた時に再起動するスクリプト
Cronで

* * * * * sh /home/ubuntu/scripts/sh/restart_bot.sh >/dev/null 2>&1

みたいにしてみたが、shをよく分かっていない。多分ちゃんと動いていない。

restart_bot.sh

#!/bin/sh

psCount=`ps aux | grep -c simple_bot.py`
if [ $psCount -ge 1 ]
then
  date >> /home/ubuntu/scripts/sh/log.txt
  echo "No problem" >> /home/ubuntu/scripts/sh/log.txt
else
  python /home/ubuntu/scripts/python/simple_bot.py & > /home/ubuntu/scripts/python/simple_bot.log 2>&1
  date >> /home/ubuntu/scripts/sh/log.txt
  echo "Restart simple_bot.py" >> /home/ubuntu/scripts/sh/log.txt
fi