class MarketProtocol(RPCProtocol): implements(MessageProcessor) def __init__(self, node_proto, router): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.handled_commands = [GET_CONTRACT, GET_IMAGE] self.multiplexer = None self.hashmap = HashMap() def connect_multiplexer(self, multiplexer): self.multiplexer = multiplexer def rpc_get_contract(self, sender, contract_hash): self.log.info("Looking up contract ID %s" % contract_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(contract_hash), "r") as file: contract = file.read() return [contract] except: return ["None"] def rpc_get_image(self, sender, image_hash): self.log.info("Looking up image with hash %s" % image_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(image_hash), "r") as file: image = file.read() return [image] except: return ["None"] def callGetContract(self, nodeToAsk, contract_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_contract(address, contract_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetImage(self, nodeToAsk, image_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_image(address, image_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def handleCallResponse(self, result, node): """ If we get a response, add the node to the routing table. If we get no response, make sure it's removed from the routing table. """ if result[0]: self.log.info("got response from %s, adding to router" % node) self.router.addContact(node) else: self.log.debug("no response from %s, removing from router" % node) self.router.removeContact(node) return result def __iter__(self): return iter(self.handled_commands)
def setimage(): parser = argparse.ArgumentParser( description="Maps a image hash to a file path in the database", usage='''usage: networkcli.py setimage [-f FILEPATH]''') parser.add_argument('-f', '--filepath', help="a path to the image") args = parser.parse_args(sys.argv[2:]) with open(args.filepath, "r") as f: image = f.read() d = digest(image) h = HashMap() h.insert(d, args.filepath) print h.get_file(d)
def __init__(self, node_proto, router, signing_key): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.multiplexer = None self.hashmap = HashMap() self.signing_key = signing_key self.listeners = [] self.handled_commands = [ GET_CONTRACT, GET_IMAGE, GET_PROFILE, GET_LISTINGS, GET_USER_METADATA, GET_CONTRACT_METADATA, FOLLOW, UNFOLLOW, GET_FOLLOWERS, GET_FOLLOWING, NOTIFY, MESSAGE ]
def get_image(self, request): @defer.inlineCallbacks def _showImage(resp=None): @defer.inlineCallbacks def _setContentDispositionAndSend(file_path, extension, content_type): request.setHeader('content-disposition', 'filename="%s.%s"' % (file_path, extension)) request.setHeader('content-type', content_type) f = open(file_path, "rb") yield FileSender().beginFileTransfer(f, request) f.close() defer.returnValue(0) if os.path.exists(image_path): yield _setContentDispositionAndSend(image_path, ".jpg", "image/jpeg") else: request.setResponseCode(http.NOT_FOUND) request.write("No such image '%s'" % request.path) request.finish() if "hash" in request.args: if HashMap().get_file(unhexlify( request.args["hash"][0])) is not None: image_path = HashMap().get_file( unhexlify(request.args["hash"][0])) else: image_path = DATA_FOLDER + "cache/" + request.args["hash"][0] if not os.path.exists(image_path) and "guid" in request.args: def get_node(node): if node is not None: self.mserver.get_image( node, unhexlify(request.args["hash"] [0])).addCallback(_showImage) else: _showImage() self.kserver.resolve(unhexlify( request.args["guid"][0])).addCallback(get_node) else: _showImage() else: request.write(NoResource().render(request)) request.finish() return server.NOT_DONE_YET
def __init__(self, contract=None, hash_value=None): """ This class can be instantiated with either an `OrderedDict` or a hash of a contract. If a hash is used, we will load the contract from either the file system or cache. Alternatively, pass in no parameters if the intent is to create a new contract. Args: contract: an `OrderedDict` containing a filled out json contract hash: a hash (in raw bytes) of a contract """ if contract is not None: self.contract = contract elif hash_value is not None: try: file_path = HashMap().get_file(hash_value) if file_path is None: file_path = DATA_FOLDER + "cache/" + hexlify(hash_value) with open(file_path, 'r') as filename: self.contract = json.load(filename, object_pairs_hook=OrderedDict) except Exception: self.contract = {} else: self.contract = {}
def __init__(self, node_proto, router): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.handled_commands = [GET_CONTRACT, GET_IMAGE] self.multiplexer = None self.hashmap = HashMap()
def delete(self, delete_images=True): """ Deletes the contract json from the OpenBazaar directory as well as the listing metadata from the db and all the related images in the file system. """ # build the file_name from the contract file_name = str( self.contract["vendor_offer"]["listing"]["item"]["title"][:100]) file_name = re.sub(r"[^\w\s]", '', file_name) file_name = re.sub(r"\s+", '_', file_name) file_path = DATA_FOLDER + "store/listings/contracts/" + file_name + ".json" h = HashMap() # maybe delete the images from disk if "image_hashes" in self.contract["vendor_offer"]["listing"][ "item"] and delete_images: for image_hash in self.contract["vendor_offer"]["listing"]["item"][ "image_hashes"]: # delete from disk image_path = h.get_file(unhexlify(image_hash)) if os.path.exists(image_path): os.remove(image_path) # remove pointer to the image from the HashMap h.delete(unhexlify(image_hash)) # delete the contract from disk if os.path.exists(file_path): os.remove(file_path) # delete the listing metadata from the db contract_hash = digest(json.dumps(self.contract, indent=4)) ListingsStore().delete_listing(contract_hash) # remove the pointer to the contract from the HashMap h.delete(contract_hash)
def update_profile(self, request): p = Profile() if not p.get().encryption_key \ and "name" not in request.args \ and "location" not in request.args: return "False" u = objects.Profile() if "name" in request.args: u.name = request.args["name"][0] if "location" in request.args: # This needs to be formatted. Either here or from the UI. u.location = CountryCode.Value(request.args["location"][0].upper()) if "handle" in request.args: u.handle = request.args["handle"][0] if "about" in request.args: u.about = request.args["about"][0] if "nsfw" in request.args: u.nsfw = True if "vendor" in request.args: u.vendor = True if "moderator" in request.args: u.moderator = True if "website" in request.args: u.website = request.args["website"][0] if "email" in request.args: u.email = request.args["email"][0] if "avatar" in request.args: with open(DATA_FOLDER + "store/avatar", 'wb') as outfile: outfile.write(request.args["avatar"][0]) avatar_hash = digest(request.args["avatar"][0]) HashMap().insert(avatar_hash, DATA_FOLDER + "store/avatar") u.avatar_hash = avatar_hash if "header" in request.args: with open(DATA_FOLDER + "store/header", 'wb') as outfile: outfile.write(request.args["header"][0]) header_hash = digest(request.args["header"][0]) HashMap().insert(header_hash, DATA_FOLDER + "store/header") u.header_hash = header_hash if "pgp_key" in request.args and "signature" in request.args: p.add_pgp_key(request.args["pgp_key"][0], request.args["signature"][0], KeyChain().guid.encode("hex")) u.encryption_key = KeyChain().encryption_pubkey p.update(u)
def __init__(self, node_proto, router, signing_key): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.multiplexer = None self.hashmap = HashMap() self.signing_key = signing_key self.listeners = [] self.handled_commands = [GET_CONTRACT, GET_IMAGE, GET_PROFILE, GET_LISTINGS, GET_USER_METADATA, GET_CONTRACT_METADATA, FOLLOW, UNFOLLOW, GET_FOLLOWERS, GET_FOLLOWING, NOTIFY, MESSAGE]
def save(self): """ Saves the json contract into the OpenBazaar/store/listings/contracts/ directory. It uses the title as the file name so it's easy on human eyes. A mapping of the hash of the contract and file path is stored in the database so we can retrieve the contract with only its hash. Additionally, the contract metadata (sent in response to the GET_LISTINGS query) is saved in the db for fast access. """ # get the contract title to use as the file name and format it file_name = str( self.contract["vendor_offer"]["listing"]["item"]["title"][:100]) file_name = re.sub(r"[^\w\s]", '', file_name) file_name = re.sub(r"\s+", '_', file_name) # save the json contract to the file system file_path = DATA_FOLDER + "store/listings/contracts/" + file_name + ".json" with open(file_path, 'w') as outfile: outfile.write(json.dumps(self.contract, indent=4)) # Create a `ListingMetadata` protobuf object using data from the full contract listings = Listings() data = listings.ListingMetadata() data.contract_hash = digest(json.dumps(self.contract, indent=4)) vendor_item = self.contract["vendor_offer"]["listing"]["item"] data.title = vendor_item["title"] if "image_hashes" in vendor_item: data.thumbnail_hash = unhexlify(vendor_item["image_hashes"][0]) data.category = vendor_item["category"] if "bitcoin" not in vendor_item["price_per_unit"]: data.price = float(vendor_item["price_per_unit"]["fiat"]["price"]) data.currency_code = vendor_item["price_per_unit"]["fiat"][ "currency_code"] else: data.price = float(vendor_item["price_per_unit"]["bitcoin"]) data.currency_code = "BTC" data.nsfw = vendor_item["nsfw"] if "shipping" not in self.contract["vendor_offer"]["listing"]: data.origin = CountryCode.Value("NA") else: data.origin = CountryCode.Value( self.contract["vendor_offer"]["listing"]["shipping"] ["shipping_origin"].upper()) for region in self.contract["vendor_offer"]["listing"]["shipping"][ "shipping_regions"]: data.ships_to.append(CountryCode.Value(region.upper())) # save the mapping of the contract file path and contract hash in the database HashMap().insert(data.contract_hash, file_path) # save the `ListingMetadata` protobuf to the database as well ListingsStore().add_listing(data)
def delete(self, delete_images=True): """ Deletes the contract json from the OpenBazaar directory as well as the listing metadata from the db and all the related images in the file system. """ # build the file_name from the contract file_name = str(self.contract["vendor_offer"]["listing"]["item"]["title"][:100]) file_name = re.sub(r"[^\w\s]", '', file_name) file_name = re.sub(r"\s+", '_', file_name) file_path = DATA_FOLDER + "store/listings/contracts/" + file_name + ".json" h = HashMap() # maybe delete the images from disk if "image_hashes" in self.contract["vendor_offer"]["listing"]["item"] and delete_images: for image_hash in self.contract["vendor_offer"]["listing"]["item"]["image_hashes"]: # delete from disk image_path = h.get_file(unhexlify(image_hash)) if os.path.exists(image_path): os.remove(image_path) # remove pointer to the image from the HashMap h.delete(unhexlify(image_hash)) # delete the contract from disk if os.path.exists(file_path): os.remove(file_path) # delete the listing metadata from the db contract_hash = digest(json.dumps(self.contract, indent=4)) ListingsStore().delete_listing(contract_hash) # remove the pointer to the contract from the HashMap h.delete(contract_hash)
def setprofile(): parser = argparse.ArgumentParser( description="Sets a profile in the database.", usage='''usage: networkcli.py setprofile [options]''') parser.add_argument('-n', '--name', help="the name of the user/store") parser.add_argument('-o', '--onename', help="the onename id") parser.add_argument('-a', '--avatar', help="the file path to the avatar image") parser.add_argument('-hd', '--header', help="the file path to the header image") parser.add_argument('-c', '--country', help="a string consisting of country from protos.countries.CountryCode") # we could add all the fields here but this is good enough to test. args = parser.parse_args(sys.argv[2:]) p = Profile() u = objects.Profile() h = HashMap() if args.name is not None: u.name = args.name if args.country is not None: u.location = countries.CountryCode.Value(args.country.upper()) if args.onename is not None: u.handle = args.onename if args.avatar is not None: with open(args.avatar, "r") as filename: image = filename.read() hash_value = digest(image) u.avatar_hash = hash_value h.insert(hash_value, args.avatar) if args.header is not None: with open(args.header, "r") as filename: image = filename.read() hash_value = digest(image) u.header_hash = hash_value h.insert(hash_value, args.header) u.encryption_key = KeyChain().encryption_pubkey p.update(u)
def get_contract(self, request): def parse_contract(contract): if contract is not None: request.setHeader('content-type', "application/json") request.write(json.dumps(contract, indent=4)) request.finish() else: request.write(NoResource().render(request)) request.finish() if "id" in request.args: if "guid" in request.args: def get_node(node): if node is not None: self.mserver.get_contract(node, unhexlify(request.args["id"][0]))\ .addCallback(parse_contract) else: request.write(NoResource().render(request)) request.finish() try: with open(DATA_FOLDER + "cache/" + request.args["id"][0], "r") as filename: contract = json.loads(filename.read(), object_pairs_hook=OrderedDict) parse_contract(contract) except Exception: self.kserver.resolve(unhexlify( request.args["guid"][0])).addCallback(get_node) else: try: with open( HashMap().get_file(unhexlify( request.args["id"][0])), "r") as filename: contract = json.loads(filename.read(), object_pairs_hook=OrderedDict) parse_contract(contract) except Exception: parse_contract(None) else: request.write(NoResource().render(request)) request.finish() return server.NOT_DONE_YET
def setprofile(): parser = argparse.ArgumentParser( description="Sets a profile in the database.", usage='''usage: networkcli.py setprofile [options]''') parser.add_argument('-n', '--name', help="the name of the user/store") parser.add_argument('-o', '--onename', help="the onename id") parser.add_argument('-a', '--avatar', help="the file path to the avatar image") parser.add_argument('-hd', '--header', help="the file path to the header image") parser.add_argument( '-c', '--country', help= "a string consisting of country from protos.countries.CountryCode") # we could add all the fields here but this is good enough to test. args = parser.parse_args(sys.argv[2:]) p = Profile() u = objects.Profile() h = HashMap() if args.name is not None: u.name = args.name if args.country is not None: u.location = countries.CountryCode.Value(args.country.upper()) if args.onename is not None: u.handle = args.onename if args.avatar is not None: with open(args.avatar, "r") as filename: image = filename.read() hash_value = digest(image) u.avatar_hash = hash_value h.insert(hash_value, args.avatar) if args.header is not None: with open(args.header, "r") as filename: image = filename.read() hash_value = digest(image) u.header_hash = hash_value h.insert(hash_value, args.header) u.encryption_key = KeyChain().encryption_pubkey p.update(u)
class MarketProtocol(RPCProtocol): implements(MessageProcessor) def __init__(self, node_proto, router, signing_key): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.multiplexer = None self.hashmap = HashMap() self.signing_key = signing_key self.listeners = [] self.handled_commands = [ GET_CONTRACT, GET_IMAGE, GET_PROFILE, GET_LISTINGS, GET_USER_METADATA, GET_CONTRACT_METADATA, FOLLOW, UNFOLLOW, GET_FOLLOWERS, GET_FOLLOWING, NOTIFY, MESSAGE ] def connect_multiplexer(self, multiplexer): self.multiplexer = multiplexer def add_listener(self, listener): self.listeners.append(listener) def rpc_get_contract(self, sender, contract_hash): self.log.info("Looking up contract ID %s" % contract_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(contract_hash), "r") as filename: contract = filename.read() return [contract] except Exception: self.log.warning("Could not find contract %s" % contract_hash.encode('hex')) return ["None"] def rpc_get_image(self, sender, image_hash): self.log.info("Looking up image with hash %s" % image_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(image_hash), "r") as filename: image = filename.read() return [image] except Exception: self.log.warning("Could not find image %s" % image_hash.encode('hex')) return ["None"] def rpc_get_profile(self, sender): self.log.info("Fetching profile") self.router.addContact(sender) try: proto = Profile().get(True) return [proto, self.signing_key.sign(proto)[:64]] except Exception: self.log.error("Unable to load the profile") return ["None"] def rpc_get_user_metadata(self, sender): self.log.info("Fetching metadata") self.router.addContact(sender) try: proto = Profile().get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.nsfw = proto.nsfw return [ m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64] ] except Exception: self.log.error("Unable to get the profile metadata") return ["None"] def rpc_get_listings(self, sender): self.log.info("Fetching listings") self.router.addContact(sender) try: proto = ListingsStore().get_proto() return [proto, self.signing_key.sign(proto)[:64]] except Exception: self.log.warning("Could not find any listings in the database") return ["None"] def rpc_get_contract_metadata(self, sender, contract_hash): self.log.info("Fetching metadata for contract %s" % hexlify(contract_hash)) self.router.addContact(sender) try: proto = ListingsStore().get_proto() l = Listings() l.ParseFromString(proto) for listing in l.listing: if listing.contract_hash == contract_hash: country_code = Profile().get().country_code listing.country_code = country_code ser = listing.SerializeToString() return [ser, self.signing_key.sign(ser)[:64]] except Exception: self.log.warning("Could not find metadata for contract %s" % hexlify(contract_hash)) return ["None"] def rpc_follow(self, sender, proto, signature): self.log.info("Follow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(proto, signature) f = Followers.Follower() f.ParseFromString(proto) if f.guid != sender.id: raise Exception('GUID does not match sending node') if f.following != self.proto.guid: raise Exception('Following wrong node') f.signature = signature FollowData().set_follower(f) proto = Profile().get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.nsfw = proto.nsfw return [ "True", m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64] ] except Exception: self.log.warning("Failed to validate follower") return ["False"] def rpc_unfollow(self, sender, signature): self.log.info("Unfollow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify("unfollow:" + self.proto.guid, signature) f = FollowData() f.delete_follower(sender.id) return ["True"] except Exception: self.log.warning("Failed to validate follower signature") return ["False"] def rpc_get_followers(self, sender): self.log.info("Fetching followers list from db") self.router.addContact(sender) ser = FollowData().get_followers() if ser is None: return ["None"] else: return [ser, self.signing_key.sign(ser)[:64]] def rpc_get_following(self, sender): self.log.info("Fetching following list from db") self.router.addContact(sender) ser = FollowData().get_following() if ser is None: return ["None"] else: return [ser, self.signing_key.sign(ser)[:64]] def rpc_notify(self, sender, message, signature): if len(message) <= 140 and FollowData().is_following(sender.id): try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(message, signature) except Exception: return ["False"] self.log.info("Received a notification from %s" % sender) self.router.addContact(sender) for listener in self.listeners: try: verifyObject(NotificationListener, listener) listener.notify(sender.id, message) except DoesNotImplement: pass return ["True"] else: return ["False"] def rpc_message(self, sender, pubkey, encrypted): try: box = Box( PrivateKey(self.signing_key.encode(nacl.encoding.RawEncoder)), PublicKey(pubkey)) plaintext = box.decrypt(encrypted) p = Plaintext_Message() p.ParseFromString(plaintext) signature = p.signature p.ClearField("signature") verify_key = nacl.signing.VerifyKey(p.signed_pubkey[64:]) verify_key.verify(p.SerializeToString(), signature) h = nacl.hash.sha512(p.signed_pubkey) pow_hash = h[64:128] if int(pow_hash[:6], 16) >= 50 or hexlify( p.sender_guid) != h[:40] or p.sender_guid != sender.id: raise Exception('Invalid guid') self.log.info("Received a message from %s" % sender) self.router.addContact(sender) for listener in self.listeners: try: verifyObject(MessageListener, listener) listener.notify(p, signature) except DoesNotImplement: pass return ["True"] except Exception: self.log.error("Received invalid message from %s" % sender) return ["False"] def callGetContract(self, nodeToAsk, contract_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_contract(address, contract_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetImage(self, nodeToAsk, image_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_image(address, image_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetProfile(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_profile(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetUserMetadata(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_user_metadata(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetListings(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_listings(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetContractMetadata(self, nodeToAsk, contract_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_contract_metadata(address, contract_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callFollow(self, nodeToAsk, proto, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.follow(address, proto, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callUnfollow(self, nodeToAsk, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.unfollow(address, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetFollowers(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_followers(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetFollowing(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_following(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callNotify(self, nodeToAsk, message, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.notify(address, message, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callMessage(self, nodeToAsk, ehemeral_pubkey, ciphertext): address = (nodeToAsk.ip, nodeToAsk.port) d = self.message(address, ehemeral_pubkey, ciphertext) return d.addCallback(self.handleCallResponse, nodeToAsk) def handleCallResponse(self, result, node): """ If we get a response, add the node to the routing table. If we get no response, make sure it's removed from the routing table. """ if result[0]: self.log.info("got response from %s, adding to router" % node) self.router.addContact(node) else: self.log.debug("no response from %s, removing from router" % node) self.router.removeContact(node) return result def __iter__(self): return iter(self.handled_commands)
def update( self, expiration_date=None, metadata_category=None, title=None, description=None, currency_code=None, price=None, process_time=None, nsfw=None, est_delivery_domestic=None, est_delivery_international=None, shipping_origin=None, shipping_regions=None, keywords=None, category=None, condition=None, sku=None, image_hashes=None, # if intending to delete an image, pass in # the hashes that are staying. images=None, # to add new images pass in a list of image files. free_shipping=None, shipping_currency_code=None, shipping_domestic=None, shipping_international=None): self.delete(False) vendor_listing = self.contract["vendor_offer"]["listing"] if expiration_date is not None: vendor_listing["item"]["expiry"] = expiration_date if metadata_category is not None: vendor_listing["metadata"]["category"] = metadata_category if metadata_category != "physical good" and vendor_listing["metadata"][ "category"] == "physical good": del vendor_listing["shipping"] elif metadata_category == "physical good" and vendor_listing[ "metadata"]["category"] != "physical good": vendor_listing["shipping"] = {} vendor_listing["shipping"]["est_delivery"] = {} vendor_listing["shipping"]["free"] = False if title is not None: vendor_listing["item"]["title"] = title if description is not None: vendor_listing["item"]["description"] = description if currency_code is not None: if currency_code.upper() != "BTC" and "bitcoin" \ in vendor_listing["item"]["price_per_unit"]: p = vendor_listing["item"]["price_per_unit"]["bitcoin"] del vendor_listing["item"]["price_per_unit"]["bitcoin"] vendor_listing["item"]["price_per_unit"]["fiat"] = {} vendor_listing["item"]["price_per_unit"]["fiat"][ "currency_code"] = currency_code vendor_listing["item"]["price_per_unit"]["fiat"]["price"] = p elif currency_code.upper() == "BTC" and "fiat" in \ vendor_listing["item"]["price_per_unit"]: p = vendor_listing["item"]["price_per_unit"]["fiat"]["price"] del vendor_listing["item"]["price_per_unit"]["fiat"] vendor_listing["item"]["price_per_unit"]["bitcoin"] = p if price is not None: if "bitcoin" in vendor_listing["item"]["price_per_unit"]: vendor_listing["item"]["price_per_unit"]["bitcoin"] = price else: vendor_listing["item"]["price_per_unit"]["fiat"][ "price"] = price if process_time is not None: vendor_listing["item"]["process_time"] = process_time if nsfw is not None: vendor_listing["item"]["nsfw"] = nsfw if keywords is not None: vendor_listing["item"]["keywords"] = [] vendor_listing["item"]["keywords"].extend(keywords) if category is not None: vendor_listing["item"]["category"] = category if image_hashes is not None: to_delete = list( set(vendor_listing["item"]["image_hashes"]) - set(image_hashes)) for image_hash in to_delete: # delete from disk h = HashMap() image_path = h.get_file(unhexlify(image_hash)) if os.path.exists(image_path): os.remove(image_path) # remove pointer to the image from the HashMap h.delete(unhexlify(image_hash)) vendor_listing["item"]["image_hashes"] = [] vendor_listing["item"]["image_hashes"].extend(image_hashes) if images is not None: if "image_hashes" not in vendor_listing["item"]: vendor_listing["item"]["image_hashes"] = [] for image in images: hash_value = digest(image).encode("hex") vendor_listing["item"]["image_hashes"].append(hash_value) with open(DATA_FOLDER + "store/media/" + hash_value, 'w') as outfile: outfile.write(image) HashMap().insert(digest(image), DATA_FOLDER + "store/media/" + hash_value) if vendor_listing["metadata"][ "category"] == "physical good" and condition is not None: vendor_listing["item"]["condition"] = condition if sku is not None: vendor_listing["item"]["sku"] = sku if vendor_listing["metadata"]["category"] == "physical good": if shipping_origin is not None: vendor_listing["shipping"]["shipping_origin"] = shipping_origin if free_shipping is not None: if free_shipping is True and vendor_listing["shipping"][ "free"] is False: vendor_listing["shipping"]["free"] = True del vendor_listing["shipping"]["flat_fee"] elif free_shipping is False and vendor_listing["shipping"][ "free"] is True: vendor_listing["shipping"]["flat_fee"] = {} vendor_listing["shipping"]["flat_fee"]["bitcoin"] = {} vendor_listing["shipping"]["free"] = False if shipping_currency_code is not None and vendor_listing[ "shipping"]["free"] is False: if shipping_currency_code == "BTC" and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"] = {} d = vendor_listing["shipping"]["flat_fee"]["fiat"][ "price"]["domestic"] i = vendor_listing["shipping"]["flat_fee"]["fiat"][ "price"]["international"] vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "domestic"] = d vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "international"] = i del vendor_listing["shipping"]["flat_fee"]["fiat"] elif shipping_currency_code != "BTC" and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: d = vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "domestic"] i = vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "international"] vendor_listing["shipping"]["flat_fee"]["fiat"] = {} vendor_listing["shipping"]["flat_fee"]["fiat"][ "price"] = {} vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "domestic"] = d vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "international"] = i vendor_listing["shipping"]["flat_fee"]["fiat"][ "currency_code"] = shipping_currency_code del vendor_listing["shipping"]["flat_fee"]["bitcoin"] if shipping_domestic is not None and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "domestic"] = shipping_domestic if shipping_international is not None and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "international"] = shipping_international if shipping_domestic is not None and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "domestic"] = shipping_domestic if shipping_international is not None and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "international"] = shipping_international if shipping_regions is not None: vendor_listing["shipping"][ "shipping_regions"] = shipping_regions if est_delivery_domestic is not None: vendor_listing["shipping"]["est_delivery"][ "domestic"] = est_delivery_domestic if est_delivery_international is not None: vendor_listing["shipping"]["est_delivery"][ "international"] = est_delivery_international self.save()
def update(self, expiration_date=None, metadata_category=None, title=None, description=None, currency_code=None, price=None, process_time=None, nsfw=None, est_delivery_domestic=None, est_delivery_international=None, shipping_origin=None, shipping_regions=None, keywords=None, category=None, condition=None, sku=None, image_hashes=None, # if intending to delete an image, pass in # the hashes that are staying. images=None, # to add new images pass in a list of image files. free_shipping=None, shipping_currency_code=None, shipping_domestic=None, shipping_international=None): self.delete(False) vendor_listing = self.contract["vendor_offer"]["listing"] if expiration_date is not None: vendor_listing["item"]["expiry"] = expiration_date if metadata_category is not None: vendor_listing["metadata"]["category"] = metadata_category if metadata_category != "physical good" and vendor_listing["metadata"][ "category"] == "physical good": del vendor_listing["shipping"] elif metadata_category == "physical good" and vendor_listing["metadata"][ "category"] != "physical good": vendor_listing["shipping"] = {} vendor_listing["shipping"]["est_delivery"] = {} vendor_listing["shipping"]["free"] = False if title is not None: vendor_listing["item"]["title"] = title if description is not None: vendor_listing["item"]["description"] = description if currency_code is not None: if currency_code.upper() != "BTC" and "bitcoin" \ in vendor_listing["item"]["price_per_unit"]: p = vendor_listing["item"]["price_per_unit"]["bitcoin"] del vendor_listing["item"]["price_per_unit"]["bitcoin"] vendor_listing["item"]["price_per_unit"]["fiat"] = {} vendor_listing["item"]["price_per_unit"]["fiat"][ "currency_code"] = currency_code vendor_listing["item"]["price_per_unit"]["fiat"]["price"] = p elif currency_code.upper() == "BTC" and "fiat" in \ vendor_listing["item"]["price_per_unit"]: p = vendor_listing["item"]["price_per_unit"]["fiat"]["price"] del vendor_listing["item"]["price_per_unit"]["fiat"] vendor_listing["item"]["price_per_unit"]["bitcoin"] = p if price is not None: if "bitcoin" in vendor_listing["item"]["price_per_unit"]: vendor_listing["item"]["price_per_unit"]["bitcoin"] = price else: vendor_listing["item"]["price_per_unit"]["fiat"]["price"] = price if process_time is not None: vendor_listing["item"]["process_time"] = process_time if nsfw is not None: vendor_listing["item"]["nsfw"] = nsfw if keywords is not None: vendor_listing["item"]["keywords"] = [] vendor_listing["item"]["keywords"].extend(keywords) if category is not None: vendor_listing["item"]["category"] = category if image_hashes is not None: to_delete = list(set(vendor_listing["item"]["image_hashes"]) - set(image_hashes)) for image_hash in to_delete: # delete from disk h = HashMap() image_path = h.get_file(unhexlify(image_hash)) if os.path.exists(image_path): os.remove(image_path) # remove pointer to the image from the HashMap h.delete(unhexlify(image_hash)) vendor_listing["item"]["image_hashes"] = [] vendor_listing["item"]["image_hashes"].extend(image_hashes) if images is not None: if "image_hashes" not in vendor_listing["item"]: vendor_listing["item"]["image_hashes"] = [] for image in images: hash_value = digest(image).encode("hex") vendor_listing["item"]["image_hashes"].append(hash_value) with open(DATA_FOLDER + "store/media/" + hash_value, 'w') as outfile: outfile.write(image) HashMap().insert(digest(image), DATA_FOLDER + "store/media/" + hash_value) if vendor_listing["metadata"]["category"] == "physical good" and condition is not None: vendor_listing["item"]["condition"] = condition if sku is not None: vendor_listing["item"]["sku"] = sku if vendor_listing["metadata"]["category"] == "physical good": if shipping_origin is not None: vendor_listing["shipping"]["shipping_origin"] = shipping_origin if free_shipping is not None: if free_shipping is True and vendor_listing["shipping"]["free"] is False: vendor_listing["shipping"]["free"] = True del vendor_listing["shipping"]["flat_fee"] elif free_shipping is False and vendor_listing["shipping"]["free"] is True: vendor_listing["shipping"]["flat_fee"] = {} vendor_listing["shipping"]["flat_fee"]["bitcoin"] = {} vendor_listing["shipping"]["free"] = False if shipping_currency_code is not None and vendor_listing["shipping"]["free"] is False: if shipping_currency_code == "BTC" and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"] = {} d = vendor_listing["shipping"]["flat_fee"]["fiat"]["price"]["domestic"] i = vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "international"] vendor_listing["shipping"]["flat_fee"]["bitcoin"]["domestic"] = d vendor_listing["shipping"]["flat_fee"]["bitcoin"]["international"] = i del vendor_listing["shipping"]["flat_fee"]["fiat"] elif shipping_currency_code != "BTC" and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: d = vendor_listing["shipping"]["flat_fee"]["bitcoin"]["domestic"] i = vendor_listing["shipping"]["flat_fee"]["bitcoin"]["international"] vendor_listing["shipping"]["flat_fee"]["fiat"] = {} vendor_listing["shipping"]["flat_fee"]["fiat"]["price"] = {} vendor_listing["shipping"]["flat_fee"]["fiat"]["price"]["domestic"] = d vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "international"] = i vendor_listing["shipping"]["flat_fee"]["fiat"][ "currency_code"] = shipping_currency_code del vendor_listing["shipping"]["flat_fee"]["bitcoin"] if shipping_domestic is not None and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "domestic"] = shipping_domestic if shipping_international is not None and "bitcoin" not in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["fiat"]["price"][ "international"] = shipping_international if shipping_domestic is not None and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "domestic"] = shipping_domestic if shipping_international is not None and "bitcoin" in \ vendor_listing["shipping"]["flat_fee"]: vendor_listing["shipping"]["flat_fee"]["bitcoin"][ "international"] = shipping_international if shipping_regions is not None: vendor_listing["shipping"]["shipping_regions"] = shipping_regions if est_delivery_domestic is not None: vendor_listing["shipping"]["est_delivery"]["domestic"] = est_delivery_domestic if est_delivery_international is not None: vendor_listing["shipping"]["est_delivery"][ "international"] = est_delivery_international self.save()
def create(self, expiration_date, metadata_category, title, description, currency_code, price, process_time, nsfw, shipping_origin, shipping_regions, est_delivery_domestic=None, est_delivery_international=None, keywords=None, category=None, condition=None, sku=None, images=None, free_shipping=None, shipping_currency_code=None, shipping_domestic=None, shipping_international=None): """ All parameters are strings except: :param expiration_date: `string` (must be formatted UTC datetime) :param keywords: `list` :param nsfw: `boolean` :param images: a `list` of image files :param free_shipping: `boolean` :param shipping_origin: a 'string' formatted `CountryCode` :param shipping_regions: a 'list' of 'string' formatted `CountryCode`s """ # TODO: import keys into the contract, import moderator information from db, sign contract. profile = Profile().get() keychain = KeyChain() self.contract = OrderedDict({ "vendor_offer": { "listing": { "metadata": { "version": "0.1", "expiry": expiration_date + " UTC", "category": metadata_category, "category_sub": "fixed price" }, "id": { "guid": keychain.guid.encode("hex"), "pubkeys": { "guid": keychain.guid_signed_pubkey[64:].encode("hex"), "bitcoin": keychain.bitcoin_master_pubkey } }, "item": { "title": title, "description": description, "process_time": process_time, "price_per_unit": {}, "nsfw": nsfw } } } }) if metadata_category == "physical good" and condition is not None: self.contract["vendor_offer"]["listing"]["item"][ "condition"] = condition if currency_code.upper() == "BTC": item = self.contract["vendor_offer"]["listing"]["item"] item["price_per_unit"]["bitcoin"] = price else: item = self.contract["vendor_offer"]["listing"]["item"] item["price_per_unit"]["fiat"] = {} item["price_per_unit"]["fiat"]["price"] = price item["price_per_unit"]["fiat"]["currency_code"] = currency_code if keywords is not None: self.contract["vendor_offer"]["listing"]["item"]["keywords"] = [] self.contract["vendor_offer"]["listing"]["item"][ "keywords"].extend(keywords) if category is not None: self.contract["vendor_offer"]["listing"]["item"][ "category"] = category if sku is not None: self.contract["vendor_offer"]["listing"]["item"]["sku"] = sku if metadata_category == "physical good": self.contract["vendor_offer"]["listing"]["shipping"] = {} shipping = self.contract["vendor_offer"]["listing"]["shipping"] shipping["shipping_origin"] = shipping_origin if free_shipping is False: self.contract["vendor_offer"]["listing"]["shipping"][ "free"] = False self.contract["vendor_offer"]["listing"]["shipping"][ "flat_fee"] = {} if shipping_currency_code == "BTC": self.contract["vendor_offer"]["listing"]["shipping"][ "flat_fee"]["bitcoin"] = {} self.contract["vendor_offer"]["listing"]["shipping"][ "flat_fee"]["bitcoin"]["domestic"] = shipping_domestic self.contract["vendor_offer"]["listing"]["shipping"][ "flat_fee"]["bitcoin"][ "international"] = shipping_international else: shipping = self.contract["vendor_offer"]["listing"][ "shipping"] shipping["flat_fee"]["fiat"] = {} shipping["flat_fee"]["fiat"]["price"] = {} shipping["flat_fee"]["fiat"]["price"][ "domestic"] = shipping_domestic shipping["flat_fee"]["fiat"]["price"][ "international"] = shipping_international shipping["flat_fee"]["fiat"][ "currency_code"] = shipping_currency_code else: self.contract["vendor_offer"]["listing"]["shipping"][ "free"] = True self.contract["vendor_offer"]["listing"]["shipping"][ "shipping_regions"] = [] for region in shipping_regions: shipping = self.contract["vendor_offer"]["listing"]["shipping"] shipping["shipping_regions"].append(region) listing = self.contract["vendor_offer"]["listing"] listing["shipping"]["est_delivery"] = {} listing["shipping"]["est_delivery"][ "domestic"] = est_delivery_domestic listing["shipping"]["est_delivery"][ "international"] = est_delivery_international if profile.HasField("handle"): self.contract["vendor_offer"]["listing"]["id"][ "blockchain_id"] = profile.handle if images is not None: self.contract["vendor_offer"]["listing"]["item"][ "image_hashes"] = [] for image in images: hash_value = digest(image).encode("hex") self.contract["vendor_offer"]["listing"]["item"][ "image_hashes"].append(hash_value) with open(DATA_FOLDER + "store/media/" + hash_value, 'w') as outfile: outfile.write(image) HashMap().insert(digest(image), DATA_FOLDER + "store/media/" + hash_value) listing = json.dumps(self.contract["vendor_offer"]["listing"], indent=4) self.contract["vendor_offer"]["signature"] = \ keychain.signing_key.sign(listing, encoder=nacl.encoding.HexEncoder)[:128] self.save()
class MarketProtocol(RPCProtocol): implements(MessageProcessor) def __init__(self, node_proto, router, signing_key): self.router = router RPCProtocol.__init__(self, node_proto, router) self.log = Logger(system=self) self.multiplexer = None self.hashmap = HashMap() self.signing_key = signing_key self.listeners = [] self.handled_commands = [GET_CONTRACT, GET_IMAGE, GET_PROFILE, GET_LISTINGS, GET_USER_METADATA, GET_CONTRACT_METADATA, FOLLOW, UNFOLLOW, GET_FOLLOWERS, GET_FOLLOWING, NOTIFY, MESSAGE] def connect_multiplexer(self, multiplexer): self.multiplexer = multiplexer def add_listener(self, listener): self.listeners.append(listener) def rpc_get_contract(self, sender, contract_hash): self.log.info("Looking up contract ID %s" % contract_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(contract_hash), "r") as filename: contract = filename.read() return [contract] except Exception: self.log.warning("Could not find contract %s" % contract_hash.encode('hex')) return ["None"] def rpc_get_image(self, sender, image_hash): self.log.info("Looking up image with hash %s" % image_hash.encode('hex')) self.router.addContact(sender) try: with open(self.hashmap.get_file(image_hash), "r") as filename: image = filename.read() return [image] except Exception: self.log.warning("Could not find image %s" % image_hash.encode('hex')) return ["None"] def rpc_get_profile(self, sender): self.log.info("Fetching profile") self.router.addContact(sender) try: proto = Profile().get(True) return [proto, self.signing_key.sign(proto)[:64]] except Exception: self.log.error("Unable to load the profile") return ["None"] def rpc_get_user_metadata(self, sender): self.log.info("Fetching metadata") self.router.addContact(sender) try: proto = Profile().get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.short_description = proto.short_description m.avatar_hash = proto.avatar_hash m.nsfw = proto.nsfw return [m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64]] except Exception: self.log.error("Unable to get the profile metadata") return ["None"] def rpc_get_listings(self, sender): self.log.info("Fetching listings") self.router.addContact(sender) try: p = Profile().get() l = Listings() l.ParseFromString(ListingsStore().get_proto()) l.handle = p.handle l.avatar_hash = p.avatar_hash return [l.SerializeToString(), self.signing_key.sign(l.SerializeToString())[:64]] except Exception: self.log.warning("Could not find any listings in the database") return ["None"] def rpc_get_contract_metadata(self, sender, contract_hash): self.log.info("Fetching metadata for contract %s" % hexlify(contract_hash)) self.router.addContact(sender) try: proto = ListingsStore().get_proto() l = Listings() l.ParseFromString(proto) for listing in l.listing: if listing.contract_hash == contract_hash: ser = listing.SerializeToString() return [ser, self.signing_key.sign(ser)[:64]] except Exception: self.log.warning("Could not find metadata for contract %s" % hexlify(contract_hash)) return ["None"] def rpc_follow(self, sender, proto, signature): self.log.info("Follow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(proto, signature) f = Followers.Follower() f.ParseFromString(proto) if f.guid != sender.id: raise Exception('GUID does not match sending node') if f.following != self.proto.guid: raise Exception('Following wrong node') f.signature = signature FollowData().set_follower(f) proto = Profile().get(False) m = Metadata() m.name = proto.name m.handle = proto.handle m.avatar_hash = proto.avatar_hash m.nsfw = proto.nsfw return ["True", m.SerializeToString(), self.signing_key.sign(m.SerializeToString())[:64]] except Exception: self.log.warning("Failed to validate follower") return ["False"] def rpc_unfollow(self, sender, signature): self.log.info("Unfollow request from %s" % sender.id.encode("hex")) self.router.addContact(sender) try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify("unfollow:" + self.proto.guid, signature) f = FollowData() f.delete_follower(sender.id) return ["True"] except Exception: self.log.warning("Failed to validate follower signature") return ["False"] def rpc_get_followers(self, sender): self.log.info("Fetching followers list from db") self.router.addContact(sender) ser = FollowData().get_followers() if ser is None: return ["None"] else: return [ser, self.signing_key.sign(ser)[:64]] def rpc_get_following(self, sender): self.log.info("Fetching following list from db") self.router.addContact(sender) ser = FollowData().get_following() if ser is None: return ["None"] else: return [ser, self.signing_key.sign(ser)[:64]] def rpc_notify(self, sender, message, signature): if len(message) <= 140 and FollowData().is_following(sender.id): try: verify_key = nacl.signing.VerifyKey(sender.signed_pubkey[64:]) verify_key.verify(message, signature) except Exception: return ["False"] self.log.info("Received a notification from %s" % sender) self.router.addContact(sender) for listener in self.listeners: try: verifyObject(NotificationListener, listener) listener.notify(sender.id, message) except DoesNotImplement: pass return ["True"] else: return ["False"] def rpc_message(self, sender, pubkey, encrypted): try: box = Box(PrivateKey(self.signing_key.encode(nacl.encoding.RawEncoder)), PublicKey(pubkey)) plaintext = box.decrypt(encrypted) p = Plaintext_Message() p.ParseFromString(plaintext) signature = p.signature p.ClearField("signature") verify_key = nacl.signing.VerifyKey(p.signed_pubkey[64:]) verify_key.verify(p.SerializeToString(), signature) h = nacl.hash.sha512(p.signed_pubkey) pow_hash = h[64:128] if int(pow_hash[:6], 16) >= 50 or hexlify(p.sender_guid) != h[:40] or p.sender_guid != sender.id: raise Exception('Invalid guid') self.log.info("Received a message from %s" % sender) self.router.addContact(sender) for listener in self.listeners: try: verifyObject(MessageListener, listener) listener.notify(p, signature) except DoesNotImplement: pass return ["True"] except Exception: self.log.error("Received invalid message from %s" % sender) return ["False"] def callGetContract(self, nodeToAsk, contract_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_contract(address, contract_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetImage(self, nodeToAsk, image_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_image(address, image_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetProfile(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_profile(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetUserMetadata(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_user_metadata(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetListings(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_listings(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetContractMetadata(self, nodeToAsk, contract_hash): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_contract_metadata(address, contract_hash) return d.addCallback(self.handleCallResponse, nodeToAsk) def callFollow(self, nodeToAsk, proto, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.follow(address, proto, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callUnfollow(self, nodeToAsk, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.unfollow(address, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetFollowers(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_followers(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callGetFollowing(self, nodeToAsk): address = (nodeToAsk.ip, nodeToAsk.port) d = self.get_following(address) return d.addCallback(self.handleCallResponse, nodeToAsk) def callNotify(self, nodeToAsk, message, signature): address = (nodeToAsk.ip, nodeToAsk.port) d = self.notify(address, message, signature) return d.addCallback(self.handleCallResponse, nodeToAsk) def callMessage(self, nodeToAsk, ehemeral_pubkey, ciphertext): address = (nodeToAsk.ip, nodeToAsk.port) d = self.message(address, ehemeral_pubkey, ciphertext) return d.addCallback(self.handleCallResponse, nodeToAsk) def handleCallResponse(self, result, node): """ If we get a response, add the node to the routing table. If we get no response, make sure it's removed from the routing table. """ if result[0]: self.log.info("got response from %s, adding to router" % node) self.router.addContact(node) else: self.log.debug("no response from %s, removing from router" % node) self.router.removeContact(node) return result def __iter__(self): return iter(self.handled_commands)