alaska 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/alaska.js +52 -0
- data/lib/alaska/context.rb +72 -0
- data/lib/alaska/runtime.rb +100 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 838fe0565db0f27a2c6f91f1cc16af4104401a05
|
4
|
+
data.tar.gz: cbc675b45795d1fd7145066f0fe711c454cc71d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7ac32056cfafd5da0fa134eadf37137ec5172c257566863e70aea3146f84869beb0ece8f1bdc5effec520c3d6a5df10703c5bb00812a925d2c5fa817dca78d7
|
7
|
+
data.tar.gz: caf187b1da186e80c3cc86498746a49ac749d07de9ba0d8ee305148158753328c2e3b35c451914a9d80677866c4e0d0a5852f7ec158efdbace151cbb9e5e1c9c
|
data/alaska.js
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
var vm = require('vm');
|
2
|
+
var http = require("http");
|
3
|
+
var sandbox = vm.createContext({ console: {log: console.log}});
|
4
|
+
|
5
|
+
var contextOptions = {displayErrors: true};
|
6
|
+
var debugOpt = '--debug true';
|
7
|
+
var debug = false;
|
8
|
+
|
9
|
+
process.argv.forEach(function (val, index, array) {
|
10
|
+
if (debugOpt === val) {
|
11
|
+
debug = true;
|
12
|
+
}
|
13
|
+
});
|
14
|
+
|
15
|
+
var webPrint = function(res, respBody) {
|
16
|
+
res.writeHead(200, {'Connection': 'keep-alive'});
|
17
|
+
res.write(respBody);
|
18
|
+
res.end();
|
19
|
+
};
|
20
|
+
|
21
|
+
var server = http.createServer(function(req, res) {
|
22
|
+
var contents = '';
|
23
|
+
|
24
|
+
req.on('data', function (dataIn) {
|
25
|
+
contents += dataIn;
|
26
|
+
});
|
27
|
+
|
28
|
+
req.on('end', function () {
|
29
|
+
try {
|
30
|
+
var result = vm.runInContext(contents, sandbox, contextOptions);
|
31
|
+
if (typeof(result) == 'undefined' && result !== null) {
|
32
|
+
webPrint(res, '["ok"]');
|
33
|
+
} else {
|
34
|
+
try {
|
35
|
+
webPrint(res, JSON.stringify(['ok', result]));
|
36
|
+
} catch (err) {
|
37
|
+
webPrint(res, '["err"]');
|
38
|
+
}
|
39
|
+
}
|
40
|
+
} catch(err) {
|
41
|
+
webPrint(res, JSON.stringify(["err", err.toString()]));
|
42
|
+
}
|
43
|
+
});
|
44
|
+
});
|
45
|
+
|
46
|
+
var port = process.env.PORT || 3001;
|
47
|
+
server.listen(port);
|
48
|
+
|
49
|
+
if (debug) {
|
50
|
+
console.log('Listening on port:', port);
|
51
|
+
console.error('Alaska.js started. Piping coffee to warmer climates.');
|
52
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'socket'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'execjs/runtime'
|
7
|
+
require 'execjs/module'
|
8
|
+
|
9
|
+
module Alaska
|
10
|
+
class Context < ExecJS::Runtime::Context
|
11
|
+
# runtime is an instance of Alaska
|
12
|
+
# src is the js code to be eval()'d in the nodejs context
|
13
|
+
def initialize(runtime, src = "") # third step, repeated .. yes, at least twice for common.css
|
14
|
+
@runtime = runtime
|
15
|
+
|
16
|
+
# compile context source, in most cases
|
17
|
+
# this is something like the CoffeeScript compiler
|
18
|
+
# or the SASS compiler
|
19
|
+
eval(src)
|
20
|
+
end
|
21
|
+
|
22
|
+
def eval(src)
|
23
|
+
if /\S/ =~ src #IMPORTANT! /\S/ =~ "()" => 0
|
24
|
+
exec(src)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def exec(src)
|
29
|
+
return "" unless src.length > 0
|
30
|
+
|
31
|
+
src = src.encode('UTF-8', :undef => :replace, :replace => '')
|
32
|
+
src = compile_source(src)
|
33
|
+
|
34
|
+
# src is either an empty object
|
35
|
+
# OR a valid JSON string in the form
|
36
|
+
# ['ok', 'result-of-coffeescript-or-sass-compiler']
|
37
|
+
# OR if an error occured
|
38
|
+
# ['err', 'some sort of error to be presented to the developer as a sprockets error']
|
39
|
+
#
|
40
|
+
status, value = src.empty? ? [] : ::JSON.parse(src, create_additions: false)
|
41
|
+
if status == "ok"
|
42
|
+
value
|
43
|
+
elsif value =~ /SyntaxError:/
|
44
|
+
raise ExecJS::RuntimeError, value
|
45
|
+
else
|
46
|
+
raise ExecJS::ProgramError, value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(identifier, *args)
|
51
|
+
eval "#{identifier}.apply(this, #{::JSON.generate(args)})"
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def compile_source(contents)
|
57
|
+
sock = Net::BufferedIO.new(@runtime.provision_socket)
|
58
|
+
request = Net::HTTP::Post.new("/")
|
59
|
+
request['Connection'] = 'close'
|
60
|
+
request.body = contents
|
61
|
+
request.exec(sock, "1.1", "/")
|
62
|
+
|
63
|
+
begin
|
64
|
+
response = Net::HTTPResponse.read_new(sock)
|
65
|
+
end while response.kind_of?(Net::HTTPContinue)
|
66
|
+
|
67
|
+
response.reading_body(sock, request.response_body_permitted?) { }
|
68
|
+
sock.close
|
69
|
+
response.body
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
require 'execjs/runtime'
|
4
|
+
require 'execjs/module'
|
5
|
+
|
6
|
+
require 'alaska/context'
|
7
|
+
|
8
|
+
module Alaska
|
9
|
+
class Runtime < ExecJS::Runtime
|
10
|
+
attr_accessor :debug, :nodejs_cmd, :port, :pid, :semaphore
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
srand
|
14
|
+
|
15
|
+
@debug = opts[:debug]
|
16
|
+
@nodejs_cmd = "node"
|
17
|
+
@pid = nil
|
18
|
+
@semaphore = Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
"Alaska"
|
23
|
+
end
|
24
|
+
|
25
|
+
def available?
|
26
|
+
#NOTE: this is brittle in terms of cross platform detection of node executable
|
27
|
+
`which #{@nodejs_cmd}`.strip.length > 0 # this must return true to be enabled
|
28
|
+
end
|
29
|
+
|
30
|
+
def deprecated?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def context_class
|
35
|
+
Alaska::Context
|
36
|
+
end
|
37
|
+
|
38
|
+
#NOTE: this should be thread-safe
|
39
|
+
def provision_socket
|
40
|
+
ensure_startup unless @pid
|
41
|
+
|
42
|
+
wait_socket = nil
|
43
|
+
checks = 0
|
44
|
+
max_retries = 12
|
45
|
+
|
46
|
+
while checks < max_retries
|
47
|
+
begin
|
48
|
+
checks += 1
|
49
|
+
wait_socket = UNIXSocket.new(@port)
|
50
|
+
break
|
51
|
+
rescue Errno::ENOENT, Errno::ECONNREFUSED, Errno::ENOTDIR
|
52
|
+
wait_socket = nil
|
53
|
+
sleep 0.5
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if checks >= max_retries
|
58
|
+
ensure_shutdown
|
59
|
+
raise ExecJS::RuntimeError, "unable to connect to alaska.js server"
|
60
|
+
end
|
61
|
+
|
62
|
+
wait_socket
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def ensure_startup
|
68
|
+
@semaphore.synchronize {
|
69
|
+
return if @pid
|
70
|
+
|
71
|
+
@port = begin
|
72
|
+
tmpfile = Tempfile.new("alaska")
|
73
|
+
path = tmpfile.path
|
74
|
+
tmpfile.close
|
75
|
+
tmpfile.unlink
|
76
|
+
path
|
77
|
+
end
|
78
|
+
|
79
|
+
alaska_js_path = File.join(File.dirname(File.expand_path(__FILE__)), '../../alaska.js')
|
80
|
+
command_options = [alaska_js_path, "--debug #{!!@debug}"] # --other --command-line --options --go --here
|
81
|
+
|
82
|
+
@pid = Process.spawn({"PORT" => @port.to_s}, @nodejs_cmd, *command_options, {:err => :out})
|
83
|
+
|
84
|
+
at_exit do
|
85
|
+
ensure_shutdown
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def ensure_shutdown
|
91
|
+
return unless @pid
|
92
|
+
|
93
|
+
Process.kill("TERM", @pid) rescue Errno::ECHILD
|
94
|
+
Process.wait(@pid) rescue Errno::ECHILD
|
95
|
+
|
96
|
+
@port = nil
|
97
|
+
@pid = nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: alaska
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jon Bardin
|
8
|
+
- Stephen Grider
|
9
|
+
- Ville Lautanala
|
10
|
+
- Giovanni Bonetti
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2015-02-10 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: execjs
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.6'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.6'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '10.4'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '10.4'
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: minitest
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '5.5'
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '5.5'
|
58
|
+
description: uses a single shared nodejs process to handle ExecJS::Runtime evaluation
|
59
|
+
email: diclophis@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- alaska.js
|
65
|
+
- lib/alaska/context.rb
|
66
|
+
- lib/alaska/runtime.rb
|
67
|
+
homepage: https://github.com/mavenlink/alaska
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.4.8
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: persistent ExecJS runtime
|
91
|
+
test_files: []
|