def __init__(self, socket=None, logstats=True): """ Socket may be provided when in the context of a threaded TCP Server. """ self.protocmd = commands_pb2.Command() self.protomsg = commands_pb2.Command() self.logstats = logstats self.socket = socket if socket: self.connected = True self.peer_ip = socket.getpeername()[0] if logstats: self.stats[STATS_COSINCE] = time.time()
def __init__(self, version=-1, socket = None, logstats= True): """ Default version is -1, will auto detect if needed on first receive Socket may be provided when in the context of a threaded TCP Server. """ self.version = version self.protocmd = commands_pb2.Command() self.protomsg = commands_pb2.Command() self.logstats = logstats self.socket = socket if socket: self.connected = True self.peer_ip = socket.getpeername()[0] if logstats: self.stats[STATS_COSINCE] = time.time()
async def async_receive(stream, ip, timeout=-1): """ Get a command block from the stream, async version :param stream: :param ip: the related ip, for stats purposes :param timeout: timeout for getting answer :return: a protobuf object """ global MY_NODE protomsg = commands_pb2.Command() # TODO: add some timeout here if timeout == -1: header = await stream.read_bytes(4) else: header = await tornado.gen.with_timeout(datetime.timedelta(seconds=timeout), stream.read_bytes(4)) if len(header) < 4: raise RuntimeError("Socket EOF") data_len = struct.unpack('>i', header[:4])[0] # TODO: and here (depending on size?) if timeout == -1: data = await stream.read_bytes(data_len) else: data = await tornado.gen.with_timeout(datetime.timedelta(seconds=timeout), stream.read_bytes(data_len)) try: MY_NODE.clients[ip]['stats'][STATS_LASTACT] = time.time() MY_NODE.clients[ip]['stats'][STATS_MSGRECV] += 1 MY_NODE.clients[ip]['stats'][STATS_BYTRECV] += 4 + data_len except: pass protomsg.ParseFromString(data) return protomsg
async def async_getblock(self, a_height): """ Command id 14 returns the block of the given height. :param a_height: int :return: protocmd with the block if exists or None """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.getblock block = await self.async_fetchone(SQL_HEIGHT_BLOCK, (a_height,), as_dict=True) if not block: return protocmd block = PosBlock().from_dict(dict(block)) # Add the block txs txs = await self.async_fetchall(SQL_TXS_FOR_HEIGHT, (block.height,)) for tx in txs: tx = PosMessage().from_dict(dict(tx)) block.txs.append(tx) block.add_to_proto(protocmd) return protocmd except Exception as e: self.app_log.error("SRV: async_getblock: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format(exc_type, fname, exc_tb.tb_lineno)) raise
async def async_gettx(self, params): """ Command id 16 returns the tx or empty protocmd. :param params: str: a transaction signature :return: protocmd with the tx or None """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.gettx txid = poscrypto.hex_to_raw(str(params)) tx = await self.async_fetchone(SQL_TX_FOR_TXID, (sqlite3.Binary(txid),), as_dict=True) if tx: tx = PosMessage().from_dict(dict(tx)) tx.add_to_proto(protocmd) return protocmd except Exception as e: self.app_log.error("SRV: async_gettx: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format(exc_type, fname, exc_tb.tb_lineno)) raise
async def async_getheaders(self, param): """ Async. Return 20 latest block headers. :param param: (string) empty: last 20 blocks headers. start_height,count or ,count (last N headers) :return: """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.getheaders if param is None or param == 'None': param = '' if param == '': blocks = await self.async_fetchall(SQL_BLOCKS_LAST, (config.BLOCK_SYNC_COUNT,)) else: start, count = param.split(',') if '' == start: blocks = await self.async_fetchall(SQL_BLOCKS_LAST, (count,)) else: blocks = await self.async_fetchall(SQL_BLOCKS_SYNC, (start, count)) for block in blocks: block = PosBlock().from_dict(dict(block)) block.add_to_proto(protocmd) return protocmd except Exception as e: self.app_log.error("SRV: async_getheaders: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format(exc_type, fname, exc_tb.tb_lineno)) raise
def __init__(self, socket=None, logstats=True): """ Socket may be provided when in the context of a threaded TCP Server. """ # cmd : from us to peer self.protocmd = commands_pb2.Command() # msg : from peer to us self.protomsg = commands_pb2.Command() self.logstats = logstats self.socket = socket self.peer_ip = '' self.connected = False # first 4 bytes allow to ID the protocol version, it's the message len on 4 bytes. self.first_bytes = [] # connection stats self.stats = [0, 0, 0, 0, 0] # last socket activity self.last_activity = 0 if socket: self.connected = True self.peer_ip = socket.getpeername()[0] if logstats: self.stats[STATS_COSINCE] = time.time()
async def async_send_void(cmd, stream, ip): """ Sends a command to the stream, async. :param cmd: the protobuff command :param stream: :param ip: the related ip, for stats purposes :return: none """ protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = cmd await async_send(protocmd, stream, ip)
async def async_getaddtxs(self, params): """ Command id 15 returns a list of txs. :param params: str: an address or address,extra :return: protocmd with the txs list or None """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.getaddtxs if ',' not in params: # address only txs = await self.async_fetchall(SQL_TXS_FOR_ADDRESS, (params, params)) else: address, option = params.split(',') if len(option) < 10: # Say this is a block height option = int(option) txs = await self.async_fetchall( SQL_TXS_FOR_ADDRESS_FROM_HEIGHT, (address, address, option)) else: # consider as a tx signature # FR: not sure this param useful after all option = poscrypto.hex_to_raw(str(option)) # Get the height of the given signature tx = await self.async_fetchone(SQL_TX_FOR_TXID, (sqlite3.Binary(option), ), as_dict=True) # Then the following txs txs = await self.async_fetchall( SQL_TXS_FOR_ADDRESS_FROM_HEIGHT, (address, address, tx.get('block_height'))) # Fill the protobuf in for tx in txs: tx = PosMessage().from_dict(dict(tx)) tx.add_to_proto(protocmd) return protocmd except Exception as e: self.app_log.error("SRV: async_getaddtxs: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format( exc_type, fname, exc_tb.tb_lineno)) raise
async def async_send_int32(cmd, value, stream, ip): """ Sends a command with int32 param to the stream, async. :param cmd: the protobuff command :param value: :param stream: :param ip: the related ip, for stats purposes :return: none """ protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = cmd protocmd.int32_value = value await async_send(protocmd, stream, ip)
async def async_send_height(cmd, height, stream, ip): """ Sends a height status to the stream, async. :param cmd: the protobuff command :param height: a PosHeight object :param stream: :param ip: the related ip, for stats purposes :return: none """ protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = cmd height.to_proto(protocmd.height_value) await async_send(protocmd, stream, ip)
async def async_send_txs(cmd, txs, stream, ip): """ Sends a list of tx to the stream, async. :param cmd: the protobuff command :param txs: a list of tx :param stream: :param ip: the related ip, for stats purposes :return: none """ protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = cmd for tx in txs: tx.add_to_proto(protocmd) await async_send(protocmd, stream, ip)
async def async_roundblocks(self, a_round): """ Command id 13 returns all blocks of the given round. FR: Harmonize. this one needs a proto as output (proto command with list of blocks) :param a_round: :return: protocmd with all blocks """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.roundblocks blocks = await self.async_fetchall(SQL_ROUND_BLOCKS, (a_round, )) for block in blocks: block = PosBlock().from_dict(dict(block)) # Add the block txs txs = await self.async_fetchall(SQL_TXS_FOR_HEIGHT, (block.height, )) for tx in txs: tx = PosMessage().from_dict(dict(tx)) block.txs.append(tx) block.add_to_proto(protocmd) # check block integrity if len(txs) != block.msg_count: self.app_log.error( "Only {} tx for block {} instead of {} announced". format(len(txs), block.height, block.msg_count)) com_helpers.MY_NODE.stop() return protocmd except Exception as e: self.app_log.error("SRV: async_roundblocks: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format( exc_type, fname, exc_tb.tb_lineno)) raise
def to_proto(self): """ Create a protobuf object from current native format. :return: a protobuf object. """ protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.block block = protocmd.block_value.add( ) # protocmd.block_value # commands_pb2.Block() block.height, block.round, block.sir = self.height, self.round, self.sir block.ts, block.previous_hash = self.timestamp, self.previous_hash for tx in self.txs: tx.add_to_proto_block(block) # todo: unify sources / names block.msg_count, block.sources = self.msg_count, self.uniques_sources block.signature, block.block_hash = self.signature, self.block_hash block.forger = self.forger # protocmd.block_value = block return protocmd
async def async_blocksync(self, height): """ returns N blocks starting with the given height. FR: Harmonize. this one needs a proto as output (proto command with list of blocks) :param height: :return: """ try: protocmd = commands_pb2.Command() protocmd.Clear() protocmd.command = commands_pb2.Command.blocksync blocks = await self.async_fetchall( SQL_BLOCKS_SYNC, (height, config.BLOCK_SYNC_COUNT)) for block in blocks: block = PosBlock().from_dict(dict(block)) # Add the block txs txs = await self.async_fetchall(SQL_TXS_FOR_HEIGHT, (block.height, )) for tx in txs: tx = PosMessage().from_dict(dict(tx)) block.txs.append(tx) # check block integrity if len(txs) != block.msg_count: self.app_log.error( "Only {} tx for block {} instead of {} announced". format(len(txs), height, block.msg_count)) com_helpers.MY_NODE.stop() block.add_to_proto(protocmd) #print(protocmd) return protocmd except Exception as e: self.app_log.error("SRV: async_blocksync: Error {}".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] self.app_log.error('detail {} {} {}'.format( exc_type, fname, exc_tb.tb_lineno)) raise
def command(name, **kwargs): """ Creates a protobuf command to be inserted into a transaction :param name: CamelCased name of command :param kwargs: command arguments as they defined in schema :return: a proto command Usage example: cmd = Iroha.command('CreateDomain', domain_id='test', default_role='user') """ command_wrapper = commands_pb2.Command() field_name = Iroha._camel_case_to_snake_case(name) internal_command = getattr(command_wrapper, field_name) for key, value in kwargs.items(): if 'permissions' == key: permissions_attr = getattr(internal_command, key) permissions_attr.extend(value) continue if 'peer' == key: peer_attr = getattr(internal_command, key) peer_attr.CopyFrom(value) continue setattr(internal_command, key, value) return command_wrapper
def main(): print "Creating new testing server" host = '127.0.0.1' port = 15000 server = socket.socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((host, port)) server.listen(1) conn, addr = server.accept() print "New connection from {}".format(addr) while (True): data = conn.recv(4) # read in 4 byte length if (not data): break data_len, = struct.unpack('!i', data) print "Attempting to read {} bytes".format(data_len) data = conn.recv(data_len) if (not data): break command = commands_pb2.Command() command.ParseFromString(data) print "Data: {}".format(command) server.close()
def valid_add_peer_command(self): command = cmd.Command() command.add_peer.peer.address = "127.0.0.1:50500" command.add_peer.peer.peer_key = b'A' * 32 return command
def run_joystick(server, name): logging.info("Running joystick mode") pygame.init() joystick = None stretch_mode = False sock = None port = 15000 modes = ["Trot", "Crawl", "Creep"] command = commands_pb2.Command() command.cmd = Cmds.STOP command.gait = Mode.TROT joystick_count = pygame.joystick.get_count() if (joystick_count == 0): logging.error("No joystick detected") logging.error("Check that one is plugged in or run with --keyboard") return elif (joystick_count == 1): joystick = pygame.joystick.Joystick(0) joystick.init() else: logging.error("To many joysticks detected") return if (joystick == None): loggign.critical("Failed to locate a valid joystick") return done = False pygame.time.set_timer(USEREVENT + 1, 100) if (server != None): logging.info("Connecting to server {}".format(server)) sock = socket.socket() sock.connect((server, port)) if (not sock): logging.error("Failed to connect to {}:{}".format(server, port)) return while (done != True): for event in pygame.event.get(): if (event.type == pygame.QUIT): done = True ''' We have a button pressed, we must handle each button on it's own There is currently only two buttons we care about. The trigger, which will enter stretch mode when pressed, and the auxilary 11, which will quit the program. ''' if (event.type == pygame.JOYBUTTONDOWN): if (event.button == Buttons.TRIGGER and command.cmd == Cmds.STOP): stretch_mode = True command.cmd = Cmds.STRETCH elif (event.button == Buttons.AUX11): command.cmd = Cmds.QUIT done = True elif (event.button == Buttons.AUX02): ''' Cycle Gait down''' if (command.gait == Mode.TROT): command.gait = Mode.CREEP else: command.gait -= 1 logging.info("Setting gait to: {0}".format( modes[command.gait])) elif (event.button == Buttons.AUX03): ''' Cycle gait up ''' if (command.gait == Mode.CREEP): command.gait = Mode.TROT else: command.gait += 1 logging.info("Setting gait to: {0}".format( modes[command.gait])) elif (event.button == Buttons.AUX06): command.cmd = Cmds.STAND elif (event.button == Buttons.AUX07): command.cmd = Cmds.PARK else: logging.warning( "Unhandled button down event: {0}".format(event)) ''' We have a button released, and like the button press, handle each button on it's own. Trigger release will indicate exiting stretch mode. Should leaving stretch mode recenter the body? ''' if (event.type == pygame.JOYBUTTONUP): if (event.button == Buttons.TRIGGER or event.button == Buttons.AUX06 or event.button == Buttons.AUX07): stretch_mode = False command.cmd = Cmds.STOP command.roll = 0.0 command.pitch = 0.0 command.yaw = 0.0 command.delta_x = 0 command.delta_y = 0 elif (event.button == Buttons.AUX02 or event.button == Buttons.AUX03): pass else: logging.warning( "Unhandled button up event: {0}".format(event)) ''' We have an axis motion event. This indicates one of the joystick axes have changed position. Can become quite jittery, and need to look into having some kind of jitter filter. If we are in stretch mode, the PITCH, ROLL, and YAW axes will correspond to rotating the body up to a max/min of 30 degrees. The aux axis currently has no usage. If we are in normal mode, th PITCH and ROLL will be used to calculate a vector on which the robot should walk. And the YAW axis will be used to send TURN commands. ''' if (event.type == pygame.JOYAXISMOTION): if (stretch_mode): if (event.axis == Axis.ROLL): command.roll = interp(event.value, [-1.0, 1.0], [-30.0, 30.0]) if (event.axis == Axis.PITCH): command.pitch = interp(event.value, [-1.0, 1.0], [-30.0, 30.0]) if (event.axis == Axis.YAW): command.yaw = interp(event.value, [-1.0, 1.0], [-30.0, 30.0]) else: ''' This is where we would create the walk vector, or the turn event ''' if (event.axis == Axis.PITCH and command.cmd != Cmds.TURN): if (event.value > 0.5): command.cmd = Cmds.WALK command.dir = Dir.BACKWARD elif (event.value < -0.5): command.cmd = Cmds.WALK command.dir = Dir.FORWARD else: command.cmd = Cmds.STOP if (event.axis == Axis.YAW and command.cmd != Cmds.WALK): if (event.value > 0.5): command.cmd = Cmds.TURN command.dir = Dir.RIGHT elif (event.value < -0.5): command.cmd = Cmds.TURN command.dir = Dir.LEFT else: command.cmd = Cmds.STOP ''' The hat on top of joystick has moved. If in stretch mode, this will perform a translation. Normal mode will have no affect at this time. ''' if (event.type == pygame.JOYHATMOTION): if (stretch_mode): command.delta_x = event.value[0] command.delta_y = event.value[1] ''' This is a timer event set to trigger 10 times every second. The idea being that we won't spam the server with commands everytime the joystick moves. Still considering if this is a valid solution or if we should just accept the XTREME traffic. ''' if (event.type == USEREVENT + 1): send_command(sock, command) # Send the one final command send_command(sock, command) if (sock != None): logging.info("Closing connection to server") sock.close() pygame.quit()
import time, json import ipaddress import commands_pb2 bcommand = commands_pb2.Command() bcommand.command = commands_pb2.Command.sendsync # Simple command serial = bcommand.SerializeToString() print("sendsync", len(serial), serial) # List of ips (peers) test_ip = "127.0.0.1" bcommand.command = commands_pb2.Command.peers ip = bcommand.ips.add() ip.ipv4 = int(ipaddress.ip_address(test_ip)) serial = bcommand.SerializeToString() print("ipv4", len(serial), serial) ip.port = 6060 serial = bcommand.SerializeToString() print("ipv4+port", len(serial), serial) bcommand = commands_pb2.Command() bcommand.command = commands_pb2.Command.peers for i in range(100): ip = bcommand.ips.add() ip.ipv4 = int(ipaddress.ip_address('127.0.0.' + str(i))) serial = bcommand.SerializeToString() print("100 ipv4", len(serial), serial)