def __init__(self, modo_local=False, hw_init=True): self.logger = get_logger(self.__class__.__name__) self.logger.debug("EHLO") self.config = Configuracion() if self.config.USAR_LOCK == 'true': self.lock = thread.allocate_lock() else: self.lock = None self.logger.debug("__init__: lock = " + str(self.lock)) self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._evento_tag, False) self._conexion = None self._timeout_id = None self._recuento_anterior = None self.inicializar_variables()
def __init__(self, hw_init=True): self.config = Configuracion() if self.config.USAR_LOCK == 'true': self.lock = thread.allocate_lock() else: self.lock = None logger.debug("__init__: lock = " + str(self.lock)) self._widget_tree = gtk.glade.XML(self.config.GLADE_FILE) self._wndPrincipal = self._widget_tree.get_widget('wndPrincipal') self._lblMensajePantalla = self._widget_tree.get_widget( 'lblMensajePantalla') self._vbox_acta = self._widget_tree.get_widget('vbox_acta') self._widget_vport = self._widget_tree.get_widget('vp_acta') self._status = self._widget_tree.get_widget('status') self._lbl_mesas = self._widget_tree.get_widget('lbl_mesas') self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._lector_callback, False) self._conexion = None self._timeout_id = None eventos = { "on_wndPrincipal_delete": self.salir, "on_tlbSalir_clicked": self.salir, "on_mnuArchivoSalir_activate": self.salir, "on_mnuAyudaAcercaDe_activate": self.mostrar_acerca_de, "on_mnuAccionesRed_activate": self.configurar_red, "on_mnuAccionesImportar_activate": self.mostrar_importar_claves, "on_tblPreferencias_clicked": self.mostrar_preferencias, "on_tlbConectar_clicked": self.conectar, "on_tblConfigurarRed_clicked": self.configurar_red, "on_tblImportarCert_clicked": self.mostrar_importar_claves, "on_tlbBajarCert_clicked": self.mostrar_autenticacion, } self._widget_tree.signal_autoconnect(eventos) self.borradores = [] self.valid_tags = None self._actas = {}
def __init__(self, hw_init=True): self.config = Configuracion() if self.config.USAR_LOCK == "true": self.lock = thread.allocate_lock() else: self.lock = None logger.debug("__init__: lock = " + str(self.lock)) self._widget_tree = gtk.glade.XML(self.config.GLADE_FILE) self._wndPrincipal = self._widget_tree.get_widget("wndPrincipal") self._lblMensajePantalla = self._widget_tree.get_widget("lblMensajePantalla") self._vbox_acta = self._widget_tree.get_widget("vbox_acta") self._widget_vport = self._widget_tree.get_widget("vp_acta") self._status = self._widget_tree.get_widget("status") self._lbl_mesas = self._widget_tree.get_widget("lbl_mesas") self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._lector_callback, False) self._conexion = None self._timeout_id = None eventos = { "on_wndPrincipal_delete": self.salir, "on_tlbSalir_clicked": self.salir, "on_mnuArchivoSalir_activate": self.salir, "on_mnuAyudaAcercaDe_activate": self.mostrar_acerca_de, "on_mnuAccionesRed_activate": self.configurar_red, "on_mnuAccionesImportar_activate": self.mostrar_importar_claves, "on_tblPreferencias_clicked": self.mostrar_preferencias, "on_tlbConectar_clicked": self.conectar, "on_tblConfigurarRed_clicked": self.configurar_red, "on_tblImportarCert_clicked": self.mostrar_importar_claves, "on_tlbBajarCert_clicked": self.mostrar_autenticacion, } self._widget_tree.signal_autoconnect(eventos) self.borradores = [] self.valid_tags = None self._actas = {}
class TransmisionApp(object): # Constantes de Estados DESCONECTADO = 0 CONECTADO = 1 AUTENTICADO = 2 MARGEN_LECTURAS_CON_COLISION = 2 MARGEN_LECTURAS_ERRONEAS = 2 COLOR_OK = '#006600' COLOR_ERR = '#FF0000' COLOR_ALERTA = '#FF0000' def __init__(self, hw_init=True): self.config = Configuracion() if self.config.USAR_LOCK == 'true': self.lock = thread.allocate_lock() else: self.lock = None logger.debug("__init__: lock = " + str(self.lock)) self._widget_tree = gtk.glade.XML(self.config.GLADE_FILE) self._wndPrincipal = self._widget_tree.get_widget('wndPrincipal') self._lblMensajePantalla = self._widget_tree.get_widget( 'lblMensajePantalla') self._vbox_acta = self._widget_tree.get_widget('vbox_acta') self._widget_vport = self._widget_tree.get_widget('vp_acta') self._status = self._widget_tree.get_widget('status') self._lbl_mesas = self._widget_tree.get_widget('lbl_mesas') self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._lector_callback, False) self._conexion = None self._timeout_id = None eventos = { "on_wndPrincipal_delete": self.salir, "on_tlbSalir_clicked": self.salir, "on_mnuArchivoSalir_activate": self.salir, "on_mnuAyudaAcercaDe_activate": self.mostrar_acerca_de, "on_mnuAccionesRed_activate": self.configurar_red, "on_mnuAccionesImportar_activate": self.mostrar_importar_claves, "on_tblPreferencias_clicked": self.mostrar_preferencias, "on_tlbConectar_clicked": self.conectar, "on_tblConfigurarRed_clicked": self.configurar_red, "on_tblImportarCert_clicked": self.mostrar_importar_claves, "on_tlbBajarCert_clicked": self.mostrar_autenticacion, } self._widget_tree.signal_autoconnect(eventos) self.borradores = [] self.valid_tags = None self._actas = {} def mostrar_autenticacion(self, menuitem): autenticacion = Autenticacion(self.config, self) autenticacion.mostrar() def mostrar(self): if not DEBUG: self._wndPrincipal.maximize() self._wndPrincipal.show() def mostrar_acerca_de(self, menuitem): acerca_de = AcercaDe(self.config) acerca_de.mostrar() def mostrar_preferencias(self, menuitem): preferencias = Preferencias(self.config) preferencias.mostrar() def mostrar_importar_claves(self, menuitem): wnd_importar_claves = ImportarClaves(self.config) wnd_importar_claves.mostrar() def configurar_red(self, *args): try: subprocess.Popen(PATH_NETWORK_CONF_APP, shell=False) except OSError as e: logger.error(MSG_ERROR_CONF_APP % str(e.message)) @bloqueante def conectar(self, toolbutton): if self.__estado_conexion != self.DESCONECTADO: self.set_mensaje(MSG_CONECTADO) self.set_status(("conexion", ST_CONECTADO)) elif self._conexion is not None: self.set_mensaje(MSG_CONECTANDO) elif self.__modulo_lector is None: self.set_mensaje(MSG_LECTOR_DESCONECTADO % self.config.PUERTO_LECTOR) self.set_status(("lector", ST_NO_LECTOR)) else: self.set_mensaje(MSG_CONECTANDO_ESPERE) self._conexion = Conexion( '%s://%s/' % (PROTOCOLO, self.config.HOST), DEBUG, self.config.TIMEOUT) self._conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) self._conexion.set_ca_certificate(self.config.CA_FILE) thread.start_new_thread(self.__conectar, ()) self.__conectar_lector() return if self.lock: logger.debug("_conectar: libero lock manual!") self.lock.release() @desbloqueante def __conectar_lector(self): self.set_mensaje(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) self.__modulo_lector.conectar_lector() return @mostrar_espera @desbloqueante def __conectar(self): """Conectar al servidor web usando un thread en segundo plano""" logger.info("llamando a conectar") result = self._conexion.test_conexion() if result is not False and result.status_ok(): if self.config.VERIFICAR_DATOS: self._verificar_datos() self.valid_tags = [ b64decode(tag).upper() for tag in result._dict['tags'] ] self.__set_estado_conexion(self.CONECTADO) self.set_status(("conexion", ST_CONECTADO)) self.set_mensaje(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) gobject.idle_add(self._set_timeout) else: error = self._conexion.diagnosticar() if error is self._conexion.UNKNOW_ERROR: ayuda = "" elif error is self._conexion.CONNECTION_ERROR: ayuda = MSG_COMPRUEBE_CONEXION elif error is self._conexion.SSL_ERROR: ayuda = MSG_VERIFIQUE_CERTIFICADOS else: ayuda = "" self.set_mensaje(MSG_INTENTE_NUEVAMENTE % ayuda, idle=True, color=self.COLOR_ERR) self._conexion = None self.set_status(("conexion", ST_DESCONECTADO)) def _set_timeout(self): if self._timeout_id is not None: gobject.source_remove(self._timeout_id) self._timeout_id = gobject.timeout_add_seconds( PING_EVERY, self._conexion.test_conexion) return False @desbloqueante def __desconectar(self): """Cierra la conexión al servidor web usando un thread en segundo plano""" if self._timeout_id is not None: gobject.source_remove(self._timeout_id) logger.info("llamando a conectar") self._conexion.desconectar() self.set_status(("conexion", ST_DESCONECTADO)) def _verificar_datos(self): # @TODO: Verificar si los datos que posee el cliente son válidos # encontrar un método para verificar esto msg = '' destino = '/tmp/datos_actualizados' destino_tmp = '/tmp' version_datos = ConfiguracionSistema.one(codigo='db_version').valor logger.debug('Verificando datos locales: {}'.format(version_datos)) respuesta = self._conexion.obtener_datos_servidor(version_datos) logger.debug('Verificando datos remotos: {}'.format( respuesta['version'])) if len(respuesta['archivo']) > 0: actualizar_datos(respuesta['ubicacion'], respuesta['archivo'], destino, destino_tmp) # Borro la cache del objeto configuracion cache_name = ConfiguracionSistema.get_cache_name() if cache_name is not None and hasattr(ConfiguracionSistema.cache, cache_name): ConfiguracionSistema.cache.clear(cache_name) # Defino un nuevo origen de datos set_data_source(destino) else: msg = 'no ' logger.debug("Funcion: obtener datos del servidor, " "Los datos para la ubicación {} {}han sido " "actualizados".format(respuesta['ubicacion'], msg)) def esperando_evento(self, ocupado, idle=True): """ Setea el puntero de la ventana principal en ocupado (True) o flecha estándar (False). Es idle por defecto porque se lo llama casi exclusivamente desde el segundo hilo. """ if ocupado: cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) else: cursor = None if idle: gobject.idle_add(self._wndPrincipal.window.set_cursor, cursor) else: self._wndPrincipal.window.set_cursor(cursor) def set_status(self, status): pass def set_mensaje(self, text, idle=False, color=None, alerta=''): """ Modifica el string de la pantalla. Acepta pango markup, ser llamado cuando gtk está idle y un color. Ver http://www.pygtk.org/docs/pygtk/pango-markup-language.html """ if color: text = MSG_BIG_SPAN_COLOR % (color, text) else: text = MSG_BIG_SPAN % text if alerta: text = MSG_BIG_SPAN_ALERT % (self.COLOR_ALERTA, alerta) + text if idle: gobject.idle_add(self._lblMensajePantalla.set_label, text) else: self._lblMensajePantalla.set_label(text) if multi_test: p = re.compile(r'<.*?>') logger.debug(">>> " + p.sub('', text)) def get_mensaje(self): """ Obtiene el string de la pantalla, sin el pango markup """ return self._lblMensajePantalla.get_text() def agregar_mensaje(self, text, idle=False): mensaje = self.get_mensaje() + '\n' + text if idle: gobject.idle_add(self._lblMensajePantalla.set_label, mensaje) else: self._lblMensajePantalla.set_label(mensaje) @mostrar_espera @bloqueante def _lector_callback(self, evento_tag, tag=None, datos_extra=None): """ Esta función es llamada cada vez que se detecta un cambio en el lector. """ token = tag.get("token") if token is not None: token = token.upper() if (tag is not None and tag != {} and len(self.valid_tags) > 0 and token not in self.valid_tags): self.set_mensaje(MSG_CHIP_NO_AUTORIZADO) else: if evento_tag == NO_TAG: logger.debug(">>> " + evento_tag) elif evento_tag == TAG_ERROR: logger.debug(evento_tag) self.set_mensaje(MSG_ERROR_LEER_CHIP) elif evento_tag == TAG_VACIO: tipo = tag['tipo'] if tipo: msg = MSG_CHIP_DE_VACIO % tipo else: msg = MSG_CHIP_VACIO self.set_mensaje(msg) elif evento_tag == TAG_DATOS or evento_tag == TAG_ADMIN: if (self.__estado_conexion == self.CONECTADO and tag['tipo'] == TAG_USUARIO_MSA): self.set_mensaje(MSG_AUTENTICANDO_USUARIO) thread.start_new_thread(self.__autenticar, (tag['datos'], )) # salgo para no desbloquear al final: return elif (self.__estado_conexion == self.AUTENTICADO and tag['clase'] == CLASE_ICODE2): if tag['tipo'] == TAG_RECUENTO: if tag['datos'] is None: self.set_mensaje(MSG_CONTENIDO_CHIP) else: self.set_mensaje(MSG_ENVIANDO_DATOS) if multi_test: # a veces esto se ejecutaba despues del # thread de enviar gobject.idle_add(self._elimimar_vista_acta) if not ACTA_DESGLOSADA: self.set_mensaje(MSG_ENVIANDO_DATOS) thread.start_new_thread( self.__enviar_recuento, (tag['datos'], )) else: self.set_mensaje(MSG_RESTO_ACTAS) thread.start_new_thread( self.agregar_acta, (tag['datos'], )) # salgo para no desbloquear al final: return elif tag['tipo'] in (TAG_USUARIO_MSA, TAG_PRESIDENTE_MESA): pass # Debería informalo? else: self.set_mensaje(MSG_CHIP_NO_TIPO_RECUENTO) else: if tag['clase'] == CLASE_ICODE2: self.set_mensaje(MSG_CHIP_NO_ICODE2 % tag['tipo']) elif tag['clase'] == CLASE_MIFARE: self.set_mensaje(MSG_CHIP_NO_RECUENTO) if self.lock: logger.debug("%s: libero lock manual!" % "_lector_callback") self.lock.release() @desbloqueante def agregar_acta(self, data): recuento = Recuento.desde_tag(data) data_mesa = None for mesa in self._estados_mesas: if mesa[0][2] == recuento.mesa.numero and mesa[0][1] \ not in (ESTADO_OK, ESTADO_PUBLICADA): data_mesa = mesa break if data_mesa is not None: dict_actas = self._actas.get(recuento.mesa.codigo) if dict_actas is None: self._actas[recuento.mesa.codigo] = {} dict_actas = self._actas.get(recuento.mesa.codigo) dict_actas[recuento.cod_categoria] = recuento recopiladas = [] for categoria in data_mesa[1:]: if categoria[0] == recuento.cod_categoria: categoria[3] = True gobject.idle_add(self._update_estados_mesas) recopiladas.append(categoria[3]) self._elimimar_vista_acta() self.set_mensaje(MSG_GENERANDO_IMG) imagen = recuento.a_imagen(svg=True, de_muestra=True, tipo=(CIERRE_TRANSMISION, recuento.cod_categoria)) path_destino = join( get_desktop_path(), "%s_%s.svg" % (recuento.mesa.numero, recuento.cod_categoria)) file_destino = open(path_destino, 'w') file_destino.write(imagen) file_destino.close() self._mostrar_acta(path_destino) self.set_mensaje(MSG_RESTO_ACTAS) if all(recopiladas): actas = dict_actas.values() recuento_ = Recuento(actas[0].mesa) campos_especiales = [ "votos_emitidos", "votos_impugnados", "votos_nulos", "votos_recurridos", "votos_observados", "cantidad_ciudadanos", "certificados_impresos" ] primer_acta = actas[0] for campo in campos_especiales: if hasattr(primer_acta, campo): setattr(recuento_, campo, getattr(primer_acta, campo)) for acta in actas: for key, value in acta._resultados.items(): if key[0] == acta.cod_categoria: recuento_._resultados[key] = value datos_tag = recuento_.a_tag() thread.start_new_thread(self.__enviar_recuento, (datos_tag, )) if multi_test: self._ultimo_recuento = datos_tag if len(self._vbox_acta.children()) == 1: botsi = BotonColor(MSG_BIG_SI, "#00cc00", "#ffffff") botno = BotonColor(MSG_BIG_NO, "#ff0000", "#000000") botsi.set_size_request(80, 70) botno.set_size_request(80, 70) botsi.connect("button-release-event", self._confirmar_transmision, datos_tag) botno.connect("button-release-event", self._cancelar_confirmacion) _hbox = gtk.HBox(False) _hbox.set_border_width(10) _hbox.pack_start(botno, padding=100) sep = gtk.VSeparator() sep.set_size_request(80, -1) _hbox.pack_start(sep, True, True) _hbox.pack_start(botsi, padding=100) self._vbox_acta.pack_end(_hbox, False, True) # Descargo y muestro el borrador nuevamente self._vbox_acta.show_all() #self.set_mensaje(MSG_BOLD % respuesta['mensaje'], # idle=True, color=self.COLOR_OK, # alerta=alerta) else: # la mesa no esta para transm self.set_mensaje(MSG_MESA_NO_HABILITADA) @mostrar_espera @desbloqueante def __enviar_recuento(self, datos_tag): """Envía el resultado al servidor web dentro de un thread en segundo plano.""" try: respuesta = self._conexion.enviar_recuento(datos_tag) if respuesta.status_ok(): alerta = '' if 'alerta' in respuesta: alerta = respuesta['alerta'] if 'acta_borrador' in respuesta: # Descargo y muestro el borrador if not ACTA_DESGLOSADA: #self._descargar_y_mostrar_acta(respuesta) self._generar_y_mostrar_acta(datos_tag) self.set_mensaje(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self.borradores.append(datos_tag) #if ACTA_DESGLOSADA: # self.__enviar_recuento(datos_tag) elif 'confirma_definitiva' in respuesta: self._generar_y_mostrar_acta(datos_tag) if len(self._vbox_acta.children()) < 2: # Muestro la botonera de confirmacion botsi = BotonColor(MSG_BIG_SI, "#00cc00", "#ffffff") botno = BotonColor(MSG_BIG_NO, "#ff0000", "#000000") botsi.set_size_request(80, 70) botno.set_size_request(80, 70) botsi.connect("button-release-event", self._confirmar_transmision, datos_tag) botno.connect("button-release-event", self._cancelar_confirmacion) _hbox = gtk.HBox(False) _hbox.set_border_width(10) _hbox.pack_start(botno, padding=100) sep = gtk.VSeparator() sep.set_size_request(80, -1) _hbox.pack_start(sep, True, True) _hbox.pack_start(botsi, padding=100) self._vbox_acta.pack_end(_hbox, False, True) # Descargo y muestro el borrador nuevamente #self._descargar_y_mostrar_acta(respuesta) self._vbox_acta.show_all() self.set_mensaje(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) else: self.set_mensaje(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) else: self.set_mensaje(MSG_ERROR_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: logger.debug(str(e)) self.set_mensaje(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def _confirmar_transmision(self, w=None, ev=None, datos_tag=None): respuesta_conf = self._conexion.confirmar_acta(datos_tag) if respuesta_conf.status_ok() and 'acta_definitiva' in respuesta_conf: # Descargo y muestro el definitivo #self._descargar_y_guardar_acta(respuesta_conf) self.set_mensaje(MSG_BOLD % respuesta_conf['mensaje'], idle=True, color=self.COLOR_OK) self._quitar_mesa(respuesta_conf['mesa']) self._update_estados_mesas() if datos_tag in self.borradores: self.borradores.remove(datos_tag) else: self.set_mensaje(MSG_ERROR_BOLD % respuesta_conf['mensaje'], idle=True, color=self.COLOR_ERR) self._elimimar_vista_acta() def _cancelar_confirmacion(self, w=None, ev=None): self.set_mensaje(MSG_CONFIRMACION_CIERRE_CANCELADA, idle=True, color=self.COLOR_OK) gobject.idle_add(self._elimimar_vista_acta) @mostrar_espera @desbloqueante def __autenticar(self, datos): """ Autentica el usuario contra el servidor web dentro de un thread en segundo plano """ try: (usuario, clave) = datos.split(',') except ValueError: self.set_mensaje(MSG_TARJETA_INVALIDA, idle=True, color=self.COLOR_ERR) else: try: respuesta = self._conexion.autenticar(usuario, clave) if respuesta.status_ok(): self.__set_estado_conexion(self.AUTENTICADO) self.set_mensaje('%s' % respuesta['mensaje'], idle=True, color=self.COLOR_OK) # @TODO: Modificar la lista de estados desde el servidor # para capturar los estados de las mesas y mostrar en # distintos colores como la web de consulta estados = respuesta['estado_mesas'] for mesa in estados: for categoria in mesa[1:]: categoria.append(False) self._estados_mesas = estados self._update_estados_mesas() else: self.set_mensaje(MSG_ERROR_GENERICO % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: logger.debug(str(e)) self.set_mensaje(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def _quitar_mesa(self, id_mesa): nuevos_estados = [] for estado in self._estados_mesas: data_mesa = estado[0] if data_mesa[2].strip() != id_mesa[5:].strip(): nuevos_estados.append([data_mesa] + estado[1:]) self._estados_mesas = nuevos_estados def _update_estados_mesas(self): lbls_mesas = [] for mesa in self._estados_mesas: data_mesa = mesa[0] if data_mesa[1] not in (ESTADO_OK, ESTADO_PUBLICADA): actas = " ".join([ ("<b>%s</b>" % cargo[0]) if cargo[3] else cargo[0] for cargo in mesa[1:] ]) lbl = "Mesa %s%s%s%s" % \ (data_mesa[2], (data_mesa[3] if data_mesa[3] is not None else "X"), " - " if len(actas) else "", actas) lbls_mesas.append(lbl) lbl_pendientes = self._widget_tree.get_widget('label1') gobject.idle_add(lbl_pendientes.set_text, "Pendientes(%s):" % len(lbls_mesas)) gobject.idle_add(self._lbl_mesas.set_markup, "\n".join(lbls_mesas)) def _elimimar_vista_acta(self): for child in self._vbox_acta.get_children(): self._vbox_acta.remove(child) def _generar_y_mostrar_acta(self, datos_tag): self._elimimar_vista_acta() recuento = Recuento.desde_tag(datos_tag) self.set_mensaje(MSG_GENERANDO_IMG) imagen = recuento.a_imagen(svg=True, de_muestra=True, tipo=(CIERRE_TRANSMISION, recuento.cod_categoria)) path_destino = join( get_desktop_path(), "%s_%s.svg" % (recuento.mesa.numero, recuento.cod_categoria)) file_destino = open(path_destino, 'w') file_destino.write(imagen) file_destino.close() self._mostrar_acta(path_destino) self.set_mensaje(MSG_RESTO_ACTAS) def _descargar_y_mostrar_acta(self, respuesta): """ Descarga el acta del servidor y lo muestra al usuario """ if not ACTA_DESGLOSADA: path_destino = join(get_desktop_path(), respuesta['file_name']) url_acta = '%s://%s/%s' % (PROTOCOLO, self.config.HOST, respuesta['url']) self._conexion.descargar(url_acta, path_destino) self._mostrar_acta(path_destino) def _mostrar_acta(self, path_destino): imgviewer = image_viewer.SimpleImageViewer(path_destino) self._vbox_acta.pack_start(imgviewer, True, True) self._vbox_acta.show_all() self._vbox_acta.show() def _descargar_y_guardar_acta(self, respuesta): """ Descarga el acta del servidor y lo guarda al usuario """ path_destino = join(os.getenv('HOME'), respuesta['file_name']) self._conexion.descargar( '%s://%s/%s' % (PROTOCOLO, self.config.HOST, respuesta['url']), path_destino) self._elimimar_vista_acta() def __set_estado_conexion(self, estado_conexion): """ """ self.__estado_conexion = estado_conexion self.__tiempo_conexion = time.time() def salir(self, *args): if self.borradores: msg = MSG_ATENCION_NO_CONFIRMADAS % len(self.borradores) dialog = gtk.MessageDialog(self._wndPrincipal, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK_CANCEL, msg) dialog.connect('response', self._respuesta_salir) dialog.run() dialog.destroy() else: self.salir_definitivo() def _respuesta_salir(self, dialog, response, data=None): if response == gtk.RESPONSE_OK: self.salir_definitivo() def salir_definitivo(self): if self.__modulo_lector: self.__modulo_lector.desconectar_lector() gtk.main_quit()
class TransmisionCore(object): # Constantes de Estados DESCONECTADO = 0 CONECTADO = 1 AUTENTICADO = 2 MARGEN_LECTURAS_CON_COLISION = 2 MARGEN_LECTURAS_ERRONEAS = 2 COLOR_OK = '#006600' COLOR_ERR = '#FF0000' COLOR_ALERTA = '#FF0000' def __init__(self, modo_local=False, hw_init=True): self.logger = get_logger(self.__class__.__name__) self.logger.debug("EHLO") self.config = Configuracion() if self.config.USAR_LOCK == 'true': self.lock = thread.allocate_lock() else: self.lock = None self.logger.debug("__init__: lock = " + str(self.lock)) self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._evento_tag, False) self._conexion = None self._timeout_id = None self._recuento_anterior = None self.inicializar_variables() def inicializar_variables(self): self.valid_tags = None self._actas = {} self._estados_mesas = {} self._acta_desglosada = False @bloqueante def conectar(self): if self.__estado_conexion != self.DESCONECTADO: self.cb_actualizacion_informacion(MSG_CONECTADO) self.cb_actualizar_opciones([('conectar', False), ('desconectar', True), ('diagnostico', True)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion)]) elif self._conexion is not None: self.cb_actualizacion_informacion(MSG_CONECTANDO) elif self.__modulo_lector is None: self.cb_actualizacion_informacion(MSG_LECTOR_DESCONECTADO) self.cb_actualizacion_estado([("lector", MSG_ST_LECTOR % ST_NO_LECTOR)]) else: self.cb_actualizacion_informacion(MSG_CONECTANDO_ESPERE) self._conexion = Conexion( '%s://%s/' % (PROTOCOLO, self.config.HOST), DEBUG, self.config.TIMEOUT) self._conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) self._conexion.set_ca_certificate(self.config.CA_FILE) thread.start_new_thread(self.__conectar, ()) self.__conectar_lector() return if self.lock: self.logger.debug("_conectar: libero lock manual!") self.lock.release() @desbloqueante def __conectar_lector(self): self.__modulo_lector.conectar_lector() return #@mostrar_espera @desbloqueante def __conectar(self): """ Conectar al servidor web usando un thread en segundo plano """ self.logger.info("llamando a conectar") result = self._conexion.test_conexion() if result is not False and result.status_ok(): self._ultima_conexion = datetime.now().strftime('%H:%M:%S') # if self.config.VALIDAR_DATOS: # self._validar_datos() self.valid_tags = [b64decode(tag).upper() for tag in result._dict['tags']] self.__set_estado_conexion(self.CONECTADO) self.cb_actualizar_opciones([('conectar', False), ('desconectar', True), ('diagnostico', True)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion)]) self.cb_actualizacion_informacion(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) self.logger.debug("Configurando envío de ECHO al servidor.") gobject.idle_add(self.__run_echo_loop) else: error = self._conexion.diagnosticar() if error is self._conexion.UNKNOW_ERROR: ayuda = "" elif error is self._conexion.CONNECTION_ERROR: ayuda = MSG_COMPRUEBE_CONEXION elif error is self._conexion.SSL_ERROR: ayuda = MSG_VERIFIQUE_CERTIFICADOS else: ayuda = "" self._conexion = None self.cb_actualizacion_informacion(MSG_INTENTE_NUEVAMENTE % ayuda, idle=True, color=self.COLOR_ERR) self.cb_actualizar_opciones([('conectar', True), ('desconectar', False), ('diagnostico', False)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_DESCONECTADO), ("ultima_conexion", '')]) def __run_echo_loop(self): """ Setea el loop dentro del cual se envia un ECHO al servidor. """ if self._timeout_id is not None: gobject.source_remove(self._timeout_id) self._timeout_id = gobject.timeout_add_seconds( PING_EVERY, self.__echo) return False def __echo(self): self._ultima_conexion = datetime.now().strftime('%H:%M:%S') result = self._conexion.test_conexion() if result.status_ok(): self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion)]) else: self.logger.debug('Se perdió la conexión') self.cb_perdida_conexion() self.desconectar_red() return True def desconectar(self): self.logger.info("Desconectando") self.desconectar_red() self.desconectar_hw() def desconectar_red(self): """ Borra la conexión, cambia el estado a desconectado y además limpia el loop de echo """ self.logger.debug("Limpiando la conexión al servidor") self._conexion = None self.inicializar_variables() self.__set_estado_conexion(self.DESCONECTADO) self.cb_actualizar_opciones([('conectar', True), ('desconectar', False), ('diagnostico', False)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_DESCONECTADO), ("ultima_conexion", '')]) self.cb_actualizacion_informacion(MSG_INICIO) if self._timeout_id is not None: gobject.source_remove(self._timeout_id) def desconectar_hw(self): """ Desconecta el hardware del lector """ self.logger.debug("Desconectando el hw del lector") self.__modulo_lector.desconectar_lector() def descargar_certificados(self, usuario, password): pass def preferencias(self): pass def preferencias(self, preferencias): pass def obtener_acta(self): pass #@mostrar_espera def confirmar_recuento(self, recuento): try: respuesta = self._conexion.confirmar_acta(recuento) if respuesta.status_ok(): alerta = '' if 'alerta' in respuesta: alerta = respuesta['alerta'] self._reiniciar_estados_categorias(respuesta['id_ubicacion']) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self._actualizar_estado_mesa(respuesta['id_ubicacion'], confirmada=True) else: self.cb_actualizacion_informacion(MSG_ERROR_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) @desbloqueante def __agregar_acta(self, recuento): pass #@mostrar_espera @desbloqueante def __enviar_recuento(self, recuento): """ Envía el resultado al servidor web dentro de un thread en segundo plano. """ try: respuesta = self._conexion.enviar_recuento(recuento) if respuesta.status_ok(): alerta = '' if 'alerta' in respuesta: alerta = respuesta['alerta'] if 'cod_categoria' in respuesta: self._actualizar_estado_categoria( respuesta['id_ubicacion'], respuesta['cod_categoria']) if 'acta_borrador' in respuesta: if self._recuento_anterior != recuento: self.cb_reiniciar_vista_confirmacion() self._reiniciar_estados_categorias( respuesta['id_ubicacion']) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self._actualizar_estado_mesa(respuesta['id_ubicacion']) self.cb_mostrar_acta(respuesta['img_acta'], usar_pestana=self._acta_desglosada) elif 'confirma_definitiva' in respuesta: self.cb_confirmacion(recuento) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self.cb_mostrar_acta(respuesta['img_acta'], usar_pestana=self._acta_desglosada) self._actualizar_estado_mesa(respuesta['id_ubicacion'], borrador=True) else: self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self.cb_reiniciar_vista_confirmacion() else: self.cb_actualizacion_informacion(MSG_ERROR_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) self.cb_reiniciar_vista_confirmacion() except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) self.cb_reiniciar_vista_confirmacion() def _actualizar_estado_mesa(self, ubicacion, borrador=False, confirmada=False): if ubicacion in self._estados_mesas: estado_actual = self._estados_mesas[ubicacion]['estado'] if estado_actual == ESTADO_ESPERA or borrador: self._estados_mesas[ubicacion]['estado'] = ESTADO_PRIMERA_CARGA elif estado_actual == ESTADO_PRIMERA_CARGA and confirmada: self._estados_mesas[ubicacion]['estado'] = ESTADO_OK self._estados_mesas[ubicacion]['cargos'] = {} self.cb_actualizacion_mesas() def _actualizar_estado_categoria(self, ubicacion, cod_categoria): if ubicacion in self._estados_mesas: if cod_categoria in self._estados_mesas[ubicacion]['cargos']: self._estados_mesas[ubicacion]['cargos'][cod_categoria] \ ['estado'] += 1 self.cb_actualizacion_mesas(activa=ubicacion) def _reiniciar_estados_categorias(self, ubicacion): if ubicacion in self._estados_mesas: for dato in self._estados_mesas[ubicacion]['cargos'].values(): dato['estado'] = 0 def _validar_recuento(self, recuento): pass def _validar_datos(self): # @TODO: Verificar si los datos que posee el cliente son válidos # encontrar un método para verificar esto msg = '' destino = '/tmp/datos_actualizados' destino_tmp = '/tmp' version_datos = ConfiguracionSistema.one(codigo='db_version').valor self.logger.debug( 'Verificando datos locales: {}'.format(version_datos)) respuesta = self._conexion.obtener_datos_servidor(version_datos) self.logger.debug( 'Verificando datos remotos: {}'.format(respuesta['version'])) if len(respuesta['archivo']) > 0: actualizar_datos(respuesta['ubicacion'], respuesta['archivo'], destino, destino_tmp) # Borro la cache del objeto configuracion cache_name = ConfiguracionSistema.get_cache_name() if cache_name is not None and hasattr(ConfiguracionSistema.cache, cache_name): ConfiguracionSistema.cache.clear(cache_name) # Defino un nuevo origen de datos set_data_source(destino) else: msg = 'no ' self.logger.debug("Funcion: obtener datos del servidor, " "Los datos para la ubicación {} {} han sido " "actualizados".format(respuesta['ubicacion'], msg)) def _validar_certificados(self): pass #@mostrar_espera @desbloqueante def autenticar(self, datos): """ Autentica el usuario contra el servidor web dentro de un thread en segundo plano """ try: (usuario, clave) = datos.split(',') except ValueError: self.cb_actualizacion_informacion(MSG_TARJETA_INVALIDA, idle=True, color=self.COLOR_ERR) else: try: respuesta = self._conexion.autenticar(usuario, clave) if respuesta.status_ok(): self.__set_estado_conexion(self.AUTENTICADO) self.cb_actualizacion_informacion('%s' % respuesta['mensaje'], idle=True, color=self.COLOR_OK) estados = respuesta['estado_mesas'] self._acta_desglosada, self._estados_mesas = \ estados_mesas_dict(estados) self.cb_actualizacion_mesas() else: self.cb_actualizacion_informacion(MSG_ERROR_GENERICO % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def certificados(self): pass def certificados(self, certificados): pass def mesas(self): return self._estados_mesas def __set_estado_conexion(self, estado_conexion): """ """ self.__estado_conexion = estado_conexion def __del__(self): self.logger.info("Desconectando") self.desconectar() #@mostrar_espera @bloqueante def _evento_tag(self, evento_tag, tag=None, datos_extra=None): """ Esta función es llamada cada vez que se detecta un cambio en el lector. """ token = tag.get("token") if token is not None: token = token.upper() if (tag is not None and tag != {} and len(self.valid_tags) > 0 and token not in self.valid_tags): self.cb_actualizacion_informacion(MSG_CHIP_NO_AUTORIZADO) else: if evento_tag == NO_TAG: self.logger.debug(">>> " + evento_tag) elif evento_tag == TAG_ERROR: self.logger.debug(evento_tag) self.cb_actualizacion_informacion(MSG_ERROR_LEER_CHIP) elif evento_tag == TAG_VACIO: tipo = tag['tipo'] if tipo == TAG_NO_ENTRA: msg = MSG_CHIP_NO_ENTRA elif tipo: msg = MSG_CHIP_DE_VACIO % tipo else: msg = MSG_CHIP_VACIO self.cb_actualizacion_informacion(msg) elif evento_tag == TAG_DATOS or evento_tag == TAG_ADMIN: if (self.__estado_conexion == self.CONECTADO and tag['tipo'] == TAG_USUARIO_MSA): self.cb_actualizacion_informacion(MSG_AUTENTICANDO_USUARIO) thread.start_new_thread(self.autenticar, (tag['datos'],)) # salgo para no desbloquear al final: return elif (self.__estado_conexion == self.AUTENTICADO and tag['clase'] == CLASE_ICODE2): if tag['tipo'] == TAG_RECUENTO: if tag['datos'] is None: self.cb_actualizacion_informacion( MSG_CONTENIDO_CHIP) else: if not self._acta_desglosada: self.cb_actualizacion_informacion( MSG_ENVIANDO_DATOS) thread.start_new_thread(self.__enviar_recuento, (tag['datos'], )) else: self.cb_actualizacion_informacion( MSG_RESTO_ACTAS) thread.start_new_thread(self.__enviar_recuento, (tag['datos'], )) # salgo para no desbloquear al final: return elif tag['tipo'] in (TAG_USUARIO_MSA, TAG_PRESIDENTE_MESA): pass # Debería informalo? elif tag['tipo'] in (TAG_INICIO, TAG_ADDENDUM): pass # Espera a que le llegue el evento tag recuento elif tag['tipo'] == TAG_NO_ENTRA: self.cb_actualizacion_informacion(MSG_CHIP_NO_ENTRA) else: self.cb_actualizacion_informacion( MSG_CHIP_NO_TIPO_RECUENTO) else: if tag['clase'] == CLASE_ICODE2: self.cb_actualizacion_informacion( MSG_CHIP_NO_ICODE2 % tag['tipo']) elif tag['clase'] == CLASE_MIFARE: self.cb_actualizacion_informacion(MSG_CHIP_NO_RECUENTO) if self.lock: self.logger.debug("%s: libero lock manual!" % "_lector_callback") self.lock.release() def __verificar_estado_servidor_tx(self, url): _conexion = Conexion(url, DEBUG, self.config.TIMEOUT) _conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) _conexion.set_ca_certificate(self.config.CA_FILE) result = _conexion.test_conexion() estado = result["status"] if result else "Error de conexion" return estado def __verificar_estado(self, pruebas): for prueba in pruebas: verificador = prueba[2] estado = verificador(prueba[1]) print "ESTADO:", estado self.logger.debug("Realizando prueba %d al sitio %s: %s", prueba[0], prueba[1], estado) self.cb_fin_prueba_estados(prueba[:2] + (estado, )) def verificar_estado(self): pruebas = [ (0, "Conexión a internet", "http://www.google.com.ar", status_for_url), (1, "Conexión al servidor de Transmisión", '{}://{}/'.format( PROTOCOLO, self.config.HOST), self.__verificar_estado_servidor_tx), (2, "Conexión al sitio de Operaciones", '{}://{}'.format( PROTOCOLO_CERTS, self.config.HOST_CERTS), status_for_url)] paginas_pruebas = [(p[0], p[2], p[3]) for p in pruebas] lista_pruebas = [p[:-1] for p in pruebas] thread.start_new_thread(self.__verificar_estado, (paginas_pruebas, )) return lista_pruebas #@mostrar_espera def __diagnostico(self, ips, pruebas): resultados = {} for ip in ips: resultados[ip] = {} for prueba in pruebas: cmd = prueba[1] % ip proc = Popen(['bash', '-c', cmd], stdout=PIPE, stderr=PIPE) out, err = proc.communicate() proc.wait() resultados[ip][prueba[0]] = out respuesta = self._conexion.enviar_diagnostico(resultados) self.cb_actualizacion_informacion(respuesta['mensaje']) def diagnostico(self): if self._conexion is not None: ips = ['8.8.8.8'] # Lista de pruebas compuesta por (clave, comando) pruebas = [ ('alive', '(ping -c 1 %s >/dev/null && echo 0) || echo 1;'), ('ping', 'ping -i 0.2 -c 5 %s | tail -n 1 | cut -d " " -f 4'), ('mtr', 'mtr --report --no-dns %s'), ('dig', 'dig %s'), ('dig_other', 'dig %s @8.8.8.8') ] thread.start_new_thread(self.__diagnostico, (ips, pruebas, )) # ------------------------------------------------------------------------# # Metodos que deben implementarse en el UI # # ------------------------------------------------------------------------# def esperando_evento(self, esperando, idle=False): """ Muestra al usuario actividad indicando que se esta procesando algo. """ raise NotImplemented def cb_actualizacion_mesas(self): """ Callback para que la UI actualice la información de las mesas. """ raise NotImplemented def cb_actualizacion_estado(self, status): """ Callback de actualización de estados """ raise NotImplemented def cb_actualizacion_informacion(self, text, idle=False, color=None, alerta=''): """ Callback para el envio de información a mostrar al usuario. """ raise NotImplemented def cb_confirmacion(self, datos_tag): """ Callback de confirmación de recuentos """ raise NotImplemented def cb_mostrar_acta(self, lista_imagenes, usar_pestana=False): """ Callback para mostrar la/s imagen/es de las actas Recibe un listado de actas con la siguiente estructura [(cod_categoria, descripcion, idx_categoria, imagen)] """ raise NotImplemented def cb_actualizar_opciones(self, lista_botones): """ Callback para interactuar con las acciones disponibles. """ raise NotImplemented def cb_perdida_conexion(self): """ Callback llamado unicamente cuando el echo_loop detecta que no hay conectividad con el servidor """ raise NotImplemented def cb_fin_prueba_estados(self, datos_prueba): """ Callback llamado cuando se finaliza una prueba de la pantalla de estado """ raise NotImplemented def cb_reiniciar_vista_confirmacion(self): """ Callback llamado cuando se reinicia la vista de confirmación de acta """ raise NotImplemented
class TransmisionCore(object): # Constantes de Estados DESCONECTADO = 0 CONECTADO = 1 AUTENTICADO = 2 MARGEN_LECTURAS_CON_COLISION = 2 MARGEN_LECTURAS_ERRONEAS = 2 COLOR_OK = '#006600' COLOR_ERR = '#FF0000' COLOR_ALERTA = '#FF0000' def __init__(self, modo_local=False, hw_init=True): self.logger = get_logger(self.__class__.__name__) self.logger.debug("EHLO") self.config = Configuracion() if self.config.USAR_LOCK == 'true': self.lock = thread.allocate_lock() else: self.lock = None self.logger.debug("__init__: lock = " + str(self.lock)) self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._evento_tag, False) self._conexion = None self._timeout_id = None self._recuento_anterior = None self.inicializar_variables() def inicializar_variables(self): self.valid_tags = None self._actas = {} self._estados_mesas = {} self._acta_desglosada = False @bloqueante def conectar(self): if self.__estado_conexion != self.DESCONECTADO: self.cb_actualizacion_informacion(MSG_CONECTADO) self.cb_actualizar_opciones([('conectar', False), ('desconectar', True), ('diagnostico', True)]) self.cb_actualizacion_estado([ ("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion) ]) elif self._conexion is not None: self.cb_actualizacion_informacion(MSG_CONECTANDO) elif self.__modulo_lector is None: self.cb_actualizacion_informacion(MSG_LECTOR_DESCONECTADO) self.cb_actualizacion_estado([("lector", MSG_ST_LECTOR % ST_NO_LECTOR)]) else: self.cb_actualizacion_informacion(MSG_CONECTANDO_ESPERE) self._conexion = Conexion( '%s://%s/' % (PROTOCOLO, self.config.HOST), DEBUG, self.config.TIMEOUT) self._conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) self._conexion.set_ca_certificate(self.config.CA_FILE) thread.start_new_thread(self.__conectar, ()) self.__conectar_lector() return if self.lock: self.logger.debug("_conectar: libero lock manual!") self.lock.release() @desbloqueante def __conectar_lector(self): self.__modulo_lector.conectar_lector() return #@mostrar_espera @desbloqueante def __conectar(self): """ Conectar al servidor web usando un thread en segundo plano """ self.logger.info("llamando a conectar") result = self._conexion.test_conexion() if result is not False and result.status_ok(): self._ultima_conexion = datetime.now().strftime('%H:%M:%S') # if self.config.VALIDAR_DATOS: # self._validar_datos() self.valid_tags = [ b64decode(tag).upper() for tag in result._dict['tags'] ] self.__set_estado_conexion(self.CONECTADO) self.cb_actualizar_opciones([('conectar', False), ('desconectar', True), ('diagnostico', True)]) self.cb_actualizacion_estado([ ("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion) ]) self.cb_actualizacion_informacion(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) self.logger.debug("Configurando envío de ECHO al servidor.") gobject.idle_add(self.__run_echo_loop) else: error = self._conexion.diagnosticar() if error is self._conexion.UNKNOW_ERROR: ayuda = "" elif error is self._conexion.CONNECTION_ERROR: ayuda = MSG_COMPRUEBE_CONEXION elif error is self._conexion.SSL_ERROR: ayuda = MSG_VERIFIQUE_CERTIFICADOS else: ayuda = "" self._conexion = None self.cb_actualizacion_informacion(MSG_INTENTE_NUEVAMENTE % ayuda, idle=True, color=self.COLOR_ERR) self.cb_actualizar_opciones([('conectar', True), ('desconectar', False), ('diagnostico', False)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_DESCONECTADO), ("ultima_conexion", '')]) def __run_echo_loop(self): """ Setea el loop dentro del cual se envia un ECHO al servidor. """ if self._timeout_id is not None: gobject.source_remove(self._timeout_id) self._timeout_id = gobject.timeout_add_seconds(PING_EVERY, self.__echo) return False def __echo(self): self._ultima_conexion = datetime.now().strftime('%H:%M:%S') result = self._conexion.test_conexion() if result.status_ok(): self.cb_actualizacion_estado([ ("conexion", MSG_ST_CONEXION % ST_CONECTADO), ("ultima_conexion", MSG_ST_ULTIMA_CONEXION % self._ultima_conexion) ]) else: self.logger.debug('Se perdió la conexión') self.cb_perdida_conexion() self.desconectar_red() return True def desconectar(self): self.logger.info("Desconectando") self.desconectar_red() self.desconectar_hw() def desconectar_red(self): """ Borra la conexión, cambia el estado a desconectado y además limpia el loop de echo """ self.logger.debug("Limpiando la conexión al servidor") self._conexion = None self.inicializar_variables() self.__set_estado_conexion(self.DESCONECTADO) self.cb_actualizar_opciones([('conectar', True), ('desconectar', False), ('diagnostico', False)]) self.cb_actualizacion_estado([("conexion", MSG_ST_CONEXION % ST_DESCONECTADO), ("ultima_conexion", '')]) self.cb_actualizacion_informacion(MSG_INICIO) if self._timeout_id is not None: gobject.source_remove(self._timeout_id) def desconectar_hw(self): """ Desconecta el hardware del lector """ self.logger.debug("Desconectando el hw del lector") self.__modulo_lector.desconectar_lector() def descargar_certificados(self, usuario, password): pass def preferencias(self): pass def preferencias(self, preferencias): pass def obtener_acta(self): pass #@mostrar_espera def confirmar_recuento(self, recuento): try: respuesta = self._conexion.confirmar_acta(recuento) if respuesta.status_ok(): alerta = '' if 'alerta' in respuesta: alerta = respuesta['alerta'] self._reiniciar_estados_categorias(respuesta['id_ubicacion']) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self._actualizar_estado_mesa(respuesta['id_ubicacion'], confirmada=True) else: self.cb_actualizacion_informacion(MSG_ERROR_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) @desbloqueante def __agregar_acta(self, recuento): pass #@mostrar_espera @desbloqueante def __enviar_recuento(self, recuento): """ Envía el resultado al servidor web dentro de un thread en segundo plano. """ try: respuesta = self._conexion.enviar_recuento(recuento) if respuesta.status_ok(): alerta = '' if 'alerta' in respuesta: alerta = respuesta['alerta'] if 'cod_categoria' in respuesta: self._actualizar_estado_categoria( respuesta['id_ubicacion'], respuesta['cod_categoria']) if 'acta_borrador' in respuesta: if self._recuento_anterior != recuento: self.cb_reiniciar_vista_confirmacion() self._reiniciar_estados_categorias( respuesta['id_ubicacion']) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self._actualizar_estado_mesa(respuesta['id_ubicacion']) self.cb_mostrar_acta(respuesta['img_acta'], usar_pestana=self._acta_desglosada) elif 'confirma_definitiva' in respuesta: self.cb_confirmacion(recuento) self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self.cb_mostrar_acta(respuesta['img_acta'], usar_pestana=self._acta_desglosada) self._actualizar_estado_mesa(respuesta['id_ubicacion'], borrador=True) else: self.cb_actualizacion_informacion(MSG_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_OK, alerta=alerta) self.cb_reiniciar_vista_confirmacion() else: self.cb_actualizacion_informacion(MSG_ERROR_BOLD % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) self.cb_reiniciar_vista_confirmacion() except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) self.cb_reiniciar_vista_confirmacion() def _actualizar_estado_mesa(self, ubicacion, borrador=False, confirmada=False): if ubicacion in self._estados_mesas: estado_actual = self._estados_mesas[ubicacion]['estado'] if estado_actual == ESTADO_ESPERA or borrador: self._estados_mesas[ubicacion]['estado'] = ESTADO_PRIMERA_CARGA elif estado_actual == ESTADO_PRIMERA_CARGA and confirmada: self._estados_mesas[ubicacion]['estado'] = ESTADO_OK self._estados_mesas[ubicacion]['cargos'] = {} self.cb_actualizacion_mesas() def _actualizar_estado_categoria(self, ubicacion, cod_categoria): if ubicacion in self._estados_mesas: if cod_categoria in self._estados_mesas[ubicacion]['cargos']: self._estados_mesas[ubicacion]['cargos'][cod_categoria] \ ['estado'] += 1 self.cb_actualizacion_mesas(activa=ubicacion) def _reiniciar_estados_categorias(self, ubicacion): if ubicacion in self._estados_mesas: for dato in self._estados_mesas[ubicacion]['cargos'].values(): dato['estado'] = 0 def _validar_recuento(self, recuento): pass def _validar_datos(self): # @TODO: Verificar si los datos que posee el cliente son válidos # encontrar un método para verificar esto msg = '' destino = '/tmp/datos_actualizados' destino_tmp = '/tmp' version_datos = ConfiguracionSistema.one(codigo='db_version').valor self.logger.debug( 'Verificando datos locales: {}'.format(version_datos)) respuesta = self._conexion.obtener_datos_servidor(version_datos) self.logger.debug('Verificando datos remotos: {}'.format( respuesta['version'])) if len(respuesta['archivo']) > 0: actualizar_datos(respuesta['ubicacion'], respuesta['archivo'], destino, destino_tmp) # Borro la cache del objeto configuracion cache_name = ConfiguracionSistema.get_cache_name() if cache_name is not None and hasattr(ConfiguracionSistema.cache, cache_name): ConfiguracionSistema.cache.clear(cache_name) # Defino un nuevo origen de datos set_data_source(destino) else: msg = 'no ' self.logger.debug("Funcion: obtener datos del servidor, " "Los datos para la ubicación {} {} han sido " "actualizados".format(respuesta['ubicacion'], msg)) def _validar_certificados(self): pass #@mostrar_espera @desbloqueante def autenticar(self, datos): """ Autentica el usuario contra el servidor web dentro de un thread en segundo plano """ try: (usuario, clave) = datos.split(',') except ValueError: self.cb_actualizacion_informacion(MSG_TARJETA_INVALIDA, idle=True, color=self.COLOR_ERR) else: try: respuesta = self._conexion.autenticar(usuario, clave) if respuesta.status_ok(): self.__set_estado_conexion(self.AUTENTICADO) self.cb_actualizacion_informacion('%s' % respuesta['mensaje'], idle=True, color=self.COLOR_OK) estados = respuesta['estado_mesas'] self._acta_desglosada, self._estados_mesas = \ estados_mesas_dict(estados) self.cb_actualizacion_mesas() else: self.cb_actualizacion_informacion(MSG_ERROR_GENERICO % respuesta['mensaje'], idle=True, color=self.COLOR_ERR) except Exception as e: self.logger.debug(str(e)) self.cb_actualizacion_informacion(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def certificados(self): pass def certificados(self, certificados): pass def mesas(self): return self._estados_mesas def __set_estado_conexion(self, estado_conexion): """ """ self.__estado_conexion = estado_conexion def __del__(self): self.logger.info("Desconectando") self.desconectar() #@mostrar_espera @bloqueante def _evento_tag(self, evento_tag, tag=None, datos_extra=None): """ Esta función es llamada cada vez que se detecta un cambio en el lector. """ token = tag.get("token") if token is not None: token = token.upper() if (tag is not None and tag != {} and len(self.valid_tags) > 0 and token not in self.valid_tags): self.cb_actualizacion_informacion(MSG_CHIP_NO_AUTORIZADO) else: if evento_tag == NO_TAG: self.logger.debug(">>> " + evento_tag) elif evento_tag == TAG_ERROR: self.logger.debug(evento_tag) self.cb_actualizacion_informacion(MSG_ERROR_LEER_CHIP) elif evento_tag == TAG_VACIO: tipo = tag['tipo'] if tipo == TAG_NO_ENTRA: msg = MSG_CHIP_NO_ENTRA elif tipo: msg = MSG_CHIP_DE_VACIO % tipo else: msg = MSG_CHIP_VACIO self.cb_actualizacion_informacion(msg) elif evento_tag == TAG_DATOS or evento_tag == TAG_ADMIN: if (self.__estado_conexion == self.CONECTADO and tag['tipo'] == TAG_USUARIO_MSA): self.cb_actualizacion_informacion(MSG_AUTENTICANDO_USUARIO) thread.start_new_thread(self.autenticar, (tag['datos'], )) # salgo para no desbloquear al final: return elif (self.__estado_conexion == self.AUTENTICADO and tag['clase'] == CLASE_ICODE2): if tag['tipo'] == TAG_RECUENTO: if tag['datos'] is None: self.cb_actualizacion_informacion( MSG_CONTENIDO_CHIP) else: if not self._acta_desglosada: self.cb_actualizacion_informacion( MSG_ENVIANDO_DATOS) thread.start_new_thread( self.__enviar_recuento, (tag['datos'], )) else: self.cb_actualizacion_informacion( MSG_RESTO_ACTAS) thread.start_new_thread( self.__enviar_recuento, (tag['datos'], )) # salgo para no desbloquear al final: return elif tag['tipo'] in (TAG_USUARIO_MSA, TAG_PRESIDENTE_MESA): pass # Debería informalo? elif tag['tipo'] in (TAG_INICIO, TAG_ADDENDUM): pass # Espera a que le llegue el evento tag recuento elif tag['tipo'] == TAG_NO_ENTRA: self.cb_actualizacion_informacion(MSG_CHIP_NO_ENTRA) else: self.cb_actualizacion_informacion( MSG_CHIP_NO_TIPO_RECUENTO) else: if tag['clase'] == CLASE_ICODE2: self.cb_actualizacion_informacion(MSG_CHIP_NO_ICODE2 % tag['tipo']) elif tag['clase'] == CLASE_MIFARE: self.cb_actualizacion_informacion(MSG_CHIP_NO_RECUENTO) if self.lock: self.logger.debug("%s: libero lock manual!" % "_lector_callback") self.lock.release() def __verificar_estado_servidor_tx(self, url): _conexion = Conexion(url, DEBUG, self.config.TIMEOUT) _conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) _conexion.set_ca_certificate(self.config.CA_FILE) result = _conexion.test_conexion() estado = result["status"] if result else "Error de conexion" return estado def __verificar_estado(self, pruebas): for prueba in pruebas: verificador = prueba[2] estado = verificador(prueba[1]) print "ESTADO:", estado self.logger.debug("Realizando prueba %d al sitio %s: %s", prueba[0], prueba[1], estado) self.cb_fin_prueba_estados(prueba[:2] + (estado, )) def verificar_estado(self): pruebas = [(0, "Conexión a internet", "http://www.google.com.ar", status_for_url), (1, "Conexión al servidor de Transmisión", '{}://{}/'.format(PROTOCOLO, self.config.HOST), self.__verificar_estado_servidor_tx), (2, "Conexión al sitio de Operaciones", '{}://{}'.format(PROTOCOLO_CERTS, self.config.HOST_CERTS), status_for_url)] paginas_pruebas = [(p[0], p[2], p[3]) for p in pruebas] lista_pruebas = [p[:-1] for p in pruebas] thread.start_new_thread(self.__verificar_estado, (paginas_pruebas, )) return lista_pruebas #@mostrar_espera def __diagnostico(self, ips, pruebas): resultados = {} for ip in ips: resultados[ip] = {} for prueba in pruebas: cmd = prueba[1] % ip proc = Popen(['bash', '-c', cmd], stdout=PIPE, stderr=PIPE) out, err = proc.communicate() proc.wait() resultados[ip][prueba[0]] = out respuesta = self._conexion.enviar_diagnostico(resultados) self.cb_actualizacion_informacion(respuesta['mensaje']) def diagnostico(self): if self._conexion is not None: ips = ['8.8.8.8'] # Lista de pruebas compuesta por (clave, comando) pruebas = [ ('alive', '(ping -c 1 %s >/dev/null && echo 0) || echo 1;'), ('ping', 'ping -i 0.2 -c 5 %s | tail -n 1 | cut -d " " -f 4'), ('mtr', 'mtr --report --no-dns %s'), ('dig', 'dig %s'), ('dig_other', 'dig %s @8.8.8.8') ] thread.start_new_thread(self.__diagnostico, ( ips, pruebas, )) # ------------------------------------------------------------------------# # Metodos que deben implementarse en el UI # # ------------------------------------------------------------------------# def esperando_evento(self, esperando, idle=False): """ Muestra al usuario actividad indicando que se esta procesando algo. """ raise NotImplemented def cb_actualizacion_mesas(self): """ Callback para que la UI actualice la información de las mesas. """ raise NotImplemented def cb_actualizacion_estado(self, status): """ Callback de actualización de estados """ raise NotImplemented def cb_actualizacion_informacion(self, text, idle=False, color=None, alerta=''): """ Callback para el envio de información a mostrar al usuario. """ raise NotImplemented def cb_confirmacion(self, datos_tag): """ Callback de confirmación de recuentos """ raise NotImplemented def cb_mostrar_acta(self, lista_imagenes, usar_pestana=False): """ Callback para mostrar la/s imagen/es de las actas Recibe un listado de actas con la siguiente estructura [(cod_categoria, descripcion, idx_categoria, imagen)] """ raise NotImplemented def cb_actualizar_opciones(self, lista_botones): """ Callback para interactuar con las acciones disponibles. """ raise NotImplemented def cb_perdida_conexion(self): """ Callback llamado unicamente cuando el echo_loop detecta que no hay conectividad con el servidor """ raise NotImplemented def cb_fin_prueba_estados(self, datos_prueba): """ Callback llamado cuando se finaliza una prueba de la pantalla de estado """ raise NotImplemented def cb_reiniciar_vista_confirmacion(self): """ Callback llamado cuando se reinicia la vista de confirmación de acta """ raise NotImplemented
class TransmisionApp(object): # Constantes de Estados DESCONECTADO = 0 CONECTADO = 1 AUTENTICADO = 2 MARGEN_LECTURAS_CON_COLISION = 2 MARGEN_LECTURAS_ERRONEAS = 2 COLOR_OK = "#006600" COLOR_ERR = "#FF0000" COLOR_ALERTA = "#FF0000" def __init__(self, hw_init=True): self.config = Configuracion() if self.config.USAR_LOCK == "true": self.lock = thread.allocate_lock() else: self.lock = None logger.debug("__init__: lock = " + str(self.lock)) self._widget_tree = gtk.glade.XML(self.config.GLADE_FILE) self._wndPrincipal = self._widget_tree.get_widget("wndPrincipal") self._lblMensajePantalla = self._widget_tree.get_widget("lblMensajePantalla") self._vbox_acta = self._widget_tree.get_widget("vbox_acta") self._widget_vport = self._widget_tree.get_widget("vp_acta") self._status = self._widget_tree.get_widget("status") self._lbl_mesas = self._widget_tree.get_widget("lbl_mesas") self.__set_estado_conexion(self.DESCONECTADO) self.__modulo_lector = ModuloLector(self._lector_callback, False) self._conexion = None self._timeout_id = None eventos = { "on_wndPrincipal_delete": self.salir, "on_tlbSalir_clicked": self.salir, "on_mnuArchivoSalir_activate": self.salir, "on_mnuAyudaAcercaDe_activate": self.mostrar_acerca_de, "on_mnuAccionesRed_activate": self.configurar_red, "on_mnuAccionesImportar_activate": self.mostrar_importar_claves, "on_tblPreferencias_clicked": self.mostrar_preferencias, "on_tlbConectar_clicked": self.conectar, "on_tblConfigurarRed_clicked": self.configurar_red, "on_tblImportarCert_clicked": self.mostrar_importar_claves, "on_tlbBajarCert_clicked": self.mostrar_autenticacion, } self._widget_tree.signal_autoconnect(eventos) self.borradores = [] self.valid_tags = None self._actas = {} def mostrar_autenticacion(self, menuitem): autenticacion = Autenticacion(self.config, self) autenticacion.mostrar() def mostrar(self): if not DEBUG: self._wndPrincipal.maximize() self._wndPrincipal.show() def mostrar_acerca_de(self, menuitem): acerca_de = AcercaDe(self.config) acerca_de.mostrar() def mostrar_preferencias(self, menuitem): preferencias = Preferencias(self.config) preferencias.mostrar() def mostrar_importar_claves(self, menuitem): wnd_importar_claves = ImportarClaves(self.config) wnd_importar_claves.mostrar() def configurar_red(self, *args): try: subprocess.Popen(PATH_NETWORK_CONF_APP, shell=False) except OSError as e: logger.error(MSG_ERROR_CONF_APP % str(e.message)) @bloqueante def conectar(self, toolbutton): if self.__estado_conexion != self.DESCONECTADO: self.set_mensaje(MSG_CONECTADO) self.set_status(("conexion", ST_CONECTADO)) elif self._conexion is not None: self.set_mensaje(MSG_CONECTANDO) elif self.__modulo_lector is None: self.set_mensaje(MSG_LECTOR_DESCONECTADO % self.config.PUERTO_LECTOR) self.set_status(("lector", ST_NO_LECTOR)) else: self.set_mensaje(MSG_CONECTANDO_ESPERE) self._conexion = Conexion("%s://%s/" % (PROTOCOLO, self.config.HOST), DEBUG, self.config.TIMEOUT) self._conexion.set_https_keys(self.config.KEY_FILE, self.config.CERT_FILE) self._conexion.set_ca_certificate(self.config.CA_FILE) thread.start_new_thread(self.__conectar, ()) self.__conectar_lector() return if self.lock: logger.debug("_conectar: libero lock manual!") self.lock.release() @desbloqueante def __conectar_lector(self): self.set_mensaje(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) self.__modulo_lector.conectar_lector() return @mostrar_espera @desbloqueante def __conectar(self): """Conectar al servidor web usando un thread en segundo plano""" logger.info("llamando a conectar") result = self._conexion.test_conexion() if result is not False and result.status_ok(): if self.config.VERIFICAR_DATOS: self._verificar_datos() self.valid_tags = [b64decode(tag).upper() for tag in result._dict["tags"]] self.__set_estado_conexion(self.CONECTADO) self.set_status(("conexion", ST_CONECTADO)) self.set_mensaje(MSG_AHORA_PASE_TARJETA, idle=True, color=self.COLOR_OK) gobject.idle_add(self._set_timeout) else: error = self._conexion.diagnosticar() if error is self._conexion.UNKNOW_ERROR: ayuda = "" elif error is self._conexion.CONNECTION_ERROR: ayuda = MSG_COMPRUEBE_CONEXION elif error is self._conexion.SSL_ERROR: ayuda = MSG_VERIFIQUE_CERTIFICADOS else: ayuda = "" self.set_mensaje(MSG_INTENTE_NUEVAMENTE % ayuda, idle=True, color=self.COLOR_ERR) self._conexion = None self.set_status(("conexion", ST_DESCONECTADO)) def _set_timeout(self): if self._timeout_id is not None: gobject.source_remove(self._timeout_id) self._timeout_id = gobject.timeout_add_seconds(PING_EVERY, self._conexion.test_conexion) return False @desbloqueante def __desconectar(self): """Cierra la conexión al servidor web usando un thread en segundo plano""" if self._timeout_id is not None: gobject.source_remove(self._timeout_id) logger.info("llamando a conectar") self._conexion.desconectar() self.set_status(("conexion", ST_DESCONECTADO)) def _verificar_datos(self): # @TODO: Verificar si los datos que posee el cliente son válidos # encontrar un método para verificar esto msg = "" destino = "/tmp/datos_actualizados" destino_tmp = "/tmp" version_datos = ConfiguracionSistema.one(codigo="db_version").valor logger.debug("Verificando datos locales: {}".format(version_datos)) respuesta = self._conexion.obtener_datos_servidor(version_datos) logger.debug("Verificando datos remotos: {}".format(respuesta["version"])) if len(respuesta["archivo"]) > 0: actualizar_datos(respuesta["ubicacion"], respuesta["archivo"], destino, destino_tmp) # Borro la cache del objeto configuracion cache_name = ConfiguracionSistema.get_cache_name() if cache_name is not None and hasattr(ConfiguracionSistema.cache, cache_name): ConfiguracionSistema.cache.clear(cache_name) # Defino un nuevo origen de datos set_data_source(destino) else: msg = "no " logger.debug( "Funcion: obtener datos del servidor, " "Los datos para la ubicación {} {}han sido " "actualizados".format(respuesta["ubicacion"], msg) ) def esperando_evento(self, ocupado, idle=True): """ Setea el puntero de la ventana principal en ocupado (True) o flecha estándar (False). Es idle por defecto porque se lo llama casi exclusivamente desde el segundo hilo. """ if ocupado: cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) else: cursor = None if idle: gobject.idle_add(self._wndPrincipal.window.set_cursor, cursor) else: self._wndPrincipal.window.set_cursor(cursor) def set_status(self, status): pass def set_mensaje(self, text, idle=False, color=None, alerta=""): """ Modifica el string de la pantalla. Acepta pango markup, ser llamado cuando gtk está idle y un color. Ver http://www.pygtk.org/docs/pygtk/pango-markup-language.html """ if color: text = MSG_BIG_SPAN_COLOR % (color, text) else: text = MSG_BIG_SPAN % text if alerta: text = MSG_BIG_SPAN_ALERT % (self.COLOR_ALERTA, alerta) + text if idle: gobject.idle_add(self._lblMensajePantalla.set_label, text) else: self._lblMensajePantalla.set_label(text) if multi_test: p = re.compile(r"<.*?>") logger.debug(">>> " + p.sub("", text)) def get_mensaje(self): """ Obtiene el string de la pantalla, sin el pango markup """ return self._lblMensajePantalla.get_text() def agregar_mensaje(self, text, idle=False): mensaje = self.get_mensaje() + "\n" + text if idle: gobject.idle_add(self._lblMensajePantalla.set_label, mensaje) else: self._lblMensajePantalla.set_label(mensaje) @mostrar_espera @bloqueante def _lector_callback(self, evento_tag, tag=None, datos_extra=None): """ Esta función es llamada cada vez que se detecta un cambio en el lector. """ token = tag.get("token") if token is not None: token = token.upper() if tag is not None and tag != {} and len(self.valid_tags) > 0 and token not in self.valid_tags: self.set_mensaje(MSG_CHIP_NO_AUTORIZADO) else: if evento_tag == NO_TAG: logger.debug(">>> " + evento_tag) elif evento_tag == TAG_ERROR: logger.debug(evento_tag) self.set_mensaje(MSG_ERROR_LEER_CHIP) elif evento_tag == TAG_VACIO: tipo = tag["tipo"] if tipo: msg = MSG_CHIP_DE_VACIO % tipo else: msg = MSG_CHIP_VACIO self.set_mensaje(msg) elif evento_tag == TAG_DATOS or evento_tag == TAG_ADMIN: if self.__estado_conexion == self.CONECTADO and tag["tipo"] == TAG_USUARIO_MSA: self.set_mensaje(MSG_AUTENTICANDO_USUARIO) thread.start_new_thread(self.__autenticar, (tag["datos"],)) # salgo para no desbloquear al final: return elif self.__estado_conexion == self.AUTENTICADO and tag["clase"] == CLASE_ICODE2: if tag["tipo"] == TAG_RECUENTO: if tag["datos"] is None: self.set_mensaje(MSG_CONTENIDO_CHIP) else: self.set_mensaje(MSG_ENVIANDO_DATOS) if multi_test: # a veces esto se ejecutaba despues del # thread de enviar gobject.idle_add(self._elimimar_vista_acta) if not ACTA_DESGLOSADA: self.set_mensaje(MSG_ENVIANDO_DATOS) thread.start_new_thread(self.__enviar_recuento, (tag["datos"],)) else: self.set_mensaje(MSG_RESTO_ACTAS) thread.start_new_thread(self.agregar_acta, (tag["datos"],)) # salgo para no desbloquear al final: return elif tag["tipo"] in (TAG_USUARIO_MSA, TAG_PRESIDENTE_MESA): pass # Debería informalo? else: self.set_mensaje(MSG_CHIP_NO_TIPO_RECUENTO) else: if tag["clase"] == CLASE_ICODE2: self.set_mensaje(MSG_CHIP_NO_ICODE2 % tag["tipo"]) elif tag["clase"] == CLASE_MIFARE: self.set_mensaje(MSG_CHIP_NO_RECUENTO) if self.lock: logger.debug("%s: libero lock manual!" % "_lector_callback") self.lock.release() @desbloqueante def agregar_acta(self, data): recuento = Recuento.desde_tag(data) data_mesa = None for mesa in self._estados_mesas: if mesa[0][2] == recuento.mesa.numero and mesa[0][1] not in (ESTADO_OK, ESTADO_PUBLICADA): data_mesa = mesa break if data_mesa is not None: dict_actas = self._actas.get(recuento.mesa.codigo) if dict_actas is None: self._actas[recuento.mesa.codigo] = {} dict_actas = self._actas.get(recuento.mesa.codigo) dict_actas[recuento.cod_categoria] = recuento recopiladas = [] for categoria in data_mesa[1:]: if categoria[0] == recuento.cod_categoria: categoria[3] = True gobject.idle_add(self._update_estados_mesas) recopiladas.append(categoria[3]) self._elimimar_vista_acta() self.set_mensaje(MSG_GENERANDO_IMG) imagen = recuento.a_imagen(svg=True, de_muestra=True, tipo=(CIERRE_TRANSMISION, recuento.cod_categoria)) path_destino = join(get_desktop_path(), "%s_%s.svg" % (recuento.mesa.numero, recuento.cod_categoria)) file_destino = open(path_destino, "w") file_destino.write(imagen) file_destino.close() self._mostrar_acta(path_destino) self.set_mensaje(MSG_RESTO_ACTAS) if all(recopiladas): actas = dict_actas.values() recuento_ = Recuento(actas[0].mesa) campos_especiales = [ "votos_emitidos", "votos_impugnados", "votos_nulos", "votos_recurridos", "votos_observados", "cantidad_ciudadanos", "certificados_impresos", ] primer_acta = actas[0] for campo in campos_especiales: if hasattr(primer_acta, campo): setattr(recuento_, campo, getattr(primer_acta, campo)) for acta in actas: for key, value in acta._resultados.items(): if key[0] == acta.cod_categoria: recuento_._resultados[key] = value datos_tag = recuento_.a_tag() thread.start_new_thread(self.__enviar_recuento, (datos_tag,)) if multi_test: self._ultimo_recuento = datos_tag if len(self._vbox_acta.children()) == 1: botsi = BotonColor(MSG_BIG_SI, "#00cc00", "#ffffff") botno = BotonColor(MSG_BIG_NO, "#ff0000", "#000000") botsi.set_size_request(80, 70) botno.set_size_request(80, 70) botsi.connect("button-release-event", self._confirmar_transmision, datos_tag) botno.connect("button-release-event", self._cancelar_confirmacion) _hbox = gtk.HBox(False) _hbox.set_border_width(10) _hbox.pack_start(botno, padding=100) sep = gtk.VSeparator() sep.set_size_request(80, -1) _hbox.pack_start(sep, True, True) _hbox.pack_start(botsi, padding=100) self._vbox_acta.pack_end(_hbox, False, True) # Descargo y muestro el borrador nuevamente self._vbox_acta.show_all() # self.set_mensaje(MSG_BOLD % respuesta['mensaje'], # idle=True, color=self.COLOR_OK, # alerta=alerta) else: # la mesa no esta para transm self.set_mensaje(MSG_MESA_NO_HABILITADA) @mostrar_espera @desbloqueante def __enviar_recuento(self, datos_tag): """Envía el resultado al servidor web dentro de un thread en segundo plano.""" try: respuesta = self._conexion.enviar_recuento(datos_tag) if respuesta.status_ok(): alerta = "" if "alerta" in respuesta: alerta = respuesta["alerta"] if "acta_borrador" in respuesta: # Descargo y muestro el borrador if not ACTA_DESGLOSADA: # self._descargar_y_mostrar_acta(respuesta) self._generar_y_mostrar_acta(datos_tag) self.set_mensaje(MSG_BOLD % respuesta["mensaje"], idle=True, color=self.COLOR_OK, alerta=alerta) self.borradores.append(datos_tag) # if ACTA_DESGLOSADA: # self.__enviar_recuento(datos_tag) elif "confirma_definitiva" in respuesta: self._generar_y_mostrar_acta(datos_tag) if len(self._vbox_acta.children()) < 2: # Muestro la botonera de confirmacion botsi = BotonColor(MSG_BIG_SI, "#00cc00", "#ffffff") botno = BotonColor(MSG_BIG_NO, "#ff0000", "#000000") botsi.set_size_request(80, 70) botno.set_size_request(80, 70) botsi.connect("button-release-event", self._confirmar_transmision, datos_tag) botno.connect("button-release-event", self._cancelar_confirmacion) _hbox = gtk.HBox(False) _hbox.set_border_width(10) _hbox.pack_start(botno, padding=100) sep = gtk.VSeparator() sep.set_size_request(80, -1) _hbox.pack_start(sep, True, True) _hbox.pack_start(botsi, padding=100) self._vbox_acta.pack_end(_hbox, False, True) # Descargo y muestro el borrador nuevamente # self._descargar_y_mostrar_acta(respuesta) self._vbox_acta.show_all() self.set_mensaje(MSG_BOLD % respuesta["mensaje"], idle=True, color=self.COLOR_OK, alerta=alerta) else: self.set_mensaje(MSG_BOLD % respuesta["mensaje"], idle=True, color=self.COLOR_OK, alerta=alerta) else: self.set_mensaje(MSG_ERROR_BOLD % respuesta["mensaje"], idle=True, color=self.COLOR_ERR) except Exception as e: logger.debug(str(e)) self.set_mensaje(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def _confirmar_transmision(self, w=None, ev=None, datos_tag=None): respuesta_conf = self._conexion.confirmar_acta(datos_tag) if respuesta_conf.status_ok() and "acta_definitiva" in respuesta_conf: # Descargo y muestro el definitivo # self._descargar_y_guardar_acta(respuesta_conf) self.set_mensaje(MSG_BOLD % respuesta_conf["mensaje"], idle=True, color=self.COLOR_OK) self._quitar_mesa(respuesta_conf["mesa"]) self._update_estados_mesas() if datos_tag in self.borradores: self.borradores.remove(datos_tag) else: self.set_mensaje(MSG_ERROR_BOLD % respuesta_conf["mensaje"], idle=True, color=self.COLOR_ERR) self._elimimar_vista_acta() def _cancelar_confirmacion(self, w=None, ev=None): self.set_mensaje(MSG_CONFIRMACION_CIERRE_CANCELADA, idle=True, color=self.COLOR_OK) gobject.idle_add(self._elimimar_vista_acta) @mostrar_espera @desbloqueante def __autenticar(self, datos): """ Autentica el usuario contra el servidor web dentro de un thread en segundo plano """ try: (usuario, clave) = datos.split(",") except ValueError: self.set_mensaje(MSG_TARJETA_INVALIDA, idle=True, color=self.COLOR_ERR) else: try: respuesta = self._conexion.autenticar(usuario, clave) if respuesta.status_ok(): self.__set_estado_conexion(self.AUTENTICADO) self.set_mensaje("%s" % respuesta["mensaje"], idle=True, color=self.COLOR_OK) # @TODO: Modificar la lista de estados desde el servidor # para capturar los estados de las mesas y mostrar en # distintos colores como la web de consulta estados = respuesta["estado_mesas"] for mesa in estados: for categoria in mesa[1:]: categoria.append(False) self._estados_mesas = estados self._update_estados_mesas() else: self.set_mensaje(MSG_ERROR_GENERICO % respuesta["mensaje"], idle=True, color=self.COLOR_ERR) except Exception as e: logger.debug(str(e)) self.set_mensaje(MSG_ERROR_COMUNICACION, idle=True, color=self.COLOR_ERR) def _quitar_mesa(self, id_mesa): nuevos_estados = [] for estado in self._estados_mesas: data_mesa = estado[0] if data_mesa[2].strip() != id_mesa[5:].strip(): nuevos_estados.append([data_mesa] + estado[1:]) self._estados_mesas = nuevos_estados def _update_estados_mesas(self): lbls_mesas = [] for mesa in self._estados_mesas: data_mesa = mesa[0] if data_mesa[1] not in (ESTADO_OK, ESTADO_PUBLICADA): actas = " ".join([("<b>%s</b>" % cargo[0]) if cargo[3] else cargo[0] for cargo in mesa[1:]]) lbl = "Mesa %s%s%s%s" % ( data_mesa[2], (data_mesa[3] if data_mesa[3] is not None else "X"), " - " if len(actas) else "", actas, ) lbls_mesas.append(lbl) lbl_pendientes = self._widget_tree.get_widget("label1") gobject.idle_add(lbl_pendientes.set_text, "Pendientes(%s):" % len(lbls_mesas)) gobject.idle_add(self._lbl_mesas.set_markup, "\n".join(lbls_mesas)) def _elimimar_vista_acta(self): for child in self._vbox_acta.get_children(): self._vbox_acta.remove(child) def _generar_y_mostrar_acta(self, datos_tag): self._elimimar_vista_acta() recuento = Recuento.desde_tag(datos_tag) self.set_mensaje(MSG_GENERANDO_IMG) imagen = recuento.a_imagen(svg=True, de_muestra=True, tipo=(CIERRE_TRANSMISION, recuento.cod_categoria)) path_destino = join(get_desktop_path(), "%s_%s.svg" % (recuento.mesa.numero, recuento.cod_categoria)) file_destino = open(path_destino, "w") file_destino.write(imagen) file_destino.close() self._mostrar_acta(path_destino) self.set_mensaje(MSG_RESTO_ACTAS) def _descargar_y_mostrar_acta(self, respuesta): """ Descarga el acta del servidor y lo muestra al usuario """ if not ACTA_DESGLOSADA: path_destino = join(get_desktop_path(), respuesta["file_name"]) url_acta = "%s://%s/%s" % (PROTOCOLO, self.config.HOST, respuesta["url"]) self._conexion.descargar(url_acta, path_destino) self._mostrar_acta(path_destino) def _mostrar_acta(self, path_destino): imgviewer = image_viewer.SimpleImageViewer(path_destino) self._vbox_acta.pack_start(imgviewer, True, True) self._vbox_acta.show_all() self._vbox_acta.show() def _descargar_y_guardar_acta(self, respuesta): """ Descarga el acta del servidor y lo guarda al usuario """ path_destino = join(os.getenv("HOME"), respuesta["file_name"]) self._conexion.descargar("%s://%s/%s" % (PROTOCOLO, self.config.HOST, respuesta["url"]), path_destino) self._elimimar_vista_acta() def __set_estado_conexion(self, estado_conexion): """ """ self.__estado_conexion = estado_conexion self.__tiempo_conexion = time.time() def salir(self, *args): if self.borradores: msg = MSG_ATENCION_NO_CONFIRMADAS % len(self.borradores) dialog = gtk.MessageDialog( self._wndPrincipal, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK_CANCEL, msg ) dialog.connect("response", self._respuesta_salir) dialog.run() dialog.destroy() else: self.salir_definitivo() def _respuesta_salir(self, dialog, response, data=None): if response == gtk.RESPONSE_OK: self.salir_definitivo() def salir_definitivo(self): if self.__modulo_lector: self.__modulo_lector.desconectar_lector() gtk.main_quit()