Exemplo n.º 1
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi("ui/qt/main_window.ui", self)
        self.setWindowTitle("Raven Trader Pro")

        qss_file = open('ui/qt/style.qss', mode='r')
        qss = qss_file.read()
        qss_file.close()
        self.setStyleSheet(qss)

        self.settings = AppInstance.settings
        self.wallet = AppInstance.wallet
        self.wallet.on_swap_mempool = self.swap_mempool
        self.wallet.on_swap_confirmed = self.swap_confirmed
        self.wallet.on_completed_mempool = self.completed_trade_mempool
        self.wallet.on_completed_confirmed = self.completed_trade_network
        self.server = ServerConnection()
        self.server_menu = None

        self.update_dynamic_menus()

        #NOTE: Most actions are connected in the main_window.ui file

        self.updateTimer = QTimer(self)
        self.updateTimer.timeout.connect(self.actionRefresh.trigger)
        self.updateTimer.start(self.settings.read("update_interval"))

        self.menu_context = {"type": None, "data": None}
        self.actionRefresh.trigger()
Exemplo n.º 2
0
def loadFonts():
    main_directory = ServerConnection.getMainDirectory()

    pyglet.resource.path.append(main_directory + '/fonts')
    pyglet.resource.reindex()

    for font in fonts:
        ServerConnection.getClientPath('fonts/'+font)
        pyglet.resource.add_font(font)
Exemplo n.º 3
0
    def seve_record(self, record):
        '''Метод шифрования рекорда и сохранения в файл'''
        #Строка для шифрования
        self.record = record
        #Создаём обьект сланна соединение с сервером
        self.server_connect = ServerConnection()
        #Проверка есть ли соединение с сервером
        self.connect = self.server_connect.get_connect()
        #Если есть то
        if self.connect:
            #Генерируем новый ключ для шифрования
            self.key = Fernet.generate_key()
            #Создаём функцию шифрвоания на основе ключа
            self.cipher = Fernet(self.key)
            #Переводим строку рекорда в байты
            self.record = bytes(str(self.record), encoding = 'utf-8')
            #Создание зашифрованной копии рекорда
            self.record = self.cipher.encrypt(self.record)
            #Перевод рекорда из байтовых в строковые значения для записи
            self.record = str(self.record.decode('utf-8'))
            #Перевод ключа из байтовых в строковые значения для записи
            self.key = str(self.key.decode('utf-8'))
            #Отправляем запрос на сервес, сохранение
            self.server_connect.set_save_server(self.key, self.record)
            #Имя файла для записи, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Всё это кладём в массив
            self.save_arr = [self.key, self.record]
            #Функция записи в файл
            with open(self.filename, 'w') as self.f_obj:
                json.dump(self.save_arr , self.f_obj)

        else:
            #Переводим строку рекорда в байты
            self.record = bytes(str(self.record), encoding = 'utf-8')
            #Генерируем новый ключ для шифрования
            self.key = Fernet.generate_key()
            #Создаём функцию шифрвоания на основе ключа
            self.cipher = Fernet(self.key)
            #Создание зашифрованной копии рекорда
            self.record = self.cipher.encrypt(self.record)
            #Имя файла для записи, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Перевод рекорда из байтовых в строковые значения для записи
            self.record = str(self.record.decode('utf-8'))
            #Перевод ключа из байтовых в строковые значения для записи
            self.key = str(self.key.decode('utf-8'))
            #Всё это кладём в массив
            self.save_arr = [self.key, self.record]
            #Функция записи в файл
            with open(self.filename, 'w') as self.f_obj:
                json.dump(self.save_arr , self.f_obj)
Exemplo n.º 4
0
def loadTileset():

    dic = {}

    sql =  "select til_name, til_path, til_type "
    sql += "from tileset "

    rows = DBConnection.getResult(sql)

    tiles =     {   'wall-nw':      (0,3),
                    'wall-n':       (1,3),
                    'wall-ne':      (2,3),
                    'wall-w':       (0,2),
                    'wall-e':       (2,2),
                    'wall-sw':      (0,1),
                    'wall-s':       (1,1),
                    'wall-se':      (2,1),
                    'door-n':       (3,3),
                    'door-s':       (3,2),
                    'ground':       (1,2),
                    'ground-alt1':  (0,0),
                    'ground-alt2':  (1,0),
                    'ground-alt3':  (2,0),
                    'empty':        (3,0)
                }

    for row in rows:

        name = row[0]
        path = row[1]
        type_tileset = row[2]

        if type_tileset == 'room':
            img = ServerConnection.getImage(path)

            tileset = cocos.tiles.TileSet(name, None)
            for n, p in tiles.items():
                prop =  {   'passable': True,
                            'transition' : False
                        }

                if n == 'door-n':
                    prop['transition'] = True

                tileset.add( prop, getTile(img,p), n)
                dic[name] = tileset
        else:
            ServerConnection.getClientPath(path)

    global TILESETS
    TILESETS.update(dic)
