Esempio n. 1
0
 def parse_listings(listings):
     if listings is not None:
         response = {"listings": []}
         for l in listings.listing:
             listing_json = {
                 "title": l.title,
                 "contract_hash": l.contract_hash.encode("hex"),
                 "thumbnail_hash": l.thumbnail_hash.encode("hex"),
                 "category": l.category,
                 "price": l.price,
                 "currency_code": l.currency_code,
                 "nsfw": l.nsfw,
                 "origin": str(CountryCode.Name(l.origin)),
                 "ships_to": []
             }
             for country in l.ships_to:
                 listing_json["ships_to"].append(
                     str(CountryCode.Name(country)))
             response["listings"].append(listing_json)
         request.setHeader('content-type', "application/json")
         request.write(json.dumps(response, indent=4))
         request.finish()
     else:
         request.write(json.dumps({}))
         request.finish()
Esempio n. 2
0
 def respond(l, node):
     if l is not None:
         listing_json = {
             "id": message_id,
             "listing": {
                 "guid": node.id.encode("hex"),
                 "title": l.title,
                 "contract_hash": l.contract_hash.encode("hex"),
                 "thumbnail_hash": l.thumbnail_hash.encode("hex"),
                 "category": l.category,
                 "price": l.price,
                 "currency_code": l.currency_code,
                 "nsfw": l.nsfw,
                 "origin": str(CountryCode.Name(l.origin)),
                 "ships_to": [],
                 "avatar_hash": l.avatar_hash.encode("hex"),
                 "handle": l.handle
             }
         }
         for country in l.ships_to:
             listing_json["listing"]["ships_to"].append(
                 str(CountryCode.Name(country)))
         self.transport.write(
             str(
                 bleach.clean(json.dumps(listing_json, indent=4),
                              tags=ALLOWED_TAGS)))
Esempio n. 3
0
    def setUp(self):
        datastore.create_database(":memory:")
        self.test_hash = "87e0555568bf5c7e4debd6645fc3f41e88df6ca8"
        self.test_hash2 = "97e0555568bf5c7e4debd6645fc3f41e88df6ca8"
        self.test_file = "Contents of test.txt"
        self.test_file2 = "Contents of test2.txt"

        self.sp = Profile()
        self.sp.name = "Test User"
        self.sp.encryption_key = "Key"
        self.sp.location = CountryCode.Value('UNITED_STATES')

        self.serialized_listings = Listings()
        self.lm = self.serialized_listings.ListingMetadata()
        self.lm.contract_hash = self.test_hash
        self.lm.title = "TEST CONTRACT TITLE"
        self.lm.price = 0
        self.lm.currency_code = "USD"
        self.lm.nsfw = False
        self.lm.origin = CountryCode.Value('ALL')

        self.hm = datastore.HashMap()
        self.hm.delete_all()

        self.ps = datastore.ProfileStore()
        self.ls = datastore.ListingsStore()
        self.ks = datastore.KeyStore()
Esempio n. 4
0
    def setUp(self):

        self.db = Database(filepath="test.db")
        self.test_hash = "87e0555568bf5c7e4debd6645fc3f41e88df6ca8"
        self.test_hash2 = "97e0555568bf5c7e4debd6645fc3f41e88df6ca8"
        self.test_file = "Contents of test.txt"
        self.test_file2 = "Contents of test2.txt"

        self.sp = Profile()
        self.key = Profile().PublicKey()
        self.key.public_key = "Key"
        self.key.signature = "Sig"
        self.sp.name = "Test User"
        self.sp.guid_key.MergeFrom(self.key)
        self.sp.location = CountryCode.Value('UNITED_STATES')

        self.serialized_listings = Listings()
        self.lm = self.serialized_listings.ListingMetadata()
        self.lm.contract_hash = self.test_hash
        self.lm.title = "TEST CONTRACT TITLE"
        self.lm.price = 0
        self.lm.currency_code = "USD"
        self.lm.nsfw = False
        self.lm.origin = CountryCode.Value('ALL')

        self.u = Following.User()
        self.u.guid = '0000000000000000000000000000000000'
        self.u.pubkey = 'signed_pubkey'

        self.m = Metadata()
        self.m.name = 'Test User'
        self.m.handle = '@TestUser'
        self.m.avatar_hash = ''
        self.m.nsfw = False
        self.u.metadata.MergeFrom(self.m)

        self.f = Followers.Follower()
        self.f.guid = '0000000000000000000000000000000001'
        self.f.following = ''
        self.f.pubkey = ''
        self.f.metadata.MergeFrom(self.m)

        self.hm = self.db.filemap
        self.hm.delete_all()

        self.ps = self.db.profile
        self.ls = self.db.listings
        self.ks = self.db.keys
        self.fd = self.db.follow
        self.ms = self.db.messages
        self.ns = self.db.notifications
        self.vs = self.db.vendors
        self.bs = self.db.broadcasts
        self.moderators = self.db.moderators
        self.purchases = self.db.purchases
        self.sales = self.db.sales
        self.settings = self.db.settings
