-
Finalidad general: representa a un usuario que desea realizar pedidos.
-
Estado interno:
pub struct Comensal {
id: u32,
ubicacion: Ubicacion,
nodo_comensal: Option<Addr<NodoComensal>>,
pedido_realizado: Option<Pedido>,
logger: Logger,
}-
Mensajes que recibe y cómo se comporta:
InfoRestaurantes: selecciona algún restaurante al azar y hace un nuevo pedido.PagoRechazado: hace un sleep y vuelve a pedir la info de restaurantes (VerRestaurantesInterno) para hacer otro pedido.ProgresoPedido: sólo lo recibe cuando el pedido finalizó, por lo que realiza un sleep y vuelve a pedir la info de los restaurantes para hacer otro pedido.LLegoPedido: informa al comensal que el pedido llegó correctamente, luego realiza un sleep y vuelve a pedir la info de los restaurantes para hacer otro pedido.
-
Mensajes que envía:
VerRestaurantesInterno: Envia al NodoComensal para solicitar la información de los restaurantes disponibles.Pedir: Envia al NodoComensal, con el restaurante elegido.
-
Finalidad general: representa la instancia de la aplicación del comensal. Actúa como intermediario entre el comensal y el resto de aplicaciones.
-
Estado interno:
pub struct NodoComensal {
ip: SocketAddrV4,
restaurantes: HashMap<u32, SocketAddrV4>, // id_restaurante -> direccion
gateway_pagos: SocketAddrV4,
comensal: Addr<Comensal>,
logger: Logger,
}-
Mensajes que recibe y cómo se comporta:
VerRestaurantesInterno: envía unVerRestaurantesa algún NodoRestaurante al azar. Si no es capaz de enviarlo, vuelve a intentar con otro, hasta que pueda hacerlo.Pedir: recibe el pedido del comensal y envíaIntentoPagoa Pagos.ProgresoPedido: si el estado es que el pedido fue cancelado o entregado, lo reenvía al comensal para que éste haga un nuevo pedido.PagoRechazado: envíaPagoRechazadoaComensalpara que éste vuelva a intentar hacer un pedido.PagoAutorizado: envía elPedidocorrespondiente a ese pago a un NodoRestaurante al azar.InfoRestaurantes: lo reenvía alComensalcon la información de los restaurantes disponibles.LLegoPedido: lo reenvia alComensalpara informarle que su pedido llegó correctamente.
-
Mensajes que envía:
VerRestaurantes: Envia al NodoRestaurante para obtener la información de los restaurantes disponibles.Pedir: Envia el pedido a un NodoRestaurante.InfoRestaurantes: Envia al Comensal con la información de los restaurantes disponibles.IntentoPago: Envia el pedido al Gateway de Pagos para intentar realizar el pago.PagoRechazado: Informa al comensal que el pago fue rechazado y que debe intentar nuevamente.LLegoPedido: Informa al comensal que su pedido llegó correctamente.ProgresoPedido: Envia el progreso del pedido al comensal.
pub struct InfoRestaurantes {
info_restaurantes: HashMap<u64, Ubicacion>, // id_restaurante -> Ubicacion
}struct VerRestaurantesInterno {
info_comensal: InfoComensal,
}struct Pedir {
id_pedido: u32,
monto: f32,
id_restaurante: u32,
id_comensal: u32,
}struct ProgresoPedido {
id_pedido: u32,
estado: EstadoPedido,
}struct PagoRechazado {
id_pedido: u32,
}struct PagoAutorizado {
id_pedido: u32,
}struct VerRestaurantes {
info_comensal: InfoComensal,
addr_app: Ipv4Addr,
}struct IntentoPago {
id_pedido: u32,
monto: f32,
id_comensal: u32
}struct TarjetaRechazada {
id_pedido: u32,
}struct LLegoPedido {
id_pedido: u32,
info_comensal: InfoComensal,
}pub struct Ubicacion(u32, u32);
pub enum EstadoPedido {
Pendiente,
Preparando,
Listo,
EnCamino,
Entregado,
Cancelado,
}-
Ver restaurantes disponibles:
-
Cuando el comensal quiere ver los restaurantes disponibles, envía un mensaje
VerRestaurantesInternoa la aplicación del comensal. -
La aplicación del comensal envía un mensaje
VerRestaurantesa la aplicación de restaurantes, que responde con un mensajeInfoRestaurantes. -
La aplicación del comensal reenvía este mensaje al comensal.
-
-
Realizar un pedido:
-
Cuando el comensal quiere realizar un pedido, envía un mensaje
Pedidoa la aplicación del comensal. -
La aplicación del comensal envía un mensaje
IntentoPagoa la aplicación de pagos, que responde con un mensajePagoAutorizadooPagoRechazado. -
Si el pago es autorizado, la aplicación del comensal envía un mensaje
Pedidoa la aplicación de restaurantes. -
Si el pago es rechazado, la aplicación del comensal envía un mensaje
TarjetaRechazadaal comensal.
-
Se utilizará TCP para envío de mensajes y UDP para recepción de mensajes, porque los pedidos pueden culminarse con el comensal caido, no se necesita acuse de recibo de los mensajes que se envían al comensal.
-
Finalidad general: representa a un restaurante que recibe pedidos, los envía a repartidores, los procesa y comunica el progreso al comensal.
-
Estado interno:
struct Restaurante {
id: u32,
ubicacion: Ubicacion,
receptor_progreso: Option<Addr<A>>,
pedidos_recibidos: HashMap<u32, Pedido>,
cocinas: Vec<Addr<Cocina<Restaurante<A>>>>,
cantidad_cocinas: usize,
cocina_proxima: usize,
logger: Logger,
}-
Mensajes que recibe:
ObtenerUbicación: Tras recibirlo devuelve su ubicación a NodoRestaurantePedir: Recibe el pedido y posteriormente envíaPedidoACocinara cocinaPedidoCocido: Actualiza el estado del pedido y notifica al receptor de progreso conProgresoPedido.AddrNodo: Asigna el nodo al restaurante que es contenido en este
-
Mensajes que envía:
PedidoACocinarProgresoPedido
-
Finalidad general: Simula la preparación de los pedidos que le llegan al restaurante.
-
Estado interno:
struct Cocina{
pedidos: VecDeque<u32>, // Usamos VecDeque para eficiencia al quitar elementos del frente
cocina_en_uso: bool,
recepcion: Addr<A>,
}-
Mensajes que recibe:
PedidoACocinar: Comienza a simular la preparación del pedido, y se envía a si mismoIniciarCoccionIniciarCoccion: Añade el pedido a la cola y empieza a cocinar, cuando termina envíaPedidoCocidoa restaurante
-
Mensajes que envía:
PedidoCocidoIniciarCoccion
-
Finalidad general: representa la instancia de la aplicación del restaurante. Actúa como intermediario entre el restaurante y el resto de aplicaciones (repartidores, comensales y los demás restaurantes).
-
Estado interno:
struct NodoRestaurante {
restaurante: (Addr<Restaurante<NodoRestaurante>>, u32),
pedidos: HashMap<u32, (SocketAddrV4, Ubicacion)>,
restaurantes: HashMap<u32, SocketAddrV4>,
ip_repartidores: Ipv4Addr,
rango_repartidores: (u16, u16),
local: SocketAddrV4,
lider: Option<SocketAddrV4>,
siguiente: SocketAddrV4,
anterior: SocketAddrV4,
rango_nodos: (u16, u16),
logger: Logger,
}-
Mensajes que recibe:
PedidoTomado: se desliga de la responsabilidad de ese pedido (lo marca como finalizado en el log compartido y lo elimina de entre los pedidos actuales)Pedir: Si es el nodo correcto, le envíaPediraRestaurante. Si no se reenvia al lider, y se hace llegar al nodo correcto.ProgresoPedido: si no es el lider, lo envía al lider. Si es el lider, lo envía al restaurante correspondiente a ese pedido. Si el restaurante lo recibe es porque el pedido se terminó de preparar, por lo que envíaPedidoTomadoal restaurante para tomar el pedido y entregarlo.InfoRestaurantesInterno(nodo): envíaInfoRestaurantesal comensal correspondienteVerRestaurantes: si no es el lider, lo reenvia al lider. Si es el lider, calcula los restaurantes cercanos a ese comensal y responde conInfoRestaurantesInternoal nodo que se lo envió, o conInfoRestaurantessi el comensal le habló directamente.
-
Mensajes que envía:
ObtenerUbicacionInfoRestaurantesInfoRestaurantesInternoProgresoPedidoPedirPedidoListoPedidoTomadoInfoRestaurantesActualizarSiguienteCambiarSiguienteRingElectionKeepAlive
struct Pedir {
pub id_pedido: u32,
pub monto: f32,
pub id_restaurante: u32,
pub ubicacion_comensal: Ubicacion,
pub dir_comensal: SocketAddrV4,
}struct PedidoTomado {
id_pedido: u32,
id_restaurante: u32,
}struct ProgresoPedido {
id_pedido: u32,
estado: EstadoPedido,
}struct PedidoListo {
id_pedido: u32,
id_restaurante: u32,
ubicacion_comensal: Ubicacion,
ubicacion_restaurante: Ubicacion,
direccion_comensal: SocketAddr,
}struct PedidoACocinar {
id_pedido: u32,
}struct IniciarCoccion {}struct InfoRestaurantesInterno {
pub comensal: SocketAddrV4,
info_restaurantes: HashMap<u32, Ubicacion>,
ubicacion_comensal: Ubicacion,
}struct AddrNodo<A>
where
A: Actor + Send + 'static,
{
addr: Addr<A>,
}pub struct InfoRestaurante {
id: u32,
ubicacion: Ubicacion,
}-
Procesar pedidos nuevos:
- Cuando llega un
Pedidonuevo, si el receptor es el destinatario lo procesa, sino lo envia al lider para que lo asigne correctamente - Si el
Restauranteno esta disponible cuando llega elPedido, el lider avisa alComensalcon unProgresoPedidocancelado. - Conforme
Restauranteprocesa los pedidos, envia actualizaciones deProgresoPedidoalComensal. - El restaurante envía
PedidoListoa algún nodo de la app de repartidores para que sea asignado a algún repartidor.
- Cuando llega un
-
Notificar pedidos listos:
- Una vez que el
Pedidose encuentre listo, se avisa a la aplicación de repartidores. - Espera a recibir
PedidoTomadopara desligarse de la responsabilidad. - En caso de no recibir respuesta, cancela el pedido e informa a
Comensal.
- Una vez que el
-
Elección de líder Se utilizará el algoritmo de ring para elección de líder.
-
Log de pedidos de todos los restaurantes Se utilizará commit de dos fases para llevar adelante un log que tenga el progreso de los pedidos de todos los restaurantes. Cada pedido, aparte de toda la información importante, tendrá un timestamp. Cada cierto tiempo, el líder se fijará en los pedidos que están abiertos. Si la antigüedad de ese pedido supera cierto umbral, se comunicará con el restaurante que tiene la responsabilidad de ese pedido. Si el restaurante no está conectado (eso se puede confirmar mediante TCP) el líder cancela el pedido y avisa al comensal.
Se utilizará TCP para envío y recepción de mensajes.
-
Finalidad general: representa a un repartidor que toma pedidos, los retira por el restaurante y los entrega al comensal.
-
Estado interno:
struct Repartidor {
ubicacion: Ubicacion,
pedido_actual: Option<Pedido>,
restaurante_actual: Option<(u32, Ubicacion)>,
dir_comensal_actual: Option<SocketAddrV4>,
nodo_repartidor: Option<Addr<NodoRepartidor>>,
}-
Mensajes que recibe:
- OfrecerPedido: si el repartidor no está ocupado y se encuentra a menos de 100 unidades de distancia del restaurante,
tiene un 75% de probabilidad de aceptar el pedido, respondiendo true en el handler. Una vez que acepta el pedido,
comienza a simular el viaje al restaurante, y luego al comensal. Al llegar al restaurante, envía
PedidoTomadoa suNodoRepartidor, para que éste lo reenvíe al restaurante. Al llegar al comensal, envíaLlegoPedidoyCobraralNodoRepartidor, que los reenvía al comensal y al gateway de pagos, respectivamente. - InfoPedidoEnCurso: actualiza la información relacionada al pedido actual.
- OfrecerPedido: si el repartidor no está ocupado y se encuentra a menos de 100 unidades de distancia del restaurante,
tiene un 75% de probabilidad de aceptar el pedido, respondiendo true en el handler. Una vez que acepta el pedido,
comienza a simular el viaje al restaurante, y luego al comensal. Al llegar al restaurante, envía
-
Mensajes que envía:
PedidoTomadoLlegoPedidoCobrar
-
Finalidad general: representa la instancia de la aplicación de repartidor. Actúa como intermediario entre el repartidor y el resto de aplicaciones y de nodos de repartidores.
-
Estado interno:
pub struct NodoRepartidor {
repartidor: Addr<Repartidor>,
pagos: SocketAddrV4,
local: SocketAddrV4,
lider: Option<SocketAddrV4>,
siguiente: SocketAddrV4,
anterior: SocketAddrV4,
rango_nodos: (u16, u16),
id_pedido_actual: Option<u32>,
ip_restaurantes: Ipv4Addr,
rango_restaurantes: (u16, u16),
anillo_actual: Vec<u16>,
pedidos_en_curso: Vec<InfoRepartidorPedido>,
logger: Logger,
}-
Mensajes que recibe:
PedidoListo: El nodo recibe un pedido listo. Intenta ofrecerlo a su repartidor local. Si el repartidor acepta, el nodo envíaInfoPedidoEnCursoal líder. Si el repartidor no lo acepta, el nodo reenvía elOfrecerPedidoal siguiente nodo en el anillo. Si no hay un líder, inicia una elección de líder.OfrecerPedido: El nodo intenta asignar el pedido a su repartidor. Si el repartidor lo acepta, el nodo envíaInfoPedidoEnCursoal líder. Si no, reenvía elOfrecerPedidoal siguiente nodo en el anillo. Si no hay un líder, inicia una elección de líder.RingElection: Maneja la elección de líder. Si es de tipoElection, agrega el puerto del nodo al mensaje y lo reenvía. Si es de tipoCoordinator, establece el líder y actualiza el anillo de nodos. Si era el líder y hay un nuevo líder, envía losInfoRepartidorPedidoque tiene en el buffer al nuevo líder.ActualizarSiguiente: Busca el siguiente nodo disponible en el anillo y actualiza su referencia.KeepAlive: Si no es del nodo que tenía almacenado como anterior, reenvía el mensajeCambiarSiguienteal nodo que tenía como anterior para que "apunte" al nuevo nodo, y envíaSolicitarPedidoEnCursoal líder pidiéndole que le pase al nuevo nodo el pedido que tenía en curso cuando se desconectó (si es que estaba ocupado y no fue cancelado por antigüedad).CambiarSiguiente: Actualiza el siguiente nodo en el anillo.InfoRepartidorPedido: Si es el líder, agrega la información del pedido a su lista de pedidos en curso. Si no es el líder, reenvía el mensaje al líder.InfoPedidoEnCurso: Actualiza la información relacionada al pedido en curso.SolicitarPedidoEnCurso: Si tiene un pedido en curso para el emisor, le envía un mensajeInfoPedidoEnCursocon la información.PedidosEnCursoRepartidores: Actualiza la lista de pedidos en curso del nodo (solo el líder recibe este mensaje).QuitarPedidoDeBuffer: Elimina un pedido del buffer de pedidos en curso.PedidoTomado: reenvía el mensaje a algún restaurante.Cobrar: reenvía el mensaje al gateway de pagos, y envíaQuitarPedidoDeBufferal líder.
-
Mensajes que envía:
OfrecerPedidoCobrarLlegoPedidoPedidoTomadoActualizarSiguienteRingElectionCambiarSiguienteInfoPedidoEnCursoPedidosEnCursoRepartidoresQuitarPedidoDeBufferKeepAliveSolicitarPedidoEnCursoProgresoPedido(en caso de cancelación)
struct AceptarPedido {
id_pedido: u32,
id_repartidor: u32,
}struct Cobrar {
id_pedido: u32,
}struct LlegoPedido {
id_pedido: u32,
direccion_comensal: SocketAddr,
}struct OfrecerPedido {
pedido: PedidoListo,
}struct PedidoListo {
id_pedido: u32,
info_comensal: InfoComensal,
info_restaurante: InfoRestaurante,
direccion_comensal: SocketAddr,
}struct PedidoTomado {
id_pedido: u32,
id_restaurante: u32,
}struct InfoPedidoEnCurso {
dir_comensal: SocketAddrV4,
pedido: Pedido,
info_restaurante: Option<(u32, Ubicacion)>,
}struct InfoRepartidorPedido {
id_pedido: u32,
dir_repartidor: SocketAddrV4,
dir_comensal: SocketAddrV4,
pedido: Pedido,
info_restaurante: Option<(u32, Ubicacion)>,
timestamp: i64,
}struct PedidosEnCursoRepartidores {
pedidos: Vec<InfoRepartidorPedido>,
}struct QuitarPedidoDeBuffer {
id_pedido: u32,
}struct RingElection {
tipo: u8,
puerto_original: u16,
puertos: Vec<u16>,
}struct KeepAlive {
dir_emisor: SocketAddrV4,
}struct CambiarSiguiente {
siguiente: SocketAddrV4,
}struct ActualizarSiguiente {}struct SolicitarPedidoEnCurso {
dir_emisor: SocketAddrV4,
}- Solicitar pedido:
-
Cuando un
PedidoListollega a unNodoRepartidor, este envíaOfrecerPedidoa su repartidor. Si el repartidor acepta el pedido, el nodo envíaInfoPedidoEnCursoal líder para que guarde ese pedido en su buffer. -
El repartidor recibe el
OfrecerPedidoy, si no está ocupado y está cerca del restaurante, tiene un 75% de probabilidad de aceptarlo. -
Si el repartidor no acepta el pedido (ya sea por estar ocupado, lejos o por probabilidad), el
NodoRepartidorreenvía elOfrecerPedidoal siguiente nodo en el anillo para que otro repartidor pueda tomarlo. Esto se repite hasta que algún repartidor acepta o se cancela el pedido.
-
Repartir pedido
-
Cuando el repartidor acepta un
OfrecerPedido, comienza a simular el viaje al restaurante. Cuando llega, envíaPedidoTomadoa suNodoRepartidorpara que este lo reenvíe al restaurante. El restaurante, al recibirPedidoTomado, se desliga de la responsabilidad del pedido. -
Luego, el repartidor simula el viaje hasta el comensal. Al llegar, envía
LlegoPedidoalNodoRepartidor(que lo reenvía al comensal) yCobrartambién alNodoRepartidor(que lo reenvía a la App de Pagos).
-
- Finalmente, el repartidor se desocupa. Si el nodo no es el líder, envía
QuitarPedidoDeBufferal líder para que elimine el pedido de su lista de pedidos en curso.


