HTTPS API REST con python - dudas


#1

Hola,
Estoy probando el servicio MQTT, valorando para mis necesidades:
Todos los mensajes se deben recibir por un cliente que se encuentra detrás de un proxy que no me permite acceder directamente al servidor por puerto 1883
Para ello estoy probando el HTTPS API, con Python, basándome en la librería publicada en GitHub.
He encontrado dos comportamientos, que no sé si se deben a problemas en mi programación, o a limitaciones de la API:

1 - recepción de mensajes con pull: si el cliente está conectado, recibe los nuevos mensajes llegados desde el último pull de la sesión, pero no consigo recibir los mensajes anteriores pendientes de entregar al cliente (sí se reciben si conecto después con un cliente con llamadas al protocolo MQTT directas).

2 - para los mensajes recibidos con pull, en el servidor no quedan marcados como entregados (siguen en unconfirmmed messages). Trabajo con QoS 1 ¿debería de alguna forma enviar el PUBACK, no veo llamada para eso -debería recibirse el packet_id del mensaje, para poder enviar una llamada con el PUBACK al servidor).

¿Alguna aclaración al respecto? Como he dicho, mi problema es que en producción, no podré acceder directamente al protocolo MQTT, pero si a las llamadas a través de HTTPS.
Gracias.


#2

Hola,

Sobre el primer punto, ¿cómo estás conectando? (pasa las partes relevantes de código)
¿Te estás conectando con el clean_session a False?

Sobre el segundo punto, confirmar que no tienes que hacer nada adicional. Un mensaje
recibido por pull debería quedar confirmado. Vamos a hacer algunas pruebas con código
para reproducir el caso que dices para que podamos ver si hay algo raro. Te decimos
algo lo antes posible.

Con respecto a que sólo podrás usar HTTPS para acceder a tu HUB MQTT en producción:
efectivamente, esta es la idea del API HTTPS: soportar entornos limitados por puerto
pero también entornos que sólo tienen posibilidad de conectar con HTTPS por lo que
esta solución debería funcionarte sin problemas.

Lo dicho, te vamos diciendo y quedamos pendientes a que nos facilites más información
sobre el primer punto.

Un saludo.


#3

Primero: Gracias por la respuesta.
Segundo: el script para pruebas lo he basado en las funciones y especificaciones que he encontrado a través del foro
El clean_session está a False, porque de hecho, luego conecto ese mismo cliente con un script que accede directamente al puerto 1883, desde un equipo sin proxy delante, y según el protocolo MQTT, y al realizar la conexión me recupera instantánemante todos los mensajes pendientes que han llegado en el periodo de desconexión sin ningún problema.

Función que uso para la creación de la sesión (python 3.8). El socket de conexión ya lo he abierto previamente ( no sé si hay alguna mejor forma de meter código en el mensaje)

Funcion para crear la sesion

def create_session (client_id, user_name, password, clean_session = True):
#Parte de una conexión de red abierta
dbg (“MQTT CONNECT - mqtt_client=%s, mqtt_user=%s)” % (client_id, user_name))

# build login parameters do login
params = {
    'clientId' : client_id,
    'userName' : user_name,
    'password' : password,
    'cleanSession' : clean_session
}
# send request
conn.request ("POST", "/login", json.dumps (params), headers = {"Connection":" keep-alive"})
result = conn.getresponse()
body   = result.read ()

dbg ("INFO: login request result: %s" % body)
if result.status != 200:
    # close connection
    conn.close ()
    return (False, "LOGIN ERROR: status=%d, reason=%s :: %s" % (result.status, result.reason, body), None)

# Login ok
login_data = json.loads (body)
dbg ("MYQTT CONNECT: login request: status=%d, reason=%s :: %s (token: %s)" % (result.status, result.reason, login_data, login_data['tokenId']))

# return data from login
session = {'login_data' : login_data, 'conn' : conn, 'client_id' : client_id, 'user_name' : user_name}
return (True, "Login ok", session)

Llamada que hago a ella desde mi código:

(status, info, session) = create_session (mqtt_client, mqtt_user, mqtt_password, clean_session = False)


Esto es un ejemplo de lo que muestra la función de conexión en su dbg:
INFO: login request result: b’{“clientId”:“xxx0000”,“validUntil”:1574932504,“stamp”:1574759704,“cleanSession”:false,“tokenId”:“ce7213a5-521f-442e-8145-bafc9adfbea7”}’

Función que uso para llamar al pull:

def pull(session):
“”"
Pide los mensajes pendientes desde la última petición
Parametros:
session – [Object] created by create_session
“”"
# get login session and connection
(conn, login_data, params, headers) = __prepare_headers (session)

# send PULL
dbg ("PULL :: (clientId=%s, userName=%s).." % (session['client_id'], session['user_name']))
conn.request ("POST", "/pull", json.dumps (params), headers)
dbg ("INFO: enviada solicitud de mensajes pendientes para el cliente")
result = conn.getresponse()
body  = result.read ().decode('utf-8')
if result.status != 200:
    return (False, "Error obteniendo mensajes del bróker: status=%d, reason=%s :: %s" % (result.status, result.reason, body))
dbg("Mensaje devuelto: status=%d, reason=%s :: %s" % (result.status, result.reason, body))
return (True, body)

Llamada a recoger mensajes con pull:

(status_pull,info_pull) = pull(session)
if status_pull:
if len(info_pull)>2: #Quiere decir que hay algún mensaje
trataRespuesta(info_pull)
else:
print(“No hay mensajes pendientes”)


La funcion trataRespuesta simplemente trata la cadena recibida, separando las distintas unidades delimitadas por {} y tratándolas con json.
Como comentaba, los mensajes que han entrado desde el anterior pull se reciben, pero lo que veo, y me produce problemas:

  • si han sido enviado con QoS 1 no quedan confirmados
  • no recibo los pendientes de entregar a ese cliente existentes en el broker antes del primer pull realizado para la sesión (parece que es funcionamiento normal del pull según la descripción de la API -mensajes recibidos desde el anterior pull-, pero me supone un problema, ya que no sé cómo recibir esos mensajes a través de la API.