Erlang 聊天室程序(十) 主题房间3 ---创建、关闭和查询
为了后面的功能,这里先实现主题房间的开启、关闭和查询。这些都是对客户端行为的响应,正常情况下需要管理员权限,由于权限部分还未实现所以这里暂时不考虑。
先定义消息格式:
开启:
#message{type="result",subject="openroom",content="succ/failed"}
关闭:
#message{type="set",subject="closeroom",content=#roominfo{id="id"}}
查询:
#message{type="get",subject="roominfo",content="all"}
#message{type="result",subject="roominfo",content=[#roominfo,#roominfo......]}
服务器代码:
修改message_router.erl 对接收到的消息进行解析和路由:
#clientinfo{pid=From}=State,
case Type of
"msg"->
......
"set"->
case Sub of
"clientinfo"->
......
"openroom"->
RoomInfo=util_RoomInfoParas:paraElements(Message),
ResultMessage=
if
is_record(RoomInfo,roominfo)->
Result=case room_manager:startNewRoom(RoomInfo)of
{fail,room_exists}->
%send failed message to client
#message{type="result",subject="openroom",content="failed name exists"};
{succ,ok}->
#message{type="result",subject="openroom",content="failed name exists"}
end;
true->
io:format("illegal RoomInfo subject:~p~n",[RoomInfo]),
%we should return failed message to client
#message{type="result",subject="openroom",content="failed illegal roominfo"}
end,
From!{downmsg,ResultMessage};
"closeroom"->
RoomInfo=util_RoomInfoParas:paraElements(Message),
ResultMessage=
if
is_record(RoomInfo,roominfo)->
#roominfo{id=Id}=RoomInfo,
room_manager:removeRoom(Id),
#message{type="result",subject="closeroom",content="succ"};
%diliver result message to client
true->
io:format("illegal RoomInfo subject:~p~n",[RoomInfo]),
#message{type="result",subject="openroom",content="failed illegal roominfo"}
%diliver result message to client
end,
From!{downmsg,ResultMessage};
_Els->
io:format("unkonw msssage subject:~p~n",[Sub])
end;
"get"->
case Sub of
"clientinfo"->
......
"roominfo"->
RoomList=room_manager:getAllRooms(),
ListJson=util_RoomInfoParas:deparaElement(RoomList),
ResultMessage=#message{type="result",subject="roominfo",content=ListJson},
%diliver result message to client
From!{downmsg,ResultMessage};
_Els->
io:format("unkonw msssage subject:~p~n",[Sub])
end;
_Els->
{error,"wrong message type"}
end
.
为了将操作的结果发送回给对应的客户端,以上代码对routeMessage 函数的参数进行了修改,添加了State参数。State 为一个#clientinfo 可以从里面取出客户端进行PID。
相应的也要修改接口函数的参数:
#message{type=Type}=Message,
case validateType(Type) of
{error,Reason}->
io:format("validate message type error:~p~n",[Reason]);
TheType->
#message{subject=Sub}=Message,
case validateSubject(Sub) of
{error,Reason}->
io:format("validate message subject error:~p~n",[Reason]);
TheSub->
routeMessage(TheType,TheSub,Message,State)
end
end
;
route(Els,State)->
io:format("message should be record:~p~n",[Els])
.
可以看到,具体的房间开启、删除都是调用的room_manager.erl中对应的方法。
以下为room_manager.erl 中查询所有房间信息的代码:
getNextRoom([],[])
.
getNextRoom([],Infos)->
case ets:first(roominfo) of
Key->
Record =ets:lookup(roominfo, Key),
NewInfos=[Record|Infos],
case ets:next(roominfo, Key) of
Next ->
getNextRoom(Next,NewInfos);
'$end_of_table'->
NewInfos
end;
'$end_of_table'->
Infos
end
;
getNextRoom(Id,Infos)->
Record =ets:lookup(roominfo, Id),
NewInfos=[Record|Infos],
case ets:next(roominfo, Id) of
Next ->
getNextRoom(Next,NewInfos);
'$end_of_table'->
NewInfos
end
.
接下来就是JSON消息的解包和打包,这里新建一个util_RoomInfoParas.erl模块:
%% Created: 2012-3-12
%% Description: TODO: Add description to util_RoomInfoParas
-module(util_RoomInfoParas).
%%
%% Include files
%%
-include("roominfo.hrl").
%%
%% Exported Functions
%%
-export([paraElements/1,deparaElement/1]).
%%
%% API Functions
%%
paraElements(Obj)->
{obj,List}=Obj,
Data =#roominfo{},
%catch exception here
io:format("data list is:~p~n",[List]),
try paraEle(List,Data)
catch
{error,Reason,NewData}->
{error,Reason,NewData}
end
.
paraEle([Ele|Els],Data)->
io:format("ele is:~p~n",[Ele]),
NewData=para(Ele,Data),
paraEle(Els,NewData)
;
paraEle([],Data)->
Data
.
para({"type",Val},Data)->
io:format("para type:~p~n",[Data]),
NewData=Data#roominfo{type=Val},
io:format("paraed content:~p~n",[NewData]),
NewData
;
para({"name",Val},Data)->
io:format("para name:~p~n",[Data]),
NewData=Data#roominfo{name=Val},
io:format("paraed content:~p~n",[NewData]),
NewData
;
para({"type",Val},Data)->
io:format("para type:~p~n",[Data]),
NewData=Data#roominfo{type=Val},
io:format("paraed content:~p~n",[NewData]),
NewData
;
para({Key,Val},Data)->
io:format("decode key is:~p~n",[Key]),
io:format("decode Val is:~p~n",[Val]),
%no mache
%throw exception
throw({error,"unkown element",Data})
.
%%
%% Local Functions
%%
deparaElement(Record)->
#roominfo{id=Id,
name=Name,
type=Type,
unum=Unum,
tablename=TableName,
status=Status,
creationDate=CreationDate}=Record,
{obj,[
{"id",list_to_binary(setDef(id,"i"))},
{"name",setDef(Name,"s")},
{"type",setDef(Type,"s")},
{"unum",setDef(Unum,"i")},
{"tablename",setDef(TableName,"s")},
{"status",setDef(Status,"s")}
]}
.
setDef(Val,Type)->
Defv=case Type of
"s"->
"";
"i"->
0;
"l"->
[]
end,
case Val of
undefined->
Defv;
Els->
Val
end
.
里面提供了#roominfo 和 JSONString 之间的互转方法。
OK,服务器端的代码就到这里,同样的先不做测试,后面一起做。