lib/tp2.rb



# frozen_string_literal: true

require 'uringmachine'
require 'tp2/version'
require 'tp2/server'
require 'tp2/logger'

class UringMachine
  def puts(str)
    write_async(1, "#{str}\n")
  end
end

module TP2
  BANNER = (
    "\n" +
    "         ooo\n" +
    "       oo\n" +
    "     o\n" +
    "   \\|/    TP2 - a modern web server for Ruby apps\n" +
    "   / \\       \n" +
    "  / x \\      https://github.com/noteflakes/tp2\n" +
    "⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺\n"
  )

  class << self
    def run(opts = nil, &app)
      if @in_run
        @config = opts if opts
        @config[:app] = app if app
        return
      end

      opts ||= @config || {}
      begin
        @in_run = true
        machine = opts[:machine] || UM.new
        machine.puts(opts[:banner]) if opts[:banner]

        opts[:logger]&.info(message: "Running TP2 #{TP2::VERSION}, UringMachine #{UM::VERSION}, Ruby #{RUBY_VERSION}")

        server = Server.new(machine, opts, &app)

        setup_signal_handling(machine, Fiber.current)
        server.run
      ensure
        @in_run = false
      end
    end

    def config(opts = nil, &app)
      return @config if !opts && !app

      @config = opts || {}
      @config[:app] = app if app
    end

    private

    def setup_signal_handling(machine, fiber)
      queue = UM::Queue.new
      trap('SIGINT') { machine.push(queue, :SIGINT) }
      machine.spin { watch_for_int_signal(machine, queue, fiber) }
    end

    # waits for signal from queue, then terminates given fiber
    # to be done
    def watch_for_int_signal(machine, queue, fiber)
      machine.shift(queue)
      machine.schedule(fiber, UM::Terminate.new)
    end
  end
end