Skip to content
This repository has been archived by the owner on Jan 3, 2020. It is now read-only.

Commit

Permalink
Merge pull request #85 from lopopolo/sinatra
Browse files Browse the repository at this point in the history
[WIP] Embed Sinatra
  • Loading branch information
lopopolo committed Jun 21, 2019
2 parents e7790ad + 9906eef commit 0cc4a8e
Show file tree
Hide file tree
Showing 246 changed files with 51,401 additions and 11 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"foolsgold",
"hubris",
"mruby",
"mruby-bin",
"mruby-gems",
Expand Down
1 change: 0 additions & 1 deletion foolsgold/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(integer_atomics)]
#![feature(proc_macro_hygiene, decl_macro)]
#![deny(warnings, intra_doc_link_resolution_failure)]
#![deny(clippy::all, clippy::pedantic)]

Expand Down
18 changes: 18 additions & 0 deletions hubris/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "hubris"
version = "0.1.0"
authors = ["Ryan Lopopolo <rjl@hyperbo.la>"]
edition = "2018"

[dependencies]
env_logger = "0.6.1"
log = "0.4.6"

[dependencies.mruby]
path = "../mruby"

[dependencies.mruby-gems]
path = "../mruby-gems"

[dependencies.nemesis]
path = "../nemesis"
64 changes: 64 additions & 0 deletions hubris/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# hubris

hubris crate is a [Sinatra](http://sinatrarb.com/) echo server that is an
integration test for the [nemesis](/nemesis), [mruby](/mruby), and
[mruby-gems](/mruby-gems) crates. hubris uses nemesis to serve a
[Sinatra Rack application](src/config.ru) that is backed by an embedded mruby
interpreter.

Nemesis is similar to [Thin](https://github.com/macournoyer/thin) in a
traditional Ruby web stack.

## Output

```console
$ curl -i 'http://localhost:8000/ferrocarril?demo=hubris&mruby' && echo
HTTP/1.1 200 OK
Content-Length: 163
Content-Type: application/json
Server: Rocket
Date: Fri, 21 Jun 2019 14:32:34 GMT

{
"method": "GET",
"path": "/ferrocarril",
"args": "demo=hubris&mruby",
"body": "",
"headers": {

},
"uuid": "fb70d164-031c-4616-aeb4-41a31295fa5b"
}
```

## Components

hubris consists of three parts: a
[patched versions of Sinatra and its dependencies](/mruby-gems/src/rubygems/),
implementations of Ruby [core](/mruby/src/extn/core) and
[standard library](/mruby/src/extn/stdlib) for mruby written in Rust and Ruby,
and a [launcher for a Nemesis server](src/main.rs).

The nemesis launcher pulls all of these components together by initializing all
of the gems that the Sinatra-based [rackup file](src/config.ru) depends on:

```rust
pub fn spawn() -> Result<(), Error> {
Builder::default()
.add_mount(
Mount::from_rackup("echo", APP, "/")
.with_init(Box::new(include_str!("config.ru")))
.with_shared_interpreter(Some(150)),
)
.serve()
}

fn interp_init(interp: &Mrb) -> Result<(), MrbError> {
rubygems::mustermann::init(&interp)?;
rubygems::rack::init(&interp)?;
rubygems::rack_protection::init(&interp)?;
rubygems::sinatra::init(&interp)?;
rubygems::tilt::init(&interp)?;
Ok(())
}
```
7 changes: 7 additions & 0 deletions hubris/src/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
AllCops:
TargetRubyVersion: 2.5
DisplayCopNames: true
Metrics:
Enabled: false
Style/Documentation:
Enabled: false
69 changes: 69 additions & 0 deletions hubris/src/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

require 'sinatra/base'
require 'json'
require 'digest/sha1'
require 'securerandom'

# Sinatra app that echoes Rack environment as JSON.
class Echo < Sinatra::Base
def self.all_methods(path, opts = {}, &block)
get(path, opts, &block)
post(path, opts, &block)
put(path, opts, &block)
delete(path, opts, &block)
patch(path, opts, &block)
options(path, opts, &block)
head(path, opts, &block)
end

def headers
env.select { |k, _v| k.start_with? 'HTTP_' }
end

def echo_response
# TODO: nemesis does not pass RACK_INPUT
body = request.body&.read || ''
hash = Digest::SHA1.base64digest(body)

headers.each do |(header, value)|
response_header = header
.sub(/^HTTP_/, '')
.split('_')
.collect(&:capitalize)
.join('-')

headers[response_header] = value
end

response_args = {
method: request.request_method,
path: request.path,
args: request.query_string,
body: body,
headers: headers,
uuid: SecureRandom.uuid
}
unless body.empty?
response_args[:bodySha1] = hash
response_args[:bodyLength] = body.length
end

# Prefer JSON if possible, including cases of unrecognised/erroneous types.
content_type 'application/json'
JSON.pretty_generate(response_args)
end

get '/status/:code' do |code|
[code.to_i, echo_response]
end

get '/favicon.ico' do # Avoid bumping counter on favicon
end

all_methods '/*' do
echo_response
end
end

run Echo
42 changes: 42 additions & 0 deletions hubris/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![deny(warnings, intra_doc_link_resolution_failure)]
#![deny(clippy::all, clippy::pedantic)]

#[macro_use]
extern crate log;

use mruby::interpreter::Mrb;
use mruby::MrbError;
use mruby_gems::rubygems;
use nemesis::{Builder, Error, Mount};

const APP: &str = include_str!("config.ru");

pub fn main() -> Result<(), i32> {
env_logger::Builder::from_env("DITTY_LOG").init();
if let Err(err) = spawn() {
error!("Failed to launch nemesis: {}", err);
eprintln!("ERR: {}", err);
Err(1)
} else {
Ok(())
}
}

pub fn spawn() -> Result<(), Error> {
Builder::default()
.add_mount(
Mount::from_rackup("echo", APP, "/")
.with_init(Box::new(interp_init))
.with_shared_interpreter(Some(150)),
)
.serve()
}

fn interp_init(interp: &Mrb) -> Result<(), MrbError> {
rubygems::mustermann::init(&interp)?;
rubygems::rack::init(&interp)?;
rubygems::rack_protection::init(&interp)?;
rubygems::sinatra::init(&interp)?;
rubygems::tilt::init(&interp)?;
Ok(())
}
1 change: 1 addition & 0 deletions mruby-bin/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub fn run(

// load gems
mruby_gems::rubygems::rack::init(&interp).map_err(Error::Ruby)?;
mruby_gems::rubygems::mustermann::init(&interp).map_err(Error::Ruby)?;

let parser = Parser::new(&interp).ok_or(Error::ReplInit)?;
interp.push_context(EvalContext::new(REPL_FILENAME));
Expand Down
1 change: 1 addition & 0 deletions mruby-gems/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
source 'https://rubygems.org'

gem 'rack', '= 2.0.7'
gem 'sinatra', '= 2.0.5'
10 changes: 10 additions & 0 deletions mruby-gems/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
GEM
remote: https://rubygems.org/
specs:
mustermann (1.0.3)
rack (2.0.7)
rack-protection (2.0.5)
rack
sinatra (2.0.5)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.5)
tilt (~> 2.0)
tilt (2.0.9)

PLATFORMS
ruby

DEPENDENCIES
rack (= 2.0.7)
sinatra (= 2.0.5)

BUNDLED WITH
2.0.1
4 changes: 4 additions & 0 deletions mruby-gems/src/rubygems.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
pub mod mustermann;
pub mod rack;
pub mod rack_protection;
pub mod sinatra;
pub mod tilt;

0 comments on commit 0cc4a8e

Please sign in to comment.