def __init__(self): self._quit = False if len(sys.argv) >= 2: config = parse_conf(sys.argv[1]) else: config = parse_conf('ivt.yml') config = config_schema.validate(config) self.config = config if len(sys.argv) >= 3: channel_config = parse_conf(sys.argv[2]) else: channel_config = parse_conf('ivt_channels.yml') self.ivt = IVT( config['project'], config['login_code'], config['login_passwd'], config['keepalive_interval'], channel_config ) WSClientTransport.APP_FACTORY = self.ivt.ivt_session_factory self.ws_url = config['ivc']+'?'+urllib.urlencode( { 'login_code': config['login_code'], 'login_passwd': config['login_passwd'], 'project': config['project'], 'hardware_model': config['hardware_model'], 'firmware_model': IVT_VERSION } ) self._retry_evt = Event() self._done_upgrade_evt = Event() self._done_upgrade_evt.set() gevent.signal(signal.SIGINT, self.close) gevent.signal(signal.SIGTERM, self.close) self._greenlet_chk_ivt_package = gevent.spawn(self._chk_new_ivt_firmware)
def main(): default_log_config(debug=True) import logging log = logging.getLogger(__name__) try: if len(sys.argv) == 2: config = parse_conf(sys.argv[1]) else: config = parse_conf('ivt.yml') config = config_schema.validate(config) ivt = IVT(config['project'], config['login_code'], config['login_passwd'], config['keepalive_interval'], config['cameras'], preview_upload_server=config.get('preview_upload_server')) # start port port = SubProcessPort( port_name=config['login_code'], port_type=RTSP_PORT_PROGRAM_NAME, log_file=RTSP_PORT_PROGRAM_NAME + '.log', ) port.start() # connect to IVC WSClientTransport.APP_FACTORY = ivt.ivt_session_factory url = config['ivc'] + '?' + urllib.urlencode( { 'login_code': config['login_code'], 'login_passwd': config['login_passwd'], 'project': config['project'] }) while True: try: client = WSClientTransport(url) client.connect() client.wait_close() time.sleep(10) except: log.exception("Client session closed") time.sleep(10) except Exception: log.exception('Failed to start IVT')
class App(object): ivt_package_schema = Schema({ 'firmware_model': Use(STRING), 'url': Use(STRING), }) def __init__(self): self._quit = False if len(sys.argv) >= 2: config = parse_conf(sys.argv[1]) else: config = parse_conf('ivt.yml') config = config_schema.validate(config) self.config = config if len(sys.argv) >= 3: channel_config = parse_conf(sys.argv[2]) else: channel_config = parse_conf('ivt_channels.yml') self.ivt = IVT( config['project'], config['login_code'], config['login_passwd'], config['keepalive_interval'], channel_config ) WSClientTransport.APP_FACTORY = self.ivt.ivt_session_factory self.ws_url = config['ivc']+'?'+urllib.urlencode( { 'login_code': config['login_code'], 'login_passwd': config['login_passwd'], 'project': config['project'], 'hardware_model': config['hardware_model'], 'firmware_model': IVT_VERSION } ) self._retry_evt = Event() self._done_upgrade_evt = Event() self._done_upgrade_evt.set() gevent.signal(signal.SIGINT, self.close) gevent.signal(signal.SIGTERM, self.close) self._greenlet_chk_ivt_package = gevent.spawn(self._chk_new_ivt_firmware) def run(self): while not self._quit: try: client = WSClientTransport(self.ws_url) client.connect() client.wait_close() except: log.exception("Client session closed") finally: if not self._quit: self._retry_evt.wait(timeout=30) self._retry_evt.clear() self._done_upgrade_evt.wait() log.info('Quit') sys.exit(0) def close(self): log.info('Closing') self._quit = True self.ivt.close() self._retry_evt.set() def _chk_new_ivt_firmware(self): gevent.sleep(5) while True: try: ivt_package = self.ivt.chk_new_ivt_firmware() if not ivt_package: continue ivt_package = self.ivt_package_schema.validate(ivt_package) target_ivt_version = ivt_package['firmware_model'] if target_ivt_version.strip() == IVT_VERSION.strip(): continue log.info('New version of IVT package {0} found'.format(ivt_package)) if self.config['debug']: # do not automatically upgrade in debug mode log.info('Will not upgrade IVT in debug mode') continue if self.ivt.is_broadcasting(): log.info('Is broadcasting, delay IVT upgrade') continue log.info('Try to upgrade IVT to version {0}'.format(target_ivt_version)) self._done_upgrade_evt.clear() self.close() self._upgrade(ivt_package['url']) log.info('Successfully upgrade IVT to version {0}'.format(target_ivt_version)) self._start_new_ivt() return except Exception: log.exception('Failed to check IVT package version or upgrade IVT') finally: self._done_upgrade_evt.set() gevent.sleep(600) def _upgrade(self, url): # to make sure subprocess's stdout will be in utf-8 encoding environ = dict(os.environ) environ['LANG'] = 'en_US.UTF-8' # download upgrade script sub = Popen(['curl', '-O', url], cwd='/root', stdout=PIPE, stderr=PIPE, env=environ) stdout, stderr = sub.communicate() if sub.returncode != 0: raise Exception(u'Failed to download upgrade script, return code {0}, {1}'.format(sub.returncode, stderr.decode('utf8'))) script = os.path.basename(urlparse(url).path) cmd = ['bash', script, self.config['ivc'], self.config['project'], self.config['login_code'], self.config['login_passwd'], self.config['hardware_model']] sub = Popen(cmd, stdout=PIPE, stderr=PIPE, cwd='/root', env=environ) try: while True: with gevent.Timeout(600): line = sub.stdout.readline() if not line: sub.wait() break else: log.info('Upgrade output: '+line.decode('utf8').strip()) except gevent.Timeout: sub.kill() raise Exception(u'Failed to upgrade, timeout') if sub.returncode != 0: raise Exception(u'Failed to upgrade, return code {0}, {1}'.format(sub.returncode, sub.stderr.read())) def _start_new_ivt(self): Popen('./ivt', close_fds=True, shell=True) log.info('New IVT started')