require 'sinatra/base'
require 'sinatra/namespace'

module HttpDouble
  class Base < Sinatra::Base
    register Sinatra::Namespace

    class << self

      def use_app(klass, &block)
        @app_class = klass
        @initializer = block
      end

      def foreground(addr, port, log_path: '/dev/null', logger: nil)
        server_class = self
        app_class = @app_class || server_class

        # Even if we use /dev/null, we need a logger to suppress warnings
        # generated by Thin::Logging#trace_logger being undefined
        log_stream = File.open(log_path, 'a')
        Base.loggers[port] = logger || Logger.new(log_stream)

        initializer = @initializer

        Thin::Server.start(addr, port) do
          initializer.call if initializer
          use RequestLogger, server_class.log
          run Class === app_class ? app_class.new : app_class
        end

      end

      def background(addr, port, **args)
        thread = Thread.new{ foreground addr, port, **args }
        thread.abort_on_exception = true
        sleep 0.05 until test_background addr, port
        thread
      end

      def log
        @log ||= []
      end

      def loggers
        @loggers ||= {}
      end

      private

      def test_background(addr, port)
        begin
          http = Net::HTTP.new addr, port
          http.head '/'
          true
        rescue SystemCallError
          false
        rescue
          true
        end
      end

    end

    not_found { [404, ''] }

  end
end

require 'sinatra/base'
require 'sinatra/namespace'

module HttpDouble
  class Base < Sinatra::Base
    register Sinatra::Namespace

    class << self

      def use_app(klass, &block)
        @app_class = klass
        @initializer = block
      end

      def foreground(addr, port, log_path: '/dev/null', logger: nil, &block)
        server_class = self
        app_class = @app_class || server_class

        # Even if we use /dev/null, we need a logger to suppress warnings
        # generated by Thin::Logging#trace_logger being undefined
        log_stream = File.open(log_path, 'a')
        Base.loggers[port] = logger || Logger.new(log_stream)

        initializer = @initializer

        Thin::Server.start(addr, port) do
          initializer.call if initializer
          use RequestLogger, server_class.log
          instance_exec &block if block
          run Class === app_class ? app_class.new : app_class
        end

      end

      def background(addr, port, **args, &block)
        thread = Thread.new{ foreground addr, port, **args, &block }
        thread.abort_on_exception = true
        sleep 0.05 until test_background addr, port
        thread
      end

      def log
        @log ||= []
      end

      def loggers
        @loggers ||= {}
      end

      private

      def test_background(addr, port)
        begin
          http = Net::HTTP.new addr, port
          http.head '/'
          true
        rescue SystemCallError
          false
        rescue
          true
        end
      end

    end

    not_found { [404, ''] }

  end
end

Allow blocks to be passed to foreground/background methods that will be executed in the context of the rack builder when starting a server
Allow blocks to be passed to foreground/background methods that will be executed in the context of the rack builder when starting a server
