Toycol

Toycol is a small framework for defining toy application protocols.

You can define your own application protocol only by writing a parser in Toycol DSL for request messages.

Since the server and client programs to run the protocol are built-in from the beginning, you only need to prepare the following two items to run your custom protocol.

  • A configuration file named like Protocolfile, Protocolfile.protocol_name and so on
  • A Rack compartible application(e.g. config.ru)

In the real world, there is (yet) no full-fledged web server or browser in the world that runs on the custom protocol you devised. Therefore, the protocol defined by this framework is in fact a "toy". However, by using this framework, you will be able to experience and learn how the connection between the application layer and the transport layer is, and how the application protocol works on the transport layer.

Example(on original "Duck" protocol)

In this protocol:

  • Client would send message like: "quack, quack /posts<3user_id=1"
  • Server would interpret client message: "GET /posts?user_id=1"

You write your definition in Protocolfile

# Protocolfile.duck (protocol file)

Protocol.define(:duck) do
  # [OPTIONAL] You can add your original request methods
  add_request_methods "OTHER"

  # [OPTIONAL] You can define your custom status codes
  custom_status_codes(
    600 => "I'm afraid you are not a duck..."
  )

  # [REQUIRED] Define how you parse request path from request message
  request.path do |message|
    %r{(?<path>\/\w*)}.match(message)[:path]
  end

  # [REQUIRED] Define how you parse query from request message
  request.query do |message|
    %r{\<3(?<query>.+)}.match(message) { |m| m[:query] }
  end

  # [REQUIRED] Define how you parse query from request message
  request.http_method do |message|
    case message.scan(/quack/).size
    when 2 then "GET"
    else "OTHER"
    end
  end
end

Don't forget, you need to prepare your application as well.

# config_duck.ru (Rack compartible application)

require "rack"
require "toycol"

# Specify which protocol to use
Toycol::Protocol.use(:duck)

class App
  def call(env)
    case env["REQUEST_METHOD"]
    when "GET"
      [
        200,
        { "Content-Type" => "text/html" },
        ["Quack, Quack! This app is running by Duck protocol."]
      ]
    when "OTHER"
      [
        600,
        { "Content-Type" => "text/html" },
        ["Sorry, this application is only for ducks...\n"]
      ]
    end
  end
end

run App.new

Then you run server & client

# In terminal for server

$ toycol server config_duck.ru
Toycol starts build-in server, listening on unix:///tmp/toycol.socket
Toycol is running on localhost:9292
=> Use Ctrl-C to stop
# In other terminal for client

$ toycol client "quack, quack /posts<3user_id=1"
[Toycol] Sent request message: quack, quack /posts<3user_id=1
---
[Toycol] Received response message:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 32

Quack, Quack! This app is running by Duck protocol.

Installation

Add this line to your application's Gemfile:

gem "toycol"

And then execute:

$ bundle install

Or install it yourself as:

$ gem install toycol

Usage

Toycol provides useful commands to define & run your protocol.

toycol generate - To define your new protocol

You can use toycol generate command to generate skeletons of Protocolfile and application.

$ toycol generate PROTOCOL_NAME

When you run this command, skeletons of Protocolfile.PROTOCOL_NAME and config_PROTOCOL_NAME.ru will be generated. If you only need one of them, you can specify the type by -t option.

$ toycol generate PROTOCOL_NAME -t protocol
# or
$ toycol generate PROTOCOL_NAME -t app

If PROTOCOL_NAME is not specified, Protocolfile and config.ru will simply be generated.

$ toycol generate

toycol server - To run server by your protocol

After you prepare Protocolfile & application, you need to start server to run the application by toycol server command.

# Please specify application file name
$ toycol server config_`PROTOCOL_NAME`.ru

Then the server will start.

Normally, toycol server command will start the server built into toycol. However, if Puma is already installed in your environment, it will start Puma by default.

If you want to explicitly specify which server to use, you can use the -u option.

$ toycol server config_`PROTOCOL_NAME`.ru -u puma
# or
$ toycol server config_`PROTOCOL_NAME`.ru -u buid_in

If you would like to check other options, run the command toycol server -h.

toycol client - To send request message by your protocol

When you would like to send the request message to the server, use toycol client.

$ toycol client "YOUR REQUEST MESSAGE"

If you would like to check other options, run the command toycol client -h.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/shioimm/toycol. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Toycol project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.