Esempio n. 5
0
 def handle_response(listings, node):
     count = 0
     if listings is not None:
         for l in listings.listing:
             try:
                 if l.contract_hash not in self.factory.outstanding_listings[message_id]:
                     listing_json = {
                         "id": message_id,
                         "listing":
                             {
                                 "guid": node.id.encode("hex"),
                                 "handle": listings.handle,
                                 "avatar_hash": listings.avatar_hash.encode("hex"),
                                 "title": l.title,
                                 "contract_hash": l.contract_hash.encode("hex"),
                                 "thumbnail_hash": l.thumbnail_hash.encode("hex"),
                                 "category": l.category,
                                 "price": l.price,
                                 "currency_code": l.currency_code,
                                 "nsfw": l.nsfw,
                                 "origin": str(CountryCode.Name(l.origin)),
                                 "ships_to": []
                             }
                     }
                     for country in l.ships_to:
                         listing_json["listing"]["ships_to"].append(str(CountryCode.Name(country)))
                     if not os.path.isfile(os.path.join( \
                             DATA_FOLDER, 'cache', l.thumbnail_hash.encode("hex"))):
                         self.factory.mserver.get_image(node, l.thumbnail_hash)
                     if not os.path.isfile(os.path.join( \
                             DATA_FOLDER, 'cache', listings.avatar_hash.encode("hex"))):
                         self.factory.mserver.get_image(node, listings.avatar_hash)
                     self.transport.write(str(bleach.clean(
                         json.dumps(listing_json, indent=4), tags=ALLOWED_TAGS)))
                     count += 1
                     self.factory.outstanding_listings[message_id].append(l.contract_hash)
                     if count == 3:
                         break
             except Exception:
                 pass
         if node.id in vendors:
             del vendors[node.id]
     else:
         if node.id in vendors:
             del vendors[node.id]
         if node.id in self.factory.mserver.protocol.multiplexer.vendors:
             del self.factory.mserver.protocol.multiplexer.vendors[node.id]
             self.factory.db.vendors.delete_vendor(node.id.encode("hex"))
         if only_following:
             vendor_list = get_following_from_vendors(vendors)
         else:
             vendor_list = vendors.values()
         if len(vendor_list) > 0:
             shuffle(vendor_list)
             node_to_ask = vendor_list[0]
             if node_to_ask is not None:
                 self.factory.mserver.get_listings(node_to_ask).addCallback(handle_response, node_to_ask)
Esempio n. 6
0
    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)
        file_name += digest(json.dumps(self.contract,
                                       indent=4)).encode("hex")[:8]

        # 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])
        if "category" in vendor_item:
            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
        self.db.HashMap().insert(data.contract_hash, file_path)

        # save the `ListingMetadata` protobuf to the database as well
        self.db.ListingsStore().add_listing(data)
Esempio n. 7
0
 def handle_response(listings, node):
     count = 0
     if listings is not None:
         for l in listings.listing:
             if l.contract_hash not in self.factory.outstanding[
                     message_id]:
                 listing_json = {
                     "id": message_id,
                     "listing": {
                         "guid": node.id.encode("hex"),
                         "handle": listings.handle,
                         "avatar_hash":
                         listings.avatar_hash.encode("hex"),
                         "title": l.title,
                         "contract_hash": l.contract_hash.encode("hex"),
                         "thumbnail_hash":
                         l.thumbnail_hash.encode("hex"),
                         "category": l.category,
                         "price": l.price,
                         "currency_code": l.currency_code,
                         "nsfw": l.nsfw,
                         "origin": str(CountryCode.Name(l.origin)),
                         "ships_to": []
                     }
                 }
                 for country in l.ships_to:
                     listing_json["listing"]["ships_to"].append(
                         str(CountryCode.Name(country)))
                 if not os.path.isfile(DATA_FOLDER + 'cache/' +
                                       l.thumbnail_hash.encode("hex")):
                     self.factory.mserver.get_image(
                         node, l.thumbnail_hash)
                 if not os.path.isfile(
                         DATA_FOLDER + 'cache/' +
                         listings.avatar_hash.encode("hex")):
                     self.factory.mserver.get_image(
                         node, listings.avatar_hash)
                 self.sendMessage(json.dumps(listing_json, indent=4),
                                  False)
                 count += 1
                 self.factory.outstanding[message_id].append(
                     l.contract_hash)
                 if count == 3:
                     return count
         vendors.remove(node)
     else:
         VendorStore().delete_vendor(node.id)
         vendors.remove(node)
     return count
