From d51fe37a66fbce2d658a7725499bf4f214c5647d Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Tue, 6 Aug 2013 13:19:26 -0400 Subject: [PATCH] added requested API commands for mobile device --- src/bitmessagemain.py | 55 ++++++++++++++++++++++---------------- src/class_singleCleaner.py | 4 +-- src/class_sqlThread.py | 19 ++++++++----- src/message_data_reader.py | 28 ++++++++++--------- src/shared.py | 7 +++-- 5 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index b63cc2b3..82bcd3de 100644 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -747,6 +747,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if len(params) != 1: return 'API Error 0000: I need 1 parameter!' encryptedPayload, = params + encryptedPayload = encryptedPayload.decode('hex') inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 'msg' shared.inventory[inventoryHash] = ( @@ -754,15 +755,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( - streamNumber, 'sendinv', inventoryHash)) + toStreamNumber, 'sendinv', inventoryHash)) elif method == 'disseminatePubkey': # The device issuing this command to PyBitmessage supplies a pubkey object that has # already had the necessary proof of work done for it to be disseminated to the rest of the # Bitmessage network. PyBitmessage accepts this pubkey object and sends it out to the - # rest of the Bitmessage network, as if it had generated the pubkey object itself. + # rest of the Bitmessage network as if it had generated the pubkey object itself. if len(params) != 1: return 'API Error 0000: I need 1 parameter!' payload, = params + payload = payload.decode('hex') inventoryHash = calculateInventoryHash(payload) objectType = 'pubkey' shared.inventory[inventoryHash] = ( @@ -772,30 +774,40 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.broadcastToSendDataQueues(( streamNumber, 'sendinv', inventoryHash)) elif method == 'getMessageDataByDestinationRIPEHash': - # Method will eventually be used by a particular Android app. + # Method will eventually be used by a particular Android app to + # select relevant messages. + if len(params) != 1: return 'API Error 0000: I need 1 parameter!' - hash, = params - #if len(hash) != 40: - # return 'API Error 0019: The length of hash should be 20 bytes (encoded in hex thus 40 characters).' - print repr(hash) - hash = hash.decode('hex') - print repr(hash) - with shared.sqlLock: - shared.sqlSubmitQueue.put('''PRAGMA case_sensitive_like = true''') - shared.sqlSubmitQueue.put('') - queryreturn = shared.sqlReturnQueue.get() + requestedHash, = params + if len(requestedHash) != 40: + return 'API Error 0019: The length of hash should be 20 bytes (encoded in hex thus 40 characters).' + requestedHash = requestedHash.decode('hex') - hash = string.replace(hash,'e','ee') - hash = string.replace(hash,'%','e%') - hash = string.replace(hash,'_','e_') - print 'searching for hash:', repr(hash) - parameters = ('%'+ hash + '%',) + # This is not a particularly commonly used API function. Before we + # use it we'll need to fill out a field in our inventory database + # which is blank by default (first20bytesofencryptedmessage). + parameters = '' with shared.sqlLock: - shared.sqlSubmitQueue.put('''SELECT payload FROM inventory WHERE hash LIKE ? ESCAPE'e'; ''') + shared.sqlSubmitQueue.put('''SELECT hash, payload FROM inventory WHERE first20bytesofencryptedmessage = '' and objecttype = 'msg' ; ''') shared.sqlSubmitQueue.put(parameters) queryreturn = shared.sqlReturnQueue.get() + for row in queryreturn: + hash, payload = row + readPosition = 16 # Nonce length + time length + readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length + t = (payload[readPosition:readPosition+20],hash) + shared.sqlSubmitQueue.put('''UPDATE inventory SET first20bytesofencryptedmessage=? WHERE hash=?; ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + + parameters = (requestedHash,) + with shared.sqlLock: + shared.sqlSubmitQueue.put('commit') + shared.sqlSubmitQueue.put('''SELECT payload FROM inventory WHERE first20bytesofencryptedmessage = ?''') + shared.sqlSubmitQueue.put(parameters) + queryreturn = shared.sqlReturnQueue.get() data = '{"receivedMessageDatas":[' for row in queryreturn: payload, = row @@ -824,11 +836,8 @@ class singleAPI(threading.Thread): se.register_introspection_functions() se.serve_forever() +# This is a list of current connections (the thread pointers at least) selfInitiatedConnections = {} - # This is a list of current connections (the thread pointers at least) - - - if shared.useVeryEasyProofOfWorkForTesting: diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 6fed68a5..d92a37ec 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -33,9 +33,9 @@ class singleCleaner(threading.Thread): for hash, storedValue in shared.inventory.items(): objectType, streamNumber, payload, receivedTime = storedValue if int(time.time()) - 3600 > receivedTime: - t = (hash, objectType, streamNumber, payload, receivedTime) + t = (hash, objectType, streamNumber, payload, receivedTime,'') shared.sqlSubmitQueue.put( - '''INSERT INTO inventory VALUES (?,?,?,?,?)''') + '''INSERT INTO inventory VALUES (?,?,?,?,?,?)''') shared.sqlSubmitQueue.put(t) shared.sqlReturnQueue.get() del shared.inventory[hash] diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 48be5e0d..625b2b2f 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -46,7 +46,7 @@ class sqlThread(threading.Thread): self.cur.execute( '''CREATE TABLE pubkeys (hash blob, transmitdata blob, time int, usedpersonally text, UNIQUE(hash) ON CONFLICT REPLACE)''' ) self.cur.execute( - '''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, UNIQUE(hash) ON CONFLICT REPLACE)''' ) + '''CREATE TABLE inventory (hash blob, objecttype text, streamnumber int, payload blob, receivedtime integer, first20bytesofencryptedmessage blob, UNIQUE(hash) ON CONFLICT REPLACE)''' ) self.cur.execute( '''CREATE TABLE knownnodes (timelastseen int, stream int, services blob, host blob, port blob, UNIQUE(host, stream, port) ON CONFLICT REPLACE)''' ) # This table isn't used in the program yet but I @@ -55,7 +55,7 @@ class sqlThread(threading.Thread): '''INSERT INTO subscriptions VALUES('Bitmessage new releases/announcements','BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw',1)''') self.cur.execute( '''CREATE TABLE settings (key blob, value blob, UNIQUE(key) ON CONFLICT REPLACE)''' ) - self.cur.execute( '''INSERT INTO settings VALUES('version','1')''') + self.cur.execute( '''INSERT INTO settings VALUES('version','2')''') self.cur.execute( '''INSERT INTO settings VALUES('lastvacuumtime',?)''', ( int(time.time()),)) self.conn.commit() @@ -190,13 +190,18 @@ class sqlThread(threading.Thread): if not shared.config.has_option('bitmessagesettings', 'sockslisten'): shared.config.set('bitmessagesettings', 'sockslisten', 'false') - # Some prewritten code for future use whenever we need to modify the database - """item = '''SELECT value FROM settings WHERE key='version';''' + # Add a new column to the inventory table to store the first 20 bytes of encrypted messages to support Android app + item = '''SELECT value FROM settings WHERE key='version';''' parameters = '' self.cur.execute(item, parameters) - if self.cur.fetchall()[0][0] == 1: - do something - increment the version to 2""" + if int(self.cur.fetchall()[0][0]) == 1: + print 'upgrading database' + item = '''ALTER TABLE inventory ADD first20bytesofencryptedmessage blob DEFAULT '' ''' + parameters = '' + self.cur.execute(item, parameters) + item = '''update settings set value=? WHERE key='version';''' + parameters = (2,) + self.cur.execute(item, parameters) try: testpayload = '\x00\x00' diff --git a/src/message_data_reader.py b/src/message_data_reader.py index f6102e02..35b2441a 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -54,16 +54,16 @@ def readPubkeys(): def readInventory(): print 'Printing everything in inventory table:' - item = '''select hash, objecttype, streamnumber, payload, receivedtime from inventory''' + item = '''select hash, objecttype, streamnumber, payload, receivedtime, first20bytesofencryptedmessage from inventory where objecttype = 'msg' ''' parameters = '' cur.execute(item, parameters) output = cur.fetchall() - for row in output: - hash, objecttype, streamnumber, payload, receivedtime = row - print 'Hash:', hash.encode('hex'), objecttype, streamnumber, '\t', payload.encode('hex'), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(receivedtime)),'utf-8') + for row in output[:50]: + hash, objecttype, streamnumber, payload, receivedtime, first20bytesofencryptedmessage = row + print 'Hash:', hash.encode('hex'), objecttype, streamnumber, '\t', 'first20bytesofencryptedmessage:', first20bytesofencryptedmessage.encode('hex'), '\t', payload.encode('hex'), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(receivedtime)),'utf-8') def readInventory2(): - searchValue = ' ' + searchValue = ' ' item = '''PRAGMA case_sensitive_like = true ''' parameters = '' @@ -74,15 +74,17 @@ def readInventory2(): searchValue = string.replace(searchValue,'_','e_') print 'Printing subset of inventory table:' - item = '''SELECT * FROM inventory WHERE hash LIKE ? ESCAPE'e'; ''' - parameters = ('%'+ searchValue + '%',) - print repr(parameters), len(parameters[0]) + item = '''SELECT substr(payload,20) FROM inventory''' + #parameters = ('%'+ searchValue + '%',) + #print repr(parameters), len(parameters[0]) + parameters = '' cur.execute(item, parameters) output = cur.fetchall() print 'Number of results:', len(output) - for row in output[:20]: - hash, objecttype, streamnumber, payload, receivedtime = row - print 'Hash:', hash.encode('hex'), objecttype, streamnumber, '\t', payload.encode('hex'), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(receivedtime)),'utf-8') + for row in output[:100]: + print row + #hash, objecttype, streamnumber, payload, receivedtime = row + #print 'Hash:', hash.encode('hex'), objecttype, streamnumber, '\t', payload.encode('hex'), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(receivedtime)),'utf-8') print 'done' @@ -125,9 +127,9 @@ def vacuum(): #readSent() #readPubkeys() #readSubscriptions() -#readInventory() +readInventory() #vacuum() #will defragment and clean empty space from the messages.dat file. -readInventory2() +#readInventory2() diff --git a/src/shared.py b/src/shared.py index 214c124f..925459f7 100644 --- a/src/shared.py +++ b/src/shared.py @@ -243,8 +243,7 @@ def reloadMyAddressHashes(): myAddressesByHash[hash] = addressInKeysFile else: - logger.error('Error in reloadMyAddressHashes: Can\'t handle address ' - 'versions other than 2 or 3.\n') + logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2 or 3.\n') if not keyfileSecure: fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) @@ -320,8 +319,8 @@ def flushInventory(): sqlLock.acquire() for hash, storedValue in inventory.items(): objectType, streamNumber, payload, receivedTime = storedValue - t = (hash,objectType,streamNumber,payload,receivedTime) - sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?)''') + t = (hash,objectType,streamNumber,payload,receivedTime,'') + sqlSubmitQueue.put('''INSERT INTO inventory VALUES (?,?,?,?,?,?)''') sqlSubmitQueue.put(t) sqlReturnQueue.get() del inventory[hash]