capricorn 0.2.25 → 2.0.0

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.
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.