Esempio n. 8
0
 def parse_profile(profile):
     if profile is not None:
         profile_json = {
             "profile": {
                 "name":
                 profile.name,
                 "location":
                 str(CountryCode.Name(profile.location)),
                 "encryption_key":
                 profile.encryption_key.public_key.encode("hex"),
                 "nsfw":
                 profile.nsfw,
                 "vendor":
                 profile.vendor,
                 "moderator":
                 profile.moderator,
                 "handle":
                 profile.handle,
                 "about":
                 profile.about,
                 "website":
                 profile.website,
                 "email":
                 profile.email,
                 "primary_color":
                 profile.primary_color,
                 "secondary_color":
                 profile.secondary_color,
                 "background_color":
                 profile.background_color,
                 "text_color":
                 profile.text_color,
                 "pgp_key":
                 profile.pgp_key.public_key,
                 "avatar_hash":
                 profile.avatar_hash.encode("hex"),
                 "header_hash":
                 profile.header_hash.encode("hex"),
                 "social_accounts": {}
             }
         }
         if "guid" in request.args:
             profile_json["profile"]["guid"] = request.args["guid"][0]
         else:
             profile_json["profile"][
                 "guid"] = self.keychain.guid.encode("hex")
         for account in profile.social:
             profile_json["profile"]["social_accounts"][str(
                 objects.Profile.SocialAccount.SocialType.Name(
                     account.type)).lower()] = {
                         "username": account.username,
                         "proof_url": account.proof_url
                     }
         request.setHeader('content-type', "application/json")
         request.write(json.dumps(profile_json, indent=4))
         request.finish()
     else:
         request.write(json.dumps({}))
         request.finish()
Esempio n. 9
0
 def respond(l, node):
     if l is not None:
         listing_json = {
             "id": message_id,
             "listing": {
                 "guid": node.id.encode("hex"),
                 "title": l.title,
                 "contract_hash": l.contract_hash.encode("hex"),
                 "thumbnail_hash": l.thumbnail_hash.encode("hex"),
                 "category": l.category,
                 "price": l.price,
                 "currency_code": l.currency_code,
                 "nsfw": l.nsfw,
                 "origin": str(CountryCode.Name(l.origin)),
                 "ships_to": []
             }
         }
         for country in l.ships_to:
             listing_json["listing"]["ships_to"].append(
                 str(CountryCode.Name(country)))
         self.sendMessage(json.dumps(listing_json, indent=4), False)
Esempio n. 10
0
 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)
