how to connect to Cassandra with Elixir - erlang

I have included cqerl in my project the Erlang driver for Elixir
According to the documentation the Erlang syntax to connect is:
{ok, Client} = cqerl:new_client({}).
I just do not know how to translate the above to Elixir syntax.

As you are using Erlang via Elixir you have to call the Erlang module like this:
{:ok, client} = :cqerl.new_client({})
If you want to invoke Cassandra using a specific address you can create a new client as described in the cqerl documentation:
{:ok, client} = :cqerl.new_client({"127.0.0.1", 9042})
or if you indend to pass in more options such as authentification as second parameter (It is usually a bad idea to put your password in the code, rather use env variables or a config file ignored by git):
{:ok, client} = :cqerl.new_client({"127.0.0.1", 9042}, , [{auth, {cqerl_auth_plain_handler, [{"Your-Username", "Your-Password"}]}}])

Related

How To Use Erlang ssl:close/2

I have an SSL server, and I want to downgrade this after receiving the first ssl:recv to a raw gen_tcp. Assuming this can be used to do that I can not find an example on how to use this. And I am not so good at using the Erlang/OTP documentation yet http://erlang.org/doc/man/ssl.html#close-2
I am a bit confused with NewController::pid() from the documentation:
How = timeout() | {NewController::pid(), timeout()}
NewController::pid() here refers to the process you want to set as the "controlling process" for the downgraded TCP socket. gen_tcp functions on the socket will only work if called from that process. You'll want to send self() here unless you want to use the downgraded TCP socket from another process.
The only example I could find of ssl:close/2 being used with a tuple as the second argument is this test. Here's a simplified version of that code to get you started:
% Assuming `SSLSocket` is the SSL socket.
{ok, TCPSocket} = ssl:close(SSLSocket, {self(), 10000}),
% You can use `TCPSocket` with `gen_tcp` now.
gen_tcp:send(TCPSocket, "foo"),

Best way to log access to web pages

One of my website is using Nitrogen with a Cowboy server.
I would like to log every access to web pages just like Apache does with access.log.
What would be the best way to do that ?
You can use cowboy middlewares https://ninenines.eu/docs/en/cowboy/1.0/guide/middlewares/
Just create a simple log module:
-module(app_web_log).
-behaviour(cowboy_middleware).
-export([execute/2]).
execute(Req, Env) ->
{{Peer, _}, Req2} = cowboy_req:peer(Req),
{Method, Req3} = cowboy_req:method(Req2),
{Path, Req4} = cowboy_req:path(Req3),
error_logger:info_msg("~p: [~p]: ~p ~p", [calendar:universal_time(), Peer, Method, Path]),
{ok, Req4, Env}.
and add it in list of middlwares:
{ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [
{env, [{dispatch, Dispatch}]},
{middlewares, [cowboy_router, app_web_log, cowboy_handler]}]).
Try using Nitrogen on top of the Yaws web server instead, since it performs access logging by default.
Each underlying webserver does it differently (or not at all) - this is something simple_bridge does not yet have abstracted.
So in the case of cowboy, you'll likely have to rig it up yourself.
If you're using a newer build of Nitrogen (if you have the file site/src/nitrogen_main_handler.erl), then you can edit that file to manually log yourself. For example, using erlang's error handler, you could add something simple like:
log_request() ->
error_logger:info_msg("~p: [~p]: ~p", [{date(), time()}, wf:peer_ip(), wf:url()]).
run() ->
handlers(),
log_request(), %% <--- insert before wf_core:run()
wf_core:run().
Then whatever happens with the log can be handled by configuring error_logger to write to disk (http://erldocs.com/17.0/kernel/error_logger.html?i=13&search=error_logger#logfile/1)
If you use an older Nitrogen (which would have site/src/nitrogen_cowboy.erl), then you would similarly edit that file, once again before the wf_core:run() call.
Alternatively, your hooks option with cowboy could work as well. I've not worked with them, so you're on your own there :)

right way to register an internal ejabberd module

