amber-kit 0.0.1
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
- 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"
|