Esempio n. 11
0
def migratev2(db):
    ser = db.listings.get_proto()
    if ser is not None:
        path = os.path.join(DATA_FOLDER, "listings.csv")
        with open(path, 'w') as csvfile:
            fieldnames = [
                "contract_type", "pricing_currency", "language", "title",
                "description", "processing_time", "price", "nsfw",
                "image_urls", "categories", "condition", "quantity",
                "sku_number", "shipping_option1_name",
                "shipping_option1_countries", "shipping_option1_service1_name",
                "shipping_option1_service1_estimated_delivery",
                "shipping_option1_service1_estimated_price",
                "shipping_option2_name", "shipping_option2_countries",
                "shipping_option2_service1_name",
                "shipping_option2_service1_estimated_delivery",
                "shipping_option2_service1_estimated_price"
            ]
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            l = objects.Listings()
            l.ParseFromString(ser)
            for listing in l.listing:
                with open(
                        db.filemap.get_file(
                            listing.contract_hash.encode("hex")),
                        "r") as filename:
                    contract = json.loads(filename.read(),
                                          object_pairs_hook=OrderedDict)

                price = ""
                if listing.currency_code.lower() == "btc":
                    price = contract["vendor_offer"]["listing"]["item"][
                        "price_per_unit"]["bitcoin"]
                    price = int(price * 100000000)
                else:
                    price = contract["vendor_offer"]["listing"]["item"][
                        "price_per_unit"]["fiat"]["price"]

                sku = ""
                if "sku" in contract["vendor_offer"]["listing"]["item"]:
                    sku = contract["vendor_offer"]["listing"]["item"]["sku"]

                condition = ""
                if "condition" in contract["vendor_offer"]["listing"]["item"]:
                    condition = contract["vendor_offer"]["listing"]["item"][
                        "condition"]

                category = ""
                if "category" in contract["vendor_offer"]["listing"]["item"]:
                    category = contract["vendor_offer"]["listing"]["item"][
                        "category"]

                contract_type = "PHYSICAL_GOOD"
                if contract["vendor_offer"]["listing"]["metadata"][
                        "category"] == "digital good":
                    contract_type = "DIGITAL_GOOD"

                row = {
                    'contract_type':
                    contract_type,
                    'pricing_currency':
                    listing.currency_code,
                    'language':
                    'english',
                    'title':
                    listing.title,
                    'description':
                    contract["vendor_offer"]["listing"]["item"]["description"],
                    'processing_time':
                    contract["vendor_offer"]["listing"]["item"]
                    ["process_time"],
                    'price':
                    price,
                    'nsfw':
                    str(listing.nsfw),
                    'image_urls':
                    '',
                    'categories':
                    category,
                    'condition':
                    condition,
                    'quantity':
                    '-1',
                    'sku_number':
                    sku
                }
                img64 = []
                for img_hash in contract["vendor_offer"]["listing"]["item"][
                        "image_hashes"]:
                    image_path = db.filemap.get_file(img_hash)
                    with open(image_path, "rb") as image_file:
                        encoded_string = base64.b64encode(image_file.read())
                    img64.append(encoded_string)
                if len(img64) == 1:
                    row["image_urls"] = img64[0]
                else:
                    img_csv = ''
                    r = 0
                    for img in img64:
                        r += 1
                        img_csv += img
                        if r != len(img64):
                            img_csv += ","
                    row["image_urls"] = img_csv
                if contract_type == "PHYSICAL_GOOD":
                    if "free" in contract["vendor_offer"]["listing"][
                            "shipping"]:
                        row["shipping_option1_name"] = "Free Shipping"
                        countries = []
                        for country in listing.ships_to:
                            countries.append(str(CountryCode.Name(country)))
                        if len(countries) == 1:
                            row["shipping_option1_countries"] = countries[0]
                        else:
                            country_csv = ''
                            r = 0
                            for c in countries:
                                r += 1
                                country_csv += c
                                if r != len(countries):
                                    country_csv += ","
                            row["shipping_option1_countries"] = country_csv
                        row["shipping_option1_service1_name"] = "default service"
                        ed = "standard shipping time"
                        row["shipping_option1_service1_estimated_delivery"] = ed
                        row["shipping_option1_service1_estimated_price"] = "0"
                    elif "flat_fee" in contract["vendor_offer"]["listing"][
                            "shipping"]:
                        cc = "bitcoin"
                        if listing.currency_code.lower() != "btc":
                            cc = "fiat"
                        if "domestic" in contract["vendor_offer"]["listing"][
                                "shipping"]["flat_fee"][cc]["price"]:
                            row["shipping_option1_name"] = "Domestic Shipping"
                            row["shipping_option1_countries"] = contract[
                                "vendor_offer"]["listing"]["shipping"][
                                    "shipping_origin"]
                            row["shipping_option1_service1_name"] = "default service"
                            ed = contract["vendor_offer"]["listing"][
                                "shipping"]["est_delivery"]["domestic"]
                            if ed == "":
                                ed = "standard shipping time"
                            row["shipping_option1_service1_estimated_delivery"] = ed
                            ship_price = contract["vendor_offer"]["listing"][
                                "shipping"]["flat_fee"][cc]["price"][
                                    "domestic"]
                            if cc == "bitcoin":
                                ship_price = int(ship_price * 100000000)
                            row["shipping_option1_service1_estimated_price"] = ship_price
                        if "international" in contract["vendor_offer"][
                                "listing"]["shipping"]["flat_fee"][cc][
                                    "price"]:
                            row["shipping_option2_name"] = "International Shipping"
                            countries = []
                            for country in listing.ships_to:
                                countries.append(str(
                                    CountryCode.Name(country)))
                            if len(countries) == 1:
                                row["shipping_option2_countries"] = countries[
                                    0]
                            else:
                                country_csv = ''
                                r = 0
                                for c in countries:
                                    r += 1
                                    country_csv += c
                                    if r != len(countries):
                                        country_csv += ","
                                row["shipping_option2_countries"] = country_csv
                            row["shipping_option2_service1_name"] = "default service"
                            ed = contract["vendor_offer"]["listing"][
                                "shipping"]["est_delivery"]["international"]
                            if ed == "":
                                ed = "standard shipping time"
                            row["shipping_option2_service1_estimated_delivery"] = ed
                            row["shipping_option2_service1_estimated_price"] = contract[
                                "vendor_offer"]["listing"]["shipping"][
                                    "flat_fee"][cc]["price"]["domestic"]

                writer.writerow(row)
        return path
    else:
        raise Exception("failed to deserialize listings")
