cli.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/python
  2. '''ONVIF Client Command Line Interface'''
  3. import re
  4. from cmd import Cmd
  5. from ast import literal_eval
  6. from json import dumps
  7. from argparse import ArgumentParser, ArgumentError, REMAINDER
  8. from suds import MethodNotFound
  9. from suds.sax.text import Text
  10. from onvif import ONVIFCamera, ONVIFService, ONVIFError
  11. from definition import SERVICES
  12. import os.path
  13. SUPPORTED_SERVICES = SERVICES.keys()
  14. class ThrowingArgumentParser(ArgumentParser):
  15. def error(self, message):
  16. usage = self.format_usage()
  17. raise ValueError("%s\n%s" % (message, usage))
  18. def success(message):
  19. print 'True: ' + str(message)
  20. def error(message):
  21. print 'False: ' + str(message)
  22. class ONVIFCLI(Cmd):
  23. prompt = 'ONVIF >>> '
  24. client = None
  25. cmd_parser = None
  26. def setup(self, args):
  27. ''' `args`: Instance of `argparse.ArgumentParser` '''
  28. # Create onvif camera client
  29. self.client = ONVIFCamera(args.host, args.port,
  30. args.user, args.password,
  31. args.wsdl, encrypt=args.encrypt)
  32. # Create cmd argument parser
  33. self.create_cmd_parser()
  34. def create_cmd_parser(self):
  35. # Create parser to parse CMD, `params` is optional.
  36. cmd_parser = ThrowingArgumentParser(prog='ONVIF CMD',
  37. usage='CMD service operation [params]')
  38. cmd_parser.add_argument('service')
  39. cmd_parser.add_argument('operation')
  40. cmd_parser.add_argument('params', default='{}', nargs=REMAINDER)
  41. self.cmd_parser = cmd_parser
  42. def do_cmd(self, line):
  43. '''Usage: CMD service operation [parameters]'''
  44. try:
  45. args = self.cmd_parser.parse_args(line.split())
  46. except ValueError as err:
  47. return error(err)
  48. # Check if args.service is valid
  49. if args.service not in SUPPORTED_SERVICES:
  50. return error('No Service: ' + args.service)
  51. args.params = ''.join(args.params)
  52. # params is optional
  53. if not args.params.strip():
  54. args.params = '{}'
  55. # params must be a dictionary format string
  56. match = re.match(r"^.*?(\{.*\}).*$", args.params)
  57. if not match:
  58. return error('Invalid params')
  59. try:
  60. args.params = dict(literal_eval(match.group(1)))
  61. except ValueError as err:
  62. return error('Invalid params')
  63. try:
  64. # Get ONVIF service
  65. service = self.client.get_service(args.service)
  66. # Actually execute the command and get the response
  67. response = getattr(service, args.operation)(args.params)
  68. except MethodNotFound as err:
  69. return error('No Operation: %s' % args.operation)
  70. except Exception as err:
  71. return error(err)
  72. if isinstance(response, (Text, bool)):
  73. return success(response)
  74. # Try to convert instance to dictionary
  75. try:
  76. success(ONVIFService.to_dict(response))
  77. except ONVIFError:
  78. error({})
  79. def complete_cmd(self, text, line, begidx, endidx):
  80. # TODO: complete service operations
  81. # service.ws_client.service._ServiceSelector__services[0].ports[0].methods.keys()
  82. if not text:
  83. completions = SUPPORTED_SERVICES[:]
  84. else:
  85. completions = [ key for key in SUPPORTED_SERVICES
  86. if key.startswith(text) ]
  87. return completions
  88. def emptyline(self):
  89. return ''
  90. def do_EOF(self, line):
  91. return True
  92. def create_parser():
  93. parser = ThrowingArgumentParser(description=__doc__)
  94. # Dealwith dependency for service, operation and params
  95. parser.add_argument('service', nargs='?',
  96. help='Service defined by ONVIF WSDL document')
  97. parser.add_argument('operation', nargs='?', default='',
  98. help='Operation to be execute defined'
  99. ' by ONVIF WSDL document')
  100. parser.add_argument('params', default='', nargs='?',
  101. help='JSON format params passed to the operation.'
  102. 'E.g., "{"Name": "NewHostName"}"')
  103. parser.add_argument('--host', required=True,
  104. help='ONVIF camera host, e.g. 192.168.2.123, '
  105. 'www.example.com')
  106. parser.add_argument('--port', default=80, type=int, help='Port number for camera, default: 80')
  107. parser.add_argument('-u', '--user', required=True,
  108. help='Username for authentication')
  109. parser.add_argument('-a', '--password', required=True,
  110. help='Password for authentication')
  111. parser.add_argument('-w', '--wsdl', default=os.path.join(os.path.dirname(os.path.dirname(__file__)), "wsdl"),
  112. help='directory to store ONVIF WSDL documents')
  113. parser.add_argument('-e', '--encrypt', default='False',
  114. help='Encrypt password or not')
  115. parser.add_argument('-v', '--verbose', action='store_true',
  116. help='increase output verbosity')
  117. parser.add_argument('--cache-location', dest='cache_location', default='/tmp/onvif/',
  118. help='location to cache suds objects, default to /tmp/onvif/')
  119. parser.add_argument('--cache-duration', dest='cache_duration',
  120. help='how long will the cache be exist')
  121. return parser
  122. def main():
  123. INTRO = __doc__
  124. # Create argument parser
  125. parser = create_parser()
  126. try:
  127. args = parser.parse_args()
  128. except ValueError as err:
  129. print str(err)
  130. return
  131. # Also need parse configuration file.
  132. # Interactive command loop
  133. cli = ONVIFCLI(stdin=input)
  134. cli.setup(args)
  135. if args.service:
  136. cmd = ' '.join(['cmd', args.service, args.operation, args.params])
  137. cli.onecmd(cmd)
  138. # Execute command specified and exit
  139. else:
  140. cli.cmdloop()
  141. if __name__ == '__main__':
  142. main()