aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-06-07 01:37:56 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-06-07 01:37:56 +0900
commitccf86ca46c6b63088c66a38ec17d18be2d4ff898 (patch)
tree25656458706b237c1b7a47fe0cdae004e6ac4a3f
parent039c04f0a63ee2a76d235de257e6f8ec80bfb970 (diff)
downloadpoe-⚙.tar.gz
-rw-r--r--Gemfile1
-rw-r--r--config.ru10
-rw-r--r--lib/poe/core.rb59
-rw-r--r--lib/poe/snippet.rb22
-rw-r--r--lib/poe/webapp.rb22
-rw-r--r--poe-config.json5
6 files changed, 115 insertions, 4 deletions
diff --git a/Gemfile b/Gemfile
index ff6db64..d9a44ef 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,4 @@
source "https://rubygems.org"
gem "msgpack", "~> 1.1"
+gem "sinatra", "~> 2.0"
diff --git a/config.ru b/config.ru
index aabaa3a..e21d5a8 100644
--- a/config.ru
+++ b/config.ru
@@ -1,10 +1,14 @@
-require "rack"
require_relative "lib/poe/webapp"
+require "rack"
+
+# Load configuration from ENV["POE_CONFIG"] or $(pwd)/poe.json
+Poe::Config.load
-use Rack::CommonLogger
if Poe.debug?
use Rack::ShowExceptions
use Rack::Lint
end
-run Sinatra::Application
+use Rack::CommonLogger
+
+run Poe::WebApp
diff --git a/lib/poe/core.rb b/lib/poe/core.rb
new file mode 100644
index 0000000..df15894
--- /dev/null
+++ b/lib/poe/core.rb
@@ -0,0 +1,59 @@
+require_relative "snippet"
+require "json"
+
+module Poe
+ module_function
+
+ def debug?
+ Poe::Config.fetch("debug", false)
+ end
+
+ def datadir
+ Poe::Config.expand_path(Poe::Config.fetch("datadir"))
+ end
+
+ def tmpdir
+ Poe::Config.expand_path(Poe::Config.fetch("tmpdir"))
+ end
+
+ module Config
+ module_function
+
+ def load(path = ENV["POE_CONFIG"])
+ path or raise "config file for poe not given; set POE_CONFIG " \
+ "environment variable to the path"
+ t = File.read(path)
+ @hash = JSON.parse(t)
+ @config_base_path = File.dirname(path)
+ end
+
+ def expand_path(path)
+ check
+ File.expand_path(path, @config_base_path)
+ end
+
+ def fetch(path, default = UNSPECIFIED)
+ check
+ path.split(".").inject(@hash) do |h, c|
+ h.fetch(c) or (
+ if default == UNSPECIFIED
+ raise KeyError, "config key %s not found" % path
+ else
+ return default
+ end
+ )
+ end
+ end
+
+ def check
+ return if defined?(@hash)
+ raise "[BUG] config is not loaded yet"
+ end
+
+ UNSPECIFIED = Object.new
+ end
+
+ class PoeError < StandardError; end
+ class SnippetNotFound < PoeError; end
+ class OutputNotFound < PoeError; end
+end
diff --git a/lib/poe/snippet.rb b/lib/poe/snippet.rb
new file mode 100644
index 0000000..18f1512
--- /dev/null
+++ b/lib/poe/snippet.rb
@@ -0,0 +1,22 @@
+require_relative "core"
+
+class Poe::Snippet
+ # FIXME
+ SID_PATTERN = /\A[0-9a-f]{32,64}\z/
+ RID_PATTERN = /\A(?:0|[1-9]\d+)\z/
+
+ attr_reader :id
+
+ def initialize(sid, *)
+ @id = sid
+ end
+
+ class << self
+ def find(sid)
+ raise Poe::SnippetNotFound, "invalid sid format" if SID_PATTERN !~ sid
+ json = File.read(File.join(Poe.datadir, "snippets", sid, "metadata.json"))
+ hash = JSON.parse(json, symbolize_keys: true)
+ new(sid, **hash)
+ end
+ end
+end
diff --git a/lib/poe/webapp.rb b/lib/poe/webapp.rb
index 2a55eaa..5e38b12 100644
--- a/lib/poe/webapp.rb
+++ b/lib/poe/webapp.rb
@@ -1,2 +1,22 @@
-require "sinatra"
+require_relative "core"
+require "sinatra/base"
require "msgpack"
+
+class Poe::WebApp < Sinatra::Base
+ post "/api/snippet/new" do
+ content_type :json
+ s = Poe::Snippet.create(params[:snippet])
+ Poe::Runner.enqueue(s)
+ s.to_json
+ end
+
+ get "/api/snippet/:sid" do
+ content_type :json
+ Poe::Snippet.find(params[:sid]).to_json
+ end
+
+ get "/api/snippet/:sid/:rid/stdout" do
+ content_type :text
+ Poe::Snippet.find(params[:sid]).result(params[:rid]).split_stdout
+ end
+end
diff --git a/poe-config.json b/poe-config.json
new file mode 100644
index 0000000..231b449
--- /dev/null
+++ b/poe-config.json
@@ -0,0 +1,5 @@
+{
+ "debug": true,
+ "tmpdir": "tmp",
+ "datadir": "data"
+}