From: <Blu...@us...> - 2009-10-24 19:35:20
|
Revision: 307 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=307&view=rev Author: BlueWolf_ Date: 2009-10-24 19:35:13 +0000 (Sat, 24 Oct 2009) Log Message: ----------- * Some changes in de Callback * Added config in the core * Callback is now outside the try, in send Modified Paths: -------------- trunk/client/core/__init__.py trunk/client/core/callback.py trunk/client/core/client.py Modified: trunk/client/core/__init__.py =================================================================== --- trunk/client/core/__init__.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/__init__.py 2009-10-24 19:35:13 UTC (rev 307) @@ -1,3 +1,8 @@ +""" +This is the client core for Virtual Playground. +You can use this by importing Client and Callback +""" + ## This file is part of Virtual Playground ## Copyright (c) 2009 Jos Ratsma + Koen Koning @@ -19,3 +24,4 @@ Client = client.Client Callback = callback.Callback +__all__ = ['Client', 'Callback'] Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/callback.py 2009-10-24 19:35:13 UTC (rev 307) @@ -16,47 +16,53 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Callback: - def connected(self, con): + def connected(self): """ - connected(self, con) This will be called when a connection with the server is made. `con` contains the core's `Client` class, so you can use it to send stuff. - This is a placeholder. - If you want to catch this event, overwrite it. + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def disconnected(self): """ - connected(self) This is called when the connection dies. For example when you close the connection manually, the server kicks you, your modem explodes or your cat eates the LAN cable. - This is a placeholder. - If you want to catch this event, overwrite it. + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def data_received(self, data): """ - data_received(self, data) - Called when we received data from the server. + Called when we received data from the server. Normally, you + don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + data: + Dict with the data that has been received + + + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def data_send(self, data): """ - data_send(self, data) - Called when we send data to the server. + Called when we send data to the server. Normally, you + don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + data: + Dict with the data that will be send. + + + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/client.py 2009-10-24 19:35:13 UTC (rev 307) @@ -20,19 +20,54 @@ class Client(threading.Thread): - def __init__(self, callback_class): - """ - This class will handle all of the connection to the server. - """ + """ + This is the client-core for Virtual Playground. This will handle the + connections and data to and from the server. + + config: + This should be a dict with settings for the client. See the + bottom of this documentation for a list of all possible + settings. + + callback_class: + The callback class will be used to notify you for certain events + that happens in the core. It has to look something like this: + + class Callback(core.Callback): + ... + + See the doc in core.Callback for more information about this. + + -------- + + The settings: + Currently, the config is a bit lonely and quiet. Do you want to + fill it? :-( - self.__call = callback_class() + """ + + def __init__(self, config, callback_class): + + self.__call = callback_class self.__sock = None self.__pinger = None + + # Create all default settings + self.__config_default(config) + self.__config = config + + self.__parse = Parser(self.__call, self) self.is_online = True threading.Thread.__init__(self) - + + + def __config_default(self, config): + #config.setdefault('whatever', 'duh') + pass + + def connect(self, host, port): """ Will (try to) connect to the server on `host`:`port`. @@ -64,7 +99,7 @@ except: time.sleep(1) - self.__call.connected(self) + self.__call.connected() self.__pinger = self.__Pinger(self.send) @@ -93,22 +128,21 @@ def send(self, data_header, data_body = {}): """ - send(data_header, data_body = {}) => None Sends `data_body` of type `data_header` to the server. It will automatically be encoded as JSON, and the delimeter character (chr(1)) will be send automatically too. `Data_header` is a string, `data_body` a dict. """ + + self.__call.data_send({data_header:data_body}) + data = simplejson.dumps({data_header:data_body}) try: - self.__call.data_send({data_header:data_body}) - data = simplejson.dumps({data_header:data_body}) self.__sock.send(data + chr(1)) except: pass def close(self): """ - close(self) => None Will close the connection to the server. If the connection in already down, it will raise an exception. This will trigger the callback `disconnected`. It may reconnect, depending on the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-15 16:19:27
|
Revision: 309 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=309&view=rev Author: BlueWolf_ Date: 2009-11-15 16:19:20 +0000 (Sun, 15 Nov 2009) Log Message: ----------- Added reason in callback.disconnected and the core can now properly reconnect Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-11-14 23:08:44 UTC (rev 308) +++ trunk/client/core/callback.py 2009-11-15 16:19:20 UTC (rev 309) @@ -23,18 +23,29 @@ send stuff. This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass - def disconnected(self): + def disconnected(self, reason): """ This is called when the connection dies. For example when you close the connection manually, the server kicks you, your modem explodes or your cat eates the LAN cable. + reason: + A string, representing the reason why it disconnected. + It currently only has two options: + * "server" - Server dropped the connection + * "manual" - Client (you) closed the connection + with .close() + + + Return True if you want it to reconnect. Be warned that this + event also will be raised when you do .close()! + This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass @@ -48,7 +59,7 @@ This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass @@ -62,7 +73,7 @@ This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-11-14 23:08:44 UTC (rev 308) +++ trunk/client/core/client.py 2009-11-15 16:19:20 UTC (rev 309) @@ -18,7 +18,6 @@ import simplejson, socket, threading, time from parser import Parser - class Client(threading.Thread): """ This is the client-core for Virtual Playground. This will handle the @@ -55,12 +54,18 @@ # Create all default settings self.__config_default(config) self.__config = config - self.__parse = Parser(self.__call, self) - self.is_online = True + self.__is_online = False + self.__disconnect_reason = None + self.__do_connect = threading.Event() + self.__do_connect.clear() + threading.Thread.__init__(self) + + self.setDaemon(True) + self.start() def __config_default(self, config): @@ -81,51 +86,65 @@ if self.__sock: raise ConnectionError("You are already connected!") - self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__do_connect.set() # Release the hounds - self.start() def run(self): """ Used by threading, not for external usage. """ - - #TODO: reconnect loop thingy here - while 1: - try: - self.__sock.connect((self.__host, self.__port)) - break - except: - time.sleep(1) + self.__do_connect.wait() # Wait to connect + + self.__is_online = True + self.__disconnect_reason = None + + self.__sock = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) + + while 1: + try: + self.__sock.connect((self.__host, + self.__port)) + break + except: + time.sleep(1) - self.__call.connected() + self.__call.connected() - self.__pinger = self.__Pinger(self.send) + self.__pinger = self.__Pinger(self.send) - #Infinite loop that receives data - buffer = '' - while 1: - try: - data = self.__sock.recv(1024) - except: - if self.is_online: self.close() - return - if not data: - if self.is_online: self.close() - return + #Infinite loop that receives data + buffer = '' + while 1: + try: + data = self.__sock.recv(1024) + except: + print 'except' + self.__disconnect_reason = "close" + break + if not data: + self.__disconnect_reason = "close" + break - buffer += data - #Each dataset must end with a delimiter: chr(1) - if chr(1) in buffer: + buffer += data + + #Each dataset must end with a delimiter: chr(1) + if chr(1) not in buffer: continue + data = buffer.split(chr(1)) buffer = data[-1] data = data[:-1] for msg in data: self.__parse(simplejson.loads(msg)) - + + if self.__is_online: + self.close() + + + def send(self, data_header, data_body = {}): """ Sends `data_body` of type `data_header` to the server. It will @@ -149,16 +168,32 @@ callback. If not, you can reuse this class by calling `connect`. """ - if not self.is_online: - raise ConnectionError("The connection is already \ - closed!") + if not self.__is_online: + raise ConnectionError("The connection is already " \ + "closed!") + # What's the reason, the meaning of this? + if self.__disconnect_reason == "close": # 42 + reason = "server" + else: + reason = "manual" + + + self.__do_connect.clear() # Block the thread-loop + + self.__is_online = False + self.__pinger.cancel() + self.__pinger = None + + self.__sock.shutdown(0) self.__sock.close() - self.is_online = False - if self.__call.disconnected(): - self.__sock = None - self.connect(self.__host, self.__port) + self.__sock = None + + if self.__call.disconnected(reason): + # Reconnect + self.__do_connect.set() + class __Pinger(): def __init__(self, send): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-28 23:31:01
|
Revision: 311 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=311&view=rev Author: BlueWolf_ Date: 2009-11-28 23:30:52 +0000 (Sat, 28 Nov 2009) Log Message: ----------- Added reason 'full' to callback.connection_closed Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/callback.py 2009-11-28 23:30:52 UTC (rev 311) @@ -35,8 +35,11 @@ reason: A string, representing the reason why it disconnected. - It currently only has two options: - * "server" - Server dropped the connection + It currently has these options: + * "closed" - Server dropped the connection + unexpectedly + * "full" - Server is full and does not except + - more connections * "manual" - Client (you) closed the connection with .close() Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/client.py 2009-11-28 23:30:52 UTC (rev 311) @@ -57,7 +57,6 @@ self.__parse = Parser(self.__call, self) self.__is_online = False - self.__disconnect_reason = None self.__do_connect = threading.Event() self.__do_connect.clear() @@ -97,7 +96,7 @@ self.__do_connect.wait() # Wait to connect self.__is_online = True - self.__disconnect_reason = None + disconnect_reason = None self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -121,11 +120,10 @@ try: data = self.__sock.recv(1024) except: - print 'except' - self.__disconnect_reason = "close" + disconnect_reason = "closed" break if not data: - self.__disconnect_reason = "close" + disconnect_reason = "closed" break buffer += data @@ -141,7 +139,7 @@ self.__parse(simplejson.loads(msg)) if self.__is_online: - self.close() + self.close(disconnect_reason) @@ -160,7 +158,7 @@ except: pass - def close(self): + def close(self, reason = "manual"): """ Will close the connection to the server. If the connection in already down, it will raise an exception. This will trigger the @@ -169,23 +167,22 @@ """ if not self.__is_online: - raise ConnectionError("The connection is already " \ - "closed!") + if reason == "manual": + # Annoy the user + raise ConnectionError("The connection is " + \ + "already closed!") + else: + return; - # What's the reason, the meaning of this? - if self.__disconnect_reason == "close": # 42 - reason = "server" - else: - reason = "manual" - self.__do_connect.clear() # Block the thread-loop self.__is_online = False self.__pinger.cancel() self.__pinger = None - self.__sock.shutdown(0) + try: self.__sock.shutdown(0) + except: pass self.__sock.close() self.__sock = None Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/parser.py 2009-11-28 23:30:52 UTC (rev 311) @@ -30,4 +30,15 @@ head = msg.keys()[0] body = msg[head] - #handle data here later... + func = getattr(self, str(head), None) + if (func): + func(body) + + def disconnect(self, msg): + """ + Called just before the server closes our connection + """ + # reason - Why it's going to disconnect us + + if msg['reason'] == 'full': + self.__client.close("full") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-14 19:48:21
|
Revision: 314 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=314&view=rev Author: BlueWolf_ Date: 2009-12-14 19:48:14 +0000 (Mon, 14 Dec 2009) Log Message: ----------- Client can now log it to the server. It uses RSA to protect the password Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Added Paths: ----------- trunk/client/core/rsa.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-12-14 19:46:21 UTC (rev 313) +++ trunk/client/core/callback.py 2009-12-14 19:48:14 UTC (rev 314) @@ -18,15 +18,33 @@ class Callback: def connected(self): """ - This will be called when a connection with the server is made. - `con` contains the core's `Client` class, so you can use it to - send stuff. + When the connection is made, this will be called. Note that the + server can still kick the connection because it is full. You + should not client.login here, because the server still has to + send a rsa-key. See callback.received_rsa for this event. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback """ pass + + def received_rsa(self, public): + """ + When a connection is made, the server will generate a rsa-key. + The client has to wait for this, before logging in. After this + event, you can use client.login (if you haven't specified a + login at client.connect) + public: + The generated public rsa-key. It is a dict with 2 + values: e and n. It's used for encoding the password + + + This is a placeholder. If you want to catch this event, + overwrite this in your own callback + """ + pass + def disconnected(self, reason): """ This is called when the connection dies. For example when you @@ -42,12 +60,17 @@ - more connections * "manual" - Client (you) closed the connection with .close() + * "duplicate" - Another client has logged in on this + account. This connection has been + kicked - Return True if you want it to reconnect. Be warned that this - event also will be raised when you do .close()! + Return True if you want it to reconnect. To avoid unexpected + behaviour, you should *only* do this when reason is "closed"! + If you provided the login in client.connect, it logs in + automatically. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback """ pass @@ -61,7 +84,7 @@ Dict with the data that has been received - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback """ pass @@ -75,8 +98,40 @@ Dict with the data that will be send. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback """ pass - + + def logged_in(self, username, uid, cid): + """ + Called when we are logged in. + + username: + The username for this user. Use this, instead what the + user typed in, because this has the right caps. Also + available in client.username. + uid: + The unique user-id for this user. Also available in + client.uid + cid: + The unique client-id for this connection. Also available + in client.cid + + This is a placeholder. If you want to catch this event, + overwrite this in your own callback + """ + + pass + + def failed_logging_in(self, reason): + """ + This happens when the user could not log in. You can safely use + client.login again. + + reason: + The reason why the user could not log in: + * "bad login" - The username and/or password is wrong. + """ + + pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-12-14 19:46:21 UTC (rev 313) +++ trunk/client/core/client.py 2009-12-14 19:48:14 UTC (rev 314) @@ -17,7 +17,12 @@ import simplejson, socket, threading, time from parser import Parser +import rsa +__name__ = "VirtualCore" +__version__ = "0.0.1" + + class Client(threading.Thread): """ This is the client-core for Virtual Playground. This will handle the @@ -40,9 +45,11 @@ -------- The settings: - Currently, the config is a bit lonely and quiet. Do you want to - fill it? :-( - + -app_name + The name of your program. Will be send when logging in. + -app_name + The version of your program. Will be send when logging. + Should be a string. """ def __init__(self, config, callback_class): @@ -55,12 +62,29 @@ self.__config_default(config) self.__config = config + # Class that parsers all incomming data self.__parse = Parser(self.__call, self) + + # So the client knows if we are online. Is used for + # disconnecting self.__is_online = False + # Treading-event so that run() waits before it's allowed to + # connect self.__do_connect = threading.Event() self.__do_connect.clear() + # Auto log in after connecting. Used by self.connect + self.__login_after_connecting = () + + # RSA + self.__rsakey = None + + # Info after logging in + self.username = None + self.uid = None # User-id + self.cid = None # Connection-id + threading.Thread.__init__(self) self.setDaemon(True) @@ -68,15 +92,18 @@ def __config_default(self, config): - #config.setdefault('whatever', 'duh') - pass + config.setdefault('app_name', __name__) + config.setdefault('app_version', __version__) - def connect(self, host, port): + def connect(self, host, port, usr = None, pwd = None, bot = False): """ Will (try to) connect to the server on `host`:`port`. If you want to reconnect, you have to close the connection first, if it's still open. + + You can optionally let it login automatically. See client.login + for the usr, pwd and bot variables. """ self.__host = host @@ -85,9 +112,16 @@ if self.__sock: raise ConnectionError("You are already connected!") - self.__do_connect.set() # Release the hounds + # Should we login after connecting? + if usr and pwd: + self.__login_after_connecting = (usr, pwd, bot) + else: + self.__login_after_connecting = (); + self.__do_connect.set() # Releasing the hounds + + def run(self): """ Used by threading, not for external usage. @@ -141,6 +175,47 @@ if self.__is_online: self.close(disconnect_reason) + def login(self, usr, pwd, bot = False): + """ + Log in to the server. You should have received the RSA-key + before calling this! + pwd is expected to be sha. Bot should be True or False. Bots + have different functions in VP. + + >>> import sha + >>> sha.new("MyVerySecretPassword").hexdigest() + 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' + """ + + if self.cid != None: + raise LoginError("You are already logged in") + + # Get our login + if not (usr and pwd): + if self.__login_after_connecting: + usr, pwd, bot = self.__login_after_connecting + else: + return # Just ignore it.. + + if not self.__sock: + raise ConnectionError("You are not connected!") + + if not self.__rsakey: + raise LoginError("No rsa-key available") + + # Convert pwd + pwd = rsa.encrypt(pwd, self.__rsakey) + + # Log in + self.send("login", { + "usr": usr, + "pwd": pwd, + "bot": bool(bot), + "for": "VP", + "client": ( self.__config['app_name'], + self.__config['app_version'] + ) + }) def send(self, data_header, data_body = {}): @@ -181,6 +256,12 @@ self.__pinger.cancel() self.__pinger = None + # Reset variables + self.__rsa = None + self.username = None + self.cid = None + self.uid = None + try: self.__sock.shutdown(0) except: pass self.__sock.close() @@ -223,3 +304,6 @@ class ConnectionError(Exception): pass + +class LoginError(Exception): + pass Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-14 19:46:21 UTC (rev 313) +++ trunk/client/core/parser.py 2009-12-14 19:48:14 UTC (rev 314) @@ -18,14 +18,13 @@ class Parser(): def __init__(self, callback, client): """ - This class parses all received messages from client. - It may need a better name... + This class parses all received messages from the server. """ - self.__call = callback - self.__client = client + self.callback = callback + self.client = client def __call__(self, msg): - self.__call.data_received(msg) + self.callback.data_received(msg) head = msg.keys()[0] body = msg[head] @@ -36,9 +35,51 @@ def disconnect(self, msg): """ - Called just before the server closes our connection + Called just before the server closes our connection. + * reason - Why the server disconnected us + "full" - Because the server is full + "duplicate" - Because another client has logged in + on the same account """ # reason - Why it's going to disconnect us - if msg['reason'] == 'full': - self.__client.close("full") + self.client.close(msg["reason"]) + + def rsa(self, msg): + """ + Called when the connection has been made and a rsa-key has been + generated. We can now log in using this key + * public - The public rsa-key, which contains e & n + """ + + self.client._Client__rsakey = msg['public'] + + self.callback.received_rsa(msg['public']) + + self.client.login(None, None) + + def login(self, msg): + """ + Called as answer for our login + * succeed - If we logged in + + if succeed is False: + * reason - Why we didn't log in + "bad login" - Username/password incorrect + + if succeed is True: + * username - The username (with right caps) + * id - The user-id + * uid - The server's connection-id + """ + + if msg['succeed'] == True: + self.client.username = msg['username'] + self.client.uid = msg['id'] + self.client.cid = msg['uid'] + + self.callback.logged_in(msg['username'], msg['id'], + msg['uid']) + + else: + self.callback.failed_logging_in(msg['reason']) Added: trunk/client/core/rsa.py =================================================================== --- trunk/client/core/rsa.py (rev 0) +++ trunk/client/core/rsa.py 2009-12-14 19:48:14 UTC (rev 314) @@ -0,0 +1,427 @@ +"""RSA module + +Module for calculating large primes, and RSA encryption, decryption, +signing and verification. Includes generating public and private keys. +""" + +__author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer" +__date__ = "2009-01-22" + +# NOTE: Python's modulo can return negative numbers. We compensate for +# this behaviour using the abs() function + +from cPickle import dumps, loads +import base64 +import math +import os +import random +import sys +import types +import zlib + +def gcd(p, q): + """Returns the greatest common divisor of p and q + + + >>> gcd(42, 6) + 6 + """ + if p<q: return gcd(q, p) + if q == 0: return p + return gcd(q, abs(p%q)) + +def bytes2int(bytes): + """Converts a list of bytes or a string to an integer + + >>> (128*256 + 64)*256 + + 15 + 8405007 + >>> l = [128, 64, 15] + >>> bytes2int(l) + 8405007 + """ + + if not (type(bytes) is types.ListType or type(bytes) is types.StringType): + raise TypeError("You must pass a string or a list") + + # Convert byte stream to integer + integer = 0 + for byte in bytes: + integer *= 256 + if type(byte) is types.StringType: byte = ord(byte) + integer += byte + + return integer + +def int2bytes(number): + """Converts a number to a string of bytes + + >>> bytes2int(int2bytes(123456789)) + 123456789 + """ + + if not (type(number) is types.LongType or type(number) is types.IntType): + raise TypeError("You must pass a long or an int") + + string = "" + + while number > 0: + string = "%s%s" % (chr(number & 0xFF), string) + number /= 256 + + return string + +def fast_exponentiation(a, p, n): + """Calculates r = a^p mod n + """ + result = a % n + remainders = [] + while p != 1: + remainders.append(p & 1) + p = p >> 1 + while remainders: + rem = remainders.pop() + result = ((a ** rem) * result ** 2) % n + return result + +def read_random_int(nbits): + """Reads a random integer of approximately nbits bits rounded up + to whole bytes""" + + nbytes = ceil(nbits/8) + randomdata = os.urandom(nbytes) + return bytes2int(randomdata) + +def ceil(x): + """ceil(x) -> int(math.ceil(x))""" + + return int(math.ceil(x)) + +def randint(minvalue, maxvalue): + """Returns a random integer x with minvalue <= x <= maxvalue""" + + # Safety - get a lot of random data even if the range is fairly + # small + min_nbits = 32 + + # The range of the random numbers we need to generate + range = maxvalue - minvalue + + # Which is this number of bytes + rangebytes = ceil(math.log(range, 2) / 8) + + # Convert to bits, but make sure it's always at least min_nbits*2 + rangebits = max(rangebytes * 8, min_nbits * 2) + + # Take a random number of bits between min_nbits and rangebits + nbits = random.randint(min_nbits, rangebits) + + return (read_random_int(nbits) % range) + minvalue + +def fermat_little_theorem(p): + """Returns 1 if p may be prime, and something else if p definitely + is not prime""" + + a = randint(1, p-1) + return fast_exponentiation(a, p-1, p) + +def jacobi(a, b): + """Calculates the value of the Jacobi symbol (a/b) + """ + + if a % b == 0: + return 0 + result = 1 + while a > 1: + if a & 1: + if ((a-1)*(b-1) >> 2) & 1: + result = -result + b, a = a, b % a + else: + if ((b ** 2 - 1) >> 3) & 1: + result = -result + a = a >> 1 + return result + +def jacobi_witness(x, n): + """Returns False if n is an Euler pseudo-prime with base x, and + True otherwise. + """ + + j = jacobi(x, n) % n + f = fast_exponentiation(x, (n-1)/2, n) + + if j == f: return False + return True + +def randomized_primality_testing(n, k): + """Calculates whether n is composite (which is always correct) or + prime (which is incorrect with error probability 2**-k) + + Returns False if the number if composite, and True if it's + probably prime. + """ + + q = 0.5 # Property of the jacobi_witness function + + # t = int(math.ceil(k / math.log(1/q, 2))) + t = ceil(k / math.log(1/q, 2)) + for i in range(t+1): + x = randint(1, n-1) + if jacobi_witness(x, n): return False + + return True + +def is_prime(number): + """Returns True if the number is prime, and False otherwise. + + >>> is_prime(42) + 0 + >>> is_prime(41) + 1 + """ + + """ + if not fermat_little_theorem(number) == 1: + # Not prime, according to Fermat's little theorem + return False + """ + + if randomized_primality_testing(number, 5): + # Prime, according to Jacobi + return True + + # Not prime + return False + + +def getprime(nbits): + """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In + other words: nbits is rounded up to whole bytes. + + >>> p = getprime(8) + >>> is_prime(p-1) + 0 + >>> is_prime(p) + 1 + >>> is_prime(p+1) + 0 + """ + + nbytes = int(math.ceil(nbits/8)) + + while True: + integer = read_random_int(nbits) + + # Make sure it's odd + integer |= 1 + + # Test for primeness + if is_prime(integer): break + + # Retry if not prime + + return integer + +def are_relatively_prime(a, b): + """Returns True if a and b are relatively prime, and False if they + are not. + + >>> are_relatively_prime(2, 3) + 1 + >>> are_relatively_prime(2, 4) + 0 + """ + + d = gcd(a, b) + return (d == 1) + +def find_p_q(nbits): + """Returns a tuple of two different primes of nbits bits""" + + p = getprime(nbits) + while True: + q = getprime(nbits) + if not q == p: break + + return (p, q) + +def extended_euclid_gcd(a, b): + """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb + """ + + if b == 0: + return (a, 1, 0) + + q = abs(a % b) + r = long(a / b) + (d, k, l) = extended_euclid_gcd(b, q) + + return (d, l, k - l*r) + +# Main function: calculate encryption and decryption keys +def calculate_keys(p, q, nbits): + """Calculates an encryption and a decryption key for p and q, and + returns them as a tuple (e, d)""" + + n = p * q + phi_n = (p-1) * (q-1) + + while True: + # Make sure e has enough bits so we ensure "wrapping" through + # modulo n + e = getprime(max(8, nbits/2)) + if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break + + (d, i, j) = extended_euclid_gcd(e, phi_n) + + if not d == 1: + raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n)) + + if not (e * i) % phi_n == 1: + raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n)) + + return (e, i) + + +def gen_keys(nbits): + """Generate RSA keys of nbits bits. Returns (p, q, e, d). + + Note: this can take a long time, depending on the key size. + """ + + while True: + (p, q) = find_p_q(nbits) + (e, d) = calculate_keys(p, q, nbits) + + # For some reason, d is sometimes negative. We don't know how + # to fix it (yet), so we keep trying until everything is shiny + if d > 0: break + + return (p, q, e, d) + +def gen_pubpriv_keys(nbits): + """Generates public and private keys, and returns them as (pub, + priv). + + The public key consists of a dict {e: ..., , n: ....). The private + key consists of a dict {d: ...., p: ...., q: ....). + """ + + (p, q, e, d) = gen_keys(nbits) + + return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) + +def encrypt_int(message, ekey, n): + """Encrypts a message using encryption key 'ekey', working modulo + n""" + + if type(message) is types.IntType: + return encrypt_int(long(message), ekey, n) + + if not type(message) is types.LongType: + raise TypeError("You must pass a long or an int") + + if message > 0 and \ + math.floor(math.log(message, 2)) > math.floor(math.log(n, 2)): + raise OverflowError("The message is too long") + + return fast_exponentiation(message, ekey, n) + +def decrypt_int(cyphertext, dkey, n): + """Decrypts a cypher text using the decryption key 'dkey', working + modulo n""" + + return encrypt_int(cyphertext, dkey, n) + +def sign_int(message, dkey, n): + """Signs 'message' using key 'dkey', working modulo n""" + + return decrypt_int(message, dkey, n) + +def verify_int(signed, ekey, n): + """verifies 'signed' using key 'ekey', working modulo n""" + + return encrypt_int(signed, ekey, n) + +def picklechops(chops): + """Pickles and base64encodes it's argument chops""" + + value = zlib.compress(dumps(chops)) + encoded = base64.encodestring(value) + return encoded.strip() + +def unpicklechops(string): + """base64decodes and unpickes it's argument string into chops""" + + return loads(zlib.decompress(base64.decodestring(string))) + +def chopstring(message, key, n, funcref): + """Splits 'message' into chops that are at most as long as n, + converts these into integers, and calls funcref(integer, key, n) + for each chop. + + Used by 'encrypt' and 'sign'. + """ + + msglen = len(message) + mbits = msglen * 8 + nbits = int(math.floor(math.log(n, 2))) + nbytes = nbits / 8 + blocks = msglen / nbytes + + if msglen % nbytes > 0: + blocks += 1 + + cypher = [] + + for bindex in range(blocks): + offset = bindex * nbytes + block = message[offset:offset+nbytes] + value = bytes2int(block) + cypher.append(funcref(value, key, n)) + + return picklechops(cypher) + +def gluechops(chops, key, n, funcref): + """Glues chops back together into a string. calls + funcref(integer, key, n) for each chop. + + Used by 'decrypt' and 'verify'. + """ + message = "" + + chops = unpicklechops(chops) + + for cpart in chops: + mpart = funcref(cpart, key, n) + message += int2bytes(mpart) + + return message + +def encrypt(message, key): + """Encrypts a string 'message' with the public key 'key'""" + + return chopstring(message, key['e'], key['n'], encrypt_int) + +def sign(message, key): + """Signs a string 'message' with the private key 'key'""" + + return chopstring(message, key['d'], key['p']*key['q'], decrypt_int) + +def decrypt(cypher, key): + """Decrypts a cypher with the private key 'key'""" + + return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) + +def verify(cypher, key): + """Verifies a cypher with the public key 'key'""" + + return gluechops(cypher, key['e'], key['n'], encrypt_int) + +# Do doctest if we're not imported +if __name__ == "__main__": + import doctest + doctest.testmod() + +__all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"] + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-14 21:23:36
|
Revision: 316 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=316&view=rev Author: BlueWolf_ Date: 2009-12-14 21:23:28 +0000 (Mon, 14 Dec 2009) Log Message: ----------- Server now sends uid(user-id) and cid(connection-id) Modified Paths: -------------- trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-12-14 21:22:34 UTC (rev 315) +++ trunk/client/core/client.py 2009-12-14 21:23:28 UTC (rev 316) @@ -47,9 +47,9 @@ The settings: -app_name The name of your program. Will be send when logging in. - -app_name - The version of your program. Will be send when logging. - Should be a string. + -app_version + The version of your program. Will be send when logging + in. Should be a string. """ def __init__(self, config, callback_class): Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-14 21:22:34 UTC (rev 315) +++ trunk/client/core/parser.py 2009-12-14 21:23:28 UTC (rev 316) @@ -75,11 +75,11 @@ if msg['succeed'] == True: self.client.username = msg['username'] - self.client.uid = msg['id'] - self.client.cid = msg['uid'] + self.client.uid = msg['uid'] + self.client.cid = msg['cid'] - self.callback.logged_in(msg['username'], msg['id'], - msg['uid']) + self.callback.logged_in(msg['username'], msg['uid'], + msg['cid']) else: self.callback.failed_logging_in(msg['reason']) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-16 20:26:40
|
Revision: 321 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=321&view=rev Author: BlueWolf_ Date: 2009-12-16 20:26:33 +0000 (Wed, 16 Dec 2009) Log Message: ----------- No id/uid will be send by the server anymore Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-12-16 20:26:07 UTC (rev 320) +++ trunk/client/core/callback.py 2009-12-16 20:26:33 UTC (rev 321) @@ -107,7 +107,7 @@ """ pass - def logged_in(self, username, uid, cid): + def logged_in(self, username, cid): """ Called when we are logged in. @@ -115,9 +115,6 @@ The username for this user. Use this, instead what the user typed in, because this has the right caps. Also available in client.username. - uid: - The unique user-id for this user. Also available in - client.uid cid: The unique client-id for this connection. Also available in client.cid Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-12-16 20:26:07 UTC (rev 320) +++ trunk/client/core/client.py 2009-12-16 20:26:33 UTC (rev 321) @@ -82,7 +82,6 @@ # Info after logging in self.username = None - self.uid = None # User-id self.cid = None # Connection-id threading.Thread.__init__(self) @@ -260,7 +259,6 @@ self.__rsa = None self.username = None self.cid = None - self.uid = None try: self.__sock.shutdown(0) except: pass Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-16 20:26:07 UTC (rev 320) +++ trunk/client/core/parser.py 2009-12-16 20:26:33 UTC (rev 321) @@ -69,17 +69,14 @@ if succeed is True: * username - The username (with right caps) - * id - The user-id - * uid - The server's connection-id + * cid - The server's connection-id """ if msg['succeed'] == True: self.client.username = msg['username'] - self.client.uid = msg['uid'] self.client.cid = msg['cid'] - self.callback.logged_in(msg['username'], msg['uid'], - msg['cid']) + self.callback.logged_in(msg['username'], msg['cid']) else: self.callback.failed_logging_in(msg['reason']) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-18 19:33:14
|
Revision: 326 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=326&view=rev Author: BlueWolf_ Date: 2009-12-18 19:33:06 +0000 (Fri, 18 Dec 2009) Log Message: ----------- Changing the documentation regarding server disconnects Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-12-18 19:32:18 UTC (rev 325) +++ trunk/client/core/callback.py 2009-12-18 19:33:06 UTC (rev 326) @@ -66,11 +66,13 @@ * "crash" - A crash happened on the server. Unless you sent malicious data or you're not admin of the server, there's nothing - you can do about it. + you can do about it + * "gone offline"- The server has just gone offline Return True if you want it to reconnect. To avoid unexpected - behaviour, you should *only* do this when reason is "closed"! + behaviour, you should *only* do this when reason is "closed" or + "gone offline"! If you provided the login in client.connect, it logs in automatically. Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-18 19:32:18 UTC (rev 325) +++ trunk/client/core/parser.py 2009-12-18 19:33:06 UTC (rev 326) @@ -36,10 +36,12 @@ def disconnect(self, msg): """ Called just before the server closes our connection. - * reason - Why the server disconnected us - "full" - Because the server is full - "duplicate" - Because another client has logged in - on the same account + * reason - Why the server disconnected us + "full" - Because the server is full + "duplicate" - Because another client has logged in + on the same account + "crash" - The server-parser has made a crash + "gone offline" - Server has just shutdown """ # reason - Why it's going to disconnect us This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-19 20:59:46
|
Revision: 328 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=328&view=rev Author: BlueWolf_ Date: 2009-12-19 20:59:37 +0000 (Sat, 19 Dec 2009) Log Message: ----------- Login-errors will go through "error" instead of "login". Added some other login-errors in the documentation Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-12-19 20:59:27 UTC (rev 327) +++ trunk/client/core/callback.py 2009-12-19 20:59:37 UTC (rev 328) @@ -135,6 +135,10 @@ reason: The reason why the user could not log in: * "bad login" - The username and/or password is wrong. + * "login not allowed" - You may not log in right now + * "bot limit reached" - There're to much bots logged + in for your account + * "login blocked" - You (or your IP) are blocked """ pass Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-19 20:59:27 UTC (rev 327) +++ trunk/client/core/parser.py 2009-12-19 20:59:37 UTC (rev 328) @@ -62,23 +62,32 @@ def login(self, msg): """ - Called as answer for our login - * succeed - If we logged in - - if succeed is False: - * reason - Why we didn't log in - "bad login" - Username/password incorrect - - if succeed is True: + Called when we can log in * username - The username (with right caps) * cid - The server's connection-id """ - if msg['succeed'] == True: - self.client.username = msg['username'] - self.client.cid = msg['cid'] - - self.callback.logged_in(msg['username'], msg['cid']) + self.client.username = msg['username'] + self.client.cid = msg['cid'] - else: - self.callback.failed_logging_in(msg['reason']) + self.callback.logged_in(msg['username'], msg['cid']) + + def error(self, msg): + """ + Called when we did something wrong! + * reason - What we did wrong + "bad login" - Username/password wrong + "login not allowed" - User may not log in right now + "bot limit reached" - Too much bots logged in for this user + "login blocked" - The user (or IP) is blocked + """ + + if msg['reason'] == "bad login": + self.callback.failed_logging_in("bad login") + elif msg['reason'] == "login not allowed": + self.callback.failed_logging_in("login not allowed") + elif msg['reason'] == "bot limit reached": + self.callback.failed_logging_in("bot limit reached") + elif msg['reason'] == "login blocked": + self.callback.failed_logging_in("login blocked") + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-12-23 13:17:17
|
Revision: 330 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=330&view=rev Author: BlueWolf_ Date: 2009-12-23 13:17:00 +0000 (Wed, 23 Dec 2009) Log Message: ----------- Client can now log in as bot. The core is now using a dict to share variables across all modules Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-12-23 13:16:28 UTC (rev 329) +++ trunk/client/core/callback.py 2009-12-23 13:17:00 UTC (rev 330) @@ -109,7 +109,7 @@ """ pass - def logged_in(self, username, cid): + def logged_in(self, username, cid, owner): """ Called when we are logged in. @@ -120,6 +120,9 @@ cid: The unique client-id for this connection. Also available in client.cid + owner: + This is the owner-username for this bot. This variable + will be None when you log in as a normal user This is a placeholder. If you want to catch this event, overwrite this in your own callback @@ -139,6 +142,8 @@ * "bot limit reached" - There're to much bots logged in for your account * "login blocked" - You (or your IP) are blocked + * "duplicate user" - There is already someone + online with this username """ pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-12-23 13:16:28 UTC (rev 329) +++ trunk/client/core/client.py 2009-12-23 13:17:00 UTC (rev 330) @@ -58,32 +58,40 @@ self.__sock = None self.__pinger = None + # This will be available ([sh]ared) to al modules in the core + self.__sh = {} + + self.__sh['call'] = callback_class + self.__sh['core'] = self + self.__sh['isbot'] = None + # Create all default settings self.__config_default(config) - self.__config = config + self.__sh['config'] = config - # Class that parsers all incomming data - self.__parse = Parser(self.__call, self) - # So the client knows if we are online. Is used for # disconnecting - self.__is_online = False + self.__sh['is_online'] = False # Treading-event so that run() waits before it's allowed to # connect self.__do_connect = threading.Event() self.__do_connect.clear() - # Auto log in after connecting. Used by self.connect - self.__login_after_connecting = () + # Auto log in after connecting. + self.__sh['login_after_connecting'] = () # RSA - self.__rsakey = None + self.__sh['rsakey'] = None # Info after logging in self.username = None + self.owner = None self.cid = None # Connection-id + # Class that parsers all incomming data + self.__parse = Parser(self.__sh) + threading.Thread.__init__(self) self.setDaemon(True) @@ -91,18 +99,19 @@ def __config_default(self, config): - config.setdefault('app_name', __name__) - config.setdefault('app_version', __version__) + config['app_name'] = str(config.get('app_name', __name__)) + config['app_version'] = str(config.get('app_version', + __version__)) - def connect(self, host, port, usr = None, pwd = None, bot = False): + def connect(self, host, port): """ Will (try to) connect to the server on `host`:`port`. If you want to reconnect, you have to close the connection first, if it's still open. - You can optionally let it login automatically. See client.login - for the usr, pwd and bot variables. + You can to Client.login and Client.bot_login directly after + this. It will be done as soon as it has received a rsa-key. """ self.__host = host @@ -111,13 +120,6 @@ if self.__sock: raise ConnectionError("You are already connected!") - # Should we login after connecting? - if usr and pwd: - self.__login_after_connecting = (usr, pwd, bot) - else: - self.__login_after_connecting = (); - - self.__do_connect.set() # Releasing the hounds @@ -128,7 +130,7 @@ while 1: self.__do_connect.wait() # Wait to connect - self.__is_online = True + self.__sh['is_online'] = True disconnect_reason = None self.__sock = socket.socket(socket.AF_INET, @@ -137,7 +139,7 @@ while 1: try: self.__sock.connect((self.__host, - self.__port)) + self.__port)) break except: time.sleep(1) @@ -171,15 +173,14 @@ for msg in data: self.__parse(simplejson.loads(msg)) - if self.__is_online: + if self.__sh['is_online']: self.close(disconnect_reason) - def login(self, usr, pwd, bot = False): + def login(self, usr, pwd): """ - Log in to the server. You should have received the RSA-key - before calling this! - pwd is expected to be sha1. Bot should be True or False. Bots - have different functions in VP. + Log in to the server as a normal user. If the RSA-key wasn't + received yet, it will login after is has received the key. pwd + is expected to be sha1. >>> import hashlib >>> hashlib.sha1("MyVerySecretPassword").hexdigest() @@ -189,34 +190,71 @@ if self.cid != None: raise LoginError("You are already logged in") - # Get our login - if not (usr and pwd): - if self.__login_after_connecting: - usr, pwd, bot = self.__login_after_connecting - else: - return # Just ignore it.. + if not self.__sh['rsakey']: + # Save this + self.__sh['login_after_connecting'] = (self.login, + (usr, pwd)) + return if not self.__sock: raise ConnectionError("You are not connected!") - if not self.__rsakey: - raise LoginError("No rsa-key available") + self.__sh['isbot'] = False # Convert pwd - pwd = rsa.encrypt(pwd, self.__rsakey) + pwd = rsa.encrypt(pwd, self.__sh['rsakey']) # Log in self.send("login", { "usr": usr, "pwd": pwd, - "bot": bool(bot), + "bot": False, "for": "VP", - "client": ( self.__config['app_name'], - self.__config['app_version'] + "client": ( self.__sh['config']['app_name'], + self.__sh['config']['app_version'] ) }) + def login_bot(self, owner, pwd, screenname): + """ + Log in as a bot. If the RSA-key wasn't received yet, it will + login after is has received the key. pwd is expected to be sha1. + + >>> import hashlib + >>> hashlib.sha1("MyVerySecretPassword").hexdigest() + 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' + """ + + if self.cid != None: + raise LoginError("You are already logged in") + + if not self.__sh['rsakey']: + # Save this + self.__sh['login_after_connecting'] = (self.login_bot, + (owner, pwd, screenname)) + return + + if not self.__sock: + raise ConnectionError("You are not connected!") + + self.__sh['isbot'] = True + + # Convert pwd + pwd = rsa.encrypt(pwd, self.__sh['rsakey']) + + # Log in + self.send("login", { + "usr": owner, + "pwd": pwd, + "name": screenname, + "bot": True, + "for": "VP", + "client": ( self.__sh['config']['app_name'], + self.__sh['config']['app_version'] + ) + }) + def send(self, data_header, data_body = {}): """ Sends `data_body` of type `data_header` to the server. It will @@ -240,7 +278,7 @@ callback. If not, you can reuse this class by calling `connect`. """ - if not self.__is_online: + if not self.__sh['is_online']: if reason == "manual": # Annoy the user raise ConnectionError("The connection is " + \ @@ -251,13 +289,14 @@ self.__do_connect.clear() # Block the thread-loop - self.__is_online = False + self.__sh['is_online'] = False self.__pinger.cancel() self.__pinger = None # Reset variables - self.__rsa = None + self.__sh['rsakey'] = None self.username = None + self.owner = None self.cid = None try: self.__sock.shutdown(0) @@ -268,6 +307,9 @@ if self.__call.disconnected(reason): # Reconnect self.__do_connect.set() + else: + # Remove auto-login + self.__sh['login_after_connecting'] = () class __Pinger(): @@ -288,7 +330,7 @@ if self.running == False: return #Ping! - self.send('PNG', {}) + self.send('ping', {}) #Start again self.timer = threading.Timer(30, self.run) Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-12-23 13:16:28 UTC (rev 329) +++ trunk/client/core/parser.py 2009-12-23 13:17:00 UTC (rev 330) @@ -16,15 +16,16 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Parser(): - def __init__(self, callback, client): + def __init__(self, sh): """ This class parses all received messages from the server. """ - self.callback = callback - self.client = client + self.sh = sh + self.call = sh['call'] + self.core = sh['core'] def __call__(self, msg): - self.callback.data_received(msg) + self.call.data_received(msg) head = msg.keys()[0] body = msg[head] @@ -45,7 +46,7 @@ """ # reason - Why it's going to disconnect us - self.client.close(msg["reason"]) + self.core.close(msg["reason"]) def rsa(self, msg): """ @@ -54,23 +55,37 @@ * public - The public rsa-key, which contains e & n """ - self.client._Client__rsakey = msg['public'] + self.sh['rsakey'] = msg['public'] - self.callback.received_rsa(msg['public']) + self.call.received_rsa(msg['public']) - self.client.login(None, None) + if self.sh['login_after_connecting'] != (): + login = self.sh['login_after_connecting'] + login[0](*login[1]) + def login(self, msg): """ Called when we can log in * username - The username (with right caps) * cid - The server's connection-id + * owner - The owner for this bot (only when logging in + as bot!) """ - self.client.username = msg['username'] - self.client.cid = msg['cid'] + if self.sh['isbot']: # Logging in as bot + self.core.owner = msg['owner'] + self.core.username = msg['username'] + self.core.cid = msg['cid'] + + self.call.logged_in(msg['username'], msg['cid'], + msg['owner']) - self.callback.logged_in(msg['username'], msg['cid']) + else: # Logging in as user + self.core.username = msg['username'] + self.core.cid = msg['cid'] + + self.call.logged_in(msg['username'], msg['cid'], None) def error(self, msg): """ @@ -80,14 +95,18 @@ "login not allowed" - User may not log in right now "bot limit reached" - Too much bots logged in for this user "login blocked" - The user (or IP) is blocked + "duplicate user" - There is already someone online with + this username """ if msg['reason'] == "bad login": - self.callback.failed_logging_in("bad login") + self.call.failed_logging_in("bad login") elif msg['reason'] == "login not allowed": - self.callback.failed_logging_in("login not allowed") + self.call.failed_logging_in("login not allowed") elif msg['reason'] == "bot limit reached": - self.callback.failed_logging_in("bot limit reached") + self.call.failed_logging_in("bot limit reached") elif msg['reason'] == "login blocked": - self.callback.failed_logging_in("login blocked") + self.call.failed_logging_in("login blocked") + elif msg['reason'] == "duplicate user": + self.call.failed_logging_in("duplicate user") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2010-01-03 16:04:29
|
Revision: 332 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=332&view=rev Author: BlueWolf_ Date: 2010-01-03 16:04:22 +0000 (Sun, 03 Jan 2010) Log Message: ----------- [Client-core] It will send it's protocol-version Modified Paths: -------------- trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2010-01-03 16:04:11 UTC (rev 331) +++ trunk/client/core/client.py 2010-01-03 16:04:22 UTC (rev 332) @@ -212,7 +212,8 @@ "for": "VP", "client": ( self.__sh['config']['app_name'], self.__sh['config']['app_version'] - ) + ), + "version": __version__ }) def login_bot(self, owner, pwd, screenname): @@ -251,7 +252,8 @@ "for": "VP", "client": ( self.__sh['config']['app_name'], self.__sh['config']['app_version'] - ) + ), + "version": __version__ }) Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2010-01-03 16:04:11 UTC (rev 331) +++ trunk/client/core/parser.py 2010-01-03 16:04:22 UTC (rev 332) @@ -87,6 +87,45 @@ self.call.logged_in(msg['username'], msg['cid'], None) + + def userlist(self, msg): + """ + Called after we've logged it. This contains a list with all + online users. This is a _list_ with: + * cid - The unique ID for this connection + * user - The username + * app - [Appname, Appversion] + * version - Which core it's using (string) + * bot - If it's a bot + * owner - The owner for this bot (only available when + bot = True) + * pos - [Z, X, Y] The position for this user. Is None + when you can't see this user. + """ + + # TODO + + pass + + def useronline(self, msg): + """ + Called after a user (or bot) has signed on. + * cid - The unique ID for this connection + * user - The username + * app - [Appname, Appversion] + * version - Which core it's using (string) + * bot - If it's a bot + * owner - The owner for this bot (only available when + bot = True) + * pos - [Z, X, Y] The position for this user. Is None + when you can't see this user. + """ + + # TODO + + pass + + def error(self, msg): """ Called when we did something wrong! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2010-04-19 19:44:47
|
Revision: 335 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=335&view=rev Author: BlueWolf_ Date: 2010-04-19 19:44:41 +0000 (Mon, 19 Apr 2010) Log Message: ----------- Some small modifications. sh['login_after_connection'] => sh['auto_login']. Will remember auto_login regardless of login being called before or after receiving the rsa-key Modified Paths: -------------- trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2010-01-08 23:44:25 UTC (rev 334) +++ trunk/client/core/client.py 2010-04-19 19:44:41 UTC (rev 335) @@ -79,7 +79,7 @@ self.__do_connect.clear() # Auto log in after connecting. - self.__sh['login_after_connecting'] = () + self.__sh['auto_login'] = () # RSA self.__sh['rsakey'] = None @@ -190,12 +190,12 @@ if self.cid != None: raise LoginError("You are already logged in") - if not self.__sh['rsakey']: - # Save this - self.__sh['login_after_connecting'] = (self.login, - (usr, pwd)) - return + # Save this + self.__sh['auto_login'] = (self.login, (usr, pwd)) + # Wait for the rsa-key to arrive + if not self.__sh['rsakey']: return + if not self.__sock: raise ConnectionError("You are not connected!") @@ -229,12 +229,13 @@ if self.cid != None: raise LoginError("You are already logged in") - if not self.__sh['rsakey']: - # Save this - self.__sh['login_after_connecting'] = (self.login_bot, + # Save this + self.__sh['auto_login'] = (self.login_bot, \ (owner, pwd, screenname)) - return + # Wait for the rsa-key to arrive + if not self.__sh['rsakey']: return + if not self.__sock: raise ConnectionError("You are not connected!") @@ -274,7 +275,7 @@ def close(self, reason = "manual"): """ - Will close the connection to the server. If the connection in + Will close the connection to the server. If the connection is already down, it will raise an exception. This will trigger the callback `disconnected`. It may reconnect, depending on the callback. If not, you can reuse this class by calling `connect`. @@ -311,7 +312,7 @@ self.__do_connect.set() else: # Remove auto-login - self.__sh['login_after_connecting'] = () + self.__sh['auto_login'] = () class __Pinger(): Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2010-01-08 23:44:25 UTC (rev 334) +++ trunk/client/core/parser.py 2010-04-19 19:44:41 UTC (rev 335) @@ -44,7 +44,6 @@ "crash" - The server-parser has made a crash "gone offline" - Server has just shutdown """ - # reason - Why it's going to disconnect us self.core.close(msg["reason"]) @@ -59,8 +58,9 @@ self.call.received_rsa(msg['public']) - if self.sh['login_after_connecting'] != (): - login = self.sh['login_after_connecting'] + if self.core.cid == None and \ + self.sh['auto_login'] != (): + login = self.sh['auto_login'] login[0](*login[1]) @@ -125,7 +125,17 @@ pass + def useroffline(self, msg): + """ + Some user has gone offline + * cid - The connection-id for this client + """ + + # TODO + + pass + def error(self, msg): """ Called when we did something wrong! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2010-08-24 23:40:57
|
Revision: 369 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=369&view=rev Author: BlueWolf_ Date: 2010-08-24 23:40:51 +0000 (Tue, 24 Aug 2010) Log Message: ----------- Added the possibility for the client to send and receive custom commands to app directly, making it easier to send stuff like money Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2010-08-23 21:59:40 UTC (rev 368) +++ trunk/client/core/callback.py 2010-08-24 23:40:51 UTC (rev 369) @@ -101,6 +101,20 @@ """ pass + def custom_receive(self, header, body): + """ + This is when custom data from the server's app has been send. This can + be used to send custom stuff like money e.d + + header: + What type the body is (string) + body: + The body of the message (can basically be every kind of object) + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + def logged_in(self, username, cid, owner): """ Called when we are logged in. Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2010-08-23 21:59:40 UTC (rev 368) +++ trunk/client/core/client.py 2010-08-24 23:40:51 UTC (rev 369) @@ -288,6 +288,16 @@ try: self.__sock.send(data + chr(1)) except: pass + + + def custom_send(self, data_header, data_body = {}): + """ + Sends custom data 'data_body' of type 'data_header' directly to the + others custom_receive of the server's app. This can be used to send + money and other custom events. + """ + + self.send("custom", {"header": data_header, "body": data_body}) def close(self, reason = "manual"): Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2010-08-23 21:59:40 UTC (rev 368) +++ trunk/client/core/parser.py 2010-08-24 23:40:51 UTC (rev 369) @@ -105,7 +105,7 @@ def useronline(self, msg): """ - Called after a user (or bot) has signed on. + Called after an user (or bot) has signed on. * cid - The unique ID for this connection * user - The username * app - [Appname, Appversion] @@ -123,7 +123,7 @@ def useroffline(self, msg): """ - Some user has gone offline + An user has gone offline * cid - The connection-id for this client """ @@ -154,4 +154,16 @@ self.call.failed_logging_in("login blocked") elif msg['reason'] == "duplicate user": self.call.failed_logging_in("duplicate user") + + def custom(self, msg): + """ + A custom command send from the server' app. + * header: + The type of the message + * body: + The message itself + """ + + self.call.custom(msg['header'], msg['body']) + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |