standard seguridad restful practices practicas patterns buenas best erlang protocols otp

erlang - restful - seguridad api rest



Cómo diseñar una API de creación de pila de protocolo Erlang flexible (1)

Insatisfecho con mi enfoque actual, estoy tratando de rediseñar la forma en que creo las pilas de protocolos en Erlang. La función ordenada por importancia:

  1. Actuación

  2. Flexibilidad y velocidad de implementación agregando nuevas variantes de protocolo

  3. Ayudaría al desarrollo explorar las variantes de protocolo del shell

Mi modelo actual ( actualmente descrito en esta pregunta ) está llegando a sus límites además de la fea asimetría de send () por llamada de función y recepción por mensaje.

La imagen general de todo el motor de protocolo se ve así:

La parte de abajo:

  • Hay varios puertos o tal vez también algunas veces un gen_tcp en la parte inferior de cada pila (hay múltiples pilas idénticas para canales independientes, por lo que no podemos ser demasiado estáticos aquí solo registrando procesos, tenemos que pasar Pids a todas partes.

  • Además de los puertos, hay unos pocos módulos que son gestionados por el supervisor (se inició con el sistema y, en ausencia de errores, se queda toda la vida).

Parte superior:

  • Disparado por la ocurrencia del evento (en el sentido general, no en el sentido event_handler) son los extremos del protocolo orientado a la conexión (por ejemplo, con la semántica connect() y close() .

  • El extremo superior de la pila de protocolos probablemente solo se pueda iniciar dinámicamente porque los módulos apilados uno encima de otro para formar la pila se pueden configurar dinámicamente y pueden cambiar de una conexión a otra.

  • Actualmente planeado pasaría una Lista de nombres de módulo + parámetros opcionales desde el nivel superior que se consumen mientras se llama a connect() en la pila.

  • Los procesos de Toplevel se vincularán para que, cuando algo salga mal, la conexión falle.

Tipos de módulos y tipos de comunicación entre ellos

Hay varios tipos de módulos encontrados hasta ahora:

  • Módulos de filtro sin estado

  • Los módulos con estado, algunos gen_server en forma, algunos gen_fsm pero la mayoría probablemente serán simples bucles de servidor ya que la recepción selectiva será útil y simplificará el código con bastante frecuencia.

Tipos de comunicación entre capas:

  • Envío y recepción independientes de paquetes (independientes desde el exterior)

  • Llamadas sincrónicas que envían algo, bloquean hasta que haya una respuesta y luego devuelvan el resultado como valor de retorno.

  • Multiplexores que hablan de múltiples módulos (esa es mi definición aquí para facilitar la discusión)

  • Demultiplexores que tienen diferentes puntos de conexión (nombrados por los átomos actualmente) para hablar con módulos orientados hacia arriba.

Actualmente, mis únicos demultiplexores están en la parte inferior estática de la pila y no en la parte superior creada dinámicamente. Los multiplexores están actualmente en la parte superior.

En las respuestas y comentarios del manejo de mi pregunta anterior relacionada, escuché que, en general, la API solo debería consistir en funciones y no en mensajes, y estoy de acuerdo con esto a menos que se convenza lo contrario.

Disculpe la larga explicación del problema, pero creo que todavía es de uso general para todo tipo de implementación de protocolo.

Escribiré lo que he planeado hasta ahora en las respuestas y también explicaré la implementación resultante y mi experiencia con ello más adelante para lograr algo generalmente útil aquí.


Voy a arrojar lo que he planeado hasta ahora como parte de las respuestas:

  • connect obtiene una Lista de módulos para apilar, pareciendo un proplist en caso de params, por ejemplo:

    connect([module1, module2, {module3, [params3]}], param0, further_params)

    cada capa se quita de la cabeza y llama a las siguientes capas a conectarse.

  • connect() "de alguna manera" pasa referencias divertidas arriba y / o abajo de las capas

    • enviar para asincronizar el envío de la pila será devuelto por el nivel inferior de conexión
    • recv para async recibiendo la pila se pasará como param al nivel inferior connect
    • llamar para enviar la sincronización y esperar a que se devuelva una respuesta - no estoy seguro de cómo manejarlos, probablemente también sea devuelto desde el nivel inferior de conexión
  • Las listas de enrutamiento de multiplexores pueden verse como estas

    connect([module1, multiplexer, [[m_a_1, m_a_2, {m_a_3, [param_a_3]}], [m_b_1, m_b_2], [{m_c_1, [param_c_1]}, m_c_2]], param0, further_params]).

Actualmente decidí que no habría una función adicional para las llamadas sincrónicas, solo estoy usando enviar para ello.

Hay un ejemplo de implementación de la idea en este caso para un módulo que es sin estado: encode/1 y decode/1 hacer algo de transformación hacia atrás en paquetes, por ejemplo, analizar la representación binaria en un registro y volver:

connect(Chan, [Down|Rest], [], Recv_fun) -> {Down_module, Param} = case Down of {F, P} -> {F, P}; F when is_atom (F) -> {F, []} end, Send_fun = Down_module:connect(Chan, Rest, Param, fun(Packet) -> recv(Packet, Recv_fun) end), {ok, fun(Packet) -> send(Packet, Send_fun) end}. send(Packet, Send_fun) -> Send_fun(encode(Packet)). recv(Packet, Recv_fun) -> Recv_fun(decode(Packet)).

Tan pronto como tenga un ejemplo claro, lo publicaré también.