amber-kit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +0 -0
- data/amber.gemspec +49 -0
- data/bin/amber +55 -0
- data/lib/amber/controller.rb +5 -0
- data/lib/amber/data/array_data.rb +15 -0
- data/lib/amber/data/date_data.rb +15 -0
- data/lib/amber/data/float_data.rb +13 -0
- data/lib/amber/data/integer_data.rb +13 -0
- data/lib/amber/data/string_data.rb +13 -0
- data/lib/amber/data.rb +14 -0
- data/lib/amber/data_delegate.rb +9 -0
- data/lib/amber/http/request.rb +229 -0
- data/lib/amber/http/response.rb +80 -0
- data/lib/amber/http.rb +9 -0
- data/lib/amber/model.rb +89 -0
- data/lib/amber/route.rb +66 -0
- data/lib/amber/route_path.rb +39 -0
- data/lib/amber/server.rb +103 -0
- data/lib/amber/storage/json.rb +116 -0
- data/lib/amber/storage/remote_json.rb +103 -0
- data/lib/amber/storage.rb +8 -0
- data/lib/amber/switch/content/form_data.rb +43 -0
- data/lib/amber/switch/content/json.rb +35 -0
- data/lib/amber/switch/content/text.rb +22 -0
- data/lib/amber/switch/content.rb +38 -0
- data/lib/amber/switch/content_delegate.rb +9 -0
- data/lib/amber/switch/request/get.rb +5 -0
- data/lib/amber/switch/request/post.rb +7 -0
- data/lib/amber/switch/request.rb +16 -0
- data/lib/amber/switch/response.rb +10 -0
- data/lib/amber/switch.rb +71 -0
- data/lib/amber/view/json.rb +9 -0
- data/lib/amber/view.rb +9 -0
- data/lib/amber.rb +48 -0
- metadata +78 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
class Amber::RoutePath
|
2
|
+
attr_reader :child, :method, :callback
|
3
|
+
|
4
|
+
def initialize(method = "GET", callback = nil)
|
5
|
+
@child = {}
|
6
|
+
@method = method
|
7
|
+
@callback = callback
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_child?
|
11
|
+
!@child.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def can_call?
|
15
|
+
@callback != nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_child(path, child)
|
19
|
+
if child.is_a? Amber::RoutePath
|
20
|
+
@child[path] = child
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
raise ArgumentError, "Child should be a route item"
|
25
|
+
end
|
26
|
+
|
27
|
+
def method=(method)
|
28
|
+
@method = method
|
29
|
+
end
|
30
|
+
|
31
|
+
def callback=(callback)
|
32
|
+
if callback.is_a? Proc
|
33
|
+
@callback = callback
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
raise ArgumentError, "Callback should be a proc"
|
38
|
+
end
|
39
|
+
end
|
data/lib/amber/server.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
class Amber::Server
|
2
|
+
attr_accessor :port, :host, :base
|
3
|
+
|
4
|
+
def initialize(port = 3001, host = '127.0.0.1')
|
5
|
+
@port = port
|
6
|
+
@host = host
|
7
|
+
@server_socket
|
8
|
+
@server_address
|
9
|
+
@fd_set = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
@server_socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
14
|
+
@server_address = Socket.sockaddr_in(@port, @host)
|
15
|
+
|
16
|
+
@server_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
17
|
+
@server_socket.bind(@server_address)
|
18
|
+
@server_socket.listen(5)
|
19
|
+
|
20
|
+
@fd_set << @server_socket
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
loop {
|
25
|
+
fd_items = IO.select(@fd_set, [], [], 5)
|
26
|
+
|
27
|
+
if fd_items.is_a?(Array)
|
28
|
+
readable_items = fd_items.first
|
29
|
+
readable_items.each do |socket|
|
30
|
+
self.communicate(socket)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def communicate(socket)
|
37
|
+
if socket == @server_socket
|
38
|
+
begin
|
39
|
+
client_socket, client_address = @server_socket.accept_nonblock
|
40
|
+
@fd_set << client_socket
|
41
|
+
rescue IO::WaitReadable, Errno::EINTR
|
42
|
+
retry
|
43
|
+
end
|
44
|
+
|
45
|
+
else
|
46
|
+
@fd_set.delete(socket)
|
47
|
+
task = Fiber.new {
|
48
|
+
self.transaction(socket)
|
49
|
+
}
|
50
|
+
task.resume
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def transaction(socket)
|
55
|
+
http_request = Amber::Http::Request.new(socket)
|
56
|
+
http_response = Amber::Http::Response.new(socket)
|
57
|
+
|
58
|
+
if http_request.receive
|
59
|
+
time = Time.new
|
60
|
+
time_string = time.strftime("%Y-%m-%d %H:%M:%S")
|
61
|
+
STDOUT.puts "#{time_string} #{http_request.method} #{http_request.url}"
|
62
|
+
begin
|
63
|
+
if (path = @base.route.find(http_request.url)) && path.can_call?
|
64
|
+
if path.method == http_request.method
|
65
|
+
result = path.callback.call http_request
|
66
|
+
case result
|
67
|
+
when Amber::View
|
68
|
+
http_response.status = result.code.to_s
|
69
|
+
http_response.header = result.header
|
70
|
+
http_response.content_type = result.content.type
|
71
|
+
http_response.body = result.content.body
|
72
|
+
when String
|
73
|
+
http_response.status = "200"
|
74
|
+
http_response.body = result
|
75
|
+
else
|
76
|
+
http_response.status = "500"
|
77
|
+
http_response.body = "<html><h1>Server Internal Error</h1></html>"
|
78
|
+
end
|
79
|
+
else
|
80
|
+
http_response.status = "301"
|
81
|
+
http_response.body = "<html><h1>Moved Permanently</h1></html>"
|
82
|
+
end
|
83
|
+
else
|
84
|
+
http_response.status = "404"
|
85
|
+
http_response.body = "<html><h1>Not Found</h1></html>"
|
86
|
+
end
|
87
|
+
rescue Exception => e
|
88
|
+
STDOUT.puts e
|
89
|
+
end
|
90
|
+
else
|
91
|
+
http_response.status = "400"
|
92
|
+
http_response.body = "<html><h1>Bad Request</h1></html>"
|
93
|
+
end
|
94
|
+
|
95
|
+
http_response.send
|
96
|
+
|
97
|
+
socket.close
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
require "socket"
|
102
|
+
require "fiber"
|
103
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
class Amber::Storage::Json < Amber::Storage
|
2
|
+
def initialize(file_path)
|
3
|
+
@file_path = file_path
|
4
|
+
end
|
5
|
+
|
6
|
+
def fetch
|
7
|
+
data = []
|
8
|
+
if raw_data = self.read_file
|
9
|
+
data = self.deserialize(raw_data)
|
10
|
+
end
|
11
|
+
data.first
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch_all
|
15
|
+
data = []
|
16
|
+
if raw_data = self.read_file
|
17
|
+
data = self.deserialize(raw_data)
|
18
|
+
end
|
19
|
+
data
|
20
|
+
end
|
21
|
+
|
22
|
+
def save(data)
|
23
|
+
if File.exist? @file_path
|
24
|
+
file = File.open(@file_path, "w")
|
25
|
+
file.puts self.serialize(data)
|
26
|
+
file.close
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(data)
|
31
|
+
if raw_data = self.read_file
|
32
|
+
origin_data = self.deserialize(raw_data)
|
33
|
+
new_data = []
|
34
|
+
|
35
|
+
if data.is_a? Array
|
36
|
+
origin_data.each do |item|
|
37
|
+
new_item = item
|
38
|
+
data.each do |data_item|
|
39
|
+
if data_item["id"] == item["id"]
|
40
|
+
new_item = data_item
|
41
|
+
end
|
42
|
+
end
|
43
|
+
new_data.push(new_item)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
origin_data.each do |item|
|
47
|
+
new_item = item
|
48
|
+
if data["id"] == item["id"]
|
49
|
+
new_item = data
|
50
|
+
end
|
51
|
+
new_data.push(new_item)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
self.save(new_data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete(data)
|
60
|
+
if raw_data = self.read_file
|
61
|
+
origin_data = self.deserialize(raw_data)
|
62
|
+
new_data = []
|
63
|
+
|
64
|
+
if data.is_a? Array
|
65
|
+
origin_data.each do |item|
|
66
|
+
retain = true
|
67
|
+
data.each do |data_item|
|
68
|
+
if data_item["id"] == item["id"]
|
69
|
+
retain = false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
new_data.push(item) if retain
|
73
|
+
end
|
74
|
+
else
|
75
|
+
origin_data.each do |item|
|
76
|
+
retain = true
|
77
|
+
if data["id"] == item["id"]
|
78
|
+
retain = false
|
79
|
+
end
|
80
|
+
new_data.push(item) if retain
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
self.save(new_data)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def serialize(data)
|
89
|
+
begin
|
90
|
+
data = [data] unless data.is_a? Array
|
91
|
+
JSON.generate(data)
|
92
|
+
rescue Exception => e
|
93
|
+
p e
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def deserialize(data)
|
98
|
+
begin
|
99
|
+
JSON.parse(data)
|
100
|
+
rescue Exception => e
|
101
|
+
p e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def read_file
|
106
|
+
if File.exist? @file_path
|
107
|
+
file = File.open(@file_path)
|
108
|
+
raw_data = file.read
|
109
|
+
raw_data = "[]" if raw_data.empty?
|
110
|
+
file.close
|
111
|
+
return raw_data
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
require "json"
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class Amber::Storage::RemoteJson < Amber::Storage
|
2
|
+
def initialize(url)
|
3
|
+
@uri = URI.parse(url)
|
4
|
+
@status = false
|
5
|
+
@data = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def query(data)
|
9
|
+
self.request({"token" => "", "data" => data})
|
10
|
+
end
|
11
|
+
|
12
|
+
def request(body = nil)
|
13
|
+
request = Net::HTTP::Post.new(@uri)
|
14
|
+
# request.body = body if body
|
15
|
+
response = nil
|
16
|
+
@status = false
|
17
|
+
@data = {}
|
18
|
+
result = Net::HTTP.start(@uri.hostname, @uri.port) do |http|
|
19
|
+
response = http.request(request)
|
20
|
+
end
|
21
|
+
|
22
|
+
case result
|
23
|
+
when Net::HTTPSuccess
|
24
|
+
info = self.deserialize(result.body)
|
25
|
+
if info.is_a? Hash
|
26
|
+
if info.has_key?("status") && info["status"] == 1
|
27
|
+
@status = true
|
28
|
+
info_data = {}
|
29
|
+
info_data = info["data"] if info.has_key?("data")
|
30
|
+
if info_data.is_a?(Array) || info_data.is_a?(Hash)
|
31
|
+
@data = info_data
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@status = false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize(data)
|
41
|
+
data_string = ""
|
42
|
+
begin
|
43
|
+
data = [data] unless data.is_a? Array
|
44
|
+
data_string = JSON.generate(data)
|
45
|
+
rescue Exception => e
|
46
|
+
p e
|
47
|
+
end
|
48
|
+
data_string
|
49
|
+
end
|
50
|
+
|
51
|
+
def deserialize(data)
|
52
|
+
data_struct = nil
|
53
|
+
begin
|
54
|
+
data_struct = JSON.parse(data)
|
55
|
+
rescue Exception => e
|
56
|
+
p e
|
57
|
+
end
|
58
|
+
data_struct
|
59
|
+
end
|
60
|
+
|
61
|
+
def pack(map)
|
62
|
+
data = nil
|
63
|
+
if map.is_a? Hash
|
64
|
+
if @data.is_a? Hash
|
65
|
+
data = {}
|
66
|
+
map.each do |key, value|
|
67
|
+
if @data.has_key? key
|
68
|
+
data[value] = @data[key]
|
69
|
+
else
|
70
|
+
data[value] = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
elsif @data.is_a? Array
|
74
|
+
data = []
|
75
|
+
@data.each do |result_data_item|
|
76
|
+
if result_data_item.is_a? Hash
|
77
|
+
data_item = {}
|
78
|
+
map.each do |key, value|
|
79
|
+
if @result_data_item.has_key? key
|
80
|
+
data_item[value] = @result_data_item[key]
|
81
|
+
else
|
82
|
+
data_item[value] = nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
data.push data_item
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
data
|
91
|
+
end
|
92
|
+
|
93
|
+
def unpack(data, map)
|
94
|
+
# map.each do |key, value|
|
95
|
+
# if data.is_a? Hash
|
96
|
+
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
require "json"
|
103
|
+
require "net/http"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Amber::Switch::Content::FormData < Amber::Switch::Content
|
2
|
+
include Amber::Switch::ContentDelegate
|
3
|
+
|
4
|
+
def initialize(data = {})
|
5
|
+
super Amber::Switch::Content::FORM_DATA_CONTENT, data
|
6
|
+
end
|
7
|
+
|
8
|
+
def data=(data)
|
9
|
+
if data.is_a? Hash
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize(data)
|
15
|
+
form_data_string = ""
|
16
|
+
if data.is_a? Hash
|
17
|
+
form_data_items = []
|
18
|
+
data.each do |key, value|
|
19
|
+
form_data_item = URI.encode(key) + "=" + URI.encode(value)
|
20
|
+
form_data_items.push form_data_item
|
21
|
+
end
|
22
|
+
form_data_string = form_data_items.join "&"
|
23
|
+
end
|
24
|
+
form_data_string
|
25
|
+
end
|
26
|
+
|
27
|
+
def deserialize(data)
|
28
|
+
form_data = {}
|
29
|
+
form_data_string = data.to_s
|
30
|
+
form_data_items = form_data_string.split '&'
|
31
|
+
form_data_items.each do |form_data_item|
|
32
|
+
info = form_data_item.split '='
|
33
|
+
if info.length == 2
|
34
|
+
key = URI.encode info[0]
|
35
|
+
value = URI.decode info[1]
|
36
|
+
form_data[key] = value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
form_data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
require "uri"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Amber::Switch::Content::Json < Amber::Switch::Content
|
2
|
+
include Amber::Switch::ContentDelegate
|
3
|
+
|
4
|
+
def initialize(data = {})
|
5
|
+
super Amber::Switch::Content::JSON_CONTENT, data
|
6
|
+
end
|
7
|
+
|
8
|
+
def data=(data)
|
9
|
+
if data.is_a? Hash
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize(data)
|
15
|
+
begin
|
16
|
+
return JSON.generate data
|
17
|
+
rescue Exception => e
|
18
|
+
p e
|
19
|
+
end
|
20
|
+
""
|
21
|
+
end
|
22
|
+
|
23
|
+
def deserialize(data)
|
24
|
+
if data.is_a? String
|
25
|
+
begin
|
26
|
+
return JSON.parse data
|
27
|
+
rescue Exception => e
|
28
|
+
p e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require "amber/switch/content_delegate"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Amber::Switch::Content::Text < Amber::Switch::Content
|
2
|
+
include Amber::Switch::ContentDelegate
|
3
|
+
|
4
|
+
def initialize(data = "")
|
5
|
+
super Amber::Switch::Content::TEXT_CONTENT, data
|
6
|
+
end
|
7
|
+
|
8
|
+
def data=(data)
|
9
|
+
if data.is_a? String
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
def serialize(data)
|
14
|
+
data.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def deserialize(data)
|
18
|
+
data.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require "amber/switch/content_delegate"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Amber::Switch::Content
|
2
|
+
attr_accessor :type
|
3
|
+
|
4
|
+
TEXT_CONTENT = 'text/plain'
|
5
|
+
FORM_DATA_CONTENT = 'application/x-www-form-urlencoded'
|
6
|
+
JSON_CONTENT = 'application/json'
|
7
|
+
|
8
|
+
def initialize(type, data = nil)
|
9
|
+
@type = type
|
10
|
+
|
11
|
+
if data
|
12
|
+
self.data = data
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def data
|
17
|
+
@data
|
18
|
+
end
|
19
|
+
|
20
|
+
def data=(data)
|
21
|
+
@data = data
|
22
|
+
end
|
23
|
+
|
24
|
+
def body
|
25
|
+
if self.class.include? Amber::Switch::ContentDelegate
|
26
|
+
return self.serialize @data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def body=(body)
|
31
|
+
if self.class.include? Amber::Switch::ContentDelegate
|
32
|
+
@data = self.deserialize body
|
33
|
+
return
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
require "amber/switch/content_delegate"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Amber::Switch::Request
|
2
|
+
attr_accessor :method, :url, :header
|
3
|
+
|
4
|
+
GET_METHOD = 'GET'
|
5
|
+
POST_METHOD = 'POST'
|
6
|
+
PUT_METHOD = 'PUT'
|
7
|
+
DELETE_METHOD = 'DELETE'
|
8
|
+
|
9
|
+
def initialize(method, url)
|
10
|
+
@method = method
|
11
|
+
@url = url
|
12
|
+
@header = {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require "json"
|
data/lib/amber/switch.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class Amber::Switch
|
2
|
+
def query(request)
|
3
|
+
if request.is_a? Amber::Switch::Request
|
4
|
+
result = nil
|
5
|
+
case request
|
6
|
+
when Amber::Switch::Request::Get
|
7
|
+
result = self.request(request.url, request.method, request.header)
|
8
|
+
when Amber::Switch::Request::Post
|
9
|
+
body = request.content.is_a?(Amber::Switch::Content) ? request.content.body : nil
|
10
|
+
result = self.request(request.url, request.method, request.header, body)
|
11
|
+
end
|
12
|
+
if result
|
13
|
+
response = Amber::Switch::Response.new
|
14
|
+
response.status = result["status"]
|
15
|
+
response.header = result["header"]
|
16
|
+
response_content_type = result["content_type"].is_a?(Array) ? result["content_type"].first : result["content_type"].to_s
|
17
|
+
case response_content_type
|
18
|
+
when Amber::Switch::Content::JSON_CONTENT
|
19
|
+
response.content = Amber::Switch::Content::Json.new
|
20
|
+
response.content.body = result["body"]
|
21
|
+
else
|
22
|
+
response.content = Amber::Switch::Content::Text.new
|
23
|
+
response.content.body = result["body"]
|
24
|
+
end
|
25
|
+
return response
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
p "#{request} should be an instance of Amber::Switch::Request"
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
def request(url, method, header = {}, body = nil)
|
34
|
+
request = nil
|
35
|
+
uri = URI(url)
|
36
|
+
response = {
|
37
|
+
"status" => false,
|
38
|
+
"code" => 400,
|
39
|
+
"content_type" => nil,
|
40
|
+
"header" => {},
|
41
|
+
"body" => nil
|
42
|
+
}
|
43
|
+
case method
|
44
|
+
when Amber::Switch::Request::GET_METHOD
|
45
|
+
request = Net::HTTP::Get.new uri
|
46
|
+
when Amber::Switch::Request::POST_METHOD
|
47
|
+
request = Net::HTTP::Post.new uri
|
48
|
+
end
|
49
|
+
if request
|
50
|
+
header.each do |key, value|
|
51
|
+
request[key] = value
|
52
|
+
end
|
53
|
+
request.body = body if body
|
54
|
+
result = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
55
|
+
http.request(request)
|
56
|
+
end
|
57
|
+
|
58
|
+
case result
|
59
|
+
when Net::HTTPSuccess
|
60
|
+
response["status"] = true
|
61
|
+
response["code"] = result.code.to_i
|
62
|
+
response["content_type"] = result.content_type
|
63
|
+
response["header"] = result.to_hash
|
64
|
+
response["body"] = result.body
|
65
|
+
end
|
66
|
+
end
|
67
|
+
response
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
require "net/http"
|