waxx 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/LICENSE +201 -0
- data/README.md +879 -0
- data/bin/waxx +120 -0
- data/lib/waxx/app.rb +173 -0
- data/lib/waxx/conf.rb +54 -0
- data/lib/waxx/console.rb +204 -0
- data/lib/waxx/csrf.rb +14 -0
- data/lib/waxx/database.rb +80 -0
- data/lib/waxx/encrypt.rb +38 -0
- data/lib/waxx/error.rb +60 -0
- data/lib/waxx/html.rb +33 -0
- data/lib/waxx/http.rb +268 -0
- data/lib/waxx/init.rb +273 -0
- data/lib/waxx/irb.rb +44 -0
- data/lib/waxx/irb_env.rb +18 -0
- data/lib/waxx/json.rb +23 -0
- data/lib/waxx/mongodb.rb +221 -0
- data/lib/waxx/mysql2.rb +234 -0
- data/lib/waxx/object.rb +115 -0
- data/lib/waxx/patch.rb +138 -0
- data/lib/waxx/pdf.rb +69 -0
- data/lib/waxx/pg.rb +246 -0
- data/lib/waxx/process.rb +270 -0
- data/lib/waxx/req.rb +116 -0
- data/lib/waxx/res.rb +98 -0
- data/lib/waxx/server.rb +304 -0
- data/lib/waxx/sqlite3.rb +237 -0
- data/lib/waxx/supervisor.rb +47 -0
- data/lib/waxx/test.rb +162 -0
- data/lib/waxx/util.rb +57 -0
- data/lib/waxx/version.rb +3 -0
- data/lib/waxx/view.rb +389 -0
- data/lib/waxx/waxx.rb +73 -0
- data/lib/waxx/x.rb +103 -0
- data/lib/waxx.rb +50 -0
- data/skel/README.md +11 -0
- data/skel/app/app/app.rb +39 -0
- data/skel/app/app/error/app_error.rb +16 -0
- data/skel/app/app/error/dhtml.rb +9 -0
- data/skel/app/app/error/html.rb +8 -0
- data/skel/app/app/error/json.rb +8 -0
- data/skel/app/app/error/pdf.rb +13 -0
- data/skel/app/app/log/app_log.rb +13 -0
- data/skel/app/app.rb +20 -0
- data/skel/app/home/home.rb +16 -0
- data/skel/app/home/html.rb +145 -0
- data/skel/app/html.rb +192 -0
- data/skel/app/usr/email.rb +66 -0
- data/skel/app/usr/html.rb +115 -0
- data/skel/app/usr/list.rb +51 -0
- data/skel/app/usr/password.rb +54 -0
- data/skel/app/usr/record.rb +98 -0
- data/skel/app/usr/usr.js +67 -0
- data/skel/app/usr/usr.rb +277 -0
- data/skel/app/waxx/waxx.rb +109 -0
- data/skel/bin/README.md +1 -0
- data/skel/db/README.md +11 -0
- data/skel/db/app/0-init.sql +88 -0
- data/skel/lib/README.md +1 -0
- data/skel/log/README.md +1 -0
- data/skel/opt/dev/config.yaml +1 -0
- data/skel/opt/prod/config.yaml +1 -0
- data/skel/opt/stage/config.yaml +1 -0
- data/skel/opt/test/config.yaml +1 -0
- data/skel/private/README.md +1 -0
- data/skel/public/lib/site.css +202 -0
- data/skel/public/lib/waxx/w.ico +0 -0
- data/skel/public/lib/waxx/w.png +0 -0
- data/skel/public/lib/waxx/waxx.js +111 -0
- data/skel/tmp/pids/README.md +1 -0
- data.tar.gz.sig +0 -0
- metadata +140 -0
- metadata.gz.sig +3 -0
data/lib/waxx/error.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Error
|
|
5
|
+
def error(x, status:200, type:nil, title:"An error occurred", message:"", args: [])
|
|
6
|
+
x.res.status = status
|
|
7
|
+
App[:app_error][type.to_sym][:get].call(x, title, message, *args)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fatal(x, e)
|
|
11
|
+
App::AppLog.log(x, cat: "Error", name:"#{x.req.uri}", value: "#{e}\n#{e.backtrace}")
|
|
12
|
+
x.res.status = 503
|
|
13
|
+
er = [
|
|
14
|
+
"ERROR:\n#{e}\n#{e.backtrace.join("\n")}",
|
|
15
|
+
"USR:\n\n#{x.usr.map{|n,v| "#{n}: #{v}"}.join("\n")}",
|
|
16
|
+
"GET:\n#{x.req.get.map{|n,v| "#{n}: #{v}"}.join("\n")}",
|
|
17
|
+
"POST:\n#{req.post.map{|n,v| "#{n}: #{v}"}.join("\n")}",
|
|
18
|
+
"ENV:\n\n#{x.req.env.map{|n,v| "#{n}: #{v}"}.join("\n")}"
|
|
19
|
+
].join("\n\n")
|
|
20
|
+
|
|
21
|
+
if Waxx['debug']['on_screen']
|
|
22
|
+
x << "<pre>#{er}</pre>"
|
|
23
|
+
else
|
|
24
|
+
get_const(App, x.ext).get(x,
|
|
25
|
+
title: "System Error",
|
|
26
|
+
content: "<h4><span class='glyphicon glyphicon-thumbs-down'></span> Sorry! Something went wrong on our end.</h4>
|
|
27
|
+
<h4><span class='glyphicon glyphicon-thumbs-up'></span> The tech support team has been notified.</h4>
|
|
28
|
+
<p>We will contact you if we need addition information. </p>
|
|
29
|
+
<p>Sorry for the inconvenience.</p>"
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
if Waxx['debug']['send_email'] and Waxx['debug']['email']
|
|
33
|
+
to_email = Waxx['debug']['email']
|
|
34
|
+
from_email = Waxx['site']['support_email']
|
|
35
|
+
subject = "[Bug] #{App['site']['name']} #{x.meth}:#{x.uri}"
|
|
36
|
+
body = er
|
|
37
|
+
begin
|
|
38
|
+
# Send email via DB.email table
|
|
39
|
+
App::Email.post(x,{
|
|
40
|
+
to_email: to_email,
|
|
41
|
+
from_email: from_email,
|
|
42
|
+
subject: subject,
|
|
43
|
+
body: body
|
|
44
|
+
})
|
|
45
|
+
rescue => e2
|
|
46
|
+
begin
|
|
47
|
+
# Only send email
|
|
48
|
+
Mail.deliver do
|
|
49
|
+
from from_email
|
|
50
|
+
to to_email
|
|
51
|
+
subject subject
|
|
52
|
+
body body
|
|
53
|
+
end
|
|
54
|
+
rescue => e3
|
|
55
|
+
puts "FATAL ERROR: Could not send bug report email: #{e2}\n#{e2.backtrace} AND #{e3}\n#{e3.backtrace}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/waxx/html.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Html
|
|
5
|
+
extend self
|
|
6
|
+
attr :view
|
|
7
|
+
|
|
8
|
+
def view
|
|
9
|
+
@view ||= name.split("::").slice(1,2).inject(App){|c, n| c.const_get(n)}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def f v, *fmt
|
|
13
|
+
v.f *fmt
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def h v
|
|
17
|
+
begin
|
|
18
|
+
v.h
|
|
19
|
+
rescue
|
|
20
|
+
v.to_s.h
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def qs v
|
|
25
|
+
Waxx::Http.qs(v)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def debug(str, level=3)
|
|
29
|
+
Waxx.debug(str, level)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
data/lib/waxx/http.rb
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
module Waxx::Http
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
def content_types
|
|
8
|
+
ContentTypes
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ctype(t, default="application/octet-stream")
|
|
12
|
+
ContentTypes[t.to_sym] || default
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def time(t=Time.new.utc)
|
|
16
|
+
t.strftime('%a, %d %b %Y %H:%M:%S UTC')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def escape(str)
|
|
20
|
+
str.to_s.gsub(/([^a-zA-Z0-9_.-]+)/) do |m|
|
|
21
|
+
'%' + m.unpack('H2' * m.bytesize).join('%').upcase
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
alias qs escape
|
|
25
|
+
|
|
26
|
+
def unescape(str)
|
|
27
|
+
str.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do |m|
|
|
28
|
+
[m.delete('%')].pack('H*')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def parse_head(io)
|
|
33
|
+
Waxx.debug("parse_head: #{io.class}", 9)
|
|
34
|
+
env = {}
|
|
35
|
+
head = ""
|
|
36
|
+
while(e = io.gets)
|
|
37
|
+
break if e.strip == ""
|
|
38
|
+
head << e
|
|
39
|
+
n, v = e.split(":", 2)
|
|
40
|
+
env[n] = v.strip
|
|
41
|
+
end
|
|
42
|
+
Waxx.debug "env.size: #{env.size}", 9
|
|
43
|
+
[env, head]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def query_string_to_hash(str, base={})
|
|
47
|
+
return base if str.nil? or str.strip == ""
|
|
48
|
+
str.strip.split(/[;&]/).each{|nv|
|
|
49
|
+
n, v = nv.split("=",2).map{|s| unescape(s)}
|
|
50
|
+
if n =~ /\[\]$/
|
|
51
|
+
n = n.sub(/\[\]$/,"")
|
|
52
|
+
base[n] ||= []
|
|
53
|
+
base[n] << v
|
|
54
|
+
else
|
|
55
|
+
base[n] = v
|
|
56
|
+
end
|
|
57
|
+
}
|
|
58
|
+
base
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def parse_multipart(env, data)
|
|
62
|
+
boundary = env['Content-Type'].match(/boundary=(.*)$/)[1]
|
|
63
|
+
parts = data.split("--"+boundary+"\r\n")
|
|
64
|
+
post = {}
|
|
65
|
+
parts.each{|part|
|
|
66
|
+
next if part.strip == ""
|
|
67
|
+
begin
|
|
68
|
+
head, body = part.split("\r\n\r\n",2)
|
|
69
|
+
headers = Hash[*(head.split("\r\n").map{|hp| hp.split(":",2).map{|i| i.strip}}.flatten)]
|
|
70
|
+
cd = Hash[*("_=#{headers['Content-Disposition']}".split(";").map{|da| da.strip.gsub('"',"").split("=",2)}.flatten)]
|
|
71
|
+
if cd['filename']
|
|
72
|
+
post[cd['name']] = {
|
|
73
|
+
filename: cd['filename'],
|
|
74
|
+
data: body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,""),
|
|
75
|
+
content_type: headers['Content-Type'],
|
|
76
|
+
headers: headers
|
|
77
|
+
}
|
|
78
|
+
else
|
|
79
|
+
post[cd['name']] = body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,"")
|
|
80
|
+
end
|
|
81
|
+
rescue => e
|
|
82
|
+
Waxx.debug "Error parse_multipart: #{e}"
|
|
83
|
+
post["Error in parse_multipart (uid-#{rand})"] = e
|
|
84
|
+
end
|
|
85
|
+
}
|
|
86
|
+
post
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def parse_cookie(str)
|
|
90
|
+
Waxx.debug "parse_cookie"
|
|
91
|
+
re = {}
|
|
92
|
+
return re if str.nil? or str == ""
|
|
93
|
+
str.split(/[;,]\s?/).each do |pairs|
|
|
94
|
+
name, values = pairs.split('=',2)
|
|
95
|
+
next unless name and values
|
|
96
|
+
name = unescape(name)
|
|
97
|
+
vals = values.split('&').collect{|v| unescape(v) }
|
|
98
|
+
if re.has_key?(name)
|
|
99
|
+
Waxx.debug "re has key"
|
|
100
|
+
if Array === re[name]
|
|
101
|
+
re[name].push vals
|
|
102
|
+
else
|
|
103
|
+
re[name] = [re[name], vals]
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
re[name] = vals
|
|
107
|
+
end
|
|
108
|
+
re[name].flatten!
|
|
109
|
+
end
|
|
110
|
+
re.freeze
|
|
111
|
+
re
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def parse_data(env, meth, io, head)
|
|
115
|
+
Waxx.debug "parse_data"
|
|
116
|
+
if %w(PUT POST PATCH).include? meth
|
|
117
|
+
data = io.read(env['Content-Length'].to_i)
|
|
118
|
+
Waxx.debug "data.size: #{data.size} #{env['Content-Type']}"
|
|
119
|
+
case env['Content-Type']
|
|
120
|
+
when /x-www-form-urlencoded/
|
|
121
|
+
post = query_string_to_hash(data).freeze
|
|
122
|
+
when /multipart/
|
|
123
|
+
post = parse_multipart(env, data).freeze
|
|
124
|
+
when /json/
|
|
125
|
+
post = (JSON.parse(data)).freeze
|
|
126
|
+
else
|
|
127
|
+
post = data.freeze
|
|
128
|
+
end
|
|
129
|
+
else
|
|
130
|
+
post = {}.freeze
|
|
131
|
+
data = nil
|
|
132
|
+
end
|
|
133
|
+
[post, data]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
Status = {
|
|
137
|
+
"200"=>"OK",
|
|
138
|
+
"206"=>"Partial Content",
|
|
139
|
+
"300"=>"Multiple Choices",
|
|
140
|
+
"301"=>"Moved Permanently",
|
|
141
|
+
"302"=>"Found",
|
|
142
|
+
"304"=>"Not Modified",
|
|
143
|
+
"400"=>"Bad Request",
|
|
144
|
+
"401"=>"Authorization Required",
|
|
145
|
+
"403"=>"Forbidden",
|
|
146
|
+
"404"=>"Not Found",
|
|
147
|
+
"405"=>"Method Not Allowed",
|
|
148
|
+
"406"=>"Not Acceptable",
|
|
149
|
+
"411"=>"Length Required",
|
|
150
|
+
"412"=>"Precondition Failed",
|
|
151
|
+
"500"=>"Internal Server Error",
|
|
152
|
+
"501"=>"Method Not Implemented",
|
|
153
|
+
"502"=>"Bad Gateway",
|
|
154
|
+
"506"=>"Variant Also Negotiates"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
ContentTypes = {
|
|
158
|
+
css: "text/css; charset=utf-8",
|
|
159
|
+
csv: "text/csv; charset=utf-8",
|
|
160
|
+
htm: "text/html; charset=utf-8",
|
|
161
|
+
html: "text/html; charset=utf-8",
|
|
162
|
+
jpg: "image/jpeg",
|
|
163
|
+
js: "application/javascript; charset=utf-8",
|
|
164
|
+
json: "application/json; charset=utf-8",
|
|
165
|
+
tab: "text/tab-separated-values; charset=utf-8",
|
|
166
|
+
txt: "text/plain; charset=utf-8",
|
|
167
|
+
xml: "text/xml",
|
|
168
|
+
gif: "image/gif",
|
|
169
|
+
jpeg: "image/jpeg",
|
|
170
|
+
atom: "application/atom+xml",
|
|
171
|
+
rss: "application/rss+xml",
|
|
172
|
+
|
|
173
|
+
mml: "text/mathml",
|
|
174
|
+
jad: "text/vnd.sun.j2me.app-descriptor",
|
|
175
|
+
wml: "text/vnd.wap.wml",
|
|
176
|
+
htc: "text/x-component",
|
|
177
|
+
|
|
178
|
+
png: "image/png",
|
|
179
|
+
tif: "image/tiff",
|
|
180
|
+
tiff: "image/tiff",
|
|
181
|
+
wbmp: "image/vnd.wap.wbmp",
|
|
182
|
+
ico: "image/x-icon",
|
|
183
|
+
jng: "image/x-jng",
|
|
184
|
+
bmp: "image/x-ms-bmp",
|
|
185
|
+
svg: "image/svg+xml",
|
|
186
|
+
svgz: "image/svg+xml",
|
|
187
|
+
webp: "image/webp",
|
|
188
|
+
|
|
189
|
+
woff: "application/font-woff",
|
|
190
|
+
jar: "application/java-archive",
|
|
191
|
+
war: "application/java-archive",
|
|
192
|
+
ear: "application/java-archive",
|
|
193
|
+
hqx: "application/mac-binhex40",
|
|
194
|
+
doc: "application/msword",
|
|
195
|
+
pdf: "application/pdf",
|
|
196
|
+
ps: "application/postscript",
|
|
197
|
+
eps: "application/postscript",
|
|
198
|
+
ai: "application/postscript",
|
|
199
|
+
rtf: "application/rtf",
|
|
200
|
+
m3u8: "application/vnd.apple.mpegurl",
|
|
201
|
+
xls: "application/vnd.ms-excel",
|
|
202
|
+
eot: "application/vnd.ms-fontobject",
|
|
203
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
204
|
+
wmlc: "application/vnd.wap.wmlc",
|
|
205
|
+
kml: "application/vnd.google-earth.kml+xml",
|
|
206
|
+
kmz: "application/vnd.google-earth.kmz",
|
|
207
|
+
cco: "application/x-cocoa",
|
|
208
|
+
jardiff: "application/x-java-archive-diff",
|
|
209
|
+
jnlp: "application/x-java-jnlp-file",
|
|
210
|
+
run: "application/x-makeself",
|
|
211
|
+
pl: "application/x-perl",
|
|
212
|
+
pm: "application/x-perl",
|
|
213
|
+
prc: "application/x-pilot",
|
|
214
|
+
pdb: "application/x-pilot",
|
|
215
|
+
rar: "application/x-rar-compressed",
|
|
216
|
+
rpm: "application/x-redhat-package-manager",
|
|
217
|
+
sea: "application/x-sea",
|
|
218
|
+
swf: "application/x-shockwave-flash",
|
|
219
|
+
sit: "application/x-stuffit",
|
|
220
|
+
tcl: "application/x-tcl",
|
|
221
|
+
tk: "application/x-tcl",
|
|
222
|
+
der: "application/x-x509-ca-cert",
|
|
223
|
+
pem: "application/x-x509-ca-cert",
|
|
224
|
+
crt: "application/x-x509-ca-cert",
|
|
225
|
+
xpi: "application/x-xpinstall",
|
|
226
|
+
xhtml: "application/xhtml+xml",
|
|
227
|
+
xspf: "application/xspf+xml",
|
|
228
|
+
zip: "application/zip",
|
|
229
|
+
|
|
230
|
+
bin: "application/octet-stream",
|
|
231
|
+
exe: "application/octet-stream",
|
|
232
|
+
dll: "application/octet-stream",
|
|
233
|
+
deb: "application/octet-stream",
|
|
234
|
+
dmg: "application/octet-stream",
|
|
235
|
+
iso: "application/octet-stream",
|
|
236
|
+
img: "application/octet-stream",
|
|
237
|
+
msi: "application/octet-stream",
|
|
238
|
+
msp: "application/octet-stream",
|
|
239
|
+
msm: "application/octet-stream",
|
|
240
|
+
|
|
241
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
242
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
243
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
244
|
+
|
|
245
|
+
mid: "audio/midi",
|
|
246
|
+
midi: "audio/midi",
|
|
247
|
+
kar: "audio/midi",
|
|
248
|
+
mp3: "audio/mpeg",
|
|
249
|
+
ogg: "audio/ogg",
|
|
250
|
+
m4a: "audio/x-m4a",
|
|
251
|
+
ra: "audio/x-realaudio",
|
|
252
|
+
|
|
253
|
+
ts: "video/mp2t",
|
|
254
|
+
mp4: "video/mp4",
|
|
255
|
+
mpeg: "video/mpeg",
|
|
256
|
+
mpg: "video/mpeg",
|
|
257
|
+
mov: "video/quicktime",
|
|
258
|
+
webm: "video/webm",
|
|
259
|
+
flv: "video/x-flv",
|
|
260
|
+
m4v: "video/x-m4v",
|
|
261
|
+
mng: "video/x-mng",
|
|
262
|
+
asx: "video/x-ms-asf",
|
|
263
|
+
asf: "video/x-ms-asf",
|
|
264
|
+
wmv: "video/x-ms-wmv",
|
|
265
|
+
avi: "video/x-msvideo",
|
|
266
|
+
|
|
267
|
+
}
|
|
268
|
+
end
|
data/lib/waxx/init.rb
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
# Trap ^C
|
|
4
|
+
Signal.trap("INT") {
|
|
5
|
+
puts "\n\nInstallation terminated by INT (^C)\n"
|
|
6
|
+
exit
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# Trap `Kill `
|
|
10
|
+
Signal.trap("TERM") {
|
|
11
|
+
puts "\n\nInstallation terminated by TERM\n"
|
|
12
|
+
exit
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# Command line init script to create a Waxx app
|
|
16
|
+
module Waxx::Init
|
|
17
|
+
extend self
|
|
18
|
+
|
|
19
|
+
# Defines the default YAML config file
|
|
20
|
+
def default_input(x, opts)
|
|
21
|
+
%(---
|
|
22
|
+
server:
|
|
23
|
+
host: localhost
|
|
24
|
+
port: 7777
|
|
25
|
+
processes: 1
|
|
26
|
+
min_threads: 4
|
|
27
|
+
max_threads: 4
|
|
28
|
+
log_dir: log
|
|
29
|
+
pid_dir: tmp/pids
|
|
30
|
+
|
|
31
|
+
site:
|
|
32
|
+
name: #{`whoami`.chomp.capitalize}'s Website
|
|
33
|
+
support_email: #{`whoami`.chomp}@#{`hostname`.chomp}
|
|
34
|
+
url: http://localhost:7777
|
|
35
|
+
|
|
36
|
+
encryption:
|
|
37
|
+
cipher: AES-256-CBC
|
|
38
|
+
key: #{SecureRandom.base64(32)[0,32]}
|
|
39
|
+
iv: #{SecureRandom.base64(16)[0,16]}
|
|
40
|
+
|
|
41
|
+
cookie:
|
|
42
|
+
user:
|
|
43
|
+
name: wxu
|
|
44
|
+
expires_after_login_mins: 1440
|
|
45
|
+
expires_after_activity_mins: 480
|
|
46
|
+
secure: true
|
|
47
|
+
agent:
|
|
48
|
+
name: wxa
|
|
49
|
+
expires_years: 30
|
|
50
|
+
secure: true
|
|
51
|
+
|
|
52
|
+
debug:
|
|
53
|
+
level: 9
|
|
54
|
+
on_screen: true
|
|
55
|
+
send_email: false
|
|
56
|
+
email: #{`whoami`.chomp}@#{`hostname`.chomp}
|
|
57
|
+
auto_reload_code: true
|
|
58
|
+
|
|
59
|
+
databases:
|
|
60
|
+
app:
|
|
61
|
+
|
|
62
|
+
default:
|
|
63
|
+
app: website
|
|
64
|
+
act: index
|
|
65
|
+
ext: html
|
|
66
|
+
|
|
67
|
+
file:
|
|
68
|
+
serve: true
|
|
69
|
+
path: public
|
|
70
|
+
|
|
71
|
+
init:
|
|
72
|
+
website: true
|
|
73
|
+
html: true
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Some nice ASCII Art to get people excited
|
|
78
|
+
def ascii_art
|
|
79
|
+
# http://www.patorjk.com/software/taag/
|
|
80
|
+
%(
|
|
81
|
+
`8.`888b ,8' .8. `8.`8888. ,8' `8.`8888. ,8'
|
|
82
|
+
`8.`888b ,8' .888. `8.`8888. ,8' `8.`8888. ,8'
|
|
83
|
+
`8.`888b ,8' :88888. `8.`8888. ,8' `8.`8888. ,8'
|
|
84
|
+
`8.`888b .b ,8' . `88888. `8.`8888.,8' `8.`8888.,8'
|
|
85
|
+
`8.`888b 88b ,8' .8. `88888. `8.`88888' `8.`88888'
|
|
86
|
+
`8.`888b .`888b,8' .8`8. `88888. .88.`8888. .88.`8888.
|
|
87
|
+
`8.`888b8.`8888' .8' `8. `88888. .8'`8.`8888. .8'`8.`8888.
|
|
88
|
+
`8.`888`8.`88' .8' `8. `88888. .8' `8.`8888. .8' `8.`8888.
|
|
89
|
+
`8.`8' `8,`' .888888888. `88888. .8' `8.`8888. .8' `8.`8888.
|
|
90
|
+
`8.` `8' .8' `8. `88888. .8' `8.`8888. .8' `8.`8888.
|
|
91
|
+
|
|
92
|
+
Version #{Waxx::Version}
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Start the init process. Fired when `waxx init folder` is called
|
|
97
|
+
def init(x, opts, input=nil)
|
|
98
|
+
puts ""
|
|
99
|
+
puts ascii_art
|
|
100
|
+
puts ""
|
|
101
|
+
# Set defaults
|
|
102
|
+
input ||= YAML.load(default_input(x, opts))
|
|
103
|
+
make_dir(x, opts/:sub_command)
|
|
104
|
+
# Ask a few questions
|
|
105
|
+
input = ask(x, input)
|
|
106
|
+
puts ""
|
|
107
|
+
puts "Here is your config..."
|
|
108
|
+
puts ""
|
|
109
|
+
puts input.to_yaml
|
|
110
|
+
puts ""
|
|
111
|
+
puts ""
|
|
112
|
+
puts "Does this look right? You can edit this YAML file later in #{opts/:sub_command}/opt/dev/config.yaml."
|
|
113
|
+
print "Install? (y|n) [y]: "
|
|
114
|
+
proceed = $stdin.gets.chomp
|
|
115
|
+
if proceed == '' or (proceed =~ /[yY]/) == 0
|
|
116
|
+
install_waxx(x, input, opts)
|
|
117
|
+
else
|
|
118
|
+
init(x, opts, input)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Make the Waxx::Root / app folder
|
|
123
|
+
def make_dir(x, name)
|
|
124
|
+
puts ""
|
|
125
|
+
if File.exist? name
|
|
126
|
+
if not Dir.empty?(name)
|
|
127
|
+
puts "Error. The directory '#{name}' already exists and is not empty."
|
|
128
|
+
puts "I don't want to destroy anything. Bailing out."
|
|
129
|
+
exit 4
|
|
130
|
+
end
|
|
131
|
+
puts "Installing into existing directory: #{name}"
|
|
132
|
+
Dir.unlink name
|
|
133
|
+
else
|
|
134
|
+
puts "Make directory: #{name}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Ask questions about the config
|
|
139
|
+
def ask(x, input)
|
|
140
|
+
get_site(x, input)
|
|
141
|
+
get_key_iv(x, input)
|
|
142
|
+
get_db(x, input)
|
|
143
|
+
input
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get config options about the site
|
|
147
|
+
def get_site(x, input)
|
|
148
|
+
puts ""
|
|
149
|
+
puts "Website/App options:"
|
|
150
|
+
print " Name [#{input/:site/:name}]: "
|
|
151
|
+
name = $stdin.gets.chomp
|
|
152
|
+
print " Support Email [#{input/:site/:support_email}]: "
|
|
153
|
+
support_email = $stdin.gets.chomp
|
|
154
|
+
print " Liston on IP/Host [#{input/:server/:host}]: "
|
|
155
|
+
host = $stdin.gets.chomp
|
|
156
|
+
print " Listen on Port [#{input/:server/:port}]: "
|
|
157
|
+
port = $stdin.gets.chomp
|
|
158
|
+
input['site']['name'] = name unless name == ''
|
|
159
|
+
input['site']['support_email'] = support_email unless support_email == ''
|
|
160
|
+
input['server']['host'] = host unless host == ''
|
|
161
|
+
input['server']['port'] = port unless port == ''
|
|
162
|
+
input['site']['url'] = "http://#{input['server']['host']}:#{input['server']['port']}"
|
|
163
|
+
input
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Get config options about the db
|
|
167
|
+
def get_db(x, input)
|
|
168
|
+
default_db = "postgresql://#{`whoami`.chomp}@localhost/#{`whoami`.chomp}"
|
|
169
|
+
puts ""
|
|
170
|
+
puts "Enter your database connection string (type://user:pass@host:port/db)"
|
|
171
|
+
puts "Types include: postgresql, mysql2, sqlite3, mongodb"
|
|
172
|
+
puts "You can edit or add more database connections by editing opt/dev/config.yaml"
|
|
173
|
+
puts "Enter 'none' if you do not want to connect to a database now"
|
|
174
|
+
puts "[#{input['databases']['app'] || default_db}] "
|
|
175
|
+
print " db: "
|
|
176
|
+
db = $stdin.gets.chomp
|
|
177
|
+
if db.downcase == "none"
|
|
178
|
+
input['databases'] = {}
|
|
179
|
+
else
|
|
180
|
+
input['databases']['app'] = db == '' ? (input['databases']['app'] || default_db) : db
|
|
181
|
+
puts "Create the standard waxx table? (The waxx table is used for migration management.)"
|
|
182
|
+
puts "The databse must already exist and the user must have create table privileges."
|
|
183
|
+
print " Create waxx table (y|n) [y]:"
|
|
184
|
+
initdb = $stdin.gets.chomp
|
|
185
|
+
initdb = initdb == '' or not (initdb =~ /[Yy]/).nil?
|
|
186
|
+
input['init']['db'] = initdb
|
|
187
|
+
end
|
|
188
|
+
input
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Get config options about the encryption
|
|
192
|
+
def get_key_iv(x, input)
|
|
193
|
+
puts ""
|
|
194
|
+
puts "The AES key and initiation vector for encryption."
|
|
195
|
+
puts "The default was generated with SecureRandom.base64()."
|
|
196
|
+
puts "Accept the default or enter 48 (or more) random characters."
|
|
197
|
+
puts "Can not start with an ampersand: &"
|
|
198
|
+
puts "See https://www.grc.com/passwords.htm for inspiration."
|
|
199
|
+
puts "[#{input['encryption']['key']}#{input['encryption']['iv']}] "
|
|
200
|
+
print " Random string: "
|
|
201
|
+
random = $stdin.gets.chomp
|
|
202
|
+
if random.size >= 48
|
|
203
|
+
input['encryption']['key'] = random[0,32]
|
|
204
|
+
input['encryption']['iv'] = random[33,16]
|
|
205
|
+
end
|
|
206
|
+
input
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Install Waxx in the target folder. Copy skel and update the config file
|
|
210
|
+
def install_waxx(x, input, opts)
|
|
211
|
+
skel_folder = "#{File.dirname(__FILE__)}/../../skel/"
|
|
212
|
+
install_folder = opts/:sub_command
|
|
213
|
+
puts ""
|
|
214
|
+
puts "Copying files from #{skel_folder} to #{install_folder}"
|
|
215
|
+
FileUtils.cp_r(skel_folder, install_folder, verbose: false)
|
|
216
|
+
if input/:init/:db
|
|
217
|
+
puts ""
|
|
218
|
+
puts "Setup Database"
|
|
219
|
+
create_waxx_table(x, input)
|
|
220
|
+
end
|
|
221
|
+
if not (input/:databases).empty?
|
|
222
|
+
# Require the correct db lib in app/app.rb
|
|
223
|
+
db_libs = {pg: 'pg', postgresql: 'pg', mysql: 'mysql2', mysql2: 'mysql2', sqlite: 'sqlite3', sqlite3: 'sqlite3', mongo: 'mongodb', mongodb: 'mongodb'}
|
|
224
|
+
db_lib = db_libs[(input/:databases/:app).split(":").first.to_sym]
|
|
225
|
+
puts "Requiring lib '#{db_lib}' in app/app.rb"
|
|
226
|
+
app_rb = File.read("#{install_folder}/app/app.rb")
|
|
227
|
+
File.open("#{install_folder}/app/app.rb","w"){|f|
|
|
228
|
+
f.puts app_rb.sub("# require '#{db_lib}'","require '#{db_lib}'")
|
|
229
|
+
}
|
|
230
|
+
end
|
|
231
|
+
puts ""
|
|
232
|
+
puts "Installing dev config"
|
|
233
|
+
input.delete "init"
|
|
234
|
+
File.open("#{install_folder}/opt/dev/config.yaml","w"){|f| f << input.to_yaml}
|
|
235
|
+
puts ""
|
|
236
|
+
puts "Waxx installed successfully."
|
|
237
|
+
puts "cd into #{install_folder} and run `waxx on` to get your waxx on"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def create_waxx_table(x, input)
|
|
241
|
+
# Require the db lib
|
|
242
|
+
case (input/:databases/:app).split(":").first.downcase
|
|
243
|
+
when 'postgresql'
|
|
244
|
+
require 'pg'
|
|
245
|
+
when 'mysql2'
|
|
246
|
+
require 'mysql2'
|
|
247
|
+
when 'sqlite3'
|
|
248
|
+
require 'sqlite3'
|
|
249
|
+
end
|
|
250
|
+
create_sql = %(
|
|
251
|
+
CREATE TABLE waxx (
|
|
252
|
+
name character varying(254) NOT NULL PRIMARY KEY,
|
|
253
|
+
value character varying(254) NOT NULL,
|
|
254
|
+
CONSTRAINT waxx_uniq UNIQUE(name)
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
insert_sql = %(INSERT INTO waxx (name, value) VALUES ('db.app.migration.last', '0'))
|
|
258
|
+
puts " Connecting to: #{input/:databases/:app}"
|
|
259
|
+
begin
|
|
260
|
+
db = Waxx::Database.connect(input/:databases/:app)
|
|
261
|
+
db.exec(create_sql)
|
|
262
|
+
db.exec(insert_sql)
|
|
263
|
+
puts " Waxx table created successfully."
|
|
264
|
+
rescue => e
|
|
265
|
+
puts %(
|
|
266
|
+
\nERROR: Could not create waxx table. Please create manually:
|
|
267
|
+
\n#{create_sql}
|
|
268
|
+
\n#{insert_sql}
|
|
269
|
+
\nError Detail: #{e}
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
data/lib/waxx/irb.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
# Thanks to http://jasonroelofs.com/2009/04/02/embedding-irb-into-your-ruby-application/
|
|
5
|
+
|
|
6
|
+
require 'irb'
|
|
7
|
+
|
|
8
|
+
# Jump into an IRB session with `waxx console`
|
|
9
|
+
module IRB
|
|
10
|
+
##
|
|
11
|
+
# Start an IRB session for Ruby < 2.4
|
|
12
|
+
def self.start_session_old(binding)
|
|
13
|
+
unless @__initialized
|
|
14
|
+
args = ARGV
|
|
15
|
+
ARGV.replace(ARGV.dup)
|
|
16
|
+
IRB.setup(nil)
|
|
17
|
+
ARGV.replace(args)
|
|
18
|
+
@__initialized = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
workspace = WorkSpace.new(binding)
|
|
22
|
+
|
|
23
|
+
irb = Irb.new(workspace)
|
|
24
|
+
|
|
25
|
+
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
|
26
|
+
@CONF[:MAIN_CONTEXT] = irb.context
|
|
27
|
+
|
|
28
|
+
catch(:IRB_EXIT) do
|
|
29
|
+
irb.eval_input
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Start an IRB session
|
|
35
|
+
# `waxx console`
|
|
36
|
+
def self.start_session(context)
|
|
37
|
+
return self.start_session_old(context) if RUBY_VERSION.to_f < 2.4
|
|
38
|
+
IRB.setup(nil)
|
|
39
|
+
workspace = IRB::WorkSpace.new(context)
|
|
40
|
+
irb = IRB::Irb.new(workspace)
|
|
41
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
|
42
|
+
irb.eval_input
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/waxx/irb_env.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
|
|
2
|
+
# Released under the Apache Version 2 License. See LICENSE.txt.
|
|
3
|
+
|
|
4
|
+
extend Waxx::Console
|
|
5
|
+
|
|
6
|
+
puts "Welcome to Waxx"
|
|
7
|
+
puts "See waxx.io for more info"
|
|
8
|
+
puts ""
|
|
9
|
+
puts "HTTP Methods with URI: "
|
|
10
|
+
puts " get '/app/env'"
|
|
11
|
+
puts " post '/person/record/1?first_name=Jane;last_name=Lee'"
|
|
12
|
+
puts " (This will set the first & last name of person 1.)"
|
|
13
|
+
puts ""
|
|
14
|
+
puts "Pass 'x' to all data methods: "
|
|
15
|
+
puts " App::Person::Record.get(x, id: 1)"
|
|
16
|
+
puts " App::Person::Record.post(x, {first_name:'Jane', last_name: 'Lee'})"
|
|
17
|
+
puts " App::Person::Record.put(x, 1, {first_name:'Joe', last_name: 'Bar'})"
|
|
18
|
+
puts ""
|