capricorn 0.2.25 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/LICENSE +19 -0
  2. data/README.md +1 -0
  3. data/bin/capricorn-app-scaffolder +27 -0
  4. data/bin/capricorn-gem-spec +33 -0
  5. data/bin/capricornctl +12 -0
  6. data/bin/capricornd +31 -0
  7. data/erlang/lib/bert/doc/overview.edoc +4 -0
  8. data/erlang/lib/bert/ebin/bert.app +9 -0
  9. data/erlang/lib/bert/rebar.config +3 -0
  10. data/erlang/lib/bert/src/bert.erl +69 -0
  11. data/erlang/lib/bertio/doc/overview.edoc +4 -0
  12. data/erlang/lib/bertio/ebin/bertio.app +9 -0
  13. data/erlang/lib/bertio/rebar.config +3 -0
  14. data/erlang/lib/bertio/src/bertio.erl +28 -0
  15. data/erlang/lib/bertrpc/doc/overview.edoc +4 -0
  16. data/erlang/lib/bertrpc/ebin/bertrpc.app +12 -0
  17. data/erlang/lib/bertrpc/include/bertrpc.hrl +1 -0
  18. data/erlang/lib/bertrpc/rebar.config +5 -0
  19. data/erlang/lib/bertrpc/src/bertrpc.erl +471 -0
  20. data/erlang/lib/bertrpc/src/bertrpc_hello_world.erl +148 -0
  21. data/erlang/lib/bertrpc/src/fd_tcp.erl +376 -0
  22. data/erlang/lib/capricorn/doc/overview.edoc +4 -0
  23. data/erlang/lib/capricorn/ebin/capricorn.app +56 -0
  24. data/erlang/lib/capricorn/include/capricorn.hrl +76 -0
  25. data/erlang/lib/capricorn/rebar.config +3 -0
  26. data/erlang/lib/capricorn/src/cap_application.erl +170 -0
  27. data/erlang/lib/capricorn/src/cap_cluster.erl +121 -0
  28. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +422 -0
  29. data/erlang/lib/capricorn/src/cap_config.erl +25 -0
  30. data/erlang/lib/capricorn/src/cap_dets_updater.erl +26 -0
  31. data/erlang/lib/capricorn/src/cap_event_sup.erl +35 -0
  32. data/erlang/lib/capricorn/src/cap_events.erl +24 -0
  33. data/erlang/lib/capricorn/src/cap_external_api.erl +87 -0
  34. data/erlang/lib/capricorn/src/cap_external_apps_api.erl +125 -0
  35. data/erlang/lib/capricorn/src/cap_external_gems_api.erl +85 -0
  36. data/erlang/lib/capricorn/src/cap_external_machines_api.erl +18 -0
  37. data/erlang/lib/capricorn/src/cap_gem_utils.erl +111 -0
  38. data/erlang/lib/capricorn/src/cap_internal_api.erl +69 -0
  39. data/erlang/lib/capricorn/src/cap_internal_apps_api.erl +38 -0
  40. data/erlang/lib/capricorn/src/cap_log.erl +113 -0
  41. data/erlang/lib/capricorn/src/cap_machine.erl +338 -0
  42. data/erlang/lib/capricorn/src/cap_machine_apps.erl +410 -0
  43. data/erlang/lib/capricorn/src/cap_machine_apps_sup.erl +57 -0
  44. data/erlang/lib/capricorn/src/cap_sup.erl +200 -0
  45. data/erlang/lib/capricorn/src/cap_util.erl +278 -0
  46. data/erlang/lib/capricorn/src/capricorn.erl +45 -0
  47. data/erlang/lib/capricorn/src/capricorn_app.erl +36 -0
  48. data/erlang/lib/emq/ebin/emq.app +17 -0
  49. data/erlang/lib/emq/src/emq.erl +261 -0
  50. data/erlang/lib/emq/src/emq_app.erl +11 -0
  51. data/erlang/lib/emq/src/emq_pool.erl +178 -0
  52. data/erlang/lib/emq/src/emq_queue.erl +332 -0
  53. data/erlang/lib/emq/src/emq_status.erl +148 -0
  54. data/erlang/lib/emq/src/emq_sup.erl +132 -0
  55. data/erlang/lib/gcd/ebin/gcd.app +18 -0
  56. data/erlang/lib/gcd/include/gcd.hrl +5 -0
  57. data/erlang/lib/gcd/rebar.config +3 -0
  58. data/erlang/lib/gcd/src/gcd.erl +51 -0
  59. data/erlang/lib/gcd/src/gcd_app.erl +13 -0
  60. data/erlang/lib/gcd/src/gcd_event.erl +39 -0
  61. data/erlang/lib/gcd/src/gcd_server.erl +30 -0
  62. data/erlang/lib/gcd/src/gcd_srv.erl +186 -0
  63. data/erlang/lib/gcd/src/gcd_sup.erl +18 -0
  64. data/erlang/rebar +0 -0
  65. data/erlang/rebar.config +9 -0
  66. data/erlang/rel/overlay/bin/capricornd +146 -0
  67. data/erlang/rel/overlay/erts-vsn/bin/erl +34 -0
  68. data/erlang/rel/overlay/erts-vsn/bin/nodetool +80 -0
  69. data/erlang/rel/overlay/etc/capricorn/app.config +59 -0
  70. data/erlang/rel/overlay/etc/capricorn/cluster-vm.args +21 -0
  71. data/erlang/rel/overlay/etc/capricorn/machine-vm.args +21 -0
  72. data/erlang/rel/reltool.config +43 -0
  73. data/ext/Makefile +2 -0
  74. data/ext/extconf.rb +1 -0
  75. data/lib/capricorn-client.rb +86 -0
  76. data/lib/capricorn-client/cli/applications.rb +256 -0
  77. data/lib/capricorn-client/cli/gems.rb +57 -0
  78. data/lib/capricorn-client/cli/machines.rb +9 -0
  79. data/lib/capricorn-client/helpers.rb +62 -0
  80. data/lib/capricorn.rb +5 -99
  81. data/lib/capricorn/driver.rb +86 -0
  82. data/lib/capricorn/recipes/apache-debian.rb +112 -0
  83. data/lib/capricorn/recipes/centos-plesk.rb +162 -0
  84. data/lib/capricorn/recipes/macports.rb +54 -0
  85. data/lib/capricorn/system_context.rb +49 -0
  86. data/lib/capricorn/version.rb +5 -0
  87. metadata +233 -74
  88. data/app_generators/engine/engine_generator.rb +0 -40
  89. data/app_generators/engine/templates/Gmfile +0 -20
  90. data/app_generators/engine/templates/MIT-LICENSE.txt +0 -20
  91. data/app_generators/engine/templates/README.rdoc +0 -7
  92. data/app_generators/engine/templates/config/initializers/rails_init.rb +0 -1
  93. data/app_generators/engine/templates/config/routes.rb +0 -2
  94. data/app_generators/engine/templates/gitignore +0 -9
  95. data/app_generators/engine/templates/init.rb +0 -1
  96. data/app_generators/engine/templates/lib/engine.rb +0 -4
  97. data/app_generators/engine/templates/rails/init.rb +0 -1
  98. data/app_generators/engine/templates/tasks/engine_tasks.rake +0 -4
  99. data/bin/capricorn +0 -20
  100. data/lib/capricorn/actor.rb +0 -23
  101. data/lib/capricorn/actor/actions.rb +0 -76
  102. data/lib/capricorn/actors/apache_actor.rb +0 -56
  103. data/lib/capricorn/actors/base_actor.rb +0 -335
  104. data/lib/capricorn/actors/host_file_actor.rb +0 -77
  105. data/lib/capricorn/actors/mysql_actor.rb +0 -20
  106. data/lib/capricorn/actors/passenger_actor.rb +0 -28
  107. data/lib/capricorn/actors/plesk_actor.rb +0 -228
  108. data/lib/capricorn/actors/sqlite3_actor.rb +0 -44
  109. data/lib/capricorn/app_runner.rb +0 -108
  110. data/lib/capricorn/apps/dev.rb +0 -15
  111. data/lib/capricorn/apps/engines.rb +0 -33
  112. data/lib/capricorn/apps/jobs.rb +0 -35
  113. data/lib/capricorn/apps/satellite.rb +0 -68
  114. data/lib/capricorn/apps/server.rb +0 -73
  115. data/lib/capricorn/client.rb +0 -48
  116. data/lib/capricorn/client/auth_token.rb +0 -98
  117. data/lib/capricorn/daemon.rb +0 -81
  118. data/lib/capricorn/exception_handler.rb +0 -79
  119. data/lib/capricorn/extentions/rubygems_plugin.rb +0 -27
  120. data/lib/capricorn/extentions/thor_extentions.rb +0 -32
  121. data/lib/capricorn/job_queue.rb +0 -203
  122. data/lib/capricorn/satellite.rb +0 -52
  123. data/lib/capricorn/satellite/actions.rb +0 -55
  124. data/lib/capricorn/satellite/dependency_loader.rb +0 -82
  125. data/lib/capricorn/satellite/persistence.rb +0 -50
  126. data/lib/capricorn/server.rb +0 -144
  127. data/lib/capricorn/server/daemon.rb +0 -83
  128. data/lib/capricorn/server/proxy.rb +0 -25
  129. data/lib/capricorn/server/security.rb +0 -120
  130. data/lib/capricorn/system.rb +0 -218
  131. data/lib/capricorn/system/config.rb +0 -49
  132. data/lib/capricorn/system/helper.rb +0 -21
  133. data/lib/capricorn/system/options.rb +0 -79
  134. data/lib/capricorn/system/process_user.rb +0 -73
  135. data/lib/capricorn/system/satellites.rb +0 -44
  136. data/lib/capricorn/system/shell.rb +0 -80
  137. data/lib/rubygems_plugin.rb +0 -1
  138. data/spec/actor/actions_spec.rb +0 -13
  139. data/spec/spec_helper.rb +0 -1
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Simon Menke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # Capricorn
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'capricorn'
4
+
5
+ def convert_app(app)
6
+ application = {}
7
+ application[:id] = app[1]
8
+ application[:node] = app[2]
9
+ application[:name] = app[3]
10
+ application[:domain] = app[4].shift
11
+ application[:aliases] = app[4]
12
+ application[:environment] = app[5]
13
+ application
14
+ end
15
+
16
+ Erlang do |cmd|
17
+ case cmd.shift
18
+ when :create
19
+ recipe = cmd.shift
20
+ app = convert_app(cmd.first)
21
+
22
+ recipe_path = File.expand_path("../../lib/capricorn/recipes/#{recipe}.rb", __FILE__)
23
+ ctx = Capricorn::SystemContext.run(recipe_path, :application => app)
24
+
25
+ send t[true, t[ctx.www_user, ctx.www_group, ctx.root_path]]
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'capricorn'
4
+ require 'rubygems/format'
5
+
6
+ Erlang do |path|
7
+
8
+ unless File.extname(path) == ".gem" and File.file?(path)
9
+ error :not_found
10
+ end
11
+
12
+ begin
13
+ format = Gem::Format.from_file_by_path(path)
14
+ rescue Exception => e
15
+ error :gem_error, e.message
16
+ end
17
+
18
+ spec = format.spec
19
+ unless spec
20
+ error :gem_error, "Invalid gem"
21
+ end
22
+
23
+ dependencies = spec.runtime_dependencies.collect do |dep|
24
+ version_requirements = dep.version_requirements.as_list.collect do |req|
25
+ op, version = *req.split(/\s+/, 2)
26
+ BERT::Tuple[op, version]
27
+ end
28
+ BERT::Tuple[dep.name, version_requirements]
29
+ end
30
+
31
+ send BERT::Tuple[spec.name, spec.version.to_s, dependencies]
32
+
33
+ end
data/bin/capricornctl ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(File.expand_path(__FILE__))+'/../../minigems'
4
+
5
+ begin
6
+ require 'capricorn-client'
7
+ rescue LoadError
8
+ $:.unshift(File.dirname(__FILE__)+'/../lib')
9
+ require 'capricorn-client'
10
+ end
11
+
12
+ Capricorn::Runner.start
data/bin/capricornd ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path('../../', $0)
4
+ src = File.expand_path('../../', __FILE__)
5
+ rel = File.join(src, 'erlang/rel/capricorn')
6
+ etc = File.join(root, 'etc/capricorn')
7
+
8
+ if ARGV.size == 1 and ARGV[0] == "install"
9
+ require 'fileutils'
10
+
11
+ FileUtils.mkdir_p(File.join(root, "etc/capricorn"),
12
+ :verbose => true)
13
+ FileUtils.mkdir_p(File.join(root, "var/run/capricorn-machine"),
14
+ :verbose => true)
15
+ FileUtils.mkdir_p(File.join(root, "var/run/capricorn-cluster"),
16
+ :verbose => true)
17
+ FileUtils.mkdir_p(File.join(root, "var/log/sasl"),
18
+ :verbose => true)
19
+
20
+ FileUtils.cp(File.join(rel, 'etc/capricorn/app.config'),
21
+ File.join(etc, 'app.config'),
22
+ :verbose => true)
23
+ FileUtils.cp(File.join(rel, 'etc/capricorn/cluster-vm.args'),
24
+ File.join(etc, 'cluster-vm.args'),
25
+ :verbose => true)
26
+ FileUtils.cp(File.join(rel, 'etc/capricorn/machine-vm.args'),
27
+ File.join(etc, 'machine-vm.args'),
28
+ :verbose => true)
29
+ else
30
+ exec(File.join(rel, 'bin/capricornd'), root, *ARGV)
31
+ end
@@ -0,0 +1,4 @@
1
+ @author Simon Menke <simon.menke@gmail.com>
2
+ @copyright 2010 Simon Menke
3
+ @version {@vsn}
4
+
@@ -0,0 +1,9 @@
1
+ %% This is the application resource file (.app file) for the bert,
2
+ %% application.
3
+ {application, bert,
4
+ [{description, "BERT encoder / decoder"},
5
+ {vsn, "0.1.0"},
6
+ {modules, [bert]},
7
+ {registered,[]},
8
+ {applications, [kernel, stdlib]}
9
+ ]}.
@@ -0,0 +1,3 @@
1
+ {cover_enabled, true}.
2
+ {erl_opts, [debug_info, fail_on_warning, {i, ".."}]}.
3
+ {lib_dirs, [".."]}.
@@ -0,0 +1,69 @@
1
+ %%% See http://github.com/mojombo/bert.erl for documentation.
2
+ %%% MIT License - Copyright (c) 2009 Tom Preston-Werner <tom@mojombo.com>
3
+
4
+ -module(bert).
5
+ -version('1.1.0').
6
+ -author("Tom Preston-Werner").
7
+
8
+ -export([encode/1, decode/1]).
9
+
10
+ -ifdef(TEST).
11
+ -include("test/bert_test.erl").
12
+ -endif.
13
+
14
+ %%---------------------------------------------------------------------------
15
+ %% Public API
16
+
17
+ -spec encode(term()) -> binary().
18
+
19
+ encode(Term) ->
20
+ term_to_binary(encode_term(Term)).
21
+
22
+ -spec decode(binary()) -> term().
23
+
24
+ decode(Bin) ->
25
+ decode_term(binary_to_term(Bin)).
26
+
27
+ %%---------------------------------------------------------------------------
28
+ %% Encode
29
+
30
+ -spec encode_term(term()) -> term().
31
+
32
+ encode_term(Term) ->
33
+ case Term of
34
+ [] -> {bert, nil};
35
+ true -> {bert, true};
36
+ false -> {bert, false};
37
+ Dict when is_record(Term, dict, 9) ->
38
+ {bert, dict, encode_term(dict:to_list(Dict))};
39
+ List when is_list(Term) ->
40
+ lists:map((fun encode_term/1), List);
41
+ Tuple when is_tuple(Term) ->
42
+ TList = tuple_to_list(Tuple),
43
+ TList2 = lists:map((fun encode_term/1), TList),
44
+ list_to_tuple(TList2);
45
+ _Else -> Term
46
+ end.
47
+
48
+ %%---------------------------------------------------------------------------
49
+ %% Decode
50
+
51
+ -spec decode_term(term()) -> term().
52
+
53
+ decode_term(Term) ->
54
+ case Term of
55
+ {bert, nil} -> [];
56
+ {bert, true} -> true;
57
+ {bert, false} -> false;
58
+ {bert, dict, Dict} ->
59
+ dict:from_list(decode_term(Dict));
60
+ {bert, Other} ->
61
+ {bert, Other};
62
+ List when is_list(Term) ->
63
+ lists:map((fun decode_term/1), List);
64
+ Tuple when is_tuple(Term) ->
65
+ TList = tuple_to_list(Tuple),
66
+ TList2 = lists:map((fun decode_term/1), TList),
67
+ list_to_tuple(TList2);
68
+ _Else -> Term
69
+ end.
@@ -0,0 +1,4 @@
1
+ @author Simon Menke <simon.menke@gmail.com>
2
+ @copyright 2010 Simon Menke
3
+ @version {@vsn}
4
+
@@ -0,0 +1,9 @@
1
+ %% This is the application resource file (.app file) for the bertio,
2
+ %% application.
3
+ {application, bertio,
4
+ [{description, "BERT Port"},
5
+ {vsn, "0.1.0"},
6
+ {modules, [bertio]},
7
+ {registered,[]},
8
+ {applications, [kernel, stdlib, bert]}
9
+ ]}.
@@ -0,0 +1,3 @@
1
+ {cover_enabled, true}.
2
+ {erl_opts, [debug_info, fail_on_warning, {i, ".."}]}.
3
+ {lib_dirs, [".."]}.
@@ -0,0 +1,28 @@
1
+ -module(bertio).
2
+
3
+ -export([open_port/2, port_close/1]).
4
+ -export([send/2, recv/1, recv/2]).
5
+
6
+ open_port(PortName, PortOptions) ->
7
+ erlang:open_port(PortName, [{packet, 4}, nouse_stdio, binary|PortOptions]).
8
+
9
+ send(Port, BERT) ->
10
+ BERP = bert:encode(BERT),
11
+ erlang:port_command(Port, BERP).
12
+
13
+ recv(Port) ->
14
+ recv(Port, 1000).
15
+
16
+ recv(Port, Timeout) ->
17
+ receive
18
+ {Port, {data, BERP}} ->
19
+ {bert, bert:decode(BERP)};
20
+ {Port, Other} ->
21
+ {Port, Other}
22
+ after Timeout ->
23
+ erlang:error(timeout)
24
+ end.
25
+
26
+ port_close(Port) ->
27
+ send(Port, stop),
28
+ erlang:port_close(Port).
@@ -0,0 +1,4 @@
1
+ @author Simon Menke <simon.menke@gmail.com>
2
+ @copyright 2010 Simon Menke
3
+ @version {@vsn}
4
+
@@ -0,0 +1,12 @@
1
+ %% This is the application resource file (.app file) for the bertrpc,
2
+ %% application.
3
+ {application, bertrpc,
4
+ [{description, "BERT-RPC Server"},
5
+ {vsn, "0.1.0"},
6
+ {modules, [bertrpc,
7
+ bertrpc_hello_world,
8
+ fd_tcp]},
9
+ {registered,[]},
10
+ {applications, [kernel, stdlib, bert]}
11
+ ]}.
12
+
@@ -0,0 +1,5 @@
1
+ {cover_enabled, true}.
2
+ {erl_opts, [debug_info, fail_on_warning, {i, ".."}]}.
3
+ {lib_dirs, [".."]}.
4
+
5
+ {erl_first_files, ["src/fd_tcp.erl", "src/bertrpc.erl"]}.
@@ -0,0 +1,471 @@
1
+ -module(bertrpc).
2
+ -behaviour(fd_tcp).
3
+
4
+
5
+
6
+ -export([call/3, call/4, call/5, call/6, cast/4, cast/5, cast/6, info/2, reply/2, stream/0]).
7
+
8
+ -export([listen_link/4, listen_link/3, listen/4, listen/3]).
9
+ -export([connect_link/3, connect_link/2, connect/3, connect/2]).
10
+
11
+ -export([behaviour_info/1]).
12
+ -export([init/1, handle_call/3, handle_cast/2, handle_data/2,
13
+ handle_info/2, terminate/2, code_change/3]).
14
+
15
+
16
+
17
+ -type client_ref() :: {pid(), reference()} .
18
+ -type request_info() :: {atom(), [term()]} .
19
+ -type action() :: {'call' | 'cast', atom(), atom(), [term()]} .
20
+
21
+ -record(request, {
22
+ action :: action(),
23
+ infos=[] :: [request_info()],
24
+ stream :: 'undefined' | [binary()] | binary(),
25
+ client :: client_ref()
26
+ }).
27
+ -type request() :: #request{} .
28
+
29
+ -record(state, {
30
+ callback :: 'undefined' | atom(),
31
+ state :: term(),
32
+
33
+ req_in :: 'undefined' | request(),
34
+ req_out :: 'undefined' | request(),
35
+ queue :: queue()
36
+ }).
37
+ -type state() :: #state{} .
38
+
39
+
40
+ -define(SOCK_OPTS, [binary, {packet, 4}]).
41
+
42
+
43
+
44
+ %%% Behaviour API
45
+ behaviour_info(callbacks) ->
46
+ [{init,1}, {handle_call, 3}, {handle_cast, 2}, {handle_info, 2}, {terminate,2}, {code_change,3}];
47
+ behaviour_info(_) ->
48
+ undefined.
49
+
50
+
51
+
52
+ %%% Start the server
53
+ listen_link(Name, Callback, Args, Port) ->
54
+ fd_tcp:listen_link(Name, ?MODULE, {Callback, Args}, Port, ?SOCK_OPTS).
55
+
56
+ listen_link(Callback, Args, Port) ->
57
+ fd_tcp:listen_link(?MODULE, {Callback, Args}, Port, ?SOCK_OPTS).
58
+
59
+
60
+ listen(Name, Callback, Args, Port) ->
61
+ fd_tcp:listen(Name, ?MODULE, {Callback, Args}, Port, ?SOCK_OPTS).
62
+
63
+ listen(Callback, Args, Port) ->
64
+ fd_tcp:listen(?MODULE, {Callback, Args}, Port, ?SOCK_OPTS).
65
+
66
+
67
+
68
+ %%% Start the client
69
+ connect_link(Name, Host, Port) ->
70
+ fd_tcp:connect_link(Name, ?MODULE, {}, Host, Port, ?SOCK_OPTS).
71
+
72
+ connect_link(Host, Port) ->
73
+ fd_tcp:connect_link(?MODULE, {}, Host, Port, ?SOCK_OPTS).
74
+
75
+
76
+ connect(Name, Host, Port) ->
77
+ fd_tcp:connect(Name, ?MODULE, {}, Host, Port, ?SOCK_OPTS).
78
+
79
+ connect(Host, Port) ->
80
+ fd_tcp:connect(?MODULE, {}, Host, Port, ?SOCK_OPTS).
81
+
82
+
83
+
84
+ %%% External Process API
85
+ call(Name, Module, Function, Arguments) ->
86
+ call(Name, Module, Function, Arguments, []).
87
+
88
+ call(Name, Module, Function, Arguments, Infos) ->
89
+ call(Name, Module, Function, Arguments, Infos, undefined).
90
+
91
+ call(Name, Module, Function, Arguments, Infos, Stream) ->
92
+ fd_tcp:call(Name, #request{
93
+ action = {call, Module, Function, Arguments},
94
+ infos = Infos,
95
+ stream = Stream
96
+ }).
97
+
98
+
99
+ cast(Name, Module, Function, Arguments) ->
100
+ cast(Name, Module, Function, Arguments, []).
101
+
102
+ cast(Name, Module, Function, Arguments, Infos) ->
103
+ cast(Name, Module, Function, Arguments, Infos, undefined).
104
+
105
+ cast(Name, Module, Function, Arguments, Infos, Stream) ->
106
+ fd_tcp:call(Name, #request{
107
+ action = {cast, Module, Function, Arguments},
108
+ infos = Infos,
109
+ stream = Stream
110
+ }).
111
+
112
+
113
+ reply(wire, {error, Reason}) ->
114
+ send_chunks(bert:encode({error, Reason}));
115
+
116
+ reply(wire, Response) ->
117
+ send_chunks(bert:encode({reply, Response}));
118
+
119
+ reply(Client, Response) ->
120
+ fd_tcp:reply(Client, Response).
121
+
122
+
123
+
124
+ %%% Internal Process API
125
+ -spec info(atom(), [term()]) -> ok .
126
+ info(Command, Options) ->
127
+ send_chunks(bert:encode({info, Command, Options})).
128
+
129
+
130
+ -spec call(atom(), atom(), [term()]) -> term() | {error, term()} .
131
+ call(Module, Function, Arguments) ->
132
+ send_chunks(bert:encode({call, Module, Function, Arguments})).
133
+
134
+
135
+ -spec cast(atom(), atom(), [term()]) -> ok .
136
+ cast(Module, Function, Arguments) ->
137
+ send_chunks(bert:encode({cast, Module, Function, Arguments})).
138
+
139
+
140
+ -spec stream() -> {ok, binary() | eof} | {error, term()} .
141
+ stream() ->
142
+ case fd_tcp:recv(0) of
143
+ {error, Reason} -> {error, Reason};
144
+ {ok, <<"">>} -> {ok, eof};
145
+ {ok, Packet} -> {ok, Packet}
146
+ end.
147
+
148
+
149
+ -spec stream([binary()] | binary() | undefined) -> ok .
150
+ stream(undefined) ->
151
+ ok;
152
+
153
+ stream(Chunks) ->
154
+ send_chunks(Chunks),
155
+ send_chunks(eof).
156
+
157
+
158
+ -spec send_chunks([binary()] | binary() | eof | undefined) -> ok .
159
+ send_chunks(Chunk) when is_binary(Chunk) ->
160
+ fd_tcp:send(Chunk);
161
+
162
+ send_chunks(eof) ->
163
+ send_chunks(<<"">>);
164
+
165
+ send_chunks(undefined) ->
166
+ ok;
167
+
168
+ send_chunks(Chunks) when is_list(Chunks) ->
169
+ [send_chunks(Chunk) || Chunk <- Chunks].
170
+
171
+
172
+
173
+ %%% Initialize the server
174
+ init({Callback, Args}) ->
175
+ case Callback:init(Args) of
176
+ {ok, SubState} ->
177
+ {ok, #state{callback=Callback, state=SubState, queue=queue:new()}};
178
+
179
+ {ok, SubState, hibernate} ->
180
+ {ok, #state{callback=Callback, state=SubState, queue=queue:new()}, hibernate};
181
+
182
+ {ok, SubState, Timeout} ->
183
+ {ok, #state{callback=Callback, state=SubState, queue=queue:new()}, Timeout};
184
+
185
+ {stop, Reason} ->
186
+ {stop, Reason};
187
+
188
+ ignore ->
189
+ ignore
190
+ end;
191
+
192
+ init({}) ->
193
+ {ok, #state{queue=queue:new()}}.
194
+
195
+
196
+
197
+ %%% Handle call messages
198
+ -spec handle_call(request(), client_ref(), state()) -> {noreply, state()}.
199
+ handle_call(#request{}=Request, From, #state{}=State) ->
200
+ {noreply, try_send_request({Request, From}, State)};
201
+
202
+ handle_call(Request, From, State) ->
203
+ #state{ callback=Callback, state=CallbackState } = State,
204
+ Response = Callback:handle_call(Request, From, CallbackState),
205
+ do_handle_callback_response(Response, State).
206
+
207
+
208
+
209
+ %%% Handle cast messages
210
+ handle_cast(stop, State) ->
211
+ {stop, normal, State};
212
+
213
+ handle_cast(Msg, State) ->
214
+ #state{ callback=Callback, state=CallbackState } = State,
215
+ Response = Callback:handle_cast(Msg, CallbackState),
216
+ do_handle_callback_response(Response, State).
217
+
218
+
219
+
220
+ %%% Handle generic messages
221
+ handle_info(Info, State) ->
222
+ #state{ callback=Callback, state=CallbackState } = State,
223
+ Response = Callback:handle_info(Info, CallbackState),
224
+ do_handle_callback_response(Response, State).
225
+
226
+
227
+
228
+ %%% Handle data messages
229
+ handle_data(Data, #state{ req_in=undefined }=State) ->
230
+ handle_data(Data, State#state{req_in = #request{}});
231
+
232
+ handle_data(<<"">>, #state{}=State) ->
233
+ {noreply, State};
234
+
235
+ handle_data(Data, #state{}=State) ->
236
+ case bert:decode(Data) of
237
+ {call, _, _, _} = Action ->
238
+ #state { req_in = Request1 } = State,
239
+ State2 = State#state { req_in = Request1#request { action = Action } },
240
+ do_handle_request(State2);
241
+ {cast, _, _, _} = Action ->
242
+ #state { req_in = Request1 } = State,
243
+ State2 = State#state { req_in = Request1#request { action = Action } },
244
+ do_handle_request(State2);
245
+ {info, Command, Options} ->
246
+ {noreply, do_handle_info(Command, Options, State)};
247
+ {reply, Result} ->
248
+ {noreply, do_handle_reply(Result, State)};
249
+ {error, Reason} ->
250
+ {noreply, do_handle_error(Reason, State)};
251
+ {noreply} ->
252
+ {noreply, do_handle_noreply(State)}
253
+ end.
254
+
255
+
256
+
257
+ %%% Before stopping the server
258
+ terminate(_Reason, _State) ->
259
+ ok.
260
+
261
+
262
+
263
+ %%% Code Changes
264
+ code_change(_OldVsn, State, _Extra) ->
265
+ {ok, State}.
266
+
267
+
268
+
269
+ %%% Internal API
270
+ do_handle_info(Command, Options, #state{}=State) ->
271
+ #state{ req_in = Request } = State,
272
+ #request{ infos = Infos } = Request,
273
+
274
+ State#state{
275
+ req_in = Request#request{ infos = [{Command, Options}|Infos] }
276
+ }.
277
+
278
+
279
+ do_handle_request(State) ->
280
+ #state{ req_in = Request } = State,
281
+ #request{ action = Action, infos = Infos } = Request,
282
+ {Type, Module, Function, Arguments} = Action,
283
+
284
+ #state{ callback = Callback, state = CallbackState } = State,
285
+
286
+ case Type of
287
+ call ->
288
+ case Callback:handle_call({Module, Function, Arguments, Infos}, wire, CallbackState) of
289
+ {reply, {error, Reason}, NewState} ->
290
+ fd_tcp:send(bert:encode({error, Reason})),
291
+ State2 = State#state{ req_in = undefined, state = NewState },
292
+ {noreply, State2};
293
+
294
+ {reply, Response, NewState} ->
295
+ fd_tcp:send(bert:encode({reply, Response})),
296
+ State2 = State#state{ req_in = undefined, state = NewState },
297
+ {noreply, State2};
298
+
299
+ {reply, {error, Reason}, NewState, hibernate} ->
300
+ fd_tcp:send(bert:encode({error, Reason})),
301
+ State2 = State#state{ req_in = undefined, state = NewState },
302
+ {noreply, State2, hibernate};
303
+
304
+ {reply, Response, NewState, hibernate} ->
305
+ fd_tcp:send(bert:encode({reply, Response})),
306
+ State2 = State#state{ req_in = undefined, state = NewState },
307
+ {noreply, State2, hibernate};
308
+
309
+ {reply, {error, Reason}, NewState, Timeout} ->
310
+ fd_tcp:send(bert:encode({error, Reason})),
311
+ State2 = State#state{ req_in = undefined, state = NewState },
312
+ {noreply, State2, Timeout};
313
+
314
+ {reply, Response, NewState, Timeout} ->
315
+ fd_tcp:send(bert:encode({reply, Response})),
316
+ State2 = State#state{ req_in = undefined, state = NewState },
317
+ {noreply, State2, Timeout};
318
+
319
+ {noreply, NewState} ->
320
+ State2 = State#state{ state = NewState },
321
+ {noreply, State2};
322
+
323
+ {noreply, NewState, hibernate} ->
324
+ State2 = State#state{ state = NewState },
325
+ {noreply, State2, hibernate};
326
+
327
+ {noreply, NewState, Timeout} ->
328
+ State2 = State#state{ state = NewState },
329
+ {noreply, State2, Timeout};
330
+
331
+ {stop, Reason, {error, E}, NewState} ->
332
+ fd_tcp:send(bert:encode({error, E})),
333
+ State2 = State#state{ req_in = undefined, state = NewState },
334
+ {stop, Reason, State2};
335
+
336
+ {stop, Reason, Reply, NewState} ->
337
+ fd_tcp:send(bert:encode({reply, Reply})),
338
+ State2 = State#state{ req_in = undefined, state = NewState },
339
+ {stop, Reason, State2};
340
+
341
+ {stop, Reason, NewState} ->
342
+ fd_tcp:send(bert:encode({error, Reason})),
343
+ State2 = State#state{ req_in = undefined, state = NewState },
344
+ {stop, Reason, State2}
345
+ end;
346
+ cast ->
347
+ fd_tcp:send(bert:encode({noreply})),
348
+
349
+ case Callback:handle_cast({Module, Function, Arguments, Infos}, CallbackState) of
350
+ {noreply, NewState} ->
351
+ State2 = State#state{ state = NewState },
352
+ {noreply, State2};
353
+
354
+ {noreply, NewState, hibernate} ->
355
+ State2 = State#state{ state = NewState },
356
+ {noreply, State2, hibernate};
357
+
358
+ {noreply, NewState, Timeout} ->
359
+ State2 = State#state{ state = NewState },
360
+ {noreply, State2, Timeout};
361
+
362
+ {stop, Reason, NewState} ->
363
+ State2 = State#state{ req_in = undefined, state = NewState },
364
+ {stop, Reason, State2}
365
+ end
366
+ end.
367
+
368
+
369
+ do_reset_out_state(State) ->
370
+ State#state{req_out=undefined}.
371
+
372
+
373
+ do_handle_reply(Result, State1) ->
374
+ #state{ req_out = Request } = State1,
375
+ #request{ client = Client } = Request,
376
+ fd_tcp:reply(Client, Result),
377
+ State2 = do_reset_out_state(State1),
378
+ try_send_request(queued, State2).
379
+
380
+
381
+ do_handle_error(Reason, State1) ->
382
+ #state{ req_out = Request } = State1,
383
+ #request{ client = Client } = Request,
384
+ fd_tcp:reply(Client, {error, Reason}),
385
+ State2 = do_reset_out_state(State1),
386
+ try_send_request(queued, State2).
387
+
388
+
389
+ do_handle_noreply(State1) ->
390
+ #state{ req_out = Request } = State1,
391
+ #request{ client = Client } = Request,
392
+ fd_tcp:reply(Client, ok),
393
+ State2 = do_reset_out_state(State1),
394
+ try_send_request(queued, State2).
395
+
396
+
397
+ % send Request from the queue (if there is one)
398
+ try_send_request(queued, #state{req_out=undefined}=State) ->
399
+ #state{ queue = Queue1 } = State,
400
+ case queue:out(Queue1) of
401
+ {{value, Request}, Queue2} ->
402
+ #request { action = Action, infos = Infos, stream = Stream } = Request,
403
+
404
+ [begin {Command, Options} = Info, info(Command, Options) end || Info <- Infos],
405
+ case Action of
406
+ {call, Module, Function, Arguments} ->
407
+ call(Module, Function, Arguments);
408
+ {cast, Module, Function, Arguments} ->
409
+ cast(Module, Function, Arguments)
410
+ end,
411
+ stream(Stream),
412
+
413
+ State#state{ queue = Queue2, req_out = Request };
414
+ {empty, _} ->
415
+
416
+ State
417
+ end;
418
+
419
+ % send a request directly
420
+ try_send_request({Request, From}, #state{req_out=undefined}=State) ->
421
+ #request { action = Action, infos = Infos, stream = Stream } = Request,
422
+
423
+ [begin {Command, Options} = Info, info(Command, Options) end || Info <- Infos],
424
+ case Action of
425
+ {call, Module, Function, Arguments} ->
426
+ call(Module, Function, Arguments);
427
+ {cast, Module, Function, Arguments} ->
428
+ cast(Module, Function, Arguments)
429
+ end,
430
+ stream(Stream),
431
+
432
+ State#state{
433
+ req_out = Request#request{ client = From }
434
+ };
435
+
436
+ % put a request on the queue
437
+ try_send_request({Request, From}, #state{}=State) ->
438
+ #state{ queue = Queue1 } = State,
439
+
440
+ Request2 = Request#request{ client = From },
441
+ Queue2 = queue:in(Request2, Queue1),
442
+
443
+ State#state{ queue = Queue2 }.
444
+
445
+
446
+ do_handle_callback_response(Response, #state{}=State) ->
447
+ case Response of
448
+ {reply, Reply, NewCallbackState} ->
449
+ {reply, Reply, State#state{ state=NewCallbackState }};
450
+
451
+ {reply, Reply, NewCallbackState, hibernate} ->
452
+ {reply, Reply, State#state{ state=NewCallbackState }, hibernate};
453
+
454
+ {reply, Reply, NewCallbackState, Timeout} ->
455
+ {reply, Reply, State#state{ state=NewCallbackState }, Timeout};
456
+
457
+ {noreply, NewCallbackState} ->
458
+ {noreply, State#state{ state=NewCallbackState }};
459
+
460
+ {noreply, NewCallbackState, hibernate} ->
461
+ {noreply, State#state{ state=NewCallbackState }, hibernate};
462
+
463
+ {noreply, NewCallbackState, Timeout} ->
464
+ {noreply, State#state{ state=NewCallbackState }, Timeout};
465
+
466
+ {stop, Reason, Reply, NewCallbackState} ->
467
+ {stop, Reason, Reply, State#state{ state=NewCallbackState }};
468
+
469
+ {stop, Reason, NewCallbackState} ->
470
+ {stop, Reason, State#state{ state=NewCallbackState }}
471
+ end.