Openfire插件开发实例--随机用户配对系统

来源:互联网 发布:如何查看网络ip地址 编辑:程序博客网 时间:2024/06/04 20:00

Openfire支持插件开发,使得它的用处大大增加。前阵子,做一个匿名聊天软件,名字叫做“子曰”,再做这个项目之前,了解了许多关于Openfire的知识,得知他支持插件开发,并且能实现所需要的功能,所以最后就决定用它。这个匿名聊天软件最核心的功能就是陌生人配对了。服务器端实现也很简单,用户配对插件思路是这样的: 

1. 如果客户端是发来请求配对用户的包并且用户队列中没有用户,将请求的用户的用户名放入用户队列中并向客户端发送等待的包。
2. 如果客户端是发来请求配对用户的包并且用户队列中有其他用户,将其用户名从队列中取出,并给客户端发送包含其他用户名的包。 
3. 如果客户端是发来请求配对用户的包并且用户队列中有用户本身,给客户端发送继续等待的包。
4. 如果客户端是发来请求退出配对的包,将其用户名从用户队列中移除。

我们写两个Java源文件
1. MatchUserPlugin.java,插件的入口和插件的所有逻辑判断。
public class MatchUserPlugin  implements Plugin {private IQRouter iqRouter;private  final Logger Log = LoggerFactory.getLogger(MatchUserPlugin.class);private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("HH:mm:ss.SSS");SessionManager sessionManager=new SessionManager();@Overridepublic void destroyPlugin() {// TODO Auto-generated method stubLog.info("------------------->MatchUserPlugin destroy!");}       /**       * 插件初始化时被调用       */@Overridepublic void initializePlugin(PluginManager pluginManager, File file) {// TODO Auto-generated method stubLog.info("------------------->MatchUserPlugin initialize!");try {iqRouter  = XMPPServer.getInstance().getIQRouter();iqRouter.addHandler(new MyIQHandler("MyIQHandler"));  } catch (Exception e) {// TODO: handle exceptionLog.info("------------------->Bind Exception:"+e.toString());}}/** * 处理数据包 * @author Administrator * */private class MyIQHandler extends IQHandler{//客户端可能发来的消息private static final String QUIT_MATCH="quit_match";//退出用户配对private static final String MATCH_USER="match_user";//请求用户配对//服务端要发送的消息private static final String MATCH_WAIT="match_wait";//等待状态private static final String MATCH_SUCCESS="match_success_server";//匹配成功private static final String QUIT_MATCH_SUCCESS="quit_match_success";//退出配对成功private static final String NAMESPACE_INFO="match:iq:info";//iq包的命名控件private static final String QUIT_CHAT="quit_chat";private Dao redisDAO;private IQHandlerInfo info;//private final  Logger log = LoggerFactory.getLogger(MyIQHandler.class);@Overridepublic void initialize(XMPPServer server) {// TODO Auto-generated method stubsuper.initialize(server);}public MyIQHandler(String moduleName) {super(moduleName);redisDAO=Dao.getInstance();// TODO Auto-generated constructor stubinfo=new IQHandlerInfo("info", NAMESPACE_INFO);}@Overridepublic IQHandlerInfo getInfo() {// TODO Auto-generated method stubreturn info;}@Overridepublic IQ handleIQ(IQ packet) throws UnauthorizedException {// TODO Auto-generated method stubIQ iq=new IQ();String childName=packet.getChildElement().getName();if(childName==null)return packet;if(!childName.equals("info")){return packet;}IQ replyIQ=IQ.createResultIQ(packet);ClientSession clientSession=sessionManager.getSession(packet.getFrom());if(clientSession==null){log("Error user info.Session not found"+sessionManager.getPreAuthenticatedKeys()+" from "+packet.getFrom());replyIQ.setChildElement(packet.getChildElement().createCopy());replyIQ.setError(PacketError.Condition.forbidden);return replyIQ;}org.dom4j.Element child= packet.getChildElement().createCopy();String type=child.attributeValue("type");String ns=child.getNamespaceURI();if(!ns.equals(NAMESPACE_INFO)){log("This namespace is valid !"+sessionManager.getPreAuthenticatedKeys()+" from "+packet.getFrom());replyIQ.setChildElement(packet.getChildElement().createCopy());replyIQ.setError(PacketError.Condition.bad_request);return replyIQ;}Element infoElement = DocumentHelper.createElement("info");infoElement.addNamespace("", NAMESPACE_INFO);switch (type) {case MATCH_USER://log("------------------->MATCH_USER");String  queueJID=redisDAO.lget();//队列中没有人if(queueJID==null){//将自己的jid放入队列,并返回等待try {redisDAO.push(packet.getFrom().toFullJID());infoElement.addAttribute("type", MATCH_WAIT);infoElement.addAttribute("data","nil");replyIQ.setChildElement(infoElement);} catch (Exception e) {// TODO: handle exception}}//队列中有人else {try {//如果队列只有自己,等待if(queueJID.equals(packet.getFrom().toFullJID())){infoElement.addAttribute("type", MATCH_WAIT);infoElement.addAttribute("data","nil");replyIQ.setChildElement(infoElement);}else{//从队列中弹出一个元素queueJID=redisDAO.lpop();infoElement.addAttribute("type", MATCH_SUCCESS);infoElement.addAttribute("data",queueJID);replyIQ.setChildElement(infoElement);}} catch (Exception e) {// TODO: handle exception}}break;case QUIT_MATCH:long idx=redisDAO.remove(packet.getFrom().toFullJID());if(idx!=-1){infoElement.addAttribute("type", QUIT_MATCH_SUCCESS);infoElement.addAttribute("data","nil");replyIQ.setChildElement(infoElement);}break;case QUIT_CHAT:return packet;default:return packet;}//switchreturn replyIQ;}}//MyIQHandlerpublic void log(String text){Log.info(text);}}


2. Dao.java,Redis数据库操作类,并模拟一个用户队列,依赖Jedis.jar.
public class Dao {private static Dao dao; private static Jedis jRedis;private final static String KEY="UserQueue";//Redis数据库中的键名private final static String LOCAL_HOST="127.0.0.1";//Redis数据库ipprivate  final Logger Log = LoggerFactory.getLogger(Dao.class);public static void main(String[] args) {// TODO Auto-generated method stubDao dao=Dao.getInstance();}/** *  * @return */public static Dao getInstance(){if(dao==null){dao = new Dao();}return dao;}/** * 移除指定元素 */public Long remove(String value){return jRedis.lrem(KEY, 1, value);}/** * 弹出最左边的数据 * @return */public  String lpop() {// TODO Auto-generated method stubreturn jRedis.lpop(KEY);}/** * 获取最左边的数据 * @return */public  String lget() {// TODO Auto-generated method stubreturn jRedis.lindex(KEY, jRedis.llen(KEY)-1);}/** * 将元素放入队列尾 * @param jid */public  void push(String jid) {// TODO Auto-generated method stubjRedis.rpush(KEY, jid);}private Dao(){if(jRedis==null){jRedis=new Jedis(LOCAL_HOST);}String ping=jRedis.ping();Log.info("---------->"+ping);}}


完整代码:https://github.com/luoyesiqiu/MatchUserPlugin