Esempio n. 12
0
 def update_profile(self, request):
     try:
         p = Profile(self.db)
         if not p.get().encryption_key \
                 and "name" not in request.args \
                 and "location" not in request.args:
             request.write(
                 json.dumps(
                     {
                         "success": False,
                         "reason": "name or location not included"
                     },
                     indent=4))
             request.finish()
             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 "short_description" in request.args:
             u.short_description = request.args["short_description"][0]
         if "nsfw" in request.args:
             u.nsfw = bool(request.args["nsfw"][0])
         if "vendor" in request.args:
             u.vendor = bool(request.args["vendor"][0])
         if "moderator" in request.args:
             u.moderator = bool(request.args["moderator"][0])
         if "website" in request.args:
             u.website = request.args["website"][0]
         if "email" in request.args:
             u.email = request.args["email"][0]
         if "primary_color" in request.args:
             u.primary_color = int(request.args["primary_color"][0])
         if "secondary_color" in request.args:
             u.secondary_color = int(request.args["secondary_color"][0])
         if "background_color" in request.args:
             u.background_color = int(request.args["background_color"][0])
         if "text_color" in request.args:
             u.text_color = int(request.args["text_color"][0])
         if "avatar" in request.args:
             u.avatar_hash = unhexlify(request.args["avatar"][0])
         if "header" in request.args:
             u.header_hash = unhexlify(request.args["header"][0])
         if "pgp_key" in request.args and "signature" in request.args:
             p.add_pgp_key(request.args["pgp_key"][0],
                           request.args["signature"][0],
                           self.keychain.guid.encode("hex"))
         enc = u.PublicKey()
         enc.public_key = self.keychain.encryption_pubkey
         enc.signature = self.keychain.signing_key.sign(enc.public_key)[:64]
         u.encryption_key.MergeFrom(enc)
         p.update(u)
         request.write(json.dumps({"success": True}))
         request.finish()
         return server.NOT_DONE_YET
     except Exception, e:
         request.write(
             json.dumps({
                 "success": False,
                 "reason": e.message
             }, indent=4))
         request.finish()
         return server.NOT_DONE_YET
Esempio n. 13
0
 def handle_response(listings, node):
     count = 0
     if listings is not None:
         for l in listings.listing:
             try:
                 if l.contract_hash not in self.factory.outstanding_listings[
                         message_id]:
                     listing_json = {
                         "id": message_id,
                         "listing": {
                             "guid":
                             node.id.encode("hex"),
                             "handle":
                             listings.handle,
                             "avatar_hash":
                             listings.avatar_hash.encode("hex"),
                             "title":
                             l.title,
                             "contract_hash":
                             l.contract_hash.encode("hex"),
                             "thumbnail_hash":
                             l.thumbnail_hash.encode("hex"),
                             "category":
                             l.category,
                             "price":
                             l.price,
                             "currency_code":
                             l.currency_code,
                             "nsfw":
                             l.nsfw,
                             "origin":
                             str(CountryCode.Name(l.origin)),
                             "ships_to": []
                         }
                     }
                     for country in l.ships_to:
                         listing_json["listing"]["ships_to"].append(
                             str(CountryCode.Name(country)))
                     if not os.path.isfile(
                             DATA_FOLDER + 'cache/' +
                             l.thumbnail_hash.encode("hex")):
                         self.factory.mserver.get_image(
                             node, l.thumbnail_hash)
                     if not os.path.isfile(
                             DATA_FOLDER + 'cache/' +
                             listings.avatar_hash.encode("hex")):
                         self.factory.mserver.get_image(
                             node, listings.avatar_hash)
                     self.transport.write(
                         str(
                             bleach.clean(json.dumps(listing_json,
                                                     indent=4),
                                          tags=ALLOWED_TAGS)))
                     count += 1
                     self.factory.outstanding_listings[
                         message_id].append(l.contract_hash)
                     if count == 3:
                         break
             except Exception:
                 pass
         vendors.remove(node)
     else:
         vendors.remove(node)
         if node.id in self.factory.mserver.protocol.multiplexer.vendors:
             del self.factory.mserver.protocol.multiplexer.vendors[
                 node.id]