<commit_before>"""
This module manages all market related activities
"""
from StringIO import StringIO
import ast
from base64 import b64decode, b64encode
import hashlib
import json
import logging
import random
import string
import traceback

from PIL import Image, ImageOps
import gnupg
import tornado
from zmq.eventloop import ioloop

import constants
from data_uri import DataURI
from orders import Orders
from protocol import proto_page, query_page

ioloop.install()

class Market(object):

    def __init__(self, transport, db):

        """This class manages the active market for the application

        Attributes:
          _transport (CryptoTransportLayer): Transport layer for messaging between nodes.
          _dht (DHT): For storage across the network.
          _market_id (int): Indicates which local market we're working with.

        """

        # Current
        self._transport = transport
        self._dht = transport.getDHT()
        self._market_id = transport.getMarketID()
        self._myself = transport.getMyself()
        self._peers = self._dht.getActivePeers()
        self._db = db
        self.orders = Orders(transport, self._market_id, db)

        # Legacy for now
        self.pages = {}
        self.welcome = False
        self.mypage = None
        self.signature = None
        self._nickname = ""

        self._log = logging.getLogger('[%s] %s' % (self._market_id, self.__class__.__name__))
        self.settings = self._transport.settings

        welcome = True

        if self.settings:
            if  'welcome' in self.settings.keys() and self.settings['welcome']:
                welcome = False

        # Register callbacks for incoming events
        self._transport.add_callback('query_myorders', self.on_query_myorders)
        self._transport.add_callback('peer', self.on_peer)
        self._transport.add_callback('query_page', self.on_query_page)
        self._transport.add_callback('query_listings', self.on_query_listings)
        self._transport.add_callback('page', self.on_page)

        self._transport.add_callback('negotiate_pubkey', self.on_negotiate_pubkey)
        self._transport.add_callback('proto_response_pubkey', self.on_response_pubkey)

        self.load_page(welcome)

        # Periodically refresh buckets
        loop = tornado.ioloop.IOLoop.instance()
        refreshCB = tornado.ioloop.PeriodicCallback(self._dht._refreshNode,
                                                    constants.refreshTimeout,
                                                    io_loop=loop)
        refreshCB.start()



    def load_page(self, welcome):

        nickname = self.settings['nickname'] if self.settings.has_key("nickname") else ""
        store_description = self.settings['storeDescription'] if self.settings.has_key("storeDescription") else ""

        self._nickname = nickname

        if welcome:
            self._db.updateEntries("settings", {'market_id': self._transport._market_id}, {"welcome":"noshow"})
        else:
            self.welcome = False

    def private_key(self):
        return self.settings['privkey']

    def on_listing_results(self, results):
        self._log.debug('Listings %s' % results)

    def save_contract(self, msg):

        contract_id = random.randint(0, 1000000)

        # Initialize default values if not set
        # if not msg.has_key("unit_price") or not msg['unit_price'] > 0:
        #     msg['unit_price'] = 0
        # if not msg.has_key("shipping_price") or not msg['shipping_price'] > 0:
        #     msg['shipping_price'] = 0
        # if not msg.has_key("item_quantity_available") or not msg['item_quantity_available'] > 0:
        #     msg['item_quantity_available'] = 1

        # Load gpg
        gpg = gnupg.GPG()

        # Insert PGP Key
        self.settings = self._db.selectEntries("settings", "market_id = '%s'" % self._market_id)[0]

        self._log.debug('Settings %s' % self._transport.settings)
        msg['Seller']['seller_PGP'] = gpg.export_keys(self._transport.settings['PGPPubkeyFingerprint'], secret="P@ssw0rd")
        msg['Seller']['seller_BTC_uncompressed_pubkey'] = self._transport.settings['pubkey']
        msg['Seller']['seller_GUID'] = self._transport._guid

        # Process and crop thumbs for images
        if msg['Contract'].has_key('item_images'):
            if msg['Contract']['item_images'].has_key('image1'):

                img = msg['Contract']['item_images']['image1']

                uri = DataURI(img)
                imageData = uri.data
                mime_type = uri.mimetype
                charset = uri.charset

                image = Image.open(StringIO(imageData))
                croppedImage = ImageOps.fit(image, (200, 200), centering=(0.5, 0.5))
                data = StringIO()
                croppedImage.save(data, format='PNG')

                new_uri = DataURI.make('image/png', charset=charset, base64=True, data=data.getvalue())

                data.close()

                msg['Contract']['item_images'] = new_uri

        # TODO: replace default passphrase
        json_string = json.dumps(msg, indent=0)
        seg_len = 52
        out_text = string.join(map(lambda x : json_string[x:x+seg_len],
           range(0, len(json_string), seg_len)), "\n")
        signed_data = gpg.sign(out_text, passphrase='<PASSWORD>', keyid=self.settings.get('PGPPubkeyFingerprint'))

        # Save contract to DHT
        contract_key = hashlib.sha1(str(signed_data)).hexdigest()

        hash_value = hashlib.new('ripemd160')
        hash_value.update(contract_key)
        contract_key = hash_value.hexdigest()

        self._db.insertEntry("contracts", {"id": contract_id, "market_id": self._transport._market_id, "contract_body": json.dumps(msg), "signed_contract_body": str(signed_data), "state": "seed", "key": contract_key})

        self._log.debug('New Contract Key: %s' % contract_key)

        # Store listing
        self._transport._dht.iterativeStore(self._transport, contract_key, str(signed_data), self._transport._guid)

        self.update_listings_index()

        # If keywords store them in the keyword index
        keywords = msg['Contract']['item_keywords']
        self._log.info('Keywords: %s' % keywords)
        for keyword in keywords:

            hash_value = hashlib.new('ripemd160')
            hash_value.update('keyword-%s' % keyword)
            keyword_key = hash_value.hexdigest()

            self._transport._dht.iterativeStore(self._transport, keyword_key, json.dumps({'keyword_index_add':contract_key}), self._transport._guid)

    def republish_contracts(self):
        #listings = self._db.contracts.find()
        listings = self._db.selectEntries("contracts")
        for listing in listings:
            self._transport._dht.iterativeStore(self._transport, listing['key'], listing.get('signed_contract_body'), self._transport._guid)
        self.update_listings_index()

    def get_notaries(self):
        self._log.debug('Getting notaries')

        notaries = []
        self.settings = self.get_settings()
        notary_guids = self.settings['notaries']<commit_msg>Refactor the market object<commit_after>"""
This module manages all market related activities
"""
from StringIO import StringIO
import ast
from base64 import b64decode, b64encode
import hashlib
import json
import logging
import random
import string
import traceback

