#!/router/bin/python try: # support import for Python 2 import outer_packages except ImportError: # support import for Python 3 import client.outer_packages from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage from client_utils.packet_builder import CTRexPktBuilder import json from common.trex_streams import * from collections import namedtuple from common.text_opts import * from common import trex_stats from client_utils import parsing_opts, text_tables import time import datetime import re import random from trex_port import Port from common.trex_types import * from trex_async_client import CTRexAsyncClient class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" # verbose levels VERBOSE_QUIET = 0 VERBOSE_REGULAR = 1 VERBOSE_HIGH = 2 def __init__(self, username, server="localhost", sync_port = 5050, async_port = 4500, quiet = False, virtual = False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual, self.prn_func) # default verbose level if not quiet: self.verbose = self.VERBOSE_REGULAR else: self.verbose = self.VERBOSE_QUIET self.ports = {} self._connection_info = {"server": server, "sync_port": sync_port, "async_port": async_port} self.system_info = {} self.server_version = {} self.__err_log = None self.async_client = CTRexAsyncClient(server, async_port, self, self.prn_func) self.streams_db = CStreamsDB() self.global_stats = trex_stats.CGlobalStats(self._connection_info, self.server_version, self.ports) self.stats_generator = trex_stats.CTRexStatsGenerator(self.global_stats, self.ports) self.events = [] self.session_id = random.getrandbits(32) self.read_only = False self.connected = False # returns the port object def get_port (self, port_id): return self.ports.get(port_id, None) # connection server ip def get_server_ip (self): return self.comm_link.get_server() # connection server port def get_server_port (self): return self.comm_link.get_port() ################# events handler ###################### def add_event_log (self, msg, ev_type, show = False): if ev_type == "server": prefix = "[server]" elif ev_type == "local": prefix = "[local]" ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') self.events.append("{:<10} - {:^8} - {:}".format(st, prefix, format_text(msg, 'bold'))) if show: self.prn_func(format_text("\n{:^8} - {:}".format(prefix, format_text(msg, 'bold')))) def handle_async_stats_update(self, dump_data): global_stats = {} port_stats = {} # filter the values per port and general for key, value in dump_data.iteritems(): # match a pattern of ports m = re.search('(.*)\-([0-8])', key) if m: port_id = int(m.group(2)) field_name = m.group(1) if self.ports.has_key(port_id): if not port_id in port_stats: port_stats[port_id] = {} port_stats[port_id][field_name] = value else: continue else: # no port match - general stats global_stats[key] = value # update the general object with the snapshot self.global_stats.update(global_stats) # update all ports for port_id, data in port_stats.iteritems(): self.ports[port_id].port_stats.update(data) def handle_async_event (self, type, data): # DP stopped show_event = False # port started if (type == 0): port_id = int(data['port_id']) ev = "Port {0} has started".format(port_id) self.async_event_port_started(port_id) # port stopped elif (type == 1): port_id = int(data['port_id']) ev = "Port {0} has stopped".format(port_id) # call the handler self.async_event_port_stopped(port_id) # port paused elif (type == 2): port_id = int(data['port_id']) ev = "Port {0} has paused".format(port_id) # call the handler self.async_event_port_paused(port_id) # port resumed elif (type == 3): port_id = int(data['port_id']) ev = "Port {0} has resumed".format(port_id) # call the handler self.async_event_port_resumed(port_id) # port finished traffic elif (type == 4): port_id = int(data['port_id']) ev = "Port {0} job done".format(port_id) # call the handler self.async_event_port_stopped(port_id) show_event = True # port was stolen... elif (type == 5): session_id = data['session_id'] # false alarm, its us if session_id == self.session_id: return port_id = int(data['port_id']) who = data['who'] ev = "Port {0} was forcely taken by '{1}'".format(port_id, who) # call the handler self.async_event_port_forced_acquired(port_id) show_event = True # server stopped elif (type == 100): ev = "Server has stopped" self.async_event_server_stopped() show_event = True else: # unknown event - ignore return self.add_event_log(ev, 'server', show_event) def async_event_port_stopped (self, port_id): self.ports[port_id].async_event_port_stopped() def async_event_port_started (self, port_id): self.ports[port_id].async_event_port_started() def async_event_port_paused (self, port_id): self.ports[port_id].async_event_port_paused() def async_event_port_resumed (self, port_id): self.ports[port_id].async_event_port_resumed() def async_event_port_forced_acquired (self, port_id): self.ports[port_id].async_event_forced_acquired() self.read_only = True def async_event_server_stopped (self): self.connected = False def get_events (self): return self.events def clear_events (self): self.events = [] ############# helper functions section ############## # measure time for functions def timing(f): def wrap(*args): time1 = time.time() ret = f(*args) # don't want to print on error if ret.bad(): return ret delta = time.time() - time1 print format_time(delta) + "\n" return ret return wrap def validate_port_list(self, port_id_list): if not isinstance(port_id_list, list): print type(port_id_list) return False # check each item of the sequence return all([ (port_id >= 0) and (port_id < self.get_port_count()) for port_id in port_id_list ]) # some preprocessing for port argument def __ports (self, port_id_list): # none means all if port_id_list == None: return range(0, self.get_port_count()) # always list if isinstance(port_id_list, int): port_id_list = [port_id_list] if not isinstance(port_id_list, list): raise ValueError("bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()): raise ValueError("bad port id {0}".format(port_id)) return port_id_list ############ boot up section ################ # connection sequence # mode can be RW - read / write, RWF - read write with force , RO - read only def connect(self, mode = "RW"): if self.is_connected(): self.disconnect() # clear this flag self.connected = False # connect sync channel rc = self.comm_link.connect() if rc.bad(): return rc # connect async channel rc = self.async_client.connect() if rc.bad(): return rc # version rc = self.transmit("get_version") if rc.bad(): return rc self.server_version = rc.data() self.global_stats.server_version = rc.data() # cache system info rc = self.transmit("get_system_info") if rc.bad(): return rc self.system_info = rc.data() # cache supported commands rc = self.transmit("get_supported_cmds") if rc.bad(): return rc self.supported_cmds = rc.data() # create ports for port_id in xrange(self.get_port_count()): speed = self.system_info['ports'][port_id]['speed'] driver = self.system_info['ports'][port_id]['driver'] self.ports[port_id] = Port(port_id, speed, driver, self.user, self.comm_link, self.session_id) # sync the ports rc = self.sync_ports() if rc.bad(): return rc # acquire all ports if mode == "RW": rc = self.acquire(force = False) # fallback to read only if failed if rc.bad(): rc.annotate(show_status = False) print format_text("Switching to read only mode - only few commands will be available", 'bold') self.release(self.get_acquired_ports()) self.read_only = True else: self.read_only = False elif mode == "RWF": rc = self.acquire(force = True) if rc.bad(): return rc self.read_only = False elif mode == "RO": # no acquire on read only rc = RC_OK() self.read_only = True self.connected = True return RC_OK() def is_read_only (self): return self.read_only def is_connected (self): return self.connected and self.comm_link.is_connected def disconnect(self): # release any previous acquired ports if self.is_connected(): self.release(self.get_acquired_ports()) self.comm_link.disconnect() self.async_client.disconnect() self.connected = False return RC_OK() def on_async_dead (self): if self.connected: msg = 'lost connection to server' self.add_event_log(msg, 'local', True) self.connected = False def on_async_alive (self): pass ########### cached queries (no server traffic) ########### def get_supported_cmds(self): return self.supported_cmds def get_version(self): return self.server_version def get_system_info(self): return self.system_info def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def get_stats_async (self): return self.async_client.get_stats() def get_connection_port (self): return self.comm_link.port def get_connection_ip (self): return self.comm_link.server def get_all_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems()] def get_acquired_ports(self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_acquired()] def get_active_ports(self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_active()] def get_paused_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_paused()] def get_transmitting_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_transmitting()] def set_verbose(self, mode): # on high - enable link verbose if mode == self.VERBOSE_HIGH: self.comm_link.set_verbose(True) else: self.comm_link.set_verbose(False) self.verbose = mode def check_verbose (self, level): return (self.verbose >= level) def get_verbose (self): return self.verbose def prn_func (self, msg, level = VERBOSE_REGULAR): if self.check_verbose(level): print msg ############# server actions ################ # ping server def ping(self): return self.transmit("ping") def get_global_stats(self): return self.transmit("get_global_stats") ########## port commands ############## def sync_ports (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].sync()) return rc # acquire ports, if port_list is none - get all def acquire (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].acquire(force)) return rc # release ports def release (self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].release()) return rc def add_stream(self, stream_id, stream_obj, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_stream(stream_id, stream_obj)) return rc def add_stream_pack(self, stream_pack_list, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_streams(stream_pack_list)) return rc def remove_stream(self, stream_id, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_stream(stream_id)) return rc def remove_all_streams(self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_all_streams()) return rc def get_stream(self, stream_id, port_id, get_pkt = False): return self.ports[port_id].get_stream(stream_id) def get_all_streams(self, port_id, get_pkt = False): return self.ports[port_id].get_all_streams() def get_stream_id_list(self, port_id): return self.ports[port_id].get_stream_id_list() def start_traffic (self, multiplier, duration, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].start(multiplier, duration)) return rc def resume_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].resume()) return rc def pause_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].pause()) return rc def stop_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].stop(force)) return rc def update_traffic (self, mult, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].update(mult)) return rc def validate (self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].validate()) return rc def get_port_stats(self, port_id=None): pass def get_stream_stats(self, port_id=None): pass def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) def transmit_batch(self, batch_list): return self.comm_link.transmit_batch(batch_list) ######################### Console (high level) API ######################### @timing def cmd_ping(self): rc = self.ping() rc.annotate("Pinging the server on '{0}' port '{1}': ".format(self.get_connection_ip(), self.get_connection_port())) return rc def cmd_connect(self, mode = "RW"): rc = self.connect(mode) rc.annotate() return rc def cmd_disconnect(self): rc = self.disconnect() rc.annotate() return rc # reset def cmd_reset(self): #self.release(self.get_acquired_ports()) rc = self.acquire(force = True) rc.annotate("Force acquiring all ports:") if rc.bad(): return rc # force stop all ports rc = self.stop_traffic(self.get_port_ids(), True) rc.annotate("Stop traffic on all ports:") if rc.bad(): return rc # remove all streams rc = self.remove_all_streams(self.get_port_ids()) rc.annotate("Removing all streams from all ports:") if rc.bad(): return rc # TODO: clear stats return RC_OK() # stop cmd def cmd_stop (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.stop_traffic(active_ports) rc.annotate("Stopping traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() # update cmd def cmd_update (self, port_id_list, mult): # find the relevant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.update_traffic(mult, active_ports) rc.annotate("Updating traffic on port(s) {0}:".format(port_id_list)) return rc # clear stats def cmd_clear(self, port_id_list): for port_id in port_id_list: self.ports[port_id].clear_stats() self.global_stats.clear_stats() return RC_OK() def cmd_invalidate (self, port_id_list): for port_id in port_id_list: self.ports[port_id].invalidate_stats() self.global_stats.invalidate() return RC_OK() # pause cmd def cmd_pause (self, port_id_list): # find the relevant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.pause_traffic(active_ports) rc.annotate("Pausing traffic on port(s) {0}:".format(port_id_list)) return rc # resume cmd def cmd_resume (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.resume_traffic(active_ports) rc.annotate("Resume traffic on port(s) {0}:".format(port_id_list)) return rc # start cmd def cmd_start (self, port_id_list, stream_list, mult, force, duration, dry): active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if active_ports: if not force: msg = "Port(s) {0} are active - please stop them or add '--force'".format(active_ports) print format_text(msg, 'bold') return RC_ERR(msg) else: rc = self.cmd_stop(active_ports) if not rc: return rc rc = self.remove_all_streams(port_id_list) rc.annotate("Removing all streams from port(s) {0}:".format(port_id_list)) if rc.bad(): return rc rc = self.add_stream_pack(stream_list.compiled, port_id_list) rc.annotate("Attaching {0} streams to port(s) {1}:".format(len(stream_list.compiled), port_id_list)) if rc.bad(): return rc # when not on dry - start the traffic , otherwise validate only if not dry: rc = self.start_traffic(mult, duration, port_id_list) rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list)) return rc else: rc = self.validate(port_id_list) rc.annotate("Validating traffic profile on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc # show a profile on one port for illustration self.ports[port_id_list[0]].print_profile(mult, duration) return rc # validate port(s) profile def cmd_validate (self, port_id_list): rc = self.validate(port_id_list) rc.annotate("Validating streams on port(s) {0}:".format(port_id_list)) return rc # stats def cmd_stats(self, port_id_list, stats_mask=set()): stats_opts = trex_stats.ALL_STATS_OPTS.intersection(stats_mask) stats_obj = {} for stats_type in stats_opts: stats_obj.update(self.stats_generator.generate_single_statistic(port_id_list, stats_type)) return stats_obj ############## High Level API With Parser ################ def cmd_connect_line (self, line): '''Connects to the TRex server''' # define a parser parser = parsing_opts.gen_parser(self, "connect", self.cmd_connect_line.__doc__, parsing_opts.FORCE) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.force: rc = self.cmd_connect(mode = "RWF") else: rc = self.cmd_connect(mode = "RW") @timing def cmd_start_line (self, line): '''Start selected traffic in specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser(self, "start", self.cmd_start_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.TOTAL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER_STRICT, parsing_opts.DRY_RUN) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.dry: print format_text("\n*** DRY RUN ***", 'bold') if opts.db: stream_list = self.streams_db.get_stream_pack(opts.db) rc = RC(stream_list != None) rc.annotate("Load stream pack (from DB):") if rc.bad(): return RC_ERR("Failed to load stream pack") else: # load streams from file stream_list = None; try: stream_list = self.streams_db.load_yaml_file(opts.file[0]) except Exception as e: s = str(e) rc=RC_ERR(s) rc.annotate() return rc rc = RC(stream_list != None) rc.annotate("Load stream pack (from file):") if stream_list == None: return RC_ERR("Failed to load stream pack") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration, opts.dry) @timing def cmd_resume_line (self, line): '''Resume active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_resume(opts.ports) @timing def cmd_stop_line (self, line): '''Stop active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_stop(opts.ports) @timing def cmd_pause_line (self, line): '''Pause active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_pause(opts.ports) @timing def cmd_update_line (self, line): '''Update port(s) speed currently active\n''' parser = parsing_opts.gen_parser(self, "update", self.cmd_update_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.MULTIPLIER, parsing_opts.TOTAL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_update(opts.ports, opts.mult) @timing def cmd_reset_line (self, line): return self.cmd_reset() def cmd_clear_line (self, line): '''Clear cached local statistics\n''' # define a parser parser = parsing_opts.gen_parser(self, "clear", self.cmd_clear_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_clear(opts.ports) def cmd_stats_line (self, line): '''Fetch statistics from TRex server by port\n''' # define a parser parser = parsing_opts.gen_parser(self, "stats", self.cmd_stats_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.STATS_MASK) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") # determine stats mask mask = self._get_mask_keys(**self._filter_namespace_args(opts, trex_stats.ALL_STATS_OPTS)) if not mask: # set to show all stats if no filter was given mask = trex_stats.ALL_STATS_OPTS stats = self.cmd_stats(opts.ports, mask) # print stats to screen for stat_type, stat_data in stats.iteritems(): text_tables.print_table_with_header(stat_data.text_table, stat_type) return RC_OK() @timing def cmd_validate_line (self, line): '''validates port(s) stream configuration\n''' parser = parsing_opts.gen_parser(self, "validate", self.cmd_validate_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") rc = self.cmd_validate(opts.ports) return rc def cmd_exit_line (self, line): print format_text("Exiting\n", 'bold') # a way to exit return RC_ERR("exit") def cmd_wait_line (self, line): '''wait for a period of time\n''' parser = parsing_opts.gen_parser(self, "wait", self.cmd_wait_line.__doc__, parsing_opts.DURATION) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") delay_sec = opts.duration if (opts.duration > 0) else 1 print format_text("Waiting for {0} seconds...\n".format(delay_sec), 'bold') time.sleep(delay_sec) return RC_OK() # run a script of commands def run_script_file (self, filename): print format_text("\nRunning script file '{0}'...".format(filename), 'bold') rc = self.cmd_connect() if rc.bad(): return with open(filename) as f: script_lines = f.readlines() cmd_table = {} # register all the commands cmd_table['start'] = self.cmd_start_line cmd_table['stop'] = self.cmd_stop_line cmd_table['reset'] = self.cmd_reset_line cmd_table['wait'] = self.cmd_wait_line cmd_table['exit'] = self.cmd_exit_line for index, line in enumerate(script_lines, start = 1): line = line.strip() if line == "": continue if line.startswith("#"): continue sp = line.split(' ', 1) cmd = sp[0] if len(sp) == 2: args = sp[1] else: args = "" print format_text("Executing line {0} : '{1}'\n".format(index, line)) if not cmd in cmd_table: print "\n*** Error at line {0} : '{1}'\n".format(index, line) print format_text("unknown command '{0}'\n".format(cmd), 'bold') return False rc = cmd_table[cmd](args) if rc.bad(): return False print format_text("\n[Done]", 'bold') return True ################################# # ------ private methods ------ # @staticmethod def _get_mask_keys(ok_values={True}, **kwargs): masked_keys = set() for key, val in kwargs.iteritems(): if val in ok_values: masked_keys.add(key) return masked_keys @staticmethod def _filter_namespace_args(namespace, ok_values): return {k: v for k, v in namespace.__dict__.items() if k in ok_values} ################################# # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False, prn_func = None): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port, prn_func) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def get_server (self): return self.server def get_port (self): return self.port def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print [msg for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params) for command in batch_list]] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format(server=self.server, port=self.port) if __name__ == "__main__": pass