Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 230 lines (192 sloc) 8.47 kb
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
1 %%% Copyright (C) 2005 Nicolas Niclausse
2 %%%
3 %%% This program is free software; you can redistribute it and/or modify
4 %%% it under the terms of the GNU General Public License as published by
5 %%% the Free Software Foundation; either version 2 of the License, or
6 %%% (at your option) any later version.
7 %%%
8 %%% This program is distributed in the hope that it will be useful,
9 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
10 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 %%% GNU General Public License for more details.
12 %%%
13 %%% You should have received a copy of the GNU General Public License
14 %%% along with this program; if not, write to the Free Software
15 %%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16
17 %%% In addition, as a special exception, you have the permission to
18 %%% link the code of this program with any library released under
19 %%% the EPL license and distribute linked combinations including
20 %%% the two.
21
22 %%%-------------------------------------------------------------------
23 %%% File : ts_file_server.erl
24 %%% Author : Nicolas Niclausse <nicolas@niclux.org>
25 %%% Description : Read a line-based file
26 %%%
27 %%% Created : 6 Jul 2005 by Nicolas Niclausse <nicolas@niclux.org>
28 %%%-------------------------------------------------------------------
29
30 -module(ts_file_server).
31 -author('nicolas.niclausse@niclux.org').
32
33 -behaviour(gen_server).
34
35 %% External exports
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
36 -export([start/0,
37 get_random_line/0,
38 get_random_line/1,
39 get_next_line/0,
40 get_next_line/1,
41 get_all_lines/0,
42 get_all_lines/1,
43 stop/0,
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
44 read/1, read/2]).
45
46 %% gen_server callbacks
47 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
48 code_change/3]).
49
3de1065 @nniclausse - use tuples instead of lists for file_server (Pablo Polvorin, TSUN-83)
nniclausse authored
50 -record(file, {items, %% tuple of lines read from a file
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
51 size, %% total number of lines
52 current=-1 %% current line in file
53 }).
54
55 -record(state, {files}).
56
57 -define(DICT, dict).
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
58
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
59 -include("ts_config.hrl").
60 -include("xmerl.hrl").
61
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
62
63 %%%----------------------------------------------------------------------
64 %%% API
65 %%%----------------------------------------------------------------------
66
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
67 %%----------------------------------------------------------------------
68 %% Func: parse_config/2
69 %% Args: Element, Config
2967f80 @nniclausse use binaries in ts_file_server (faster and more memory efficient)
nniclausse authored
70 %% Returns: Binary
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
71 %% Purpose: parse a request defined in the XML config file
72 %%----------------------------------------------------------------------
73
74 read(Filenames) ->
75 gen_server:call({global, ?MODULE}, {read, Filenames}, ?config(file_server_timeout)).
76
77 read(Filenames, Timeout) ->
78 gen_server:call({global, ?MODULE}, {read, Filenames}, Timeout).
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
79
80 start() ->
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
81 ?LOG("Starting~n",?DEB),
82 gen_server:start_link({global, ?MODULE}, ?MODULE, [], []).
83
84
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
85
a6df2dc @nniclausse handle case where file_server is called from a dynamic substitution (fix...
nniclausse authored
86 get_random_line({Pid,_DynData}) when is_pid(Pid)->
87 %% called within a substitution (eg. file is 'default')
944cb8b @nniclausse only return the value when called from a substitution (TSUNG-140)
nniclausse authored
88 case get_random_line(default) of
89 {ok, Val} -> Val;
90 Error -> Error
91 end;
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
92 get_random_line(FileID)->
93 gen_server:call({global, ?MODULE}, {get_random_line, FileID}).
94 get_random_line() ->
95 get_random_line(default).
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
96
a6df2dc @nniclausse handle case where file_server is called from a dynamic substitution (fix...
nniclausse authored
97 get_next_line({Pid,_DynData}) when is_pid(Pid)->
98 %% called within a substitution (eg. file is 'default')
944cb8b @nniclausse only return the value when called from a substitution (TSUNG-140)
nniclausse authored
99 case get_next_line(default) of
100 {ok, Val} -> Val;
101 Error -> Error
102 end;
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
103 get_next_line(FileID)->
104 gen_server:call({global, ?MODULE}, {get_next_line, FileID}).
105 get_next_line() ->
106 get_next_line(default).
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
107
a6df2dc @nniclausse handle case where file_server is called from a dynamic substitution (fix...
nniclausse authored
108 get_all_lines({Pid,_DynData}) when is_pid(Pid)->
109 %% called within a substitution (eg. file is 'default')
944cb8b @nniclausse only return the value when called from a substitution (TSUNG-140)
nniclausse authored
110 case get_all_lines(default) of
111 {ok, Val} -> Val;
112 Error -> Error
113 end;
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
114 get_all_lines(FileID)->
115 gen_server:call({global, ?MODULE}, {get_all_lines, FileID}).
116 get_all_lines() ->
117 get_all_lines(default).
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
118
119 stop()->
120 gen_server:call({global, ?MODULE}, stop).
121
122 %%%----------------------------------------------------------------------
123 %%% Callback functions from gen_server
124 %%%----------------------------------------------------------------------
125
126 %%----------------------------------------------------------------------
127 %% Func: init/1
128 %% Returns: {ok, State} |
129 %% {ok, State, Timeout} |
130 %% ignore |
131 %% {stop, Reason}
132 %%----------------------------------------------------------------------
133 init([]) ->
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
134 {ok, #state{files=?DICT:new()}}.
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
135
136
137 %%----------------------------------------------------------------------
138 %% Func: handle_call/3
139 %% Returns: {reply, Reply, State} |
140 %% {reply, Reply, State, Timeout} |
141 %% {noreply, State} |
142 %% {noreply, State, Timeout} |
143 %% {stop, Reason, Reply, State} | (terminate/2 is called)
144 %% {stop, Reason, State} (terminate/2 is called)
145 %%----------------------------------------------------------------------
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
146 handle_call({get_all_lines, FileID}, _From, State) ->
147 FileDesc = ?DICT:fetch(FileID, State#state.files),
3de1065 @nniclausse - use tuples instead of lists for file_server (Pablo Polvorin, TSUN-83)
nniclausse authored
148 Reply = {ok, tuple_to_list(FileDesc#file.items)},
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
149 {reply, Reply, State};
150
151 handle_call({get_random_line, FileID}, _From, State) ->
152 FileDesc = ?DICT:fetch(FileID, State#state.files),
153 I = random:uniform(FileDesc#file.size),
3de1065 @nniclausse - use tuples instead of lists for file_server (Pablo Polvorin, TSUN-83)
nniclausse authored
154 Reply = {ok, element(I, FileDesc#file.items)},
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
155 {reply, Reply, State};
156
157 handle_call({get_next_line, FileID}, _From, State) ->
158 FileDesc = ?DICT:fetch(FileID, State#state.files),
159 I = (FileDesc#file.current + 1) rem FileDesc#file.size,
3de1065 @nniclausse - use tuples instead of lists for file_server (Pablo Polvorin, TSUN-83)
nniclausse authored
160 Reply = {ok, element(I+1, FileDesc#file.items)},
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
161 NewFileDesc = FileDesc#file{current=I},
162 {reply, Reply,
163 State#state{files=?DICT:store(FileID, NewFileDesc, State#state.files)}};
164
165 handle_call({read, Filenames}, _From, State) ->
166 lists:foldl(fun open_file/2, {reply, ok, State}, Filenames);
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
167
1eca127 @nniclausse remove warnings
nniclausse authored
168 handle_call(stop, _From, State)->
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
169 {stop, normal, ok, State}.
170
171 %%----------------------------------------------------------------------
172 %% Func: handle_cast/2
173 %% Returns: {noreply, State} |
174 %% {noreply, State, Timeout} |
175 %% {stop, Reason, State} (terminate/2 is called)
176 %%----------------------------------------------------------------------
1eca127 @nniclausse remove warnings
nniclausse authored
177 handle_cast(_Msg, State) ->
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
178 {noreply, State}.
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
179
180 %%----------------------------------------------------------------------
181 %% Func: handle_info/2
182 %% Returns: {noreply, State} |
183 %% {noreply, State, Timeout} |
184 %% {stop, Reason, State} (terminate/2 is called)
185 %%----------------------------------------------------------------------
1eca127 @nniclausse remove warnings
nniclausse authored
186 handle_info(_Info, State) ->
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
187 {noreply, State}.
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
188
189 %%----------------------------------------------------------------------
190 %% Func: terminate/2
191 %% Purpose: Shutdown the server
192 %% Returns: any (ignored by gen_server)
193 %%----------------------------------------------------------------------
1eca127 @nniclausse remove warnings
nniclausse authored
194 terminate(_Reason, _State) ->
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
195 ok.
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
196
197 %%--------------------------------------------------------------------
198 %% Func: code_change/3
199 %% Purpose: Convert process state when code is changed
200 %% Returns: {ok, NewState}
201 %%--------------------------------------------------------------------
1eca127 @nniclausse remove warnings
nniclausse authored
202 code_change(_OldVsn, State, _Extra) ->
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
203 {ok, State}.
204
205 %%%----------------------------------------------------------------------
206 %%% Internal functions
207 %%%----------------------------------------------------------------------
208
209 %%----------------------------------------------------------------------
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
210 %% Open a file and return a new state
211 %%----------------------------------------------------------------------
212 open_file({ID, Path}, {reply, Result, State}) ->
213 case ?DICT:find(ID, State#state.files) of
214 {ok, _} ->
215 ?LOGF("File with id ~p already opened (path is ~p)~n",[ID, Path], ?WARN),
216 {reply, {error, already_open}, State};
217 error ->
218 ?LOGF("Opening file ~p~n",[Path], ?INFO),
219
2967f80 @nniclausse use binaries in ts_file_server (faster and more memory efficient)
nniclausse authored
220 case file:read_file(Path) of
221 {ok, Bin} ->
222 List_items = binary:split( Bin , <<"\n">> , [global,trim]),
223 FileDesc = #file{items = list_to_tuple(List_items), size=length(List_items)},
224 {reply, Result, State#state{files = ?DICT:store(ID, FileDesc, State#state.files)}};
225 {error,Reason} ->
226 ?LOGF("Error while opening file ~p :~p~n",[ Path, Reason], ?ERR),
227 {reply, {error, Path}, State}
bec018f @nniclausse add multiple files support in file_server (initial patch by Jerome Sautr...
nniclausse authored
228 end
2af2c53 @nniclausse add ts_file_server. It can be used to read data from a file during dynam...
nniclausse authored
229 end.
Something went wrong with that request. Please try again.