Advertisement
Guest User

Untitled

a guest
Oct 11th, 2016
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.92 KB | None | 0 0
  1. #!/usr/bin/python
  2. # twisted imports
  3. from twisted.words.protocols import irc
  4. from twisted.internet import reactor, protocol, ssl, task
  5. from twisted.python import log
  6.  
  7. # system imports
  8. import time, sys, unicodedata, re
  9.  
  10. import zlib, socket, struct, pickle
  11.  
  12. NUM_NATIONS = 250
  13.  
  14.  
  15. class Game:
  16.     def __init__(self):
  17.         self.name = ""
  18.         self.tth = 0
  19.         self.server=""
  20.         self.port=0
  21.         self.processedTurn=0
  22.  
  23.     def tthformat(self):
  24.         days = 86400
  25.         hour = 3600
  26.         minute = 60
  27.  
  28.         tths = ""
  29.  
  30.         if((self.tth/1000) > days):
  31.             tths += "%dd " % int((self.tth/1000)/days)
  32.  
  33.         r = (self.tth/1000) % days
  34.  
  35.         if(r > hour):
  36.             tths += "%dh " % int(r/hour)
  37.  
  38.         r = r % hour
  39.  
  40.         if(r > minute):
  41.             tths += "%dm " % int(r/minute)
  42.  
  43.         return tths
  44.  
  45.     def getdom4Status(self):
  46.         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  47.         s.connect((self.server,self.port))
  48.         s.sendall("\x66\x48\x01\x00\x00\x00\x03")
  49.         compdata = s.recv(1024*1024)
  50.         zdata = compdata[10:]
  51.         data = zlib.decompress(zdata)
  52.         retstr = ""
  53.         ## Actually interesting data starts at byte 7
  54.         idata = data[6:]
  55.  
  56.         #eextract the name
  57.         name = ""
  58.         idx = 0
  59.         while ord(idata[idx]) > 0:
  60.             name = name + idata[idx]
  61.             idx+=1
  62.  
  63.         # Burn the next 7 unintersting pieces
  64.         idx += 7
  65.         idata = idata[idx:]
  66.         tthl = struct.unpack('<L',idata[0:4])
  67.  
  68.         idata = idata[5:]
  69.  
  70.         nationStatus = idata[0:NUM_NATIONS]
  71.         submitted = idata[NUM_NATIONS:NUM_NATIONS*2]
  72.         connected = idata[NUM_NATIONS*2:NUM_NATIONS*3]
  73.  
  74.         idata = idata[NUM_NATIONS*3:]
  75.         turnNumber = struct.unpack('<l',idata[0:4])[0]
  76.         numNations = reduce(lambda x,y: x+y,map(lambda x:1 if ord(x)==1 else 0,nationStatus[5:]))
  77.         subNations = reduce(lambda x,y: x+y,map(lambda x:1 if ord(x)>0 else 0,submitted[5:]))
  78.  
  79.         self.name = name
  80.         self.tth = tthl[0]
  81.         self.currentTurn = turnNumber
  82.         self.nations = numNations
  83.         self.subNations = subNations
  84.  
  85.     def updateStatus(self, g):
  86.         self.tth = g.tth
  87.         self.currentTurn = g.currentTurn
  88.         self.subNations = g.subNations
  89.  
  90.     def checkTurn(self):
  91.         if self.currentTurn > self.processedTurn:
  92.             self.processedTurn = self.currentTurn
  93.             return "New turn in %s (%d)" % (self.name, self.currentTurn)
  94.         else:
  95.             return None
  96.  
  97.  
  98.  
  99. class DiosBot(irc.IRCClient):
  100.     nickname = 'DiosBot' # nickname
  101.     password = '' # server pass
  102.  
  103.     def save(self):
  104.         try:
  105.             f = open('diosbot.txt','wb')
  106.             pickle.dump(self.games,f)
  107.             f.close()
  108.         except IOError:
  109.             return
  110.  
  111.         try:
  112.             f = open('diosbotr.txt','wb')
  113.             pickle.dump(self.remember,f)
  114.             f.close()
  115.         except IOError:
  116.             return
  117.  
  118.  
  119.     def load(self):
  120.         try:
  121.             f = open('diosbot.txt','rb');
  122.             self.games = pickle.load(f)
  123.             f.close()
  124.         except IOError:
  125.             self.games = {}
  126.         except EOFError as e:
  127.             print e
  128.             self.games = {}
  129.  
  130.         try:
  131.             f = open('diosbotr.txt','rb');
  132.             self.remember = pickle.load(f)
  133.             f.close()
  134.         except IOError:
  135.             self.remember = {}
  136.         except EOFError as e:
  137.             print e
  138.             self.remember = {}
  139.  
  140.  
  141.     def poll(self):
  142.         """ Poll games and shit"""
  143.  
  144.         for gname, g in self.games.iteritems():
  145.             g.getdom4Status()
  146.             tt = g.checkTurn()
  147.             if tt:
  148.                 self.msg(self.channel, tt)
  149.  
  150.         self.save()
  151.  
  152.  
  153.     def connectionMade(self):
  154.         irc.IRCClient.connectionMade(self)
  155.  
  156.         ## We'll use this to setup the bot.
  157.         self.games = {}
  158.         self.remember = {}
  159.         self.load()
  160.  
  161.         ## Setup the polling timer  Run every 10 minutes
  162.         l = task.LoopingCall(self.poll)
  163.         l.start(60*10)
  164.  
  165.     def connectionLost(self, reason):
  166.         irc.IRCClient.connectionLost(self, reason)
  167.         self.save()
  168.  
  169.     # callbacks for events
  170.  
  171.     def signedOn(self):
  172.         """Called when bot has succesfully signed on to server."""
  173.         self.join(self.factory.channel)
  174.  
  175.     def joined(self, channel):
  176.         """This will get called when the bot joins the channel."""
  177.         self.channel = channel
  178.  
  179.  
  180.     def privmsg(self, user, channel, msg):
  181.         """This will get called when the bot receives a message."""
  182.         user = user.split('!', 1)[0]
  183.  
  184.         # Check to see if they're sending me a private message
  185.         if channel == self.nickname:
  186.             return
  187.  
  188.         if channel == self.factory.channel:
  189.  
  190.             ## Asking for staus by server/port
  191.             mm = re.match(r"!status (\S+)\s+([0-9]+)",msg)
  192.             if mm:
  193.                 ## Status Request
  194.                 g = Game()
  195.                 g.server = mm.group(1)
  196.                 g.port = int(mm.group(2))
  197.                 g.getdom4Status()
  198.                 self.msg(channel, "Game: %s Turn:%d Submitted: %d/%d Time to Host: %s" % (g.name, g.currentTurn, g.subNations, g.nations, g.tthformat()))
  199.  
  200.                 if g.name in self.games.keys() :
  201.                     self.games[g.name].updateStatus(g)
  202.                     tt = self.games[g.name].checkTurn()
  203.                     if tt:
  204.                         self.msg(channel, tt)
  205.                 else:
  206.                     self.games[g.name] = g
  207.                     g.processedTurn = g.currentTurn
  208.                     self.save()
  209.  
  210.             ## Save the database to disk
  211.             mm = re.match(r"!save", msg)
  212.             if mm:
  213.                 self.save()
  214.  
  215.             ## Remember
  216.             mm = re.match(r".r (\S+)\s+(.+)", msg)
  217.             if mm:
  218.                 found = False
  219.                 subj = mm.group(1)
  220.                 obj = mm.group(2)
  221.  
  222.                 for rr in self.remember.keys():
  223.                     if(rr.lower() == subj.lower()):
  224.                         old = self.remember[rr]
  225.                         self.msg(channel, "%s: Forgetting %s %s, remembring this instead" % (user, rr, old))
  226.                         self.remember[rr] = obj
  227.                         found = True
  228.  
  229.                 if not found:
  230.                     self.remember[subj] = obj
  231.                     self.msg(channel, "%s: Done." % user)
  232.                 self.save()
  233.  
  234.             mm = re.match(r"\?(\S+)", msg)
  235.             if mm:
  236.                 subj = mm.group(1)
  237.  
  238.                 for rr in self.remember.keys():
  239.                     if(rr.lower() == subj.lower()):
  240.                         old = self.remember[rr]
  241.                         self.msg(channel, "%s %s" % (rr, old))
  242.  
  243.     def alterCollidedNick(self, nickname):
  244.         return nickname+'_'
  245.  
  246.     def action(self, user, channel, msg):
  247.         pass
  248.  
  249.     def irc_NICK(self, prefix, params):
  250.         """Called when an IRC user changes their nickname."""
  251.  
  252.  
  253. class DiosBotFactory(protocol.ClientFactory):
  254.     """A factory for LogBots.
  255.    A new protocol instance will be created each time we connect to the server.
  256.    """
  257.     protocol = DiosBot
  258.  
  259.     def __init__(self):
  260.         self.channel = '#dom4goons' #channel
  261.  
  262.     def clientConnectionLost(self, connector, reason):
  263.         """If we get disconnected, reconnect to server."""
  264.         connector.connect()
  265.  
  266.     def clientConnectionFailed(self, connector, reason):
  267.         print "connection failed:", reason
  268.         reactor.stop()
  269.  
  270.  
  271. if __name__ == '__main__':
  272.     # create factory protocol and application
  273.     f = DiosBotFactory()
  274.  
  275.     # connect factory to this host and port
  276.     hostname = 'irc.synirc.net' # irc-server-hostname
  277.     port = 6697 #port
  278.     reactor.connectSSL(hostname, port, f, ssl.ClientContextFactory())
  279.  
  280.     # run bot
  281.     reactor.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement