/config.erl

http://mailerl.googlecode.com/ · Erlang · 293 lines · 185 code · 44 blank · 64 comment · 0 complexity · bbbc24607f053e0609333e940549aafc MD5 · raw file

  1. %%%-------------------------------------------------------------------
  2. %%% File : config.erl
  3. %%% Author : Fyodor Ustinov <>
  4. %%% Description : CONFIGURATION STUB
  5. %%%
  6. %%% Created : 10 Sep 2009 by Fyodor Ustinov <>
  7. %%%-------------------------------------------------------------------
  8. -module(config).
  9. -define(SERVER, config).
  10. -behaviour(gen_server).
  11. %% API
  12. -export([start_link/0, get/1, get/2, get/3, get/4, subst/3, subst/4,
  13. set/2, set_node/2, set/3, save/0,
  14. drop/1, drop/2, drop_node/1]).
  15. %% gen_server callbacks
  16. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
  17. terminate/2, code_change/3]).
  18. -record(s, {
  19. modules = dict:new(),
  20. node = dict:new(),
  21. global = dict:new()
  22. }).
  23. %%====================================================================
  24. %% API
  25. %%====================================================================
  26. %%--------------------------------------------------------------------
  27. %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
  28. %% Description: Starts the server
  29. %%--------------------------------------------------------------------
  30. start_link() ->
  31. gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
  32. %%====================================================================
  33. %% gen_server callbacks
  34. %%====================================================================
  35. %%--------------------------------------------------------------------
  36. %% Function: init(Args) -> {ok, State} |
  37. %% {ok, State, Timeout} |
  38. %% ignore |
  39. %% {stop, Reason}
  40. %% Description: Initiates the server
  41. %%--------------------------------------------------------------------
  42. init([]) ->
  43. process_flag(trap_exit, true),
  44. D = try
  45. {ok, Dict} = file:read_file("config"),
  46. erlang:binary_to_term(Dict)
  47. catch
  48. _:_ ->
  49. #s{}
  50. end,
  51. {ok, D}.
  52. %%--------------------------------------------------------------------
  53. %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
  54. %% {reply, Reply, State, Timeout} |
  55. %% {noreply, State} |
  56. %% {noreply, State, Timeout} |
  57. %% {stop, Reason, Reply, State} |
  58. %% {stop, Reason, State}
  59. %% Description: Handling call messages
  60. %%--------------------------------------------------------------------
  61. handle_call({get_module, Module, Key}, _From, S) ->
  62. Rc = case dict:find(Module, S#s.modules) of
  63. {ok , Mod} ->
  64. case dict:find(Key, Mod) of
  65. {ok, Value} ->
  66. Value;
  67. _ ->
  68. false
  69. end;
  70. _ ->
  71. false
  72. end,
  73. {reply, Rc, S}
  74. ;
  75. handle_call({get_node, Key}, _From, S) ->
  76. Rc = case dict:find(Key, S#s.node) of
  77. {ok, Value} -> Value;
  78. _ -> false
  79. end,
  80. {reply, Rc, S}
  81. ;
  82. handle_call({get_global, Key}, _From, S) ->
  83. Rc = case dict:find(Key, S#s.global) of
  84. {ok, Value} -> Value;
  85. _ -> false
  86. end,
  87. {reply, Rc, S}
  88. .
  89. %%--------------------------------------------------------------------
  90. %% Function: handle_cast(Msg, State) -> {noreply, State} |
  91. %% {noreply, State, Timeout} |
  92. %% {stop, Reason, State}
  93. %% Description: Handling cast messages
  94. %%--------------------------------------------------------------------
  95. handle_cast({set_global, Key, Value}, S) ->
  96. D1 = dict:store(Key, Value, S#s.global),
  97. {noreply, S#s{global = D1}}
  98. ;
  99. handle_cast({set_node, Key, Value}, S) ->
  100. D1 = dict:store(Key, Value, S#s.node),
  101. {noreply, S#s{node = D1}}
  102. ;
  103. handle_cast({set_module, Module, Key, Value}, S) ->
  104. M = case dict:find(Module, S#s.modules) of
  105. {ok , Mod} ->
  106. Mod;
  107. _ ->
  108. dict:new()
  109. end,
  110. D1 = dict:store(Key, Value, M),
  111. D2 = dict:store(Module, D1, S#s.modules),
  112. {noreply, S#s{modules = D2}}
  113. ;
  114. %% ------------------------------------------------------------------
  115. %%% Drop key
  116. %% ------------------------------------------------------------------
  117. handle_cast({drop_global, Key}, S) ->
  118. {noreply, S#s{global = dict:erase(Key, S#s.global)}}
  119. ;
  120. handle_cast({drop_node, Key}, S) ->
  121. {noreply, S#s{node = dict:erase(Key, S#s.node)}}
  122. ;
  123. handle_cast({drop_module, Module, Key}, S) ->
  124. case dict:find(Module, S#s.modules) of
  125. {ok , Mod} ->
  126. D1 = dict:erase(Key, Mod),
  127. {noreply, S#s{modules = dict:store(Module, D1, S#s.modules)}};
  128. _ ->
  129. {noreply, S}
  130. end
  131. ;
  132. handle_cast(save, S) ->
  133. file:write_file("config",erlang:term_to_binary(S)),
  134. {noreply, S}
  135. ;
  136. handle_cast(_Info, State) ->
  137. io:format("Cast ~p~n",[_Info]),
  138. {noreply, State}
  139. .
  140. %%--------------------------------------------------------------------
  141. %% Function: handle_info(Info, State) -> {noreply, State} |
  142. %% {noreply, State, Timeout} |
  143. %% {stop, Reason, State}
  144. %% Description: Handling all non call/cast messages
  145. %%--------------------------------------------------------------------
  146. handle_info(_Info, State) ->
  147. io:format("Info ~p~n",[_Info]),
  148. {noreply, State}
  149. .
  150. %%--------------------------------------------------------------------
  151. %% Function: terminate(Reason, State) -> void()
  152. %% Description: This function is called by a gen_server when it is about to
  153. %% terminate. It should be the opposite of Module:init/1 and do any necessary
  154. %% cleaning up. When it returns, the gen_server terminates with Reason.
  155. %% The return value is ignored.
  156. %%--------------------------------------------------------------------
  157. terminate(_Reason, S) ->
  158. file:write_file("config",erlang:term_to_binary(S)),
  159. ok
  160. .
  161. %%--------------------------------------------------------------------
  162. %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
  163. %% Description: Convert process state when code is changed
  164. %%--------------------------------------------------------------------
  165. code_change(_OldVsn, State, _Extra) ->
  166. {ok, State}
  167. .
  168. %%--------------------------------------------------------------------
  169. %%% Internal functions
  170. %%--------------------------------------------------------------------
  171. drop(Key) ->
  172. gen_server:cast(config, {drop_global, Key})
  173. .
  174. drop(Module, Key) ->
  175. gen_server:cast(config, {drop_module, Module, Key})
  176. .
  177. drop_node(Key) ->
  178. gen_server:cast(config, {drop_node, Key})
  179. .
  180. set(Key, Val) ->
  181. gen_server:cast(config,{set_global, Key, Val})
  182. .
  183. set(Module, Key, Val) ->
  184. gen_server:cast(config,{set_module, Module, Key, Val})
  185. .
  186. set_node(Key, Val) ->
  187. gen_server:cast(config, {set_node, Key, Val})
  188. .
  189. get(Key) ->
  190. gen_server:call(config,{get_global, Key})
  191. .
  192. get(Key, Default) ->
  193. case gen_server:call(config,{get_global, Key}) of
  194. false ->
  195. Default;
  196. Else ->
  197. Else
  198. end
  199. .
  200. get(Module, Key, Default) ->
  201. case gen_server:call(config, {get_module, Module, Key}) of
  202. false ->
  203. case gen_server:call(config, {get_node, Key}) of
  204. false ->
  205. case gen_server:call(config, {get_global, Key}) of
  206. false ->
  207. Default;
  208. Else ->
  209. Else
  210. end;
  211. Else ->
  212. Else
  213. end;
  214. Else ->
  215. Else
  216. end
  217. .
  218. subst(Module, What, Where, Old) ->
  219. D1 = lists:ukeysort(1, config:subst(Module, What, Where)),
  220. lists:ukeysort(1, lists:keymerge(1, D1, Old))
  221. .
  222. subst(Module, What, Where)
  223. when is_atom(Where) ->
  224. Subst = config:get(Module, Where, []),
  225. subst(What, Subst)
  226. .
  227. subst(_, []) ->
  228. []
  229. ;
  230. subst(What, [H | T]) ->
  231. case mlib:match(What, erlang:element(1, H)) of
  232. true ->
  233. [_|Rc] = erlang:tuple_to_list(H),
  234. Rc;
  235. false ->
  236. subst(What, T)
  237. end
  238. .
  239. get(Subst, Module, Key, Def) ->
  240. case lists:keysearch(Key, 1, Subst) of
  241. {value, {Key, Val}} ->
  242. Val;
  243. false ->
  244. config:get(Module, Key, Def)
  245. end
  246. .
  247. save() ->
  248. gen_server:cast(config, save)
  249. .