capricorn 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
- data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
- data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
- data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
- data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
- data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
- data/erlang/lib/ejson/Makefile +24 -0
- data/erlang/lib/ejson/ebin/ejson.app +9 -0
- data/erlang/lib/ejson/include/ejson.hrl +40 -0
- data/erlang/lib/ejson/rebar.config +3 -0
- data/erlang/lib/ejson/src/ejson.erl +22 -0
- data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
- data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
- data/erlang/lib/ejson/test/arrays.escript +47 -0
- data/erlang/lib/ejson/test/compound.escript +56 -0
- data/erlang/lib/ejson/test/literals.escript +30 -0
- data/erlang/lib/ejson/test/numbers.escript +70 -0
- data/erlang/lib/ejson/test/objects.escript +51 -0
- data/erlang/lib/ejson/test/strings.escript +49 -0
- data/erlang/lib/ejson/test/timing.escript +43 -0
- data/erlang/lib/ejson/test/timing.json +382 -0
- data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
- data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
- data/erlang/lib/misultin/LICENSE.txt +41 -0
- data/erlang/lib/misultin/Makefile +26 -0
- data/erlang/lib/misultin/README.txt +120 -0
- data/erlang/lib/misultin/ebin/misultin.app +9 -0
- data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
- data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
- data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
- data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
- data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
- data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
- data/erlang/lib/misultin/include/misultin.hrl +95 -0
- data/erlang/lib/misultin/make.bat +55 -0
- data/erlang/lib/misultin/priv/README.txt +12 -0
- data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
- data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
- data/erlang/lib/misultin/rebar.config +3 -0
- data/erlang/lib/misultin/src/misultin.app.src +9 -0
- data/erlang/lib/misultin/src/misultin.erl +338 -0
- data/erlang/lib/misultin/src/misultin_http.erl +488 -0
- data/erlang/lib/misultin/src/misultin_req.erl +280 -0
- data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
- data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
- data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
- data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
- data/erlang/rebar.config +2 -0
- data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
- data/erlang/rel/reltool.config +5 -0
- data/lib/capricorn/recipes/apache-debian.rb +1 -1
- data/lib/capricorn/recipes/centos-plesk.rb +1 -1
- data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
- data/lib/capricorn/recipes/macports.rb +1 -1
- data/lib/capricorn/version.rb +1 -1
- metadata +51 -4
@@ -20,6 +20,7 @@
|
|
20
20
|
cap_cluster,
|
21
21
|
cap_cluster_gems,
|
22
22
|
cap_config,
|
23
|
+
cap_console_dispatcher,
|
23
24
|
cap_dets_updater,
|
24
25
|
cap_events,
|
25
26
|
cap_event_sup,
|
@@ -53,6 +54,6 @@
|
|
53
54
|
cap_secondary_services,
|
54
55
|
cap_sup
|
55
56
|
]},
|
56
|
-
{applications, [kernel, stdlib, sasl, inets, bertio, bertrpc, emq]},
|
57
|
+
{applications, [kernel, stdlib, sasl, inets, bertio, bertrpc, emq, misultin, ejson]},
|
57
58
|
{mod, {capricorn_app, []}}
|
58
59
|
]}.
|
@@ -2,7 +2,7 @@
|
|
2
2
|
-behaviour(gen_server).
|
3
3
|
-include("capricorn.hrl").
|
4
4
|
|
5
|
-
-export([start_link/0, push/1, missing/0, lookup/1, lookup/2, pull/1, pull/2, check/0, all/0]).
|
5
|
+
-export([start_link/0, push/1, missing/0, lookup/1, lookup/2, pull/1, pull/2, check/0, all/0, all/1]).
|
6
6
|
-export([init/1, handle_call/3, handle_cast/2,
|
7
7
|
handle_info/2, terminate/2, code_change/3]).
|
8
8
|
|
@@ -52,6 +52,11 @@ all() ->
|
|
52
52
|
gen_server:call(cap_cluster_gems, {all}).
|
53
53
|
|
54
54
|
|
55
|
+
-spec all(node()) -> {ok, [gem_id()]} .
|
56
|
+
all(Node) ->
|
57
|
+
gen_server:call({cap_cluster_gems, Node}, {all}).
|
58
|
+
|
59
|
+
|
55
60
|
-spec check() -> ok .
|
56
61
|
check() ->
|
57
62
|
gen_server:cast(cap_cluster_gems, check).
|
@@ -0,0 +1,214 @@
|
|
1
|
+
-module(cap_console_dispatcher).
|
2
|
+
-export([start_link/1, stop/0]).
|
3
|
+
-include("capricorn.hrl").
|
4
|
+
|
5
|
+
% start misultin http server
|
6
|
+
start_link(Port) ->
|
7
|
+
misultin:start_link([
|
8
|
+
{port, Port},
|
9
|
+
{loop, fun(Req) -> handle_http(Req, Port) end},
|
10
|
+
{ws_loop, fun(Ws) -> handle_websocket(Ws) end}
|
11
|
+
]).
|
12
|
+
|
13
|
+
% stop misultin
|
14
|
+
stop() ->
|
15
|
+
misultin:stop().
|
16
|
+
|
17
|
+
% callback on request received
|
18
|
+
handle_http(Req, _Port) ->
|
19
|
+
handle_rest(Req:get(method), Req:resource([lowercase, urldecode]), Req).
|
20
|
+
|
21
|
+
|
22
|
+
handle_rest('GET', [], Req) ->
|
23
|
+
Req:ok("Hello World.");
|
24
|
+
|
25
|
+
handle_rest(Method, ["machines" |Rest], Req) ->
|
26
|
+
handle_machines_rest(Method, Rest, Req);
|
27
|
+
|
28
|
+
handle_rest(Method, ["gems" |Rest], Req) ->
|
29
|
+
handle_gems_rest(Method, Rest, Req);
|
30
|
+
|
31
|
+
handle_rest(_, _, Req) ->
|
32
|
+
handle_404(Req).
|
33
|
+
|
34
|
+
|
35
|
+
handle_gems_rest('GET', [], Req) ->
|
36
|
+
{ok, All} = cap_cluster_gems:all(cap_config:get(machine, cluster, cluster)),
|
37
|
+
JSON = lists:foldl(fun(Gem, Acc) ->
|
38
|
+
[gem_id_to_json(Gem) |Acc]
|
39
|
+
end, [], All),
|
40
|
+
Req:ok([{"Content-Type", "application/json"}], ejson:encode(JSON));
|
41
|
+
|
42
|
+
handle_gems_rest('POST', [], Req) ->
|
43
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_gems_rest: POST, []");
|
44
|
+
|
45
|
+
handle_gems_rest(Method, [Gem, Version |Rest], Req) ->
|
46
|
+
handle_gem_rest(Method, {Gem, Version}, Rest, Req);
|
47
|
+
|
48
|
+
handle_gems_rest(_, _, Req) ->
|
49
|
+
handle_404(Req).
|
50
|
+
|
51
|
+
|
52
|
+
handle_gem_rest('GET', {Gem, Version}, [], Req) ->
|
53
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: GET, ~p, []", [{Gem, Version}]);
|
54
|
+
|
55
|
+
handle_gem_rest('PUT', {Gem, Version}, [], Req) ->
|
56
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: PUT, ~p, []", [{Gem, Version}]);
|
57
|
+
|
58
|
+
handle_gem_rest('DELETE', {Gem, Version}, [], Req) ->
|
59
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: DELETE, ~p, []", [{Gem, Version}]);
|
60
|
+
|
61
|
+
handle_gem_rest(_, _, _, Req) ->
|
62
|
+
handle_404(Req).
|
63
|
+
|
64
|
+
|
65
|
+
handle_machines_rest('GET', [], Req) ->
|
66
|
+
Nodes = [atom_to_list(node()) | [atom_to_list(Node) || Node <- nodes()]],
|
67
|
+
Machines = [list_to_binary(Node) || Node <- Nodes,
|
68
|
+
string:substr(Node, 1, 8) == "machine-"],
|
69
|
+
Req:ok([{"Content-Type", "application/json"}], ejson:encode(Machines));
|
70
|
+
|
71
|
+
handle_machines_rest(Method, [Machine |Rest], Req) ->
|
72
|
+
handle_machine_rest(Method, Machine, Rest, Req);
|
73
|
+
|
74
|
+
handle_machines_rest(_, _, Req) ->
|
75
|
+
handle_404(Req).
|
76
|
+
|
77
|
+
|
78
|
+
handle_machine_rest(Method, Machine, ["applications" |Rest], Req) ->
|
79
|
+
handle_apps_rest(Method, Machine, Rest, Req);
|
80
|
+
|
81
|
+
handle_machine_rest(_, _, _, Req) ->
|
82
|
+
handle_404(Req).
|
83
|
+
|
84
|
+
|
85
|
+
handle_apps_rest('GET', Machine, [], Req) ->
|
86
|
+
All = cap_machine_apps:all(list_to_atom(Machine)),
|
87
|
+
JSON = lists:foldl(fun(App, Acc) ->
|
88
|
+
[app_to_json(App) |Acc]
|
89
|
+
end, [], All),
|
90
|
+
Req:ok([{"Content-Type", "application/json"}], ejson:encode(JSON));
|
91
|
+
|
92
|
+
handle_apps_rest('POST', Machine, [], Req) ->
|
93
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, []", [Machine]);
|
94
|
+
|
95
|
+
handle_apps_rest(Method, Machine, [Application |Rest], Req) ->
|
96
|
+
handle_app_rest(Method, Machine, Application, Rest, Req);
|
97
|
+
|
98
|
+
handle_apps_rest(_, _, _, Req) ->
|
99
|
+
handle_404(Req).
|
100
|
+
|
101
|
+
|
102
|
+
handle_app_rest('GET', Machine, Application, [], Req) ->
|
103
|
+
Resp = cap_machine_apps:one(list_to_atom(Machine), ?l2b(Application)),
|
104
|
+
case Resp of
|
105
|
+
{ok, App} ->
|
106
|
+
JSON = ejson:encode(app_to_json(App)),
|
107
|
+
Req:ok([{"Content-Type", "application/json"}], JSON);
|
108
|
+
_ ->
|
109
|
+
handle_404(Req)
|
110
|
+
end;
|
111
|
+
|
112
|
+
handle_app_rest('PUT', Machine, Application, [], Req) ->
|
113
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: PUT, ~p, ~p, []", [Machine, Application]);
|
114
|
+
|
115
|
+
handle_app_rest('DELETE', Machine, Application, [], Req) ->
|
116
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: DELETE, ~p, ~p, []", [Machine, Application]);
|
117
|
+
|
118
|
+
handle_app_rest('POST', Machine, Application, ["start"], Req) ->
|
119
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [start]", [Machine, Application]);
|
120
|
+
|
121
|
+
handle_app_rest('POST', Machine, Application, ["restart"], Req) ->
|
122
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [restart]", [Machine, Application]);
|
123
|
+
|
124
|
+
handle_app_rest('POST', Machine, Application, ["stop"], Req) ->
|
125
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [stop]", [Machine, Application]);
|
126
|
+
|
127
|
+
handle_app_rest('POST', Machine, Application, ["update"], Req) ->
|
128
|
+
Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [update]", [Machine, Application]);
|
129
|
+
|
130
|
+
handle_app_rest(_, _, _, _, Req) ->
|
131
|
+
handle_404(Req).
|
132
|
+
|
133
|
+
|
134
|
+
handle_404(Req) ->
|
135
|
+
Req:respond(404, [{"Content-Type", "text/plain"}], "Page not found.").
|
136
|
+
|
137
|
+
|
138
|
+
% callback on received websockets data
|
139
|
+
handle_websocket(Ws) ->
|
140
|
+
receive
|
141
|
+
{browser, Data} ->
|
142
|
+
Ws:send(["received '", Data, "'"]),
|
143
|
+
handle_websocket(Ws);
|
144
|
+
_Ignore ->
|
145
|
+
handle_websocket(Ws)
|
146
|
+
after 5000 ->
|
147
|
+
Ws:send("pushing!"),
|
148
|
+
handle_websocket(Ws)
|
149
|
+
end.
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
app_to_json(App) ->
|
156
|
+
% -record(application, {
|
157
|
+
% id=undefined :: 'undefined' | binary(),
|
158
|
+
% node=undefined :: 'undefined' | atom(),
|
159
|
+
% name=undefined :: 'undefined' | binary(),
|
160
|
+
% domains=[] :: [binary(),...],
|
161
|
+
% environment=development :: atom(),
|
162
|
+
% www_user=undefined :: 'undefined' | binary(),
|
163
|
+
% www_group=undefined :: 'undefined' | binary(),
|
164
|
+
% root_path=undefined :: 'undefined' | binary(),
|
165
|
+
% installed_gems=[] :: [gem_id()],
|
166
|
+
% required_gems=[] :: [binary()],
|
167
|
+
% rvsn={rvsn, 0}
|
168
|
+
% }).
|
169
|
+
|
170
|
+
{[
|
171
|
+
{<<"id">>, App#application.id},
|
172
|
+
{<<"node">>, ?a2b(App#application.node)},
|
173
|
+
{<<"name">>, App#application.name},
|
174
|
+
{<<"domains">>, App#application.domains},
|
175
|
+
{<<"environment">>, ?a2b(App#application.environment)},
|
176
|
+
{<<"www_user">>, App#application.www_user},
|
177
|
+
{<<"www_group">>, App#application.www_group},
|
178
|
+
{<<"root_path">>, App#application.root_path},
|
179
|
+
{<<"installed_gems">>, lists:foldl(fun(Gem, Acc1) ->
|
180
|
+
[gem_id_to_json(Gem) |Acc1]
|
181
|
+
end, [], App#application.required_gems)},
|
182
|
+
{<<"required_gems">>, App#application.required_gems}
|
183
|
+
]}.
|
184
|
+
|
185
|
+
|
186
|
+
gem_id_to_json(Gem) ->
|
187
|
+
% -record(gem_id, {
|
188
|
+
% name :: binary(),
|
189
|
+
% version :: version()
|
190
|
+
% }).
|
191
|
+
% -type version_part() :: pos_integer() | string() .
|
192
|
+
% -type version_parts() :: [version_part(),...] .
|
193
|
+
% -type version() :: {version_parts()} .
|
194
|
+
|
195
|
+
{Parts} = Gem#gem_id.version,
|
196
|
+
Version = lists:foldl(fun(Part, Acc2) ->
|
197
|
+
Str = case Part of
|
198
|
+
Part when is_integer(Part) ->
|
199
|
+
integer_to_list(Part);
|
200
|
+
Part ->
|
201
|
+
Part
|
202
|
+
end,
|
203
|
+
|
204
|
+
case Acc2 of
|
205
|
+
undefined -> Str;
|
206
|
+
_ -> Acc2 ++ [$. |Str]
|
207
|
+
end
|
208
|
+
end, undefined, Parts),
|
209
|
+
|
210
|
+
{[
|
211
|
+
{<<"name">>, Gem#gem_id.name},
|
212
|
+
{<<"version">>, ?l2b(Version)}
|
213
|
+
]}.
|
214
|
+
|
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
|
7
7
|
-export([start_link/0]).
|
8
|
-
-export([create/4, create/5, import/7, import/8, update/3, update/4, fupdate/1, fupdate/2, update_gem/1, update_gem/2, all/0, all/1]).
|
8
|
+
-export([create/4, create/5, import/7, import/8, update/3, update/4, fupdate/1, fupdate/2, update_gem/1, update_gem/2, all/0, all/1, one/1, one/2]).
|
9
9
|
-export([init/1, handle_call/3, handle_cast/2,
|
10
10
|
handle_info/2, terminate/2, code_change/3]).
|
11
11
|
|
@@ -105,6 +105,20 @@ all(Node) ->
|
|
105
105
|
|
106
106
|
|
107
107
|
|
108
|
+
-spec one(binary()) -> application().
|
109
|
+
|
110
|
+
one(Id) ->
|
111
|
+
gen_server:call(cap_machine_apps, {one, Id}).
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
-spec one(atom(), binary()) -> application().
|
116
|
+
|
117
|
+
one(Node, Id) ->
|
118
|
+
gen_server:call({cap_machine_apps, Node}, {one, Id}).
|
119
|
+
|
120
|
+
|
121
|
+
|
108
122
|
%%% Initialize the server
|
109
123
|
init([]) ->
|
110
124
|
Root = cap_config:get(machine, database, "var/run/capricorn"),
|
@@ -126,6 +140,16 @@ handle_call({all}, _From, #ctx{apps=Apps}=State) ->
|
|
126
140
|
All = dets:foldl(fun(App, Acc) -> [App|Acc] end, [], Apps),
|
127
141
|
{reply, All, State};
|
128
142
|
|
143
|
+
handle_call({one, Id}, _From, #ctx{}=State) ->
|
144
|
+
try
|
145
|
+
{ok, App} = do_lookup_app(Id, State),
|
146
|
+
{reply, {ok, App}, State}
|
147
|
+
catch
|
148
|
+
T:E ->
|
149
|
+
?LOG_ERROR("error while getting one app ~s: ~p", [Id, E]),
|
150
|
+
{reply, {T, E}, State}
|
151
|
+
end;
|
152
|
+
|
129
153
|
handle_call(_Request, _From, State) ->
|
130
154
|
{reply, ok, State}.
|
131
155
|
|
@@ -88,6 +88,7 @@ start_server(NodeType) ->
|
|
88
88
|
|
89
89
|
start_primary_services(cluster) ->
|
90
90
|
ExternalApi = cap_config:get(cluster, api),
|
91
|
+
ConsolePort = cap_config:get(cluster, console_port),
|
91
92
|
|
92
93
|
supervisor:start_link({local, cap_primary_services}, cap_sup,
|
93
94
|
{{one_for_one, 10, 3600},[
|
@@ -121,6 +122,12 @@ start_primary_services(cluster) ->
|
|
121
122
|
1000,
|
122
123
|
worker,
|
123
124
|
[cap_external_api]},
|
125
|
+
{cap_console_dispatcher,
|
126
|
+
{cap_console_dispatcher, start_link, [ConsolePort]},
|
127
|
+
permanent,
|
128
|
+
1000,
|
129
|
+
worker,
|
130
|
+
[cap_console_dispatcher]},
|
124
131
|
{cap_runtime,
|
125
132
|
{cap_runtime, start_link, ["cluster"]},
|
126
133
|
permanent,
|
@@ -130,6 +137,7 @@ start_primary_services(cluster) ->
|
|
130
137
|
]});
|
131
138
|
start_primary_services(machine) ->
|
132
139
|
InternalApi = cap_config:get(machine, api),
|
140
|
+
ConsolePort = cap_config:get(machine, console_port),
|
133
141
|
|
134
142
|
supervisor:start_link({local, cap_primary_services}, cap_sup,
|
135
143
|
{{one_for_one, 10, 3600},[
|
@@ -169,6 +177,12 @@ start_primary_services(machine) ->
|
|
169
177
|
infinity,
|
170
178
|
supervisor,
|
171
179
|
[cap_machine_apps_sup]},
|
180
|
+
{cap_console_dispatcher,
|
181
|
+
{cap_console_dispatcher, start_link, [ConsolePort]},
|
182
|
+
permanent,
|
183
|
+
1000,
|
184
|
+
worker,
|
185
|
+
[cap_console_dispatcher]},
|
172
186
|
{cap_runtime,
|
173
187
|
{cap_runtime, start_link, ["machine"]},
|
174
188
|
permanent,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
all: test
|
3
|
+
|
4
|
+
test: beam
|
5
|
+
test/literals.escript
|
6
|
+
test/numbers.escript
|
7
|
+
test/strings.escript
|
8
|
+
test/objects.escript
|
9
|
+
test/arrays.escript
|
10
|
+
test/compound.escript
|
11
|
+
test/timing.escript
|
12
|
+
|
13
|
+
BUILT=\
|
14
|
+
ebin/ejson.beam \
|
15
|
+
ebin/ejson_decode.beam \
|
16
|
+
ebin/ejson_encode.beam \
|
17
|
+
ebin/mochijson2.beam \
|
18
|
+
ebin/rfc4627.beam
|
19
|
+
|
20
|
+
beam: $(BUILT)
|
21
|
+
|
22
|
+
ebin/%.beam: src/%.erl
|
23
|
+
@mkdir -p ebin
|
24
|
+
erlc -o ebin/ $<
|
@@ -0,0 +1,9 @@
|
|
1
|
+
%% This is the application resource file (.app file) for the bert,
|
2
|
+
%% application.
|
3
|
+
{application, ejson,
|
4
|
+
[{description, "JSON encoder / decoder"},
|
5
|
+
{vsn, "0.1.0"},
|
6
|
+
{modules, [ejson, ejson_decode, ejson_encode]},
|
7
|
+
{registered,[]},
|
8
|
+
{applications, [kernel, stdlib]}
|
9
|
+
]}.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
% Characters
|
3
|
+
-define(DQ, 34). % Double quote
|
4
|
+
-define(PL, 43). % Plus sign
|
5
|
+
-define(CM, 44). % Comma
|
6
|
+
-define(HY, 45). % Hyphen
|
7
|
+
-define(PR, 46). % Period
|
8
|
+
-define(FS, 47). % Forward solidus
|
9
|
+
-define(ZR, 48). % Zero
|
10
|
+
-define(NI, 57). % Nine
|
11
|
+
-define(CL, 58). % Colon
|
12
|
+
-define(UE, 69). % E
|
13
|
+
-define(LB, 91). % Left bracket
|
14
|
+
-define(RS, 92). % Reverse solidus
|
15
|
+
-define(RB, 93). % Right bracket
|
16
|
+
-define(LE, 101). % e
|
17
|
+
-define(LC, 123). % Left curly brace
|
18
|
+
-define(RC, 125). % Right curly brace
|
19
|
+
|
20
|
+
% Escapes
|
21
|
+
-define(ESDQ, 16#5C22). % \"
|
22
|
+
-define(ESRS, 16#5C5C). % \\
|
23
|
+
-define(ESFS, 16#5C2F). % \/
|
24
|
+
-define(ESBS, 16#5C62). % \b
|
25
|
+
-define(ESFF, 16#5C66). % \f
|
26
|
+
-define(ESNL, 16#5C6E). % \n
|
27
|
+
-define(ESCR, 16#5C72). % \r
|
28
|
+
-define(ESTB, 16#5C74). % \t
|
29
|
+
-define(ESUE, 16#5C75). % \u
|
30
|
+
|
31
|
+
% Whitespace
|
32
|
+
-define(BS, 8). % Backspace
|
33
|
+
-define(TB, 9). % Tab
|
34
|
+
-define(NL, 10). % New line
|
35
|
+
-define(FF, 12). % Form feed
|
36
|
+
-define(CR, 13). % Carriage return
|
37
|
+
-define(SP, 32). % Space
|
38
|
+
|
39
|
+
% Error
|
40
|
+
-define(EXIT(E), throw({error, E})).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
-module(ejson).
|
3
|
+
|
4
|
+
-export([decode/1, encode/1]).
|
5
|
+
|
6
|
+
decode(Data) when is_list(Data) ->
|
7
|
+
decode(list_to_binary(Data));
|
8
|
+
decode(Data) when is_binary(Data) ->
|
9
|
+
case (catch ejson_decode:value(Data)) of
|
10
|
+
{error, Reason} ->
|
11
|
+
throw({invalid_json, Reason});
|
12
|
+
{_Rest, EJson} ->
|
13
|
+
EJson
|
14
|
+
end.
|
15
|
+
|
16
|
+
encode(Term) ->
|
17
|
+
case (catch ejson_encode:value(Term)) of
|
18
|
+
{error, Reason} ->
|
19
|
+
throw({invalid_erljson, Reason});
|
20
|
+
Else ->
|
21
|
+
Else
|
22
|
+
end.
|