4 srfsh.py - provides a basic shell for issuing OpenSRF requests
10 - runs <count> opensrf.math requests and prints the average time
12 request <service> <method> [<param1>, <param2>, ...]
13 - performs an opensrf request
16 - sets an environment variable
18 Environment variables:
19 SRFSH_OUTPUT = pretty - print pretty JSON and key/value pairs for network objects
20 = raw - print formatted JSON
22 SRFSH_LOCALE = <locale> - request responses to be returned in locale <locale> if available
25 import os, sys, time, readline, atexit, re
26 import osrf.json, osrf.system, osrf.ses, osrf.conf, osrf.log, osrf.net
28 router_command_map = {
29 'services' : 'opensrf.router.info.class.list',
30 'service-stats' : 'opensrf.router.info.stats.class.node.all',
31 'service-nodes' : 'opensrf.router.info.stats.class.all'
34 # List of words to use for readline tab completion
35 tab_complete_words = [
46 # add the router commands to the tab-complete list
47 for rcommand in router_command_map.keys():
48 tab_complete_words.append(rcommand)
50 # -------------------------------------------------------------------
52 # -------------------------------------------------------------------
56 'request' : handle_request,
57 'router' : handle_router,
58 'math_bench' : handle_math_bench,
67 line = raw_input("srfsh# ")
72 if str.lower(line) == 'exit' or str.lower(line) == 'quit':
75 parts = str.split(line)
76 command = parts.pop(0)
78 if command not in command_map:
79 print "unknown command: '%s'" % command
82 command_map[command](parts)
84 except EOFError: # ^-d
87 except KeyboardInterrupt: # ^-c
94 def handle_router(parts):
97 print "usage: router <query>"
102 if query not in router_command_map:
103 print "router query options: %s" % ','.join(router_command_map.keys())
106 return handle_request(['router', router_command_map[query]])
108 # -------------------------------------------------------------------
109 # Set env variables to control behavior
110 # -------------------------------------------------------------------
111 def handle_set(parts):
113 pattern = re.compile('(.*)=(.*)').match(cmd)
114 key = pattern.group(1)
115 val = pattern.group(2)
117 print "%s = %s" % (key, val)
119 def handle_get(parts):
121 print get_var(parts[0])
126 # -------------------------------------------------------------------
128 # -------------------------------------------------------------------
129 def handle_help(foo):
132 # -------------------------------------------------------------------
133 # performs an opensrf request
134 # -------------------------------------------------------------------
135 def handle_request(parts):
138 print "usage: request <service> <api_name> [<param1>, <param2>, ...]"
141 service = parts.pop(0)
142 method = parts.pop(0)
143 locale = __get_locale()
144 jstr = '[%s]' % "".join(parts)
148 params = osrf.json.to_object(jstr)
150 print "Error parsing JSON: %s" % jstr
153 ses = osrf.ses.ClientSession(service, locale=locale)
157 req = ses.request2(method, tuple(params))
163 resp = req.recv(timeout=120)
164 except osrf.net.XMPPNoRecipient:
165 print "Unable to communicate with %s" % service
169 osrf.log.log_internal("Looping through receive request")
172 total = time.time() - start
174 otp = get_var('SRFSH_OUTPUT')
176 print "Received Data: %s\n" % osrf.json.debug_net_object(resp.content())
178 print "Received Data: %s\n" % osrf.json.pprint(osrf.json.to_json(resp.content()))
184 print "Total request time: %f" % total
188 def handle_math_bench(parts):
190 count = int(parts.pop(0))
191 ses = osrf.ses.ClientSession('opensrf.math')
194 for cnt in range(100):
196 sys.stdout.write('.')
198 sys.stdout.write( str( cnt / 10 ) )
202 for cnt in range(count):
204 starttime = time.time()
205 req = ses.request('add', 1, 2)
206 resp = req.recv(timeout=2)
207 endtime = time.time()
209 if resp.content() == 3:
210 sys.stdout.write("+")
212 times.append( endtime - starttime )
214 print "What happened? %s" % str(resp.content())
217 if not ( (cnt + 1) % 100):
218 print ' [%d]' % (cnt + 1)
224 print "\naverage time %f" % (total / len(times))
229 # -------------------------------------------------------------------
230 # Defines the tab-completion handling and sets up the readline history
231 # -------------------------------------------------------------------
232 def setup_readline():
234 class SrfshCompleter(object):
236 def __init__(self, words):
240 def complete(self, prefix, index):
242 if prefix != self.prefix:
246 # find all words that start with this prefix
247 self.matching_words = [
248 w for w in self.words if w.startswith(prefix)
251 if len(self.matching_words) == 0:
254 if len(self.matching_words) == 1:
255 return self.matching_words[0]
257 sys.stdout.write('\n%s\nsrfsh# %s' %
258 (' '.join(self.matching_words), readline.get_line_buffer()))
262 completer = SrfshCompleter(tuple(tab_complete_words))
263 readline.parse_and_bind("tab: complete")
264 readline.set_completer(completer.complete)
266 histfile = os.path.join(get_var('HOME'), ".srfsh_history")
268 readline.read_history_file(histfile)
271 atexit.register(readline.write_history_file, histfile)
273 readline.set_completer_delims(readline.get_completer_delims().replace('-',''))
277 file = os.path.join(get_var('HOME'), ".srfsh.xml")
278 osrf.system.System.connect(config_file=file, config_context='srfsh')
281 # Load the user defined external plugins
282 # XXX Make this a real module interface, with tab-complete words, commands, etc.
284 plugins = osrf.conf.get('plugins')
287 # XXX standard srfsh.xml does not yet define <plugins> element
288 #print("No plugins defined in /srfsh/plugins/plugin\n")
291 plugins = osrf.conf.get('plugins.plugin')
292 if not isinstance(plugins, list):
295 for module in plugins:
296 name = module['module']
297 init = module['init']
298 print "Loading module %s..." % name
301 string = 'import %s\n%s.%s()' % (name, name, init)
306 sys.stderr.write("\nError importing plugin %s, with init symbol %s: \n%s\n" % (name, init, e))
309 if not get_var('SRFSH_OUTPUT'):
310 set_var('SRFSH_OUTPUT', 'raw')
312 # XXX Do we need to differ between LANG and LC_MESSAGES?
313 if not get_var('SRFSH_LOCALE'):
314 set_var('SRFSH_LOCALE', get_var('LC_ALL'))
316 def set_var(key, val):
317 os.environ[key] = val
320 return os.environ.get(key, '')
324 Return the defined locale for this srfsh session.
326 A locale in OpenSRF is currently defined as a [a-z]{2}-[A-Z]{2} pattern.
327 This function munges the LC_ALL setting to conform to that pattern; for
328 example, trimming en_CA.UTF-8 to en-CA.
331 >>> srfsh.set_var('SRFSH_LOCALE', 'zz-ZZ')
332 >>> print __get_locale()
334 >>> srfsh.set_var('SRFSH_LOCALE', 'en_CA.UTF-8')
335 >>> print __get_locale()
339 env_locale = get_var('SRFSH_LOCALE')
341 pattern = re.compile(r'^\s*([a-z]+)[^a-zA-Z]([A-Z]+)').search(env_locale)
342 lang = pattern.group(1)
343 region = pattern.group(2)
344 locale = "%s-%s" % (lang, region)
350 if __name__ == '__main__':