Exemplo n.º 5
0
def loadObjects():

    sql =  "select obj_name, obj_description, til_path, obj_til_x, obj_til_y "
    sql += "from object "
    sql += "inner join tileset on obj_til_xid = til_id ";

    rows = DBConnection.getResult(sql)

    dic = {}
    text = {}

    for obj in rows:
        name = obj[0]
        decription = obj[1]
        region = obj[3] * TILE_SIZE[0], obj[4] * TILE_SIZE[0], TILE_SIZE[0], TILE_SIZE[1]
        path = obj[2]

        img = ServerConnection.getImage(path,region)

        text[name]= decription
        dic[name] = img

    global OBJECTS
    global TEXTS

    OBJECTS.update(dic)
    TEXTS['object'].update(text)
Exemplo n.º 6
0
def loadEnemies():

    sql =  "select ene_name, ene_description, til_path, ene_til_x, ene_til_y "
    sql += "from enemy "
    sql += "inner join tileset on ene_til_xid = til_id ";

    rows = DBConnection.getResult(sql)

    dic = {}
    text = {}

    for ene in rows:
        name = ene[0]
        decription = ene[1]
        region = ene[3] * TILE_SIZE[0], ene[4] * TILE_SIZE[0], TILE_SIZE[0], TILE_SIZE[1]
        path = ene[2]

        img = ServerConnection.getImage(path,region)

        dic[name] = img
        text[name]= decription

    global ENEMIES
    global TEXTS


    ENEMIES.update(dic)
    TEXTS['enemy'].update(text)
Exemplo n.º 7
0
def test():

    game = cocos.director.director.init(width=SCREEN_SIZE[0], height=SCREEN_SIZE[1], caption=TITLE)
    
    logo = ServerConnection.getImage('img/gui/logo.png')
    game.set_icon(logo)

    try:
        user = DBConnection.getUser(getpass.getuser())

        user = User(user)
        hero = user.getHero()

        dungeon = Dungeon(hero)
        game.push_handlers(dungeon)
        
        credits_scene = creditsScene()


        #main scene

        main_command =  [
                        ('Play',play,[dungeon[0]]),
                        ('Credits',play,[credits_scene]),
                        ('Quit',game.close,[])
                        ]

        main_scene =  cocos.scene.Scene()
        menu =  MainMenu(main_command)

        #Title
        label = cocos.text.Label(TITLE,position = (400,500), font_name = 'Drakoheart Leiend', font_size = 45, anchor_x = 'center')
        main_scene.add(label)

        main_scene.add(menu)

        #music
        bgm = ServerConnection.getMusic('bgm/main_screen.ogg')
        bgm_player = pyglet.media.Player()
        bgm_player.queue(bgm)
        bgm_player.eos_action = bgm_player.EOS_LOOP
        bgm_player.play()

        cocos.director.director.run(main_scene)

    except UDungeonException as ude:
        print ude.message
Exemplo n.º 8
0
    def __init__(self,name):

        self.image = ServerConnection.getImage('img/tileset/hero.png')
        self.name =  name.capitalize()

        self.inventory = []

        self.__thaco = 20
        self.__ac = 10
        self.__dr = 0
        self.__hp = [20,20]
Exemplo n.º 9
0
    def serve(self):
        while not self.done:
            r, _, _ = select.select([self.sock], [], [], 0.1)  #timeout in s
            if r:
                s = r[0]
                data, addr = s.recvfrom(1016)
                message = Message.from_bytes(data)
                streamID = message.header.streamID

                if streamID in self.connections:
                    self.connections[streamID].receive(message)
                else:
                    c = ServerConnection(addr, self, streamID, self.window,
                                         self.timeout, self.outFileName)
                    c.receive(message)
                    self.connections[streamID] = c
                    c.start()

            else:
                while not self.toSend.empty():
                    bMessage, addr = self.toSend.get()
                    self.sock.sendto(bMessage, addr)  # this has to be a tuple
        self.sock.close()
        self.closed = True
        self.endAllConnections()
Exemplo n.º 10
0
def init():
    ServerConnection.createDirectories()
    loadTileset()
    loadObjects()
    loadEnemies()
    loadFonts()

    main_directory = ServerConnection.getMainDirectory()
    pyglet.resource.path.append(main_directory + '/bgm')
    pyglet.resource.reindex()

    ServerConnection.getClientPath('img/gui/gui.png')
    ServerConnection.getClientPath('bgm/main_screen.ogg')
