module Mooro class TerminateServer < StandardError end class Server @host: String @port: Integer @max_connections: Integer @stdlog: IO @shutdown: bool @logger: Ractor @supervisor: Thread @workers: Array[Ractor] # Logic on how to serve each client # Server.serve must be a pure function, and any variables must be passed explicitly # The only means of passing a Method or Proc as a nested proc are currently hacky # Mooro's workaround is to define a class method, which is able to be called # This comes with the caveat that no shared object can live in the function body def self.serve: (TCPSocket io) -> untyped def initialize: (Integer max_connections, ?::String host, ?::Integer port, ?IO stdlog) -> void def start: () -> void def stop: () -> void # Create a logger Ractor # The logger logs messages to @stdlog with the timestamp of when the # message was processed # workers & listener ----> logger # Workers and the listener will send messages to logger (push based) # Logger only yields one value # Logger terminates on receiving :terminate def make_logger: (?ractor_name: ::String) -> Ractor # Create a worker Ractor # The worker actually serves the client # listener --->> worker ----> logger # Workers take a client from the listener (pull based) # and send messages to logger when non-standard behavior occurs (push based) # Worker terminates when the listener closes its outgoing port def make_worker: (Ractor listener, Ractor logger, ?ractor_name: ::String) -> Ractor # Create a supervisor thread on the main Ractor # The listener dispatches clients for the workers to take on # listener --->> worker # listener ----> logger # Listener terminates on receiving :terminate def make_supervisor: (Ractor logger, Array[Ractor] workers) -> Thread end end