Erlang 聊天室程序(十) 主题房间3 ---创建、关闭和查询

     为了后面的功能,这里先实现主题房间的开启、关闭和查询。这些都是对客户端行为的响应,正常情况下需要管理员权限,由于权限部分还未实现所以这里暂时不考虑。

     先定义消息格式:

     开启:     

      #message{type="set",subject="openroom",content=#roominfo{type="type",name="name"}}

      #message{type="result",subject="openroom",content="succ/failed"}

     关闭:

      #message{type="set",subject="closeroom",content=#roominfo{id="id"}}

      #message{type="result",subject="closeroom",content="succ/failed"}

 

      查询:

      #message{type="get",subject="roominfo",content="all"}

      #message{type="result",subject="roominfo",content=[#roominfo,#roominfo......]}

     服务器代码:

     修改message_router.erl 对接收到的消息进行解析和路由:

routeMessage(Type,Sub,Message,State)->
        #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。

      相应的也要修改接口函数的参数:

 

route(Message,State)when is_record(Message,message)->
    #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 中查询所有房间信息的代码:

getAllRooms()->    
    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模块:

%% Author: Administrator
%% 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,服务器端的代码就到这里,同样的先不做测试,后面一起做。

 

 

 

 

posted on 2012-03-13 19:10  心笑峰  阅读(902)  评论(0编辑  收藏  举报

导航