def __init__(self): self.listOfQ = [] self.listOfC = [] self.listOfF = [] self.USERS = UserList() self.TrumpObjects = {} self.resetList = []
def __init__(self, nick, realname, channels, admins, _ssl=False, reconnect=False, password=False, oper_user=False, oper_pass=False): self.users = UserList() self.user = User(nick=nick, real=realname) self.users.append(self.user) self.channels = ChannelList(self.users) self._nick = nick self._real = realname self.logger = logging.getLogger('teslabot.irc') self._init_channels = channels self._ssl = _ssl self._reconnect = reconnect self._reconnect_time = 0 self._password = password self._buffer = '' self._ipaddr = None self._oper = False self._oper_user = oper_user self._oper_pass = oper_pass self._msg_time = [] self._msg_last_id = 0 self._max_mps = 5 self._throttle = False self._ping = 0 self._stimeout_count = 0 self._SOCKET_TIMEOUT = 5 self._PING_TIMEOUT = 5 self._PING_FREQUENCY = 12 self._last_msg = 0 self.alive = 1 # Define users with administrator privileges for admin in admins: user = User(src=admin, admin=True) self.users.append(user)
def create_app(): app = Flask(__name__) app.user = User() app.userList = UserList() app.usermap = UserLocationStore() app.friendStore = FriendStore() app.messageStore = MessageStore() app.userlocation = UserLocation() app.register_blueprint(site) app.register_blueprint(myMap) app.register_blueprint(register) app.register_blueprint(adminTable) app.register_blueprint(add) app.register_blueprint(add_doc) app.register_blueprint(image) app.register_blueprint(event) app.register_blueprint(notifications) app.store = Store() app.commentStore = CommentStore() app.requestStore = RequestStore() app.store_images = Store_Image() app.store_documents = Store_Document() app.register_blueprint(friends) app.register_blueprint(messages) app.register_blueprint(new) app.time = Timesql() app.init_db = init_db() app.savelocation = SaveLocation() app.notificationStore = NotificationStore() # app.store.add_event(Event('World War II', date='15/12/1942', place='Turkey',content= 'Donec sed odio dui. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh ultricies vehicula ut id elit')) # app.store.add_event(Event('Train Accident', date='01/02/1985', place='California', content = 'Donec sed odio dui. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh ultricies vehicula ut id elit')) return app
def __init__(self, name: str, lang: str, diff: str = '') -> None: super().__init__(name) self.users: UserList = UserList() self.chatroom: PrivateChatroom = PrivateChatroom(name) self.current_img = "" self.mongo_manager = MongoManager() self.lang = lang self.diff = diff self.current_word = self._get_word() self.word = self.current_word['word'] self.tries = 0 self.round_counter = 0 self.is_full = (self.users.length() == self.MAX_USERS) self.creator = None self.is_started = False
def __init__(self, nick, realname, channels, admins, _ssl = False, reconnect = False, password = False, oper_user = False, oper_pass = False): self.users = UserList() self.user = User(nick=nick, real=realname) self.users.append(self.user) self.channels = ChannelList(self.users) self._nick = nick self._real = realname self.logger = logging.getLogger('teslabot.irc') self._init_channels = channels self._ssl = _ssl self._reconnect = reconnect self._reconnect_time = 0 self._password = password self._buffer = '' self._ipaddr = None self._oper = False self._oper_user = oper_user self._oper_pass = oper_pass self._msg_time = [] self._msg_last_id = 0 self._max_mps = 5 self._throttle = False self._ping = 0 self._stimeout_count = 0 self._SOCKET_TIMEOUT = 5 self._PING_TIMEOUT = 5 self._PING_FREQUENCY = 12 self._last_msg = 0 self.alive = 1 # Define users with administrator privileges for admin in admins: user = User(src=admin, admin=True) self.users.append(user)
class rocky(object): def __init__(self): self.listOfQ = [] self.listOfC = [] self.listOfF = [] self.USERS = UserList() self.TrumpObjects = {} self.resetList = [] def register(self, websocket, key, room, seatNo): gamerObject = self.USERS.checkForkey(key) if (self.USERS.canEnterTheRoom( room, seatNo)): ## Need to replace with sqllite logic print("Will add in room " + str(room)) else: print("Room is full or invalid seat no ") return False if gamerObject: # print (user) print("user already in table") if websocket in self.USERS.ws: print("ok ") else: print("we will re assign the socket with new one ") gamerObject.websocket = websocket gamerObject.seatNo = seatNo gamerObject.room = room ## Need this for swaping seat and Room self.USERS.addGameroRomm(room, seatNo, gamerObject) self.USERS.ws.append(websocket) return True else: #username = ("P" + "___" + key) ## This will change to sqllite Actitivy in USerList Object ## str( random.randint(9,7568) print(str(room) + "<-->" + str(seatNo)) gamerObject = Gamer( key, key, websocket, room, seatNo ) ## Will imporve the secuirty later , by checking for key and get email self.USERS.addtoList(gamerObject) self.USERS.addGameroRomm(room, seatNo, gamerObject) return True def unregister(self, websocket, room, seat): print("Before ") if self.USERS.removeFromRoom(websocket): if room in self.TrumpObjects: th = self.TrumpObjects[room] if th.P1 is not None and th.P1.seatNo == seat: th.P1 = None elif th.P2 is not None and th.P2.seatNo == seat: th.P2 = None elif th.P3 is not None and th.P3.seatNo == seat: th.P3 = None elif th.P4 is not None and th.P4.seatNo == seat: th.P4 = None elif th.P5 is not None and th.P5.seatNo == seat: th.P5 = None elif th.P6 is not None and th.P6.seatNo == seat: th.P6 = None Room = self.USERS.listOfRooms[room] PV.roomInfo(Room, False, th.tt.listOfKunugu, self.TrumpObjects[room].watchlist) print(str(room) + "::" + str(seat) + " free") print("free from list " + str(websocket)) return True def IsthereTrumpSession(self, websocket, room, seat): try: print("IsthereTrumpSession?? " + str(websocket)) #roomUsers = (self.USERS.getRoomDetails(websocket)) Room = self.USERS.listOfRooms[room] if not Room: return False r = room if r in self.TrumpObjects: gamer = self.USERS.getUserBywebSocket(websocket) if gamer: playerHand = [] P0 = self.TrumpObjects[r] playerInRoom = P0.getPlayerBySeat(gamer.userID, websocket, seat) if playerInRoom == "Not vacant": print("Still it is NOT vacant " + str(seat)) return False playerHand = playerInRoom.showHand() print("Reconnected fine " + str(playerInRoom.__dict__['name']) + " " + str(playerInRoom.__dict__['seatNo'])) PV.roomInfo(Room, gamer, P0.tt.listOfKunugu, P0.watchlist) RR = self.TrumpObjects[r].rules d = {} for we in range(1, 7): P = P0.tt.getPlayerName("P" + str(we)) d["SN" + str(we)] = P if RR.TrumpSet: reconnectMessage = { "villi": str(RR.villi), 'trump': RR.trump, 'dude': RR.dude, 'dudeTeam': RR.Dudeteam, 'hand': playerHand, 'VSF': [], "playsofar": P0.thisPlayForSunu, "names": d, "base0": P0.tt.t0base, "base1": P0.tt.t1base, "Mc": P0.tt.gameCount, "KunuguSeat": P0.tt.listOfKunugu } else: reconnectMessage = { "villi": str(RR.villi), 'trump': RR.trump, 'dude': RR.dude, "TrumpIsnotSet": 1, 'dudeTeam': RR.Dudeteam, 'hand': playerHand, 'VSF': RR.VSF, "playsofar": P0.thisPlayForSunu, "names": d, "base0": P0.tt.t0base, "base1": P0.tt.t1base, "Mc": P0.tt.gameCount, "KunuguSeat": P0.tt.listOfKunugu } for kk in (self.listOfQ): if kk['SN'] == gamer.seatNo + 1: message = { "event": "question", "usr": kk["usr"], "t": kk["t"], "quNo": kk["quNo"], "c": kk["c"], "r": kk["r"], "SN": kk["SN"], "VSF": kk["VSF"], "loopStart": kk["loopStart"] } self.listOfQ.remove(kk) message.update(reconnectMessage) self.askQustion(message, gamer) return True for kk in (self.listOfC): if kk['SN'] == gamer.seatNo + 1: message = { "event": "play", "hand": playerHand, "usr": kk["usr"], "pid": kk["pid"], "t": kk["t"], "playsofar": kk["playsofar"], "c": kk["c"], "r": kk["r"], "SN": kk["SN"] } self.listOfC.remove(kk) message.update(reconnectMessage) self.askCard(message, gamer) return True for kk in (self.listOfF): if kk['SN'] == gamer.seatNo + 1: message = { "event": "fold", "hand": playerHand, "usr": kk["usr"], "fid": kk["fid"], "r": kk["r"], "SN": kk["SN"] } self.listOfF.remove(kk) message.update(reconnectMessage) self.askFold(message, gamer) return True reconnectMessage.update({ "event": "Reconnect", "spinner": (P0.spinner + 6 - playerInRoom.seatNo) % 6 }) payload = json.dumps(reconnectMessage).encode('utf8') PV.mySendMessage(websocket, payload) else: print("Gamer is not found .Not registered ") return True else: False except Exception as ex: print(ex) print("Reconect Exception ") def askQustion(self, message, client): payload = json.dumps(message).encode('utf8') PV.mySendMessage(client.websocket, payload) self.listOfQ.append({ "quNo": message["quNo"], "status": "Asked", "ans": "", "usr": message["usr"], "t": message["t"], "c": message["c"], "r": message["r"], "SN": message["SN"], "VSF": message["VSF"], "loopStart": message["loopStart"] }) print("Question1 Asked " + message["usr"]) def askCard(self, message, client): payload = json.dumps(message).encode('utf8') PV.mySendMessage(client.websocket, payload) self.listOfC.append({ "pid": message["pid"], 'playsofar': message['playsofar'], "status": "Asked", "card": "", "usr": message["usr"], "t": message["t"], "c": message["c"], "r": message["r"], "SN": message["SN"] }) print("Card Asked " + message["usr"]) def askFold(self, message, client): payload = json.dumps(message).encode('utf8') PV.mySendMessage(client.websocket, payload) self.listOfF.append({ "fid": message["fid"], "status": "Asked", "usr": message["usr"], "r": message["r"], "SN": message["SN"] }) print("Fold Asked " + message["usr"]) def canWeStart(self, websocket, roomNo, seatNo): Room = self.USERS.listOfRooms[roomNo] PV.roomInfo(Room, False, [], []) if not Room: print("ERROR:2002 Issue while registring room and users__") websocket.sendMessage( "{'message':'Can't find room '}".encode('utf8'), False) return False if not None in Room: ## Need to change to Room logic . if roomNo in self.TrumpObjects: print("Game started already wont restart this time ") return "Game already" th = TrumpHandler.TrumpHandler(Room) self.TrumpObjects[roomNo] = th th.doTheDeal() th.tt.getOrderOfPlayers() PV.MatchIsDone( { "won": "", "base0": 5, "base1": 5, "dialoge": "let's start Maggi", "Mc": 0, "KunuguSeat": [] }, Room, []) PV.sendCard(th) quNO = "R" + str(roomNo) + str(0) P0 = th.tt.orderofPlay[0] villiSoFar = [{"S" + str(P0.seatNo): ""}] message = { "event": "question", "usr": P0.name, "SN": P0.seatNo, "t": "Team0", "quNo": quNO, "c": 0, "r": roomNo, "VSF": villiSoFar, "loopStart": 28 } self.askQustion(message, P0) PV.whoIsSpinner(th.tt.orderofPlay, P0, th.watchlist) th.spinner = P0.seatNo else: PV.boradCast( "Room: " + str(roomNo) + " need " + str(Room.count(None)), Room) def getAnswerOfOldquestion(self, AnsNo): obj = "" for kk in self.listOfQ: if kk['status'] == "DONE" and kk["quNo"] == AnsNo: obj = kk break self.listOfQ.remove(obj) return (kk) def getCardOfRequest(self, pid): obj = "" for kk in self.listOfC: if kk['status'] == "DONE" and kk["pid"] == pid: obj = kk break self.listOfC.remove(obj) return (kk) def managePlay(self, pid): lastCard = self.getCardOfRequest(pid) print(lastCard) r = lastCard["r"] seat = "S" + str(lastCard["SN"]) RR = self.TrumpObjects[r].rules TT = self.TrumpObjects[r].tt self.TrumpObjects[r].thisPlayForSunu.append({seat: lastCard["card"]}) self.TrumpObjects[r].thisPlay.append(lastCard["card"]) PlaySoFar = self.TrumpObjects[r].thisPlay c = lastCard["c"] ## --> Order of Index TT.orderofPlay[c].removeCard(lastCard["card"]) PV.playSoFar({"playsofar": self.TrumpObjects[r].thisPlayForSunu}, self.TrumpObjects[r], self.TrumpObjects[r].watchlist) if len(PlaySoFar) == 6: print("Will check who got it ") print(PlaySoFar) if RR.IsTrumpInPlay(PlaySoFar): print("Trump Round") newC = RR.trumpInAction(PlaySoFar) else: newC = RR.whoIsLeader(PlaySoFar) team = TT.orderofPlay[newC].team print(newC) print(team) self.TrumpObjects[r].thisPlay = [] self.TrumpObjects[r].thisPlayForSunu = [] if team == "Team0": RR.t0Pidi.append(PlaySoFar) else: RR.t1Pidi.append(PlaySoFar) TT.opener = newC TT.getOrderOfPlayers() PV.heGotPidi( TT.orderofPlay, TT.orderofPlay[(c + 1) % 6], self.TrumpObjects[r].watchlist ) ## Need to send my seat also & dummy one . it should sending after win or not PlaySoFar = [] ### To prevent 6 cards in second play TTO = TT.orderofPlay[(c + 1) % 6] if self.didHeWon(RR, TT, self.TrumpObjects[r].watchlist): print("match is over ") TTO = TT.orderofPlay[(c + 1) % 6] # {"fid":message["fid"],"status":"Asked","usr":message["usr"],"r":message["r"],"SN":message["SN"]} message = { "event": "fold", "usr": TTO.name, "fid": lastCard["pid"][:2], "t": TTO.team, "r": r, "SN": TTO.seatNo } self.askFold(message, TTO) self.startNextMatch(r, False, message) return True TTO = TT.orderofPlay[(c + 1) % 6] pid = lastCard["pid"][:2] + str(int(lastCard["pid"][2:]) + 1) message = { "event": "play", "hand": TTO.showHand(), "usr": TTO.name, "pid": pid, "t": TTO.team, "playsofar": self.TrumpObjects[r].thisPlayForSunu, "c": (c + 1) % 6, "r": r, "SN": TTO.seatNo } self.askCard(message, TTO) PV.whoIsSpinner(TT.orderofPlay, TTO, self.TrumpObjects[r].watchlist) self.TrumpObjects[r].spinner = TTO.seatNo def startNextMatch(self, r, okFromUI, fobject): if okFromUI: ## Need to add condition to check all 6 players are in table , then only it sends cards and call SetNextGame , getOrder functions th = self.TrumpObjects[r] resendAgain = th.emptySeat(fobject['SN']) if resendAgain: self.askFold(fobject, resendAgain) PV.chatSend( { "event": "chatSend", "r": r, "usr": "******", "role": "CPU", "text": "One of the seat is Empty ,can't start the game" }, th.tt.orderofPlay, th.watchlist) return False RR = th.rules TT = th.tt TT.VSF = [{}] RR.TrumpSet = False TT.setNextGame() TT.getOrderOfPlayers() th.doTheDeal() PV.sendCard(th) quNO = "R" + str(r) + str(0) P0 = TT.orderofPlay[0] message = { "event": "question", "usr": P0.name, "t": P0.team, "SN": P0.seatNo, "quNo": quNO, "c": 0, "r": r, "VSF": [], "loopStart": 28 } self.askQustion(message, self.TrumpObjects[r].tt.orderofPlay[0]) PV.whoIsSpinner(TT.orderofPlay, TT.orderofPlay[0], th.watchlist) th.spinner = P0.seatNo for kk in self.listOfF: if (kk['r'] == r): self.listOfF.remove( kk ) ## This will make sure that no fold is pending , to prevent client issue and unexpected restart else: print("Need to wait for ok from UI ") def didHeWon(self, rules, tt, watchlist): t0P = rules.getPoints(rules.t0Pidi) t1P = rules.getPoints(rules.t1Pidi) print('Team0 ' + str(t0P)) print('Team1 ' + str(t1P)) if rules.t1GetPoint: if rules.villi <= t1P: dialoge = str(t0P) + "/" + str(t1P) + ( " Red won with one base") tt.t1VillichuWon(rules.villi, rules.dudeSeatNo) message = { "won": "Team1", "base0": tt.t0base, "base1": tt.t1base, "dialoge": dialoge, "Mc": tt.gameCount, "KunuguSeat": tt.listOfKunugu } PV.MatchIsDone(message, tt.orderofPlay, watchlist) return True if (56 - rules.villi) < t0P: dialoge = str(t0P) + "/" + str(t1P) + ( " Black won with two base") tt.t1VillichuLoss(rules.villi) message = { "won": "Team0", "base0": tt.t0base, "base1": tt.t1base, "dialoge": dialoge, "Mc": tt.gameCount, "KunuguSeat": tt.listOfKunugu } PV.MatchIsDone(message, tt.orderofPlay, watchlist) return True else: if rules.villi <= t0P: dialoge = str(t0P) + "/" + str(t1P) + ( " Black won with one base ") tt.t0VillichuWon(rules.villi, rules.dudeSeatNo) message = { "won": "Team0", "base0": tt.t0base, "base1": tt.t1base, "dialoge": dialoge, "Mc": tt.gameCount, "KunuguSeat": tt.listOfKunugu } PV.MatchIsDone(message, tt.orderofPlay, watchlist) return True if (56 - rules.villi) < t1P: dialoge = str(t0P) + "/" + str(t1P) + ( " Red won with two base") tt.t0VillichuLoss(rules.villi) message = { "won": "Team1", "base0": tt.t0base, "base1": tt.t1base, "dialoge": dialoge, "Mc": tt.gameCount, "KunuguSeat": tt.listOfKunugu } PV.MatchIsDone(message, tt.orderofPlay, watchlist) return True return False def manageVilli(self, AnsNo): lastVilli = self.getAnswerOfOldquestion(AnsNo) r = lastVilli["r"] gamers = self.USERS.listOfRooms[r] RR = self.TrumpObjects[r].rules TT = self.TrumpObjects[r].tt c = lastVilli["c"] seat = "S" + str(lastVilli["SN"]) RR.VSF.append({seat: lastVilli["ans"]}) print(RR.VSF) if lastVilli["ans"] == "P": RR.skipped.add(lastVilli["usr"]) if ( len(RR.skipped) == 6 ): ## Need to change for 6 and RR.dudeSeatNo == lastVilli["SN"] print(RR.villi) RR.TrumpSet = True PV.TrumpIsSet( { "villi": str(RR.villi), "trump": RR.trump, "dude": RR.dude, "dudeTeam": RR.Dudeteam }, TT.orderofPlay, self.TrumpObjects[r].watchlist) if RR.Dudeteam == "Team1": RR.t1GetPoint = True else: RR.t1GetPoint = False pid = "R" + str(r) + str(1) ##self.sendCard(self.TrumpObjects[r]) ## Not need message = { "event": "play", "hand": TT.orderofPlay[0].showHand(), "usr": TT.orderofPlay[0].name, "pid": pid, "t": "Team0", "playsofar": [], "c": 0, "r": r, "SN": TT.orderofPlay[0].seatNo } self.askCard(message, TT.orderofPlay[0]) PV.whoIsSpinner(TT.orderofPlay, TT.orderofPlay[0], self.TrumpObjects[r].watchlist) self.TrumpObjects[r].spinner = TT.orderofPlay[0].seatNo return True else: RR.villi = int( lastVilli["ans"] [1:3]) ## Fixed for thirikail marakail , +1 +2 etc RR.trump = lastVilli["ans"][0] RR.dude = lastVilli["usr"] RR.dudeSeatNo = lastVilli["SN"] RR.Dudeteam = lastVilli["t"] if lastVilli["usr"] in RR.skipped: RR.skipped.remove(lastVilli["usr"]) message = { "seat": seat, "Villi": lastVilli["ans"], "VSF": RR.VSF, "dude": RR.dude, "dudeTeam": RR.Dudeteam } PV.heCalled(message, gamers, self.TrumpObjects[r].watchlist) quNo = lastVilli["quNo"][:2] + str(int(lastVilli["quNo"][2:]) + 1) TTO = TT.orderofPlay[(c + 1) % 6] message = { "event": "question", "usr": TTO.name, "t": TTO.team, "quNo": quNo, "c": (c + 1) % 6, "r": r, "SN": TTO.seatNo, "VSF": RR.VSF, "loopStart": RR.villi + 1 } self.askQustion(message, TTO) PV.whoIsSpinner(TT.orderofPlay, TTO, self.TrumpObjects[r].watchlist) self.TrumpObjects[r].spinner = TTO.seatNo def resetBase(self, usr, room, seatNo): Room = self.USERS.listOfRooms[room] if not (Room[seatNo].userID == usr): print("Invalid player request to reset the game ") return False for kk in self.resetList: if room in kk: if (kk[room] + seatNo) % 2 == 1: print("going to reset for " + str(room + 1)) TT = self.TrumpObjects[room].tt TT.t0base = 5 TT.t1base = 5 TT.gameCount = 0 TT.listOfKunugu = [] TT.KunugSetAt = -1 TT.lastKunugTeam = "" for yo in self.listOfQ: if int(yo['r']) == room: print("Removing # QUESTION: due to Reset") self.listOfQ.remove(yo) for yo in self.listOfC: if int(yo['r']) == room: print("Removing # card list due to Reset") self.listOfC.remove(yo) PV.MatchIsDone( { "won": "", "base0": 5, "base1": 5, "dialoge": "Reset by " + str(kk[room] + 1) + "_" + str(seatNo + 1), "Mc": 0, "KunuguSeat": [] }, Room, self.TrumpObjects[room].watchlist) self.startNextMatch( room, True, { "event": "fold", "usr": TT.orderofPlay[0].name, "fid": -1, "t": TT.orderofPlay[0].team, "r": room, "SN": TT.orderofPlay[0].seatNo }) self.resetList = [] return True print(" Reset request for " + str(room) + " " + str(seatNo)) d = {} d[room] = seatNo self.resetList.append(d) def gotoLobby(self, usr, room, seatNo): Room = self.USERS.listOfRooms[room] if not (Room[seatNo].userID == usr): print("Invalid player request to reset the game ") return False if room in self.TrumpObjects: th = self.TrumpObjects[room] if th.P1.seatNo == seatNo + 1: th.P1 = None elif th.P2.seatNo == seatNo + 1: print(th.P2.name) th.P2 = None elif th.P3.seatNo == seatNo + 1: th.P3 = None elif th.P4.seatNo == seatNo + 1: th.P4 = None elif th.P5.seatNo == seatNo + 1: th.P5 = None elif th.P6.seatNo == seatNo + 1: th.P6 = None self.USERS.listOfRooms[room][seatNo] = None print("send to lobby") def addToWatchlist(self, websocket, room): if room in self.TrumpObjects: print("Will add in watch list") self.TrumpObjects[room].watchlist.append(websocket) th = self.TrumpObjects[room] Room = self.USERS.listOfRooms[room] PV.roomInfo(Room, False, th.tt.listOfKunugu, th.watchlist) else: print("invalid room") def removeToWatchlist(self, websocket, room): if room in self.TrumpObjects: if websocket in self.TrumpObjects[room].watchlist: self.TrumpObjects[room].watchlist.remove(websocket) else: print("Not able to remove")
from gameroom.free_gameroom import FreeGameroom from gameroom.gameroom import Gameroom, GameroomList from gameroom.solo_gameroom import SoloGameroom from gameroom.tuto_gameroom import TutoGameroom from message import UserMessage from mongo_manager import AbsentEntryError, MissingParameterError, MongoManager from user import User, UserList Payload.max_decode_packets = 1000 app = Flask(__name__) app.config['SECRET_KEY'] = random.randbytes(16) socketio = SocketIO(app, cors_allowed_origins="*", ping_timeout=12000) connectedUsers = {} connected_users_list = UserList() db = MongoManager() chatrooms = ChatroomList() gamerooms = GameroomList() ######### # UTILS # ######### def verify_session(event): def verify_session_decor(fn): def wrapper(*args, **kwargs): user = connected_users_list.get_instance_by_sid(request.sid) if user is None: print(f'Unauthorized user event: {event}') resp = get_resp(0, 'Unauthorized: user not connected', {})
class IRC(object): """ IRC protocol interface. Attributes: user: A User object to store the bot's user details logger: A Logger object channels: A ChannelList object admins: A list of User objects ssl: A boolean to enable or disable SSL wrapper _init_channels: A list of channels that is joined when the client is connected _reconnect: Whether or not to reconnect when socket connection is lost _password: The connection password (if any) _buffer: A socket buffer string _oper: Boolean indicating whether or not the server accepts the client as an IRCOP _oper_user: A username string argument for the OPER command _oper_pass: A password string argument for the OPER command _ping: UNIX time of last ping request _stimeout_count: A counter to keep track of the number of timeouts _SOCKET_TIMEOUT: The number of seconds before the socket times out _PING_TIMEOUT: The number of seconds after which a PING message is considered timed out _PING_FREQUENCY: The number of seconds (in multiples of _SOCKET_TIMEOUT) that must elapse before a PING message is sent to the server. _last_msg: UNIX time of latest received message """ def __init__(self, nick, realname, channels, admins, _ssl = False, reconnect = False, password = False, oper_user = False, oper_pass = False): self.users = UserList() self.user = User(nick=nick, real=realname) self.users.append(self.user) self.channels = ChannelList(self.users) self._nick = nick self._real = realname self.logger = logging.getLogger('teslabot.irc') self._init_channels = channels self._ssl = _ssl self._reconnect = reconnect self._reconnect_time = 0 self._password = password self._buffer = '' self._ipaddr = None self._oper = False self._oper_user = oper_user self._oper_pass = oper_pass self._msg_time = [] self._msg_last_id = 0 self._max_mps = 5 self._throttle = False self._ping = 0 self._stimeout_count = 0 self._SOCKET_TIMEOUT = 5 self._PING_TIMEOUT = 5 self._PING_FREQUENCY = 12 self._last_msg = 0 self.alive = 1 # Define users with administrator privileges for admin in admins: user = User(src=admin, admin=True) self.users.append(user) def run(self): """ Keeps the the connection alive by continuously calling _recv(). It will attempt to reconnect if connection is lost and reconnect is enabled. """ while self.alive: try: self._recv() except socket.error as e: self.reconnect() def _get_headers(self): return ':' + self.user.nick + '!' + self.user.real + '@' + self.user.host def join(self, chan): """Accepts channel name string.""" self.send('JOIN :{0}'.format(chan)) @property def nick(self): return self.user.nick @nick.setter def nick(self, value): self.send('NICK {0}'.format(value)) self.user.nick = value def notice(self, msg, nick): """Accepts a string or a list of messages.""" if type(msg) == list: for line in msg: if len(line) > 0: self.send(u'NOTICE {0} :{1}'.format(nick, line)) self.logger.info('>{0}< {1}'.format(nick, line)) else: msg = msg.split('\r\n') for line in msg: maxlen = 512 - len(self._get_headers()) - len(nick) - 12 if len(line) < maxlen: self.send('NOTICE {0} :{1}'.format(nick, line)) self.logger.info('>{0}< {1}'.format(nick, line)) else: self.send('NOTICE {0} :{1}'.format(nick, line[:maxlen-1])) self.logger.info('>{0}< {1}'.format(nick, line[:maxlen-1])) self.notice(line, line[maxlen-1:]) def mode(self, target, modes = False, args = False): """Sends a MODE command. Args: target: A channel or nick string modes: A string of flags args: An argument string """ if not modes: self.send('MODE {0}'.format(target)) elif modes and not args: self.send('MODE {0} {1}'.format(target, modes)) elif modes and args: self.send('MODE {0} {1} {2}'.format(target, modes, args)) def kick(self, nick, chan, reason = ''): self.send(u'KICK {0} {1} :{2}'.format(chan, nick, reason)) def _get_avg_mps(self): """Returns the average rate of sent messages per second.""" x1 = self._msg_last_id - self._max_mps t1 = self._msg_time[self._msg_last_id - self._max_mps] x2 = self._msg_last_id t2 = self._msg_time[self._msg_last_id] avg_mps = (x2 - x1) / (t2 - t1) return avg_mps def _is_throttling(self): """Returns true if the rate of messages per second has exceeded the limit. Formula: (x2 - x1)/(t2 - t1) = mps (average messages per second) where (x1, t1) and (x2, t2) represent amount of x messages covered in y seconds. The distance between (x1, t1) and (x2, t2) is determined by _max_mps (5 by default). If the average mps exceeds _max_mps, throttling occurs. When throttling, messages are sent every 1 second. When the average mps is equal to or less than 1, throttling stops. Data structure: _msg_time: a list of UNIX time values, whose index represents the number of messages. Although in practice, the difference between each index is the only relevant fact. As a result, we "pop" values from the beginning of the list that are no longer needed. """ self._msg_time.append(time.time()) throttle = False if self._throttle: avg_mps = self._get_avg_mps() if self._msg_last_id % self._max_mps == 0: # In order to prevent the list from growing big, we drop values we no longer need. self._msg_time.pop(0) self._msg_last_id -= 1 if avg_mps <= 1: self.logger.warning('Throttling disabled.') self._throttle = False else: self.logger.warning('Throttling.') throttle = True elif len(self._msg_time) > self._max_mps: avg_mps = self._get_avg_mps() # In order to prevent the list from growing large, we drop values we no longer need. if self._msg_last_id % self._max_mps == 0: self._msg_time.pop(0) self._msg_last_id -= 1 if avg_mps >= self._max_mps: self.logger.warning('Throttling enabled.') self._throttle = throttle = True else: throttle = False self._msg_last_id += 1 return throttle def send(self, msg, silent = False): """msg should be 512 bytes or less""" if self._is_throttling(): time.sleep(1) # Encode to bytes -- assuming it's a utf-8 string msg = msg.encode('utf-8') self.sock.send(msg + '\r\n') if not silent: self.logger.debug('{0}'.format(msg)) def leave(self, chan, reason = 'Leaving'): self.send('PART {0} :{1}'.format(chan, reason)) def say(self, msg, dst): msg = msg.split('\r\n') for line in msg: maxlen = 512 - len(self._get_headers()) - len(dst) - 12 if len(line) < maxlen: self.send(u'PRIVMSG {0} :{1}'.format(dst, line)) self.logger.info(u'[{0}] <{1}> {2}'.format(dst, self.user.nick, line)) else: self.send(u'PRIVMSG ' + dst + ' :' + line[:maxlen-1]) self.logger.info(u'[{0}] <{1}> {2}'.format(dst, self.user.nick, line[:maxlen-1])) self.say(line[maxlen-1:], dst) def names(self, chan): self.send('NAMES {0}'.format(chan)) def action(self, msg, dst): self.send('PRIVMSG ' + dst + ' :\x01ACTION ' + msg + '\x01') def whois(self, nick): self.send('WHOIS {0}'.format(nick)) def oper(self, username = False, password = False): if not username: username = self._oper_user if not password: password = self._oper_pass self.send('OPER {0} {1}'.format(username, password), True) def is_chan(self, chan): """Returns true if a given string is a valid channel name.""" if chan[:1] in ('&', '#', '+', '!'): return True return False def _on_privmsg(self, user, args): """Calls the appropriate handler for a given PRIVMSG type. Either channel, private, or CTCP message. Args: user: A User class instance args: A string of arguments """ dst, msg = args.split(' ', 1) # CTCP query/reply if msg[1] == '\x01' and msg[-1] == '\x01': ctcp_msg = msg[2:-1] if len(ctcp_msg.split()) > 1: cmd, subargs = ctcp_msg.split(' ', 1) else: cmd = ctcp_msg subargs = None self.on_ctcp(user, cmd, subargs) # Channel message if self.is_chan(dst[:1]): self.on_channel_message(user, self.channels.get(dst), msg[1:]) # Private query elif dst.lower() == self.user.nick.lower(): self.on_private_message(user, msg[1:]) else: self.logger.warning("Unrecognized PRIVMSG format.") def quit(self, msg = 'Quitting', force = None): try: if force: sys.exit() self.send('QUIT :{0}'.format(msg)) self.sock.close() self.alive = 0 finally: self.logger.info('Disconnected from [{0}].'.format(self.user.host)) def ping(self): self.send('PING {0}'.format(self._host)) self._ping = time.time() def _set_hostname(self, hostname): self.user.host = hostname def _recv_timeout(self): self._stimeout_count += 1 if self._stimeout_count >= self._PING_FREQUENCY and not self._ping: self._stimeout_count = 0 self.ping() elif self._ping: diff = time.time() - self._ping if diff >= self._PING_TIMEOUT: self.logger.info('Disconnected due to timeout.') self.reconnect() def _recv(self, timeout = False): """Processes messages received from the IRC server and calls the appropriate handlers.""" buffer = '' self._last_msg = time.time() try: buffer = self._buffer + self.sock.recv(512) except (socket.error, ssl.SSLError) as e: if e.message == 'The read operation timed out'\ or e.message == 'timed out': self._recv_timeout() return except socket.timeout: self._recv_timeout() return self._buffer = '' # Server has closed the socket connection if len(buffer) == 0: self.logger.debug('Server has closed socket connection.') raise socket.error data = buffer.split('\r\n') # If not empty, this is part of a new message. Add it to the buffer. self._buffer += data.pop() # Server didn't send CRLF if not len(data): return # Remove empty strings due to an \r\n in the beginning if data[0] == '': data.pop(0) for msg in data: self.logger.debug('{0}'.format(msg)) # Assuming it's UTF-8 encoded. If not, ignore errors. self._parse_message(msg.decode('utf-8', 'ignore')) def _parse_message(self, msg): """Parses a given IRC message.""" if msg[:4] == 'PING': self.send('PONG {0}'.format(msg[5:])) return elif msg[:5] == 'ERROR': self.quit(force=True) src, cmd, args = msg.split(' ', 2) user = self.users.get(src[1:]) if cmd == 'PONG' and self._ping: diff = time.time() - self._ping self._ping = 0 self.logger.debug('PONG acknowledged ({0}s).'.format(diff)) elif cmd == 'PRIVMSG': self._on_privmsg(user, args) elif cmd == 'MODE': args = args.split(' ', 2) subargs = False if self.is_chan(args[0]): if len(args) == 3: subargs = args.pop().split() chan, modes = args channel = self.channels.get(chan) self.on_channel_mode(user, channel, modes, subargs) elif cmd == 'NOTICE': self.on_notice(user, args) elif cmd == 'TOPIC': chan = args.split(' ', 1)[0] topic = args.split(' ', 1)[1][1:] self.on_channel_topic(user, self.channels[chan], topic) elif cmd == 'JOIN': if args[0] != ':': chan = args else: chan = args[1:] channel = self.channels.add(chan) self.on_channel_join(user, channel) elif cmd == 'KICK': chan, target, reason = args.split(' ', 2) channel = self.channels[chan] target = self.users.get(target) self.on_channel_kick(user, channel, target, reason[1:]) elif cmd == 'NICK': self.users.get(user=user).nick = args elif cmd == 'PART': subargs = args.split() if len(subargs) == 2: chan, reason = subargs self.on_channel_part(user, self.channels[chan], reason[1:]) else: chan = args.split()[0] self.on_channel_part(user, self.channels[chan]) elif cmd == RPL_WELCOME: self.on_connect() elif cmd == RPL_YOUREOPER: self._oper = True elif cmd == RPL_HOSTHIDDEN: self._set_hostname(args) elif cmd in (RPL_WHOISUSER, RPL_WHOISIDLE, RPL_WHOISACTUALLY, RPL_WHOISHOST): self._on_whois(cmd, args) elif cmd == ERR_NICKNAMEINUSE: self.on_nickinuse() elif cmd in (RPL_TOPIC, RPL_TOPICWHOTIME, RPL_NAMREPLY): self.channels.on_reply(cmd, args) elif cmd in (RPL_MOTDSTART, RPL_MOTD, RPL_ENDOFMOTD): self.on_motd(args) def on_motd(self, msg): if not __debug__: self.logger.info(msg.split(':', 1)[1]) def _on_whois(self, cmd, args): if cmd == RPL_WHOISUSER: if args.split(' ')[1] == self.user.nick: # Self-WHOIS self._set_hostname(args.split(' ')[3]) # Get the hostname self.logger.debug('Setting hostname to [{0}].'.format(self.user.host)) else: pass elif cmd == RPL_WHOISIDLE: args = args.split() user = self.users.get(args[1]) user.idle = int(args[2]) user.signon = int(args[3]) elif cmd == RPL_WHOISACTUALLY: self._ipaddr = args.split()[-1][1:-1] elif cmd == RPL_WHOISHOST: self._ipaddr = args.split()[-1] def ipaddr(self): return self._ipaddr def connect(self, host, port): """Attempts to establish a socket connection with a given IRC server.""" self._host = host self._port = port try: self.logger.info('Connecting to {0}:{1}.'.format(host, port)) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self._ssl: self.sock = ssl.wrap_socket(self.sock, cert_reqs=ssl.CERT_NONE) self.sock.settimeout(self._SOCKET_TIMEOUT) self.sock.connect((host, port)) self.alive = 1 if self._password: self.send('PASS {0}'.format(self._password)) self.send('NICK {0}'.format(self._nick)) self.send('USER {0} 0 * :{0}'.format(self._real)) except socket.error as e: self.logger.critical('Failed to connect to {0}:{1}.'.format(host, port)) def reconnect(self): if self._reconnect: # Wait 15 seconds before reconnecting again tdiff = time.time() - self._reconnect_time if self._reconnect_time and tdiff < 15: self.logger.info('Attempting to reconnect in 15 seconds...') time.sleep(15) self.logger.debug('Reconnecting.') self.connect(self._host, self._port) self._reconnect_time = time.time() else: self.logger.info('Reconnection disabled.') def on_connect(self): self.whois(self.user.nick) if self._oper_user and self._oper_pass: self.oper() for channel in self._init_channels: self.join(channel) def on_channel_mode(self, user, channel, modes, args = False): """Called when a channel mode is changed. TODO: Recognize channel modes that aren't specific to users. Args: args: A list of arguments """ for i, mode in enumerate(modes[1:]): if mode in ('a', 'q', 'o', 'h', 'v'): target = self.users.get(args[i]) if modes[0] == '+': target.modes.add(channel.name, mode) else: target.modes.remove(channel.name, mode) def on_channel_message(self, user, channel, msg): raise NotImplementedError def on_channel_join(self, user, channel): """on_channel_join is called when a user (including the bot) joins a channel. Args: channel: A Channel instance user: A user instance """ # Requests channel modes self.mode(channel.name) def on_channel_part(self, user, channel, reason): """on_channel_part is called when a user (including the bot) leaves the channel.""" user.modes.remove(channel.name, -1) if user.nick == self.user.nick: self.channels.remove(channel) else: channel.remove(user) def on_channel_kick(self, user, channel, target, reason): raise NotImplementedError def on_channel_topic(self, user, channel, topic): raise NotImplementedError def on_private_message(self, user, msg): raise NotImplementedError def on_notice(self, user, msg): if not __debug__: self.logger.info('-{0}- {1}'.format(user.nick, msg)) def on_nickinuse(self): raise NotImplementedError def ctcp(self, msg, nick): self.send(u'PRIVMSG {2} :{0}{1}{0}'.format('\x01', msg, nick)) def on_ctcp(self, user, cmd, args): global __version__ if cmd == 'VERSION': self.notice('VERSION Teslabot {0}'.format(__version__), user.nick)
class IRC(object): """ IRC protocol interface. Attributes: user: A User object to store the bot's user details logger: A Logger object channels: A ChannelList object admins: A list of User objects ssl: A boolean to enable or disable SSL wrapper _init_channels: A list of channels that is joined when the client is connected _reconnect: Whether or not to reconnect when socket connection is lost _password: The connection password (if any) _buffer: A socket buffer string _oper: Boolean indicating whether or not the server accepts the client as an IRCOP _oper_user: A username string argument for the OPER command _oper_pass: A password string argument for the OPER command _ping: UNIX time of last ping request _stimeout_count: A counter to keep track of the number of timeouts _SOCKET_TIMEOUT: The number of seconds before the socket times out _PING_TIMEOUT: The number of seconds after which a PING message is considered timed out _PING_FREQUENCY: The number of seconds (in multiples of _SOCKET_TIMEOUT) that must elapse before a PING message is sent to the server. _last_msg: UNIX time of latest received message """ def __init__(self, nick, realname, channels, admins, _ssl=False, reconnect=False, password=False, oper_user=False, oper_pass=False): self.users = UserList() self.user = User(nick=nick, real=realname) self.users.append(self.user) self.channels = ChannelList(self.users) self._nick = nick self._real = realname self.logger = logging.getLogger('teslabot.irc') self._init_channels = channels self._ssl = _ssl self._reconnect = reconnect self._reconnect_time = 0 self._password = password self._buffer = '' self._ipaddr = None self._oper = False self._oper_user = oper_user self._oper_pass = oper_pass self._msg_time = [] self._msg_last_id = 0 self._max_mps = 5 self._throttle = False self._ping = 0 self._stimeout_count = 0 self._SOCKET_TIMEOUT = 5 self._PING_TIMEOUT = 5 self._PING_FREQUENCY = 12 self._last_msg = 0 self.alive = 1 # Define users with administrator privileges for admin in admins: user = User(src=admin, admin=True) self.users.append(user) def run(self): """ Keeps the the connection alive by continuously calling _recv(). It will attempt to reconnect if connection is lost and reconnect is enabled. """ while self.alive: try: self._recv() except socket.error as e: self.reconnect() def _get_headers(self): return ':' + self.user.nick + '!' + self.user.real + '@' + self.user.host def join(self, chan): """Accepts channel name string.""" self.send('JOIN :{0}'.format(chan)) @property def nick(self): return self.user.nick @nick.setter def nick(self, value): self.send('NICK {0}'.format(value)) self.user.nick = value def notice(self, msg, nick): """Accepts a string or a list of messages.""" if type(msg) == list: for line in msg: if len(line) > 0: self.send(u'NOTICE {0} :{1}'.format(nick, line)) self.logger.info('>{0}< {1}'.format(nick, line)) else: msg = msg.split('\r\n') for line in msg: maxlen = 512 - len(self._get_headers()) - len(nick) - 12 if len(line) < maxlen: self.send('NOTICE {0} :{1}'.format(nick, line)) self.logger.info('>{0}< {1}'.format(nick, line)) else: self.send('NOTICE {0} :{1}'.format(nick, line[:maxlen - 1])) self.logger.info('>{0}< {1}'.format( nick, line[:maxlen - 1])) self.notice(line, line[maxlen - 1:]) def mode(self, target, modes=False, args=False): """Sends a MODE command. Args: target: A channel or nick string modes: A string of flags args: An argument string """ if not modes: self.send('MODE {0}'.format(target)) elif modes and not args: self.send('MODE {0} {1}'.format(target, modes)) elif modes and args: self.send('MODE {0} {1} {2}'.format(target, modes, args)) def kick(self, nick, chan, reason=''): self.send(u'KICK {0} {1} :{2}'.format(chan, nick, reason)) def _get_avg_mps(self): """Returns the average rate of sent messages per second.""" x1 = self._msg_last_id - self._max_mps t1 = self._msg_time[self._msg_last_id - self._max_mps] x2 = self._msg_last_id t2 = self._msg_time[self._msg_last_id] avg_mps = (x2 - x1) / (t2 - t1) return avg_mps def _is_throttling(self): """Returns true if the rate of messages per second has exceeded the limit. Formula: (x2 - x1)/(t2 - t1) = mps (average messages per second) where (x1, t1) and (x2, t2) represent amount of x messages covered in y seconds. The distance between (x1, t1) and (x2, t2) is determined by _max_mps (5 by default). If the average mps exceeds _max_mps, throttling occurs. When throttling, messages are sent every 1 second. When the average mps is equal to or less than 1, throttling stops. Data structure: _msg_time: a list of UNIX time values, whose index represents the number of messages. Although in practice, the difference between each index is the only relevant fact. As a result, we "pop" values from the beginning of the list that are no longer needed. """ self._msg_time.append(time.time()) throttle = False if self._throttle: avg_mps = self._get_avg_mps() if self._msg_last_id % self._max_mps == 0: # In order to prevent the list from growing big, we drop values we no longer need. self._msg_time.pop(0) self._msg_last_id -= 1 if avg_mps <= 1: self.logger.warning('Throttling disabled.') self._throttle = False else: self.logger.warning('Throttling.') throttle = True elif len(self._msg_time) > self._max_mps: avg_mps = self._get_avg_mps() # In order to prevent the list from growing large, we drop values we no longer need. if self._msg_last_id % self._max_mps == 0: self._msg_time.pop(0) self._msg_last_id -= 1 if avg_mps >= self._max_mps: self.logger.warning('Throttling enabled.') self._throttle = throttle = True else: throttle = False self._msg_last_id += 1 return throttle def send(self, msg, silent=False): """msg should be 512 bytes or less""" if self._is_throttling(): time.sleep(1) # Encode to bytes -- assuming it's a utf-8 string msg = msg.encode('utf-8') self.sock.send(msg + '\r\n') if not silent: self.logger.debug('{0}'.format(msg)) def leave(self, chan, reason='Leaving'): self.send('PART {0} :{1}'.format(chan, reason)) def say(self, msg, dst): msg = msg.split('\r\n') for line in msg: maxlen = 512 - len(self._get_headers()) - len(dst) - 12 if len(line) < maxlen: self.send(u'PRIVMSG {0} :{1}'.format(dst, line)) self.logger.info(u'[{0}] <{1}> {2}'.format( dst, self.user.nick, line)) else: self.send(u'PRIVMSG ' + dst + ' :' + line[:maxlen - 1]) self.logger.info(u'[{0}] <{1}> {2}'.format( dst, self.user.nick, line[:maxlen - 1])) self.say(line[maxlen - 1:], dst) def names(self, chan): self.send('NAMES {0}'.format(chan)) def action(self, msg, dst): self.send('PRIVMSG ' + dst + ' :\x01ACTION ' + msg + '\x01') def whois(self, nick): self.send('WHOIS {0}'.format(nick)) def oper(self, username=False, password=False): if not username: username = self._oper_user if not password: password = self._oper_pass self.send('OPER {0} {1}'.format(username, password), True) def is_chan(self, chan): """Returns true if a given string is a valid channel name.""" if chan[:1] in ('&', '#', '+', '!'): return True return False def _on_privmsg(self, user, args): """Calls the appropriate handler for a given PRIVMSG type. Either channel, private, or CTCP message. Args: user: A User class instance args: A string of arguments """ dst, msg = args.split(' ', 1) # CTCP query/reply if msg[1] == '\x01' and msg[-1] == '\x01': ctcp_msg = msg[2:-1] if len(ctcp_msg.split()) > 1: cmd, subargs = ctcp_msg.split(' ', 1) else: cmd = ctcp_msg subargs = None self.on_ctcp(user, cmd, subargs) # Channel message if self.is_chan(dst[:1]): self.on_channel_message(user, self.channels.get(dst), msg[1:]) # Private query elif dst.lower() == self.user.nick.lower(): self.on_private_message(user, msg[1:]) else: self.logger.warning("Unrecognized PRIVMSG format.") def quit(self, msg='Quitting', force=None): try: if force: sys.exit() self.send('QUIT :{0}'.format(msg)) self.sock.close() self.alive = 0 finally: self.logger.info('Disconnected from [{0}].'.format(self.user.host)) def ping(self): self.send('PING {0}'.format(self._host)) self._ping = time.time() def _set_hostname(self, hostname): self.user.host = hostname def _recv_timeout(self): self._stimeout_count += 1 if self._stimeout_count >= self._PING_FREQUENCY and not self._ping: self._stimeout_count = 0 self.ping() elif self._ping: diff = time.time() - self._ping if diff >= self._PING_TIMEOUT: self.logger.info('Disconnected due to timeout.') self.reconnect() def _recv(self, timeout=False): """Processes messages received from the IRC server and calls the appropriate handlers.""" buffer = '' self._last_msg = time.time() try: buffer = self._buffer + self.sock.recv(512) except (socket.error, ssl.SSLError) as e: if e.message == 'The read operation timed out'\ or e.message == 'timed out': self._recv_timeout() return except socket.timeout: self._recv_timeout() return self._buffer = '' # Server has closed the socket connection if len(buffer) == 0: self.logger.debug('Server has closed socket connection.') raise socket.error data = buffer.split('\r\n') # If not empty, this is part of a new message. Add it to the buffer. self._buffer += data.pop() # Server didn't send CRLF if not len(data): return # Remove empty strings due to an \r\n in the beginning if data[0] == '': data.pop(0) for msg in data: self.logger.debug('{0}'.format(msg)) # Assuming it's UTF-8 encoded. If not, ignore errors. self._parse_message(msg.decode('utf-8', 'ignore')) def _parse_message(self, msg): """Parses a given IRC message.""" if msg[:4] == 'PING': self.send('PONG {0}'.format(msg[5:])) return elif msg[:5] == 'ERROR': self.quit(force=True) src, cmd, args = msg.split(' ', 2) user = self.users.get(src[1:]) if cmd == 'PONG' and self._ping: diff = time.time() - self._ping self._ping = 0 self.logger.debug('PONG acknowledged ({0}s).'.format(diff)) elif cmd == 'PRIVMSG': self._on_privmsg(user, args) elif cmd == 'MODE': args = args.split(' ', 2) subargs = False if self.is_chan(args[0]): if len(args) == 3: subargs = args.pop().split() chan, modes = args channel = self.channels.get(chan) self.on_channel_mode(user, channel, modes, subargs) elif cmd == 'NOTICE': self.on_notice(user, args) elif cmd == 'TOPIC': chan = args.split(' ', 1)[0] topic = args.split(' ', 1)[1][1:] self.on_channel_topic(user, self.channels[chan], topic) elif cmd == 'JOIN': if args[0] != ':': chan = args else: chan = args[1:] channel = self.channels.add(chan) self.on_channel_join(user, channel) elif cmd == 'KICK': chan, target, reason = args.split(' ', 2) channel = self.channels[chan] target = self.users.get(target) self.on_channel_kick(user, channel, target, reason[1:]) elif cmd == 'NICK': self.users.get(user=user).nick = args elif cmd == 'PART': subargs = args.split() if len(subargs) == 2: chan, reason = subargs self.on_channel_part(user, self.channels[chan], reason[1:]) else: chan = args.split()[0] self.on_channel_part(user, self.channels[chan]) elif cmd == RPL_WELCOME: self.on_connect() elif cmd == RPL_YOUREOPER: self._oper = True elif cmd == RPL_HOSTHIDDEN: self._set_hostname(args) elif cmd in (RPL_WHOISUSER, RPL_WHOISIDLE, RPL_WHOISACTUALLY, RPL_WHOISHOST): self._on_whois(cmd, args) elif cmd == ERR_NICKNAMEINUSE: self.on_nickinuse() elif cmd in (RPL_TOPIC, RPL_TOPICWHOTIME, RPL_NAMREPLY): self.channels.on_reply(cmd, args) elif cmd in (RPL_MOTDSTART, RPL_MOTD, RPL_ENDOFMOTD): self.on_motd(args) def on_motd(self, msg): if not __debug__: self.logger.info(msg.split(':', 1)[1]) def _on_whois(self, cmd, args): if cmd == RPL_WHOISUSER: if args.split(' ')[1] == self.user.nick: # Self-WHOIS self._set_hostname(args.split(' ')[3]) # Get the hostname self.logger.debug('Setting hostname to [{0}].'.format( self.user.host)) else: pass elif cmd == RPL_WHOISIDLE: args = args.split() user = self.users.get(args[1]) user.idle = int(args[2]) user.signon = int(args[3]) elif cmd == RPL_WHOISACTUALLY: self._ipaddr = args.split()[-1][1:-1] elif cmd == RPL_WHOISHOST: self._ipaddr = args.split()[-1] def ipaddr(self): return self._ipaddr def connect(self, host, port): """Attempts to establish a socket connection with a given IRC server.""" self._host = host self._port = port try: self.logger.info('Connecting to {0}:{1}.'.format(host, port)) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self._ssl: self.sock = ssl.wrap_socket(self.sock, cert_reqs=ssl.CERT_NONE) self.sock.settimeout(self._SOCKET_TIMEOUT) self.sock.connect((host, port)) self.alive = 1 if self._password: self.send('PASS {0}'.format(self._password)) self.send('NICK {0}'.format(self._nick)) self.send('USER {0} 0 * :{0}'.format(self._real)) except socket.error as e: self.logger.critical('Failed to connect to {0}:{1}.'.format( host, port)) def reconnect(self): if self._reconnect: # Wait 15 seconds before reconnecting again tdiff = time.time() - self._reconnect_time if self._reconnect_time and tdiff < 15: self.logger.info('Attempting to reconnect in 15 seconds...') time.sleep(15) self.logger.debug('Reconnecting.') self.connect(self._host, self._port) self._reconnect_time = time.time() else: self.logger.info('Reconnection disabled.') def on_connect(self): self.whois(self.user.nick) if self._oper_user and self._oper_pass: self.oper() for channel in self._init_channels: self.join(channel) def on_channel_mode(self, user, channel, modes, args=False): """Called when a channel mode is changed. TODO: Recognize channel modes that aren't specific to users. Args: args: A list of arguments """ for i, mode in enumerate(modes[1:]): if mode in ('a', 'q', 'o', 'h', 'v'): target = self.users.get(args[i]) if modes[0] == '+': target.modes.add(channel.name, mode) else: target.modes.remove(channel.name, mode) def on_channel_message(self, user, channel, msg): raise NotImplementedError def on_channel_join(self, user, channel): """on_channel_join is called when a user (including the bot) joins a channel. Args: channel: A Channel instance user: A user instance """ # Requests channel modes self.mode(channel.name) def on_channel_part(self, user, channel, reason): """on_channel_part is called when a user (including the bot) leaves the channel.""" user.modes.remove(channel.name, -1) if user.nick == self.user.nick: self.channels.remove(channel) else: channel.remove(user) def on_channel_kick(self, user, channel, target, reason): raise NotImplementedError def on_channel_topic(self, user, channel, topic): raise NotImplementedError def on_private_message(self, user, msg): raise NotImplementedError def on_notice(self, user, msg): if not __debug__: self.logger.info('-{0}- {1}'.format(user.nick, msg)) def on_nickinuse(self): raise NotImplementedError def ctcp(self, msg, nick): self.send(u'PRIVMSG {2} :{0}{1}{0}'.format('\x01', msg, nick)) def on_ctcp(self, user, cmd, args): global __version__ if cmd == 'VERSION': self.notice('VERSION Teslabot {0}'.format(__version__), user.nick)
def init_flask_openid(app): return OpenID(app) def init_flask(name): app = Flask(name) app.config.update(SECRET_KEY='development key', DEBUG=True) return app app = init_flask(__name__) oid = init_flask_openid(app) from user import UserList user_list = UserList() def render_time(fn): @wraps(fn) def inner(*args, **kwargs): start = time.time() result = fn(*args, **kwargs) end = time.time() try: return result.replace("TTTTIME", "%.4f" % (end - start)) except AttributeError: return result return inner
class Server: group_id = 191177272 access_token = 'access_token=f068c796542cba0f4dbdd0f6e39ba656a489731d36cfdcbdf7cee30de822ae000aa9e1aa8293bc61d77c7' v = 'v=5.103' # Текущая версия VkAPI body = 'https://api.vk.com/method/' # Тело запроса data = UserList() closest_time = 'z' # to make it bigger than numbers closest_events = dict() def __init__(self): Server.getLongPollServer(self) self.find_closest_events() def find_closest_events(self): self.closest_events, self.closest_time = dict(), 'z' for key, value in self.data.get_dict().items(): for sub_key, sub_value in value.items(): if sub_key <= self.closest_time: self.closest_time = sub_key self.closest_events[key] = sub_value def send_notifications(self): for key, value in self.closest_events.items(): message, user_id, random_id = value, key, random.randint(0, 100) method = 'messages.send?' + 'user_id=' + str(user_id) + '&random_id=' + str(random_id) \ + '&message=' + message r = requests.get("&".join([Server.body + method, Server.v, Server.access_token])) self.data.delete_event(key, self.closest_time) self.data.update_file() self.find_closest_events() def getLongPollServer(self): method = 'groups.getLongPollServer?group_id=191177272' reply = requests.get("&".join([Server.body + method, Server.v, Server.access_token])) data = json.loads(reply.text) self.server = data['response']['server'] self.key = data['response']['key'] self.ts = data['response']['ts'] # print(self.server, self.key, self.ts) def simple_request(self): method = self.server + '?act=a_check&key=' + self.key + '&ts=' + self.ts + "&wait=25" return requests.get(method) def simple_loop(self): reply = json.loads(self.simple_request().text) self.ts = reply['ts'] if self.closest_time != '' and self.check_date(): self.send_notifications() if reply['updates']: message = reply['updates'][0]['object']['message']['text'] user_id = reply['updates'][0]['object']['message']['from_id'] self.data.add_rec(str(user_id), {datetime.datetime.now().strftime('%Y-%m-%d:%H.%M'): message}) random_id = random.randint(0, 100) method = 'messages.send?' + 'user_id=' + str(user_id) + '&random_id=' + str(random_id) \ + '&message=' + message r = requests.get("&".join([Server.body + method, Server.v, Server.access_token])) print("&".join([Server.body + method, Server.v, Server.access_token])) self.simple_loop() def check_date(self): if datetime.datetime.now().strftime('%Y-%m-%d:%H.%M') == self.closest_time: return True return False