Lately I have been woorking with ejabberd and internal module development.
I would like to have an internal module developed using gen_mod + gen_server behaviours. My module has an ejabberd hook which is based on this one: http://metajack.im/2008/08/28/writing-ejabberd-modules-presence-storms
My start_link function is like:
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
Where ?PROCNAME is:
-define(PROCNAME, ejabberd_mod_mine)
So in my localhost it is registered as ejabberd_mod_mine_localhost
As you see in the tutorial I linked, they use an hook in order to parse the presence stanza directly, but what if I want to compare the From value with a value I saved in the gen_server state? I thought of using a gen_server cast passing the packet to it, but the problem is that the function hook runs in a different process and therefore I cannot use:
gen_server:cast(self(), {filter, Packet})
and I can just use:
gen_server:cast(ejabberd_mod_mine_localhost, {filter, Packet})
But should I hardcode the name of the process? What if the host name is different? Should I register my gen_server using just its module name?
A common pattern is to use the domain of either the sender or the receiving user (depending on what you are trying to do). For example mod_offline (that store packets on DB when the destination user is offline) uses the destination JID to discover on which domain it have to run, something like:
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME)

How to pass extra arguments to RabbitMQ connection in Erlang client

I have written some extension modules for eJabberd most of which pass pieces of information to RabbitMQ for various reasons. All has been fine until we brought the server up in staging where we have a Rabbit cluster rather than a single box.
In order to utilize the cluster you need to pass "x-ha-policy" parameter to Rabbit with either the "all" or "nodes" value. This works fine for the Java and Python Producers and Consumers, but the eJabberd (using the Erlang AMQP client of course) has me a bit stumped. The x-ha-policy parameter needs to be passed into the "client_properties" parameter which is just the "catchall" for extra parameters.
In Python with pika I can do:
client_params = {"x-ha-policy": "all"}
queue.declare(host, vhost, username, password, arguments=client_params)
and that works. However the doc for the Erlang client says the arguments should be passed in as a list per:
[{binary(), atom(), binary()}]
If it were just [{binary(), binary()}] I could see the relationship with key/value but not sure what the atom would be there.
Just to be clear, I am a novice Erlang programmer so this may be a common construct that I am not familiar with, so no answer would be too obvious.
I found this in amqp_network_connection.erl, which looks like a wrapper to set some default values:
client_properties(UserProperties) ->
{ok, Vsn} = application:get_key(amqp_client, vsn),
Default = [{<<"product">>, longstr, <<"RabbitMQ">>},
{<<"version">>, longstr, list_to_binary(Vsn)},
{<<"platform">>, longstr, <<"Erlang">>},
{<<"copyright">>, longstr,
<<"Copyright (c) 2007-2012 VMware, Inc.">>},
{<<"information">>, longstr,
<<"Licensed under the MPL. "
"See http://www.rabbitmq.com/">>},
{<<"capabilities">>, table, ?CLIENT_CAPABILITIES}],
lists:foldl(fun({K, _, _} = Tuple, Acc) ->
lists:keystore(K, 1, Acc, Tuple)
end, Default, UserProperties).
Apparently the atom describes the value type. I don't know the available types, but there's a chance that longstr will work in your case.

How to load thrift client in Erlang

I wish to use scribe to export some data from a Erlang application, but I have a problem with running Thrift client. I install Thrift, in the erlang lib directory. I'm using: thrift-0.6.1
I found some example code to connect from erlang via thrift to scribe:
{ok, C} = thrift_client:start_link("localhost", 1463, scribe_thrift,
[{strict_read, false},
{strict_write, false},
{framed, true}]),
but erlang is returning this error:
** exception error: undefined function thrift_client:start_link/4
When I try to run application:start(thrift), for a moment I see some code completion for thrift*
7> thrift_client:
call/3 close/1 module_info/0 module_info/1 new/2
send_call/3
and there is no method start_link.
I think these days you want something like thrift_client_util:new(Host, Port, ProtoModule, Options)
which in your case would be:
thrift_client_util:new("localhost", 1463, scribe_thrift,
[{strict_read, false},
{strict_write, false},
{framed, true}]).
And an important point to bear in mind with the thrift API in erlang is that all calls return you a new client state value which you must use for subsequent calls. Using a client state value twice leads to wailing and the gnashing of teeth.
I got thrift integrated with my project a couple of months back. There are some initialization steps required to obtain the client.
{ok, TFactory} =
thrift_socket_transport:new_transport_factory(
"localhost", 8899, []),
{ok, PFactory} =
thrift_binary_protocol:new_protocol_factory(TFactory, []),
{ok, Protocol} = PFactory(),
{ok, Client} = thrift_client:new(Protocol, scribe_thrift),
For more context, you can probably take a look at a module from my git repo.

Resources