from PIL import Image, ImageOps
import gnupg
import tornado
from zmq.eventloop import ioloop

import constants
from data_uri import DataURI
from orders import Orders
from protocol import proto_page, query_page

ioloop.install()

class Market(object):

    def __init__(self, transport, db):

        """This class manages the active market for the application

        Attributes:
          _transport (CryptoTransportLayer): Transport layer for messaging between nodes.
          _dht (DHT): For storage across the network.
          _market_id (int): Indicates which local market we're working with.

        """

        # Current
        self._transport = transport
        self._dht = transport.getDHT()
        self._market_id = transport.getMarketID()
        self._myself = transport.getMyself()
        self._peers = self._dht.getActivePeers()
        self._db = db
        self.orders = Orders(transport, self._market_id, db)

        # Legacy for now
        self.pages = {}
        self.welcome = False
        self.mypage = None
        self.signature = None
        self._nickname = ""

        self._log = logging.getLogger('[%s] %s' % (self._market_id, self.__class__.__name__))
        self.settings = self._transport.settings

        self.gpg = gnupg.GPG()

        welcome = True

        if self.settings:
            if  'welcome' in self.settings.keys() and self.settings['welcome']:
                welcome = False

        # Register callbacks for incoming events
        self._transport.add_callback('query_myorders', self.on_query_myorders)
        self._transport.add_callback('peer', self.on_peer)
        self._transport.add_callback('query_page', self.on_query_page)
        self._transport.add_callback('query_listings', self.on_query_listings)
        self._transport.add_callback('page', self.on_page)

        self._transport.add_callback('negotiate_pubkey', self.on_negotiate_pubkey)
        self._transport.add_callback('proto_response_pubkey', self.on_response_pubkey)

        self.load_page(welcome)

        # Periodically refresh buckets
        loop = tornado.ioloop.IOLoop.instance()
        refreshCB = tornado.ioloop.PeriodicCallback(self._dht._refreshNode,
                                                    constants.refreshTimeout,
                                                    io_loop=loop)
        refreshCB.start()



    def load_page(self, welcome):

        nickname = self.settings['nickname'] if self.settings.has_key("nickname") else ""
        store_description = self.settings['storeDescription'] if self.settings.has_key("storeDescription") else ""

        self._nickname = nickname

        if welcome:
            self._db.updateEntries("settings", {'market_id': self._transport._market_id}, {"welcome":"noshow"})
        else:
            self.welcome = False

    def private_key(self):
        return self.settings['privkey']

    def on_listing_results(self, results):
        self._log.debug('Listings %s' % results)

    def process_contract_image(self, image):
        uri = DataURI(img)
        imageData = uri.data
        #mime_type = uri.mimetype
        charset = uri.charset

        image = Image.open(StringIO(imageData))
        croppedImage = ImageOps.fit(image, (200, 200), centering=(0.5, 0.5))
        data = StringIO()
        croppedImage.save(data, format='PNG')
        new_uri = DataURI.make('image/png', charset=charset, base64=True, data=data.getvalue())
        data.close()

        return new_uri

    def get_contract_id(self):
        return random.randint(0, 1000000)

    def linebreak_signing_data(self, data):
        json_string = json.dumps(data, indent=0)
        seg_len = 52
        out_text = string.join(map(lambda x : json_string[x:x+seg_len],
           range(0, len(json_string), seg_len)), "\n")
        return out_text

    def generate_contract_key(self, signed_contract):
        contract_hash = hashlib.sha1(str(signed_contract)).hexdigest()
        hash_value = hashlib.new('ripemd160')
        hash_value.update(contract_hash)
        return hash_value.hexdigest()

    def save_contract_to_db(self, contract_id, body, signed_body, key):
        self._db.insertEntry("contracts", {"id": contract_id,
                                           "market_id": self._transport._market_id,
                                           "contract_body": json.dumps(body),
                                           "signed_contract_body": str(signed_body),
                                           "state": "seed",
                                           "key": key})

    def update_keywords_on_network(self, key, keywords):
        for keyword in keywords:

            hash_value = hashlib.new('ripemd160')
            hash_value.update('keyword-%s' % keyword)
            keyword_key = hash_value.hexdigest()

            self._transport._dht.iterativeStore(self._transport, keyword_key, json.dumps({'keyword_index_add':key}), self._transport._guid)


    def save_contract(self, msg):

        contract_id = self.get_contract_id()

        # Refresh market settings
        self.settings = self.get_settings()

        msg['Seller']['seller_PGP'] = self.gpg.export_keys(self.settings['PGPPubkeyFingerprint'], secret="P@ssw0rd")
        msg['Seller']['seller_BTC_uncompressed_pubkey'] = self.settings['pubkey']
        msg['Seller']['seller_GUID'] = self.settings['guid']

        # Process and crop thumbs for images
        if msg['Contract'].has_key('item_images'):
            if msg['Contract']['item_images'].has_key('image1'):

                img = msg['Contract']['item_images']['image1']
                new_uri = self.process_contract_image(img)
                msg['Contract']['item_images'] = new_uri

        # Line break the signing data
        out_text = self.linebreak_signing_data(msg)

        # Sign the contract
        signed_data = self.gpg.sign(out_text, passphrase='<PASSWORD>', keyid=self.settings.get('PGPPubkeyFingerprint'))

        # Save contract to DHT
        contract_key = self.generate_contract_key(signed_data)

        # Store contract in database
        self.save_contract_to_db(contract_id, msg, signed_data, contract_key)

        # Store listing
        self._transport._dht.iterativeStore(self._transport, contract_key, str(signed_data), self._transport._guid)
        self.update_listings_index()

        # If keywords are present
        keywords = msg['Contract']['item_keywords']
        self.update_keywords_on_network(contract_key, keywords)

    def republish_contracts(self):
        listings = self._db.selectEntries("contracts")
        for listing in listings:
            self._transport._dht.iterativeStore(self._transport, listing['key'], listing.get('signed_contract_body'), self._transport._guid)
        self.update_listings_index()

    def get_notaries(self):
        self._log.debug('Getting notaries')

        notaries = []
        self.settings = self.get_settings()
        notary_guids = self.settings['notaries']
{'fraction_non_alphanumeric': 0.10850989927058007, 'fraction_numerical': 0.006043765196248697, 'mean_word_length': 2.637190500252653, 'pattern_counts': {'":': 14, '<': 5, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5781385', 'n_tokens_mistral': 4232, 'n_tokens_neox': 3998, 'n_words': 834}