How to start deps application automatcially in Chicago Boss? - erlang

I can't figure out how to automatically start an "deps" applciation in Chicago Boss.
Use applcation:which_applications() I can see a bunch started like "lager, ranch, cowboy ..etc etc". How do I start another one I added?
If I go to console and run application:start(oauth2) and it's ok. I can start it.
But I tried to change src/xxx.app.src and add it to {applications,[]}, but no go. Isn't this the place to load/start any application that mine depends on?
But I can't find how boss loads and start all the other applications either.
By the way, this oauth2 appliation doesn't contain an application-behavior file (oauth2_app.erl) so I don't know if this is related. Since I can manually start it ok.
So, confused. Any help would be appreciated.
Plus: I remember that I did start application by adding the application:start(xxx) into the /priv/init/xxx_01_news.erl init function but that's very hackish I think.

You can use rebar.config to add your dependency applications then edit boss.config file this way:
First: Add the dependency applications name in applications.
Second: Add their specific configurations as follows.
boss.config file:
[
{boss, [
{path, "./deps/boss"},
{applications, [your_app_name, your_app_dep_1, your_app_dep_2]},
{assume_locale, "en"},
%% ... other configuration
%% APPLICATION CONFIGURATIONS
{your_app_name, []},
{your_app_dep_1, []},
{your_app_dep_2, []}
].
Edit: This way CB expects another boss application so looks for the router file and warns if cannot find it. However starting the dependencies inside its init function is not a dirty way and I suggest to consider it.

Related

Does Erlang's ssh_sftp library provide for a way to listen for directory changes?

I need to watch or listen to a folder on an SFTP server for any changes. At some given time in the future (I don't know when), the folder will be updated with a file. Instead of pinging every minute, how would I setup a listener or watcher on that folder so I know when it has that file? Does Erlang's ssh_sftp module provide a function for this?
Neither SFTP nor FTP protocol have any mechanism to notify a client about changes in a remote folder. The only solution to detect changes is to periodically enumerate remote directory tree and find differences.
Ref : https://winscp.net/eng/docs/library_example_watch_for_changes
I don't know whether you still need it or not but I have already implemented what you need. I won't be able to share the code due to legal agreements however I can hint you the way to implement it.
Requirement: Run a function whenever a file lands to a directory instead of polling the directory at a defined interval to make processing efficient.
Step 1: Start the ssh daemon process with sftp as a subsystem
{ok, Pid} = ssh:daemon(Port, [{user_passwords, [{User, Pass}]},
{system_dir, SystemDir},
{user_dir, UserDir},
{key_cb, cac_auth},
{shell, {cacsftpd_server, display_info, []}},
{subsystems, [ssh_sftpd:subsystem_spec([{cwd,
Home}, {file_handler, sftpd_file_handler}])]}])
Step 2: In sftpd_file_handler you can apply the trigger to call ur desired handler once the file is completely transferred ;)).
While not in Erlang, but rather Elixir, take a look at: https://github.com/Codenaut/exsftpd/blob/master/lib/sftpd_file_handler.ex
The essential bit is the write function:
defmodule Exsftpd.SftpFileHandler do
...
def write(io_device, data, state) do
{:file.write(io_device, data), state}
my_custom_function(state)
{:ok, state}
end
...
end
Here you can call whatever function you desire after (or instead of) writing the content to the filesystem.
Initialise the server like so: (see https://github.com/Codenaut/exsftpd/blob/master/lib/server.ex for a more elaborate example):
:ssh.daemon(2222,
system_dir: '/tmp/ssh',
subsystems: [
Exsftpd.SftpdChannel.subsystem_spec(
file_handler: {Exsftpd.SftpFileHandler, []}
)
],
user_dir: '/tmp/ssh/users'
)

Can I use an existing OTP application inside another application or module?

I'm building a system that needs to use a previously built OTP application (lets call it X). If I want to build a new OTP application / module, how can I use the application that already exists from a module, for instance?
I assumed I could call start, since it follows the application behaviour, and so I built a minimalistic application Y that has the following code:
y.erl:
-module(y).
-behaviour(application).
start(_StartType, _StartArgs) ->
io:format("going to call x_app~n"),
{ok, _} = x_app:start([]),
io:format("called x_app~n"),
y:start_link().
stop(_State) ->
ok = x_app:stop([]),
ok.
Rebar compiles this code successfully and generates no warnings.
rel/y/bin/y start outputs nothing at all (I hoped to get the output of at least one io:format)
rel/y/bin/y stop outputs Node is not running!
You need to list application x as a dependent application in your application's .app resource file, or since you're using rebar, in your .app.src file:
{application, your_app,
[{description,"your application"},
{vsn, "0.1"},
{modules,[]},
{registered, []},
{mod,{your_app,[]}},
{env, []},
{applications,[kernel, stdlib, x]}]}.
Note in the very last line that x is listed as an application dependency. This results in the Erlang application controller ensuring that x is started before it starts your application. And if you're starting your application interactively in an Erlang shell via application:ensure_all_started/1,2 this declaration will ensure that x is started first before your app starts.

erlang webmachine not reading dispatch.conf

I'm working through an online tutorial on webmachine http://en.wikiversity.org/wiki/Web_Development_with_Webmachine_for_Erlang. I've downloaded the source from github, created a new application using
/webmachine/scripts/new_webmachine.sh prp
then used make to build it and started it with the standard start script. The skeleton app runs fine and you can see the home page but there is no dispatch.conf file present in the /priv directory and even if I add one it doesn't seem to pick it up - amongst the startup log I can see there is a (default?) dispatch setup but adding and altering dispatch.conf doesn't change it.
=PROGRESS REPORT==== 23-Jul-2014::20:03:32 ===
supervisor: {local,prp_sup}
started: [{pid,<0.81.0>},
{name,webmachine_mochiweb},
{mfargs,
{webmachine_mochiweb,start,
[[{ip,"0.0.0.0"},
{port,8080},
{log_dir,"priv/log"},
{dispatch,[{[],prp_resource,[]}]}]]}},
{restart_type,permanent},
{shutdown,5000},
{child_type,worker}]
I've looked around to see if the configuration has moved somehow but the documentation that comes with the source seems to suggest /priv/dispatch.conf is correct. I'm stumped - any help would be gratefully accepted.
Thanks,
Joe
The example that you are following is not correct. When using new_webmachine.sh to create you webmachine app, the configuration of the routes will not be stored in priv/dispatch.conf but created in src/prp_config.erl.
In order to get it to use dispatch.conf you need to change prp_config:dispatch/0 to:
-spec dispatch() -> [webmachine_dispatcher:route()].
dispatch() ->
{ok, Routes} = file:consult("priv/dispatch.conf"),
Routes.
and then add priv/dispatch.conf as:
{[], prp_resource, []}.

Erlang: add libraries to application

I use erlIDE (based on Eclipse) to work on Erlang projects. Till today everything was fine, but today I have to use external library (couchbeam) in my application. I found out, what is hell, btw.)
The problem is simple – I cannot include external library to compiler path. I've used rebar to get couchbeam's dependencies and it also downloaded ibrowse, mochiweb and ejson.
How can I include those libraries to compiler path without modifing ERL_LIBS to work on project in erlIDE?
I do not want modify ERL_LIBS, because I can change projects's path, start new one (then I should modify ERL_LIBS again) and so on.
I've tried compiler options in erlIDE:
{pa, {pa, 'site_stater/deps/couchbeam/'}}
or
{pa, {pa, '../deps/couchbeam/'}}
where 'site_stater' – is project's name
I wonder how professional erlang programmers organaze their projects workflow (where they write erlang progs, how debuggin it, deal with external libraries and so on).
Many thanks for your attension.
UPDATE
I wrote simple function to load libraries, but I think it is still wrong way to deal with this problem:
load_libraries() ->
ProjectRoot = filename:join([filename:absname("./"), "site_stater"]),
{ok, DepsList} = file:list_dir(ProjectRoot ++ "/deps/"),
lists:foreach(fun (Folder) ->
RealFolder = ProjectRoot ++ "/deps/" ++ Folder,
case filelib:is_dir(RealFolder) of
true ->
code:add_patha(filename:join([RealFolder, "/ebin"]));
false -> ok
end
end,
DepsList),
ok.
I can't verify it right now, but you should be able to use {pa, '../deps/couchbeam/'} in the compiler options. If that doesn't work, please try using an absolute path.
The compiler settings are not finished yet, we plan to have some simpler way to refer to external libraries but we're not there yet. Every such query from users increases the importance of fixing it!
regards,
Vlad

Working example for Erlang Server Interface

I am trying to make Erlang's Inets mode_esi work and run some function. So, far, I did not succeed. Can someone post a minimal example of how to run Inets so that a url like http:localhost:8099/esi/my_mod:foo will invoke the method my_mod:foo/3?
Addition: I have started inets with these commands:
inets:start(),
inets:start(httpd, [{port, 8099}, {server_name, "localhost"}, {document_root, "."},
{server_root, "."}, {erl_script_alias, {"/esi", [my_esi, io]}}]).
The module is:
-module(my_esi).
-export([foo/3]).
foo(Sid, Env, In) -> mod_esi:deliver(Sid, ["bla"]).
But browsing to http://localhost:8099/esi/my_esi:foo result in an error message.
To clarify what has already been said, I'll give a working example (from the ground up). This is to help those who came here from google, mostly because it's how I found it ;)
First, create the module:
# filename: my_esi.erl
-module(my_esi).
-export([foo/3,bar/3]).
foo(Sid, Env, In) -> mod_esi:deliver(Sid, ["foo"]).
bar(Sid, Env, In) -> mod_esi:deliver(Sid, ["bar"]).
Save it, then compile it:
erlc my_esi.erl
You'll now have my_esi.beam
Then run the shell from bash
erl
Within the shell type the following:
inets:start().
{Httpd_State,Httpd_Pid} = inets:start(httpd, [{port, 8099}, {server_name, "localhost"}, {document_root, "."}, {modules,[mod_esi]},{server_root, "."}, {erl_script_alias, {"/esi", [my_esi, io]}}]).
The important part here is:
{modules,[mod_esi]}
If you need other modules, load them by appending them to the list.
To clarify how/why:
I will first admit that it does seems a bit strange at first, and that the documentation was less helpful than I had hoped. However, I realised that:
modules() -> [atom()]
becomes:
{modules, [mod_access, mod_esi, ..., etc.]}
Hope it helps someone :)
I've solved it myself. For some reason, beyond my understanding, the exact same code worked when I invoked Inets with a configuration file (a modified version of inets/examples/server_root/conf/8080.conf). I suppose that the example file includes a more complete list of properties that Inets required than what I listed in inets:start(httpd, [...]). If anyone encounters Inets problem in the future, my advice is to start with the example configuration.
Ok, here goes:
set {erl_script_alias, {"/esi", [my_mod]}} for the inets web server, so the module is accepted.
Write my_mod. Something like:
-module(my_mod).
-export([foo/3]).
foo(SessID, _Env, _Input) ->
mod_esi:deliver(SessID, ["Data ", <<"as">>, " an iolist"]).
Make sure mod_esi is part of inets section called module: {modules, [.., mod_esi, ..}}
This step is very important: Breathe 3 times, recite the holy words "I pray to thee, inets, that you will work this time". Cross your fingers.
Drink a cup of coffee. Tea will not do. It has to be coffee.
Enjoy your web server.

Resources