Current section
Files
Jump to
Current section
Files
src/chumak_pull.erl
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
%% @doc ZeroMQ Pull Pattern for Erlang
%%
%% This pattern implement Pull especification
%% from: http://rfc.zeromq.org/spec:30/PIPELINE#toc4
-module(chumak_pull).
-behaviour(chumak_pattern).
-export([valid_peer_type/1, init/1, peer_flags/1, accept_peer/2, peer_ready/3,
send/3, recv/2,
send_multipart/3, recv_multipart/2, peer_recv_message/3,
queue_ready/3, peer_disconected/2, identity/1
]).
-record(chumak_pull, {
identity :: string(),
pending_recv :: nil | {from, From::term()},
pending_recv_multipart :: nil | {from, From::term()},
recv_queue :: queue:queue()
}).
valid_peer_type(push) -> valid;
valid_peer_type(_) -> invalid.
init(Identity) ->
State = #chumak_pull{
identity=Identity,
recv_queue=queue:new(),
pending_recv=nil,
pending_recv_multipart=nil
},
{ok, State}.
identity(#chumak_pull{identity=Identity}) -> Identity.
peer_flags(_State) ->
{pull, [incomming_queue]}.
accept_peer(State, PeerPid) ->
{reply, {ok, PeerPid}, State}.
peer_ready(State, _PeerPid, _Identity) ->
{noreply, State}.
send(State, Data, From) ->
send_multipart(State, [Data], From).
recv(#chumak_pull{pending_recv=nil, pending_recv_multipart=nil}=State, From) ->
case queue:out(State#chumak_pull.recv_queue) of
{{value, Multipart}, NewRecvQueue} ->
Msg = binary:list_to_bin(Multipart),
{reply, {ok, Msg}, State#chumak_pull{recv_queue=NewRecvQueue}};
{empty, _RecvQueue} ->
{noreply, State#chumak_pull{pending_recv={from, From}}}
end;
recv(State, _From) ->
{reply, {error, already_pending_recv}, State}.
send_multipart(State, _Multipart, _From) ->
{reply, {error, not_use}, State}.
recv_multipart(#chumak_pull{pending_recv=nil, pending_recv_multipart=nil}=State, From) ->
case queue:out(State#chumak_pull.recv_queue) of
{{value, Multipart}, NewRecvQueue} ->
{reply, {ok, Multipart}, State#chumak_pull{recv_queue=NewRecvQueue}};
{empty, _RecvQueue} ->
{noreply, State#chumak_pull{pending_recv_multipart={from, From}}}
end;
recv_multipart(State, _From) ->
{reply, {error, already_pending_recv}, State}.
peer_recv_message(State, _Message, _From) ->
%% This function will never called, because use incomming_queue property
{noreply, State}.
queue_ready(#chumak_pull{pending_recv=nil, pending_recv_multipart=nil}=State, _Identity, PeerPid) ->
{out, Multipart} = chumak_peer:incomming_queue_out(PeerPid),
NewRecvQueue = queue:in(Multipart, State#chumak_pull.recv_queue),
{noreply, State#chumak_pull{recv_queue=NewRecvQueue}};
%% when pending recv
queue_ready(#chumak_pull{pending_recv={from, PendingRecv}, pending_recv_multipart=nil}=State, _Identity, PeerPid) ->
{out, Multipart} = chumak_peer:incomming_queue_out(PeerPid),
Msg = binary:list_to_bin(Multipart),
gen_server:reply(PendingRecv, {ok, Msg}),
{noreply, State#chumak_pull{pending_recv=nil}};
%% when pending recv_multipart
queue_ready(#chumak_pull{pending_recv=nil, pending_recv_multipart={from, PendingRecv}}=State, _Identity, PeerPid) ->
{out, Multipart} = chumak_peer:incomming_queue_out(PeerPid),
gen_server:reply(PendingRecv, {ok, Multipart}),
{noreply, State#chumak_pull{pending_recv_multipart=nil}}.
peer_disconected(State, _PeerPid) ->
{noreply, State}.