X-Git-Url: http://gitweb.pimeys.fr/?p=bots%2Fbasile.git;a=blobdiff_plain;f=nk.py;h=0aafbc16aff64606b07b40e5d5ccf0e6a6ea6e69;hp=c80adfd0ff303adc7e0be438292e4a06d6f80869;hb=HEAD;hpb=3d828f49cb74dd5992502c51d3f820f5e79faa52 diff --git a/nk.py b/nk.py index c80adfd..0aafbc1 100644 --- a/nk.py +++ b/nk.py @@ -8,6 +8,7 @@ import socket import json import ssl +import traceback #: Config de basile import config @@ -15,7 +16,7 @@ import config class NKError(Exception): def __init__(self,msg): Exception.__init__(self) - self.msg=msg + self.msg = msg def __str__(self): return str(self.msg) def __unicode__(self): @@ -30,43 +31,126 @@ class NKHelloFailed(NKError): class NKUnknownError(NKError): pass +class NKDeadServer(NKError): + pass + +def full_read(socket): + # On récupère d'abord la taille du message + length_str = '' + char = socket.recv(1) + while char != '\n': + length_str += char + char = socket.recv(1) + total = int(length_str) + # On utilise une memoryview pour recevoir les données chunk par chunk efficacement + view = memoryview(bytearray(total)) + next_offset = 0 + while total - next_offset > 0: + recv_size = socket.recv_into(view[next_offset:], total - next_offset) + next_offset += recv_size + try: + msg = json.loads(view.tobytes()) + except (TypeError, ValueError) as e: + raise NKNotJson("L'objet reçu n'est pas un JSON") + return msg + def connect(): - sock=socket.socket() + sock = socket.socket() try: # On établit la connexion sur port 4242 sock.connect((config.nk_server, config.nk_port)) # On passe en SSL - sock=ssl.wrap_socket(sock,ca_certs='../keys/ca_.crt') + sock = ssl.wrap_socket(sock, ca_certs='../keys/ca_.crt') # On fait un hello - sock.write('["hello", "Basile"]') + sock.write(json.dumps(["hello", "Basile"])) # On récupère la réponse du hello - out=sock.read() - out=json.loads(out) + out = full_read(sock) except Exception as exc: # Si on a foiré quelque part, c'est que le serveur est down raise NKRefused(str(exc)) - if out["retcode"]==0: + if out["retcode"] == 0: return sock - elif out["retcode"]==11: + elif out["retcode"] == 11: raise NKHelloFailed(out["errmsg"]) else: raise NKUnknownError(out["errmsg"]) -def login(username,password,typ="bdd"): - sock=connect() - if typ=="special": # ça c'est pour Basile lui-même - masque='[]' - elif typ=="bdd": - masque='[[], [], true]' +def login(username, password, typ="bdd"): + sock = connect() + if typ == "special": # ça c'est pour Basile lui-même + masque = [] + elif typ == "bdd": + masque = [[], [], True] try: # Basile a un compte special user - commande='["login", [%s,%s,"%s",%s]]'%(json.dumps(username),json.dumps(password),typ,masque) - sock.write(commande) - out=sock.read() + commande = ["login", [username, password, typ, masque]] + sock.write(json.dumps(commande)) + out = full_read(sock) except Exception as exc: # Si on a foiré quelque part, c'est que le serveur est down raise NKRefused(str(exc)) - # On vérifie ensuite que le login - return json.loads(out),sock + return out, sock + +def get_infos(sock, idbde, serv, canal): + """Récupère les données de l'utilisateur NK n°``idbde``""" + try: + sock.write(json.dumps(["compte", idbde])) + ret = full_read(sock) + retcode = ret["retcode"] + if retcode == 0: + return ret["msg"] + else: + serv.privmsg(canal, ret["errmsg"].encode("utf-8")) + except Exception as exc: + trace = traceback.format_exc() + msg = "failed\n%s" % trace + for l in msg.split("\n"): + serv.privmsg(canal, l) + #log(self.serveur, "priv", auteur, " ".join(message) + "[failed]") + +def get_solde(sock, idbde, serv, canal): + """Récupère le (success, solde, pseudo) de l'utilisateur NK n°``idbde``""" + infos = get_infos(sock, idbde, serv, canal) + if infos: + return (True, infos["solde"], infos["pseudo"]) + else: + return (False, None, None) + +def consomme(sock, idbde, conso, serv, canal): + """Fais consommer une conso à l'utilisateur NK n°``idbde``""" + try: + sock.write(json.dumps(["get_boutons", ["", ""]])) + ret = full_read(sock) + retcode = ret["retcode"] + if retcode == 0: + boutons = ret["msg"] + boutons = [b for b in boutons if b["label"].lower() == conso.lower()] + if len(boutons) == 0: + serv.privmsg(canal, (u"Impossible de trouver la conso %s" % (conso)).encode("utf-8")) + return False + bouton = boutons[0] + sock.write(json.dumps(["consos", [[bouton["id"], idbde, 1]]])) + ret = full_read(sock) + if ret["retcode"] == 0: + [[retcode, [idbouton, idbde], errmsg]] = ret["msg"] + if retcode != 0: + serv.privmsg(canal, errmsg.encode("utf-8")) + else: + success, solde, pseudo = get_solde(sock, idbde, serv, canal) + if success: + serv.privmsg(canal, (u"%s consomme 1 %s (nouveau solde : %.2f)" % (pseudo, bouton["label"], solde/100.0)).encode("utf-8")) + else: + serv.privmsg(canal, (u"%s consommé mais impossible de récupérer le solde après transaction." % (bouton["label"])).encode("utf-8")) + return True # on a réussi à consommer la conso + else: + serv.privmsg(canal, ret["errmsg"].encode("utf-8")) + return False + else: + serv.privmsg(canal, ret["errmsg"]) + except Exception as exc: + trace = traceback.format_exc() + msg = "failed\n%s" % trace + for l in msg.split("\n"): + serv.privmsg(canal, l)