diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/guff.cr | 160 | ||||
| -rw-r--r-- | src/guff/config.cr | 98 | ||||
| -rw-r--r-- | src/guff/version.cr | 3 | 
3 files changed, 261 insertions, 0 deletions
diff --git a/src/guff.cr b/src/guff.cr new file mode 100644 index 0000000..7e32bfc --- /dev/null +++ b/src/guff.cr @@ -0,0 +1,160 @@ +require "sqlite3" +require "http/server" +require "./guff/*" + +module Guff +  class Database < ::SQLite3::Database +    # TODO (add table_exists?) +  end + +  class Model +    getter :db + +    def initialize(@config : Config) +      # create site database +      db_path = "%s/site.db" % [config["data"]] +      @db = Database.new(db_path) +    end +  end + +  class Handler < ::HTTP::Handler +    getter :model +    getter :config + +    def initialize(@model : Model, @config : Config) +    end + +    def call(context : HTTP::Server::Context) +      # do nothing by default +      call_next(context) +    end +  end + + +  class BlogHandler < Handler +    MATCHES = [%r{ +      ^/ + +      # match YYYY/MM/DD/SLUG.html +      (?<year>\d{4}) +      / +      (?<month>\d{2}) +      / +      (?<day>\d{2}) +      / +      (?<slug>[a-z0-9._-]+) +      \.html + +      $ +    }x, %r{ +      ^/ + +      # match YYYY/MM/DD +      (?<year>\d{4}) +      / +      (?<month>\d{2}) +      / +      (?<day>\d{2}) +      /? + +      $ +    }x, %r{ +      ^/ + +      # match YYYY/MM +      (?<year>\d{4}) +      / +      (?<month>\d{2}) +      /? + +      $ +    }x, %r{ +      ^/ + +      # match YYYY +      (?<year>\d{4}) +      /? + +      $ +    }x, %r{ +      ^/ + +      # match index +      blog/? +      | + +      $ +    }x] + +    def call(context : HTTP::Server::Context) +      path = context.request.path || "" +      if md = MATCHES.reduce(nil) { |r, m| r || m.match(path) } +        context.response.puts "blog match: %s" % [md.to_s] +      else +        call_next(context) +      end +    end +  end + +  class SlugHandler < Handler +    MOCK_SLUGS = { +      "foo": "test slug foo", +      "bar": "test slug bar", +      "baz": "test slug baz", +    } + +    def call(context : HTTP::Server::Context) +      puts "SlugHandler: path = %s" % [context.request.path] +      call_next(context) +    end +  end + +  class Server +    def self.run(model : Model, config : Config) +      new(model, config).run +    end + +    def initialize(@model : Model, @config : Config) +      # create server +      @server = HTTP::Server.new( +        config["host"], +        config["port"].to_i, +        get_handlers(model, config) +      ) do |context| +        context.response.puts "asdf" +      end +    end + +    def run +      puts "listening on %s:%s" % %w{host port}.map { |k| @config[k] } +      @server.listen +    end + +    private def get_handlers( +      model : Model, +      config : Config +    ) : Array(HTTP::Handler) +      @handlers ||= [ +        HTTP::ErrorHandler.new, +        HTTP::LogHandler.new, +        HTTP::DeflateHandler.new, +        BlogHandler.new(model, config), +        SlugHandler.new(model, config), +        HTTP::StaticFileHandler.new(config["public"]), +      ] +    end +  end + +  def self.run(app, args) +    # parse env and cli options +    config = Config.new(app, args) + +    # create model +    model = Model.new(config) + +    # create server +    Server.run(model, config) +  end +end + +Guff.run($0, ARGV) diff --git a/src/guff/config.cr b/src/guff/config.cr new file mode 100644 index 0000000..6021c63 --- /dev/null +++ b/src/guff/config.cr @@ -0,0 +1,98 @@ +require "option_parser" + +module Guff +  class Config +    DEFAULTS = { +      "host":         "localhost", +      "port":         "8989", +      "data":         "./data", +      "public":       "./public", +      "environment":  "development", +    } + +    DIRS = %w{ +      data +      public +    } + +    def initialize(app, args) +      @data = defaults +      parse_args(app, args) +    end + +    def [](key : String) : String +      @data[key] +    end + +    def []=(key : String, val : String | Nil) : String +      @data[key] = val +    end + +    private def defaults : Hash(String, String) +      DEFAULTS.merge(DEFAULTS.keys.reduce({} of String => String) do |r, key| +        env_key = "GUFF_" + key.upcase +        r[key] = ENV[env_key] if ENV.has_key?(env_key) +        r +      end) +    end + +    private def parse_args(app, args) +      OptionParser.parse(args) do |p| +        p.on( +          "-h HOST", +          "--host HOST", +          "Host (defaults to \"localhost\")." +        ) do |host| +          self["host"] = host +        end + +        p.on( +          "-p PORT", +          "--port PORT", +          "Port (defaults to 8989)." +        ) do |port| +          self["port"] = port +        end + +        p.on( +          "-d PATH", +          "--data-dir PATH", +          "Path to data directory (defaults to \"./data\")." +        ) do |path| +          self["data"] = path +        end +         +        p.on( +          "-u PATH", +          "--public-dir PATH", +          "Path to public directory (defaults to \"./public\")." +        ) do |path| +          self["public"] = path +        end + +        p.on( +          "-e ENV", +          "--environment ENV", +          "Environment (defaults to \"development\")." +        ) do |path| +          self["public"] = path +        end + + +        p.on( +          "--help", +          "Print usage" +        ) do  +          puts p.to_s +        end +      end + +      # expand output directory paths and create them +      %w{data public}.each do |key| +        self[key] = File.expand_path(File.join(File.dirname(app), self[key])) +        # puts "DEBUG: %s: %s" % [key, self[key]] +        Dir.mkdir(self[key], 0o770) unless File.directory?(self[key]) +      end +    end +  end +end diff --git a/src/guff/version.cr b/src/guff/version.cr new file mode 100644 index 0000000..898a0d6 --- /dev/null +++ b/src/guff/version.cr @@ -0,0 +1,3 @@ +module Guff +  VERSION = "0.1.0" +end  | 