Exemplo n.º 11
0
    def load_record(self):
        '''Метод расшифровки рекорда и загрузка его из файла'''
        #Создаём обьект сланна соединение с сервером
        self.server_connect = ServerConnection()
        #Проверка есть ли соединение с сервером
        self.connect = self.server_connect.get_connect()
        #Если есть то
        if self.connect:
            #Получаем рекорд с сервера
            self.server_record = self.server_connect.get_save_server()
            #Избавляемся от ненужных символов
            self.server_record = self.server_record.replace('"', "")
            self.server_record = self.server_record.replace('[', '')
            self.server_record = self.server_record.replace(']', '')
            self.server_record = self.server_record.replace(' ', '')
            #Нарезаем в кортеж
            self.server_record_split = self.server_record.split(',')
            #Перевод значений из считенного массива в байты
            self.key_serv = bytes(self.server_record_split[0], encoding = 'utf-8')
            self.record_serv = bytes(self.server_record_split[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher_serv = Fernet(self.key_serv)
            #Расшифровка сообщения создание расшифрованной копии
            self.record_serv = self.cipher_serv.decrypt(self.record_serv)
            self.record_serv = self.record_serv.decode('utf-8')
            self.record_serv = int(self.record_serv)

            #Имя файла для загрузки, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Функция чтения из файла
            with open(self.filename) as self.f_obj:
                self.load_arr = json.load(self.f_obj)
            #Перевод значений из считенного массива в байты
            self.key = bytes(self.load_arr[0], encoding = 'utf-8')
            self.record = bytes(self.load_arr[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher = Fernet(self.key)
            #Расшифровка сообщения создание расшифрованной копии
            self.record = self.cipher.decrypt(self.record)
            self.record = self.record.decode('utf-8')
            self.record = int(self.record)

            if self.record <= self.record_serv:
                return self.record_serv
            else:
                return self.record
        else:
            #Имя файла для загрузки, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Функция чтения из файла
            with open(self.filename) as self.f_obj:
                self.load_arr = json.load(self.f_obj) 
            #Перевод значений из считенного массива в байты
            self.key = bytes(self.load_arr[0], encoding = 'utf-8')
            self.record = bytes(self.load_arr[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher = Fernet(self.key)
            #Расшифровка сообщения создание расшифрованной копии
            self.record = self.cipher.decrypt(self.record)
            self.record = self.record.decode('utf-8')
            self.record = int(self.record)
            return self.record
Exemplo n.º 12
0
class Encoder():
    '''Класс который шифрует рекорд и отправляет его в json файл
    или разшифровывает и выводит обратно для сравнения'''
    
    '''# Передаёт рекорд и ключ если нужно в конструктор
    def __init__(self, record, key = b''):
        #Строка для шифрования
        self.record = record
        #Ключ для шифрования
        self.key = key'''

    def seve_record(self, record):
        '''Метод шифрования рекорда и сохранения в файл'''
        #Строка для шифрования
        self.record = record
        #Создаём обьект сланна соединение с сервером
        self.server_connect = ServerConnection()
        #Проверка есть ли соединение с сервером
        self.connect = self.server_connect.get_connect()
        #Если есть то
        if self.connect:
            #Генерируем новый ключ для шифрования
            self.key = Fernet.generate_key()
            #Создаём функцию шифрвоания на основе ключа
            self.cipher = Fernet(self.key)
            #Переводим строку рекорда в байты
            self.record = bytes(str(self.record), encoding = 'utf-8')
            #Создание зашифрованной копии рекорда
            self.record = self.cipher.encrypt(self.record)
            #Перевод рекорда из байтовых в строковые значения для записи
            self.record = str(self.record.decode('utf-8'))
            #Перевод ключа из байтовых в строковые значения для записи
            self.key = str(self.key.decode('utf-8'))
            #Отправляем запрос на сервес, сохранение
            self.server_connect.set_save_server(self.key, self.record)
            #Имя файла для записи, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Всё это кладём в массив
            self.save_arr = [self.key, self.record]
            #Функция записи в файл
            with open(self.filename, 'w') as self.f_obj:
                json.dump(self.save_arr , self.f_obj)

        else:
            #Переводим строку рекорда в байты
            self.record = bytes(str(self.record), encoding = 'utf-8')
            #Генерируем новый ключ для шифрования
            self.key = Fernet.generate_key()
            #Создаём функцию шифрвоания на основе ключа
            self.cipher = Fernet(self.key)
            #Создание зашифрованной копии рекорда
            self.record = self.cipher.encrypt(self.record)
            #Имя файла для записи, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Перевод рекорда из байтовых в строковые значения для записи
            self.record = str(self.record.decode('utf-8'))
            #Перевод ключа из байтовых в строковые значения для записи
            self.key = str(self.key.decode('utf-8'))
            #Всё это кладём в массив
            self.save_arr = [self.key, self.record]
            #Функция записи в файл
            with open(self.filename, 'w') as self.f_obj:
                json.dump(self.save_arr , self.f_obj)

    def load_record(self):
        '''Метод расшифровки рекорда и загрузка его из файла'''
        #Создаём обьект сланна соединение с сервером
        self.server_connect = ServerConnection()
        #Проверка есть ли соединение с сервером
        self.connect = self.server_connect.get_connect()
        #Если есть то
        if self.connect:
            #Получаем рекорд с сервера
            self.server_record = self.server_connect.get_save_server()
            #Избавляемся от ненужных символов
            self.server_record = self.server_record.replace('"', "")
            self.server_record = self.server_record.replace('[', '')
            self.server_record = self.server_record.replace(']', '')
            self.server_record = self.server_record.replace(' ', '')
            #Нарезаем в кортеж
            self.server_record_split = self.server_record.split(',')
            #Перевод значений из считенного массива в байты
            self.key_serv = bytes(self.server_record_split[0], encoding = 'utf-8')
            self.record_serv = bytes(self.server_record_split[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher_serv = Fernet(self.key_serv)
            #Расшифровка сообщения создание расшифрованной копии
            self.record_serv = self.cipher_serv.decrypt(self.record_serv)
            self.record_serv = self.record_serv.decode('utf-8')
            self.record_serv = int(self.record_serv)

            #Имя файла для загрузки, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Функция чтения из файла
            with open(self.filename) as self.f_obj:
                self.load_arr = json.load(self.f_obj)
            #Перевод значений из считенного массива в байты
            self.key = bytes(self.load_arr[0], encoding = 'utf-8')
            self.record = bytes(self.load_arr[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher = Fernet(self.key)
            #Расшифровка сообщения создание расшифрованной копии
            self.record = self.cipher.decrypt(self.record)
            self.record = self.record.decode('utf-8')
            self.record = int(self.record)

            if self.record <= self.record_serv:
                return self.record_serv
            else:
                return self.record
        else:
            #Имя файла для загрузки, если нет создаётсяавтматически
            self.filename = 'record/record.json'
            #Функция чтения из файла
            with open(self.filename) as self.f_obj:
                self.load_arr = json.load(self.f_obj) 
            #Перевод значений из считенного массива в байты
            self.key = bytes(self.load_arr[0], encoding = 'utf-8')
            self.record = bytes(self.load_arr[1], encoding = 'utf-8')
            #Создание нового шифровальщика на основе старого считанного ключа
            self.cipher = Fernet(self.key)
            #Расшифровка сообщения создание расшифрованной копии
            self.record = self.cipher.decrypt(self.record)
            self.record = self.record.decode('utf-8')
            self.record = int(self.record)
            return self.record
Exemplo n.º 13
0
def run(idx, client_queue, debug):
    logger = Logger(debug)

    logger.log("Start dispatcher {0}".format(idx))

    inputs = []
    outputs = []
    server_connections = {}

    while True:
        #add new client to input list
        start_ = datetime.datetime.now()
        try:
            h = client_queue.get_nowait()
            fd = rebuild_handle(h)
            client = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
        except queue.Empty:
            pass
        except Exception as ex:
            logger.log(ex)
        else:
            logger.log('Dispatcher {0} got new client {1}'.format(
                idx, client.getpeername()))
            inputs.append(client)
            sc = ServerConnection(client)
            server_connections[client] = sc

        if not inputs:
            continue

        logger.log('Dispatcher {0}: inputs={1}, outputs={2}'.format(
            idx, len(inputs), len(outputs)))

        readable, writable, exceptional = select.select(
            inputs, outputs, inputs)

        logger.log(
            'Dispatcher {0}: readable {1}, writable {2}, exceptions {3}'.
            format(idx, len(readable), len(writable), len(exceptional)))

        for client in readable:
            try:
                logger.log('Dispatcher {0} read data from client {1}'.format(
                    idx, client.getpeername()))
                messages = read(idx, server_connections[client], logger)
                logger.log('Dispatcher{0}: processed {1} messages'.format(
                    idx, len(messages)))
                messages = process_messages(messages)
                add_messages_to_write_buffer(idx, server_connections[client],
                                             messages, logger)
                dummy_messages(server_connections[client])
                if not client in outputs:
                    logger.log(
                        'Dispatcher {0}: add client {1} to write select list'.
                        format(idx, client))
                    outputs.append(client)

                logger.log('Dispatcher {0}: exit read for client {1}'.format(
                    idx, client.getpeername()))
            except socket.error as error:
                logger.log(repr(error))
                inputs.remove(client)
                # TODO handle message queue
            except ValueError as error:
                logger.log('Client {0} disconnected'.format(
                    client.getpeername()))
                if client in outputs:
                    outputs.remove(client)
                if client in inputs:
                    inputs.remove(client)
                client.close()
                del server_connections[client]
            else:
                if client not in outputs:
                    outputs.append(client)

        for client in writable:
            try:
                if client in server_connections:
                    write(idx, server_connections[client], logger)
                    if len(server_connections[client].write_buffer) == 0:
                        logger.log(
                            'Dispatcher {0}: write buffer for client {1} is empty'
                            .format(idx, client))
                        outputs.remove(client)
            except socket.error as error:
                logger.log(repr(error))
                inputs.remove(client)
                # TODO handle message queue
            except ValueError as error:
                logger.log('Client {0} disconnected'.format(
                    client.getpeername()))
                if client in outputs:
                    outputs.remove(client)
                if client in inputs:
                    inputs.remove(client)
                client.close()
                del server_connections[client]

        # Handle "exceptional conditions"
        for client in exceptional:
            logger.log('Handling exceptional condition for'.format(
                client.getpeername()))
            # Stop listening for input on the connection
            inputs.remove(client)
            outputs.remove(client)
            client.close()

        end_ = datetime.datetime.now()
        logger.log('Dispatcher {0}: loop took {1} ms'.format(
            idx, (end_ - start_).microseconds / 1000))
Exemplo n.º 14
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi("ui/qt/main_window.ui", self)
        self.setWindowTitle("Raven Trader Pro")

        qss_file = open('ui/qt/style.qss', mode='r')
        qss = qss_file.read()
        qss_file.close()
        self.setStyleSheet(qss)

        self.settings = AppInstance.settings
        self.wallet = AppInstance.wallet
        self.wallet.on_swap_mempool = self.swap_mempool
        self.wallet.on_swap_confirmed = self.swap_confirmed
        self.wallet.on_completed_mempool = self.completed_trade_mempool
        self.wallet.on_completed_confirmed = self.completed_trade_network
        self.server = ServerConnection()
        self.server_menu = None

        self.update_dynamic_menus()

        #NOTE: Most actions are connected in the main_window.ui file

        self.updateTimer = QTimer(self)
        self.updateTimer.timeout.connect(self.actionRefresh.trigger)
        self.updateTimer.start(self.settings.read("update_interval"))

        self.menu_context = {"type": None, "data": None}
        self.actionRefresh.trigger()

#
# Action callbacks
#

    def on_url_handled(self, uri):
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized
                            | Qt.WindowActive)
        self.activateWindow()
        #CAUTION: This uri comes from an external source. caution must be used
        if uri.startswith(self.settings.protocol_path() + "://"):
            (_, hex) = uri.split("://")
            hex = hex.strip('/')  #strip any leading/traind /'s
            if re.search("^[0-9a-fA-F]*$", hex):
                self.complete_order(hex_prefill=hex)
            else:
                logging.warn("Unknown format: {} attempted".format(uri))
        else:
            logging.warn(
                "Unknown handle: {} attempted. Expected {}://<signed partial hex>"
                .format(uri, self.settings.protocol_path()))

    def new_buy_order(self, prefill=None):
        if self.menu_context["type"] == "asset":
            prefill = make_prefill(self.menu_context["data"])
        buy_dialog = NewOrderDialog("buy", prefill=prefill, parent=self)
        if (buy_dialog.exec_()):
            buy_swap = buy_dialog.build_trade()
            self.created_order(buy_swap)

    def new_sell_order(self, prefill=None):
        if self.menu_context["type"] == "asset":
            prefill = make_prefill(self.menu_context["data"])
        sell_dialog = NewOrderDialog("sell", prefill=prefill, parent=self)
        if (sell_dialog.exec_()):
            sell_swap = sell_dialog.build_trade()
            self.created_order(sell_swap)

    def new_trade_order(self, prefill=None):
        if self.menu_context["type"] == "asset":
            prefill = make_prefill(self.menu_context["data"])
        trade_dialog = NewTradeDialog(prefill=prefill, parent=self)
        if (trade_dialog.exec_()):
            trade_swap = trade_dialog.build_trade()
            self.created_order(trade_swap)

    def created_order(self, trade):
        logging.info("New {}: {}".format(trade.type,
                                         json.dumps(trade.__dict__)))
        self.wallet.add_swap(trade)
        self.wallet.save_data()
        self.update_lists()
        self.view_trade_details(trade)

    def action_remove_trade(self, _, confirm=True):
        if self.menu_context["type"] != "trade":
            return
        trade = self.menu_context["data"]
        if confirm and len(trade.order_utxos) > 0:
            result = show_hard_delete_prompt(self)
            if result == 1:  # I don't know why it returns this and not YesRole :shrug:
                grouped_invalidate = False
                if len(trade.order_utxos
                       ) > 1:  #If we have only one item, no need to ask
                    delete_resp = show_hard_delete_type_prompt(self)
                    if delete_resp not in [1, 0]:
                        return  #anything outside of a 1/0 represents a cancel
                    grouped_invalidate = (delete_resp == 1)
                logging.info("Hard-Deleting Trade")
                signed_tx = trade.construct_invalidate_tx(grouped_invalidate)
                if signed_tx:
                    txid = self.preview_complete(signed_tx,
                                                 "Invalidate Old Trades")
                    if txid:
                        self.wallet.add_waiting(txid)
                        trade.sent_invalidate_tx(txid)
                        self.wallet.remove_swap(trade)
            elif result == 0:
                logging.info("Soft-Deleting Trade")
                self.wallet.remove_swap(trade)
            elif result == QMessageBox.Cancel:
                return
        else:
            self.wallet.remove_swap(trade)  #simple delete
        self.actionRefresh.trigger()

    def action_view_trade(self, force=True):
        if self.menu_context["type"] != "trade":
            return

        if self.menu_context["data"].order_count == 0:
            show_error("No trades left", "Trade pool is now empty. :(")
            return

        self.view_trade_details(self.menu_context["data"], force)

    def action_setup_trade(self):
        if self.menu_context["type"] != "trade":
            return
        self.setup_trades(self.menu_context["data"], True)
        self.actionRefresh.trigger()

    def action_refill_trade(self):
        if self.menu_context["type"] != "trade":
            return
        (num_new_trades, confirmed) = show_number_prompt(
            "Refill trade pool?",
            "How many additional trades would you like to add to the trade pool?"
        )
        if confirmed and num_new_trades > 0:
            logging.info("Refill {} trades".format(num_new_trades))
            trade = self.menu_context["data"]
            trade.order_count += num_new_trades
            self.setup_trades(trade, True)
            self.actionRefresh.trigger()

    def action_remove_order(self, _, confirm=True):
        if self.menu_context["type"] != "order":
            return
        if confirm:
            if show_prompt("Remove Trade?",
                           "Are you sure you want to remove this order?"
                           ) == QMessageBox.No:
                return
        self.wallet.remove_completed(self.menu_context["data"])
        self.actionRefresh.trigger()

    def action_view_order(self):
        if self.menu_context["type"] != "order":
            return
        self.view_order_details(self.menu_context["data"])

    def trade_double_clicked(self, row_widget):
        list = row_widget.listWidget()
        row = list.itemWidget(row_widget)
        self.menu_context = {"type": "trade", "data": row.get_data()}
        self.action_view_trade(force=False)

    def order_double_clicked(self, row_widget):
        list = row_widget.listWidget()
        row = list.itemWidget(row_widget)
        self.menu_context = {"type": "order", "data": row.get_data()}
        self.action_view_order()

    def action_reset_locks(self):
        self.wallet.refresh_locks(clear=True)
        self.actionRefresh.trigger()

    def view_online_cryptoscope(self):
        if self.menu_context["type"] != "order":
            return
        base = "https://rvn.cryptoscope.io/tx/?txid={}" if self.settings.rpc_mainnet()\
          else "https://rvnt.cryptoscope.io/tx/?txid={}"
        do_url(base.format(self.menu_context["data"].txid))

    def server_list_orders(self):
        #if not self.settings.rpc_mainnet():
        #  show_error("Mainnet Only", "Sorry! Server Swaps are mainnet only currently.")
        #  return

        server_diag = ServerOrdersDialog(self.server, parent=self)
        if server_diag.exec_():
            self.execute_server_orders(server_diag.selected_orders)

    def server_post_trade(self):
        if self.menu_context["type"] != "trade":
            return

        #if not self.settings.rpc_mainnet():
        #  show_error("Mainnet Only", "Sorry! Server Swaps are mainnet only currently.")
        #  return
        trade = self.menu_context["data"]
        if len(trade.transactions) == 0:
            show_error("No trades to publish.")
            return

        confirm_diag = show_prompt(
            "Send Orders?",
            "Confirm post {} trades to server?".format(len(trade.order_utxos)))
        if confirm_diag == QMessageBox.Yes:
            posted = 0
            for active_order in trade.transactions:
                (success, response) = self.server.post_swap(active_order)
                if success:
                    posted += 1
                else:
                    logging.error("Error posting: {}".format(response))

            if posted == len(trade.transactions):
                show_dialog("Success", "All trades posted succesfull!")
            elif posted > 0:
                show_dialog(
                    "Warning",
                    "{}/{} trades posted.".format(posted,
                                                  len(trade.transactions)),
                    response)
            else:
                show_error("Error!", "No trades posted.", response)

#
# Context Menus
#

    def open_asset_menu(self, list, list_item, click_position, asset):
        menu = QMenu()
        widget_inner = list.itemWidget(list_item)
        menu.addAction(self.actionNewBuy)
        menu.addAction(self.actionNewSell)
        menu.addAction(self.actionNewTrade)
        self.menu_context = {"type": "asset", "data": asset}
        action = menu.exec_(widget_inner.mapToGlobal(click_position))

    def open_trade_menu(self, list, list_item, click_position, trade):
        menu = QMenu()
        widget_inner = list.itemWidget(list_item)
        menu.addAction(self.actionRemoveTrade)
        menu.addAction(self.actionRefillTrade)
        menu.addAction(
            self.actionSetupTrade) if trade.missing_trades() > 0 else None
        menu.addAction(
            self.actionViewTrade) if len(trade.order_utxos) > 0 else None
        menu.addAction(
            self.actionServerPostOrder) if self.settings.server_enabled(
            ) and len(trade.order_utxos) > 0 else None
        self.menu_context = {"type": "trade", "data": trade}
        action = menu.exec_(widget_inner.mapToGlobal(click_position))

    def open_order_menu(self, list, list_item, click_position, swap):
        menu = QMenu()
        widget_inner = list.itemWidget(list_item)
        menu.addAction(self.actionViewOrder)
        menu.addAction(self.actionRemoveOrder)
        menu.addAction(self.actionViewOnlineCryptoscope) if swap.txid else None
        self.menu_context = {"type": "order", "data": swap}
        menu.exec_(widget_inner.mapToGlobal(click_position))

#
# Sub-Dialogs
#

    def setup_trades(self, trade, force_create):
        missing = trade.missing_trades()
        has_items = len(trade.order_utxos) > 0
        if missing == 0:
            return (True, None)
        setup_max = 1
        if missing > 1:
            setup_all = show_prompt_3(
                "Setup All Trades?",
                "Would you like to setup all trades right now? If not, you can continue to make them one-by-one."
            )
            if setup_all == QMessageBox.Yes:
                setup_max = None
            if setup_all == QMessageBox.Cancel:
                return (False, None)
        check_unlock()
        pool_filled = trade.attempt_fill_trade_pool(max_add=setup_max)
        if not pool_filled:
            (setup_success,
             setup_result) = trade.setup_trade(max_add=setup_max)
            if setup_success and setup_result:
                setup_txid = self.preview_complete(setup_result,
                                                   "Setup Trade Order")
                if setup_txid:
                    self.wallet.add_waiting(setup_txid,
                                            self.setup_mempool_confirmed,
                                            self.setup_network_confirmed,
                                            callback_data=trade)
                    self.actionRefresh.trigger()
                    return (True, setup_txid)
                    #Wait for confirmation, then run this again.
                elif has_items and not force_create:
                    return (True, None)
                else:
                    return (False, "Transaction Error: {}".format(setup_txid))
            elif has_items and not force_create:
                return (True, None)
            else:
                show_error("Not enough assets", setup_result)
                return (False, setup_result)
        else:
            return (True, None)

    def complete_order(self, _=None, hex_prefill=None):
        order_dialog = OrderDetailsDialog(None,
                                          parent=self,
                                          raw_prefill=hex_prefill,
                                          dialog_mode="complete")
        if (order_dialog.exec_()):
            partial_swap = order_dialog.build_order()
            finished_swap = partial_swap.complete_order()
            if finished_swap:
                logging.info("Swap constructed, ready for execute: {}".format(
                    partial_swap))
                sent_txid = self.preview_complete(finished_swap,
                                                  "Confirm Transaction [2/2]")
                if sent_txid:
                    self.wallet.swap_executed(partial_swap, sent_txid)

    def execute_server_orders(self, orders):
        orders_hex = [
            b64_to_hex(order["b64SignedPartial"]) for order in orders
            if "b64SignedPartial" in order
        ]
        if len(orders_hex) == 1:
            self.complete_order(hex_prefill=orders_hex[0])
        elif len(orders) > 1:
            check_unlock()
            #decode_swap returns (succes, result)
            parsed_orders = [
                SwapTransaction.decode_swap(order_hex)[1]
                for order_hex in orders_hex
            ]
            composite_trade = SwapTransaction.composite_transactions(
                parsed_orders)
            logging.info(parsed_orders)
            logging.info(composite_trade)

    def preview_complete(self, raw_tx, message, swap=None):
        preview_dialog = PreviewTransactionDialog(swap,
                                                  raw_tx,
                                                  preview_title=message,
                                                  parent=self)
        if preview_dialog.exec_():
            logging.info("Transaction Approved. Sending!")
            submitted_txid = do_rpc("sendrawtransaction",
                                    log_error=False,
                                    hexstring=raw_tx)
            if type(submitted_txid) is str:
                return submitted_txid  #we are expecting a string
            elif "error" in submitted_txid:  #otherwise it's an error object
                error = submitted_txid["error"]
                logging.error(
                    "Error ocurred when attempting to submit raw transaction. {}"
                    .format(error))
                show_error("Transaction Error",
                           "Error ocurred while submitting the transaction!",
                           error["message"], self)
            else:
                logging.error("Unknown response from transaction: {}".format(
                    submitted_txid))
                show_error(
                    "Transaction Error",
                    "Unknown error ocurred while submitting the transaction!",
                    submitted_txid, self)
        return None

    def view_trade_details(self, trade, force_order=False):
        (success, result) = self.setup_trades(trade, force_order)
        if success:
            if result == None:
                details = OrderDetailsDialog(trade,
                                             parent=self,
                                             dialog_mode="multiple")
                return details.exec_()
            elif result:
                show_dialog(
                    "Sent",
                    "Transaction has been submitted. Please try again soon.",
                    result, self)
        elif result:
            show_error("Error", "Transactions could not be setup for trade.",
                       result, self)

    def view_order_details(self, swap):
        details = OrderDetailsDialog(swap, parent=self, dialog_mode="single")
        return details.exec_()

    def update_order_details(self, widget):
        list = widget.listWidget()
        swap_row = list.itemWidget(widget)
        details = OrderDetailsDialog(swap_row.get_data(),
                                     parent=self,
                                     dialog_mode="update")
        return (details.exec_(), details.spnUpdateUnitPrice.value())

#
# Transaction Callbacks
#

    def swap_mempool(self, transaction, order):
        logging.info("Own Swap In Mempool")
        self.actionRefresh.trigger()

    def swap_confirmed(self, transaction, order):
        logging.info("Own Swap Confirmed")
        self.actionRefresh.trigger()

    def completed_trade_mempool(self, transaction, order):
        logging.info("Trade Mempool Confirmed")
        self.actionRefresh.trigger()

    def completed_trade_network(self, transaction, order):
        logging.info("Trade Final Confirm")
        self.actionRefresh.trigger()

    def setup_mempool_confirmed(self, transaction, trade):
        logging.info("Trade Setup Mempool Confirmed")
        txid = transaction["txid"]
        #Naive approach, just lock the UTXO's immediately once we see it confirmed in mempool.
        for i in range(0, trade.missing_trades()):
            utxo_data = vout_to_utxo(transaction["vout"][i], txid, i)
            trade.add_utxo_to_pool(utxo_data)
        self.actionRefresh.trigger()

    def setup_network_confirmed(self, transaction, trade):
        logging.info("Trade Setup Final Confirm")
        self.actionRefresh.trigger()

#
# Dynamic Menu Items
#

    def update_rpc_connection(self, _, index, connection):
        #Save any changes to swaps
        old_index = self.settings.rpc_index()
        AppInstance.on_close()
        self.updateTimer.stop()
        self.settings.set_rpc_index(index)
        if test_rpc_status():
            logging.info("Switching RPC")
            self.lstMyAssets.clear()  #Fully clear lists to fix bugs
            self.lstAllOrders.clear()
            self.lstPastOrders.clear()
            AppInstance.on_load()
            self.actionRefresh.trigger()
        else:
            logging.info("Error testing RPC")
            self.settings.set_rpc_index(old_index)
        self.update_dynamic_menus()
        self.updateTimer.start(self.settings.read("update_interval"))


#
# Updating
#

    def update_status(self):
        num_waiting = self.wallet.num_waiting()
        if num_waiting == 0:
            self.statusBar().clearMessage()
        elif num_waiting == 1:
            first_waiting = self.wallet.waiting[0]
            self.statusBar().showMessage("Waiting on 1 TX: {}".format(
                first_waiting[0]))
        else:
            self.statusBar().showMessage(
                "Waiting on {} TXs".format(num_waiting))

    def refresh_main_window(self):
        self.wallet.update_wallet()

        avail_balance = self.wallet.available_balance
        total_balance = self.wallet.total_balance

        self.lblBalanceTotal.setText(
            "Total Balance: {:.8g} RVN [{:.8g} Assets]".format(
                total_balance[0], total_balance[2]))
        self.lblBalanceAvailable.setText(
            "Total Available: {:.8g} RVN [{:.8g} Assets]".format(
                avail_balance[0], avail_balance[2]))
        self.update_lists()
        self.update_status()

    def update_dynamic_menus(self):
        self.menuConnection.clear()

        for index, rpc in enumerate(self.settings.read("rpc_connections")):
            rpc_action = QAction(rpc["title"], self, checkable=True)
            rpc_action.triggered.connect(
                lambda chk, data=rpc, index=index: self.update_rpc_connection(
                    chk, index, data))
            rpc_action.setCheckable(True)
            rpc_action.setChecked(self.settings.rpc_index() == index)
            self.menuConnection.addAction(rpc_action)

    def update_lists(self):
        self.add_update_trade_items(self.lstAllOrders, self.wallet.swaps)

        self.add_update_swap_items(self.lstPastOrders, [
            swap for swap in self.wallet.history
            if (swap.state in ["pending", "completed"]) and swap.own
        ])
        self.add_update_swap_items(self.lstCompletedOrders, [
            swap for swap in self.wallet.history
            if (swap.state in ["pending", "completed"]) and not swap.own
        ])

        self.add_update_asset_items(self.lstMyAssets, [
            self.wallet.assets[asset_name]
            for asset_name in self.wallet.my_asset_names
        ])

    def add_update_asset_items(self, list, asset_list):
        self.add_udpate_items(list, asset_list, lambda x: x["name"],
                              QTwoLineRowWidget.from_asset,
                              self.open_asset_menu)

    def add_update_swap_items(self, list, swap_list):
        self.add_udpate_items(list, swap_list, lambda x: hash(x),
                              QTwoLineRowWidget.from_swap,
                              self.open_order_menu)

    def add_update_trade_items(self, list, swap_list):
        self.add_udpate_items(list, swap_list, lambda x: hash(x),
                              QTwoLineRowWidget.from_trade,
                              self.open_trade_menu)

    def add_udpate_items(self, list_widget, item_list, fn_key_selector,
                         fn_row_factory, fn_context_menu):
        existing_rows = {}
        seen_keys = []
        for idx in range(0, list_widget.count()):
            row = list_widget.item(idx)
            row_widget = list_widget.itemWidget(row)
            row_data = row_widget.get_data()
            row_key = fn_key_selector(row_data)
            existing_rows[row_key] = row
            row_widget.refresh()  #Trigger update function
        existing_keys = [*existing_rows.keys()]
        for current_item in item_list:
            item_key = fn_key_selector(current_item)
            seen_keys.append(item_key)
            if item_key not in existing_keys:
                self.add_update_list_widget(list_widget, current_item,
                                            fn_row_factory, fn_context_menu)
                existing_keys.append(item_key)
        for old_key in [key for key in existing_keys if key not in seen_keys]:
            item_row = list_widget.row(existing_rows[old_key])
            list_widget.takeItem(item_row)

    def add_update_list_widget(self,
                               list,
                               widget_data,
                               fn_widget_generator,
                               fn_context_menu,
                               existing=None):
        if existing:
            list.removeItemWidget(existing)

        list_widget = fn_widget_generator(widget_data)
        list_item = existing if existing else QListWidgetItem(list)
        list_item.setSizeHint(list_widget.sizeHint())

        list_widget.setContextMenuPolicy(Qt.CustomContextMenu)
        list_widget.customContextMenuRequested.connect(
            lambda pt: fn_context_menu(list, list_item, pt, widget_data))

        if not existing:
            list.addItem(list_item)

        list.setItemWidget(list_item, list_widget)
        return list_item
Exemplo n.º 15
0
 def on_init():
     AppInstance.storage = AppStorage()
     AppInstance.wallet = WalletManager()
     AppInstance.server = ServerConnection()
     AppInstance.on_load()