⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clusterimdelegate.java

📁 lumaQQ的源文件
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.ui;

import static edu.tsinghua.lumaqq.resource.Messages.*;

import java.net.InetSocketAddress;

import edu.tsinghua.lumaqq.ecore.face.Face;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.QQPort;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.net.IConnection;
import edu.tsinghua.lumaqq.qq.packets.ErrorPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.RequestAgentReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.RequestBeginReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in._05.TransferReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ClusterCommandPacket;
import edu.tsinghua.lumaqq.ui.helper.FaceRegistry;
import edu.tsinghua.lumaqq.ui.helper.FileSegmentor;
import edu.tsinghua.lumaqq.ui.helper.IMOutParser;
import edu.tsinghua.lumaqq.ui.helper.MessageIDGenerator;

/**
 * 发送一条群消息的流程封装类。发送一条消息不是一个非常easy的过程,必须要判断多种情况,比如
 * 是否含有自定义表情,等等,不同的内容,需要的流程不一样
 * 
 * @author luma
 */
public class ClusterIMDelegate {
    private QQClient client;
    private String originalMessage;
    private String message;
    private int totalFragments;
    private int currentFragment;
    private char messageId;
    private IIMSender sender;
    
    // 用在自定义表情时
    private int sessionId;
    private int[] sessionIdArray;
    private InetSocketAddress agentAddress;
    private IConnection port;
    
    private IMOutParser tool;
    
    // 当前发送第几个表情
    private int currentIndex;
    // 一共有几个表情,这个数目包含了重复的
    private int count;
    
    // 期待的请求中转服务器回复包的序号
    private char expectedSequence;
    
    /** 最多一次发送多少个自定义表情,这个值是QQ的限制,是否能超过这个限制,没试过 */
    private static final int MAX_CUSTOM_FACES = 20;
    
    // 临时变量,在每个表情发送时,这些变量会被初始化
    private int segmentCount;
    private int nextSegment;    
    private FileSegmentor segmentor;
    private int status;
    
    /** 表情还没开始发送 */
    private static final int BEFORE_SENDING = 0;
    /** 正在发送一个表情,这个表情还没发完 */
    private static final int SENDING_ONE = 1;
    /** 上次已经发完了一个表情 */
    private static final int JUST_FINISH = 2;
    
    public ClusterIMDelegate(QQClient client) {
        this.client = client;      
        tool = new IMOutParser();
        expectedSequence = 0;
    }
    
    /**
     * 开始一个消息发送流程
     */
    public void start() {
        if(originalMessage == null)
            return;
        
        // 对原始消息做预处理
        preprocess();
	    
	    // 通知发送开始
	    sender.notifyStart(originalMessage);   
	    // 执行相应的流程
	    if(tool.hasCustomFace())
	        doCustomFlow();
	    else
	        doNormalFlow();
    }
    
    /**
     * 发送结束
     */
    private void over() {
        resetVariables();
	    sender.notifyOver();
    }
    
    /**
     * 发送失败
     */
    private void fail(String msg) {
        resetVariables();
        sender.notifyFail(msg);
    }
    
    /**
     * 发送超时
     */
    private void timeout() {
        dispose();
        String temp = originalMessage;
        resetVariables();
        sender.notifyTimeout(temp);
    }
    
    /**
     * 重置某些状态变量
     */
    private void resetVariables() {
	    expectedSequence = 0;
	    currentIndex = 0;
        originalMessage = null;
    }
    
	/**
	 * 释放资源
	 */
	public void dispose() {
		if(port == null)
			return;
		
		client.releaseConnection(port.getId());
		port = null;
	}

	/**
	 * 发送下一个分片
	 * 
	 * @return
	 * 		true表示发送成功,false表示已经没有更多分片需要发送
	 */
	private boolean sendNextFragment() {
	    // 得到下一个要发送的分片
	    String fragment = getNextFragment();
	    if(fragment == null)
	        return false;
	    sender.send(fragment);
	    return true;
	}
    
    /**
     * 普通消息发送流程
     */
    private void doNormalFlow() {
        sendNextFragment();
    }
    
	/**
	 * @return
	 * 		下一个要发送的分片,如果为null,表示已经发送完成
	 */
	private String getNextFragment() {
	    if(++currentFragment == totalFragments)
	        return null;
	    
	    int start = QQ.QQ_MAX_SEND_IM * currentFragment;
	    int end = QQ.QQ_MAX_SEND_IM + start;
	    if(end > message.length())
	        end = message.length();
	    return message.substring(start, end);
	}

    /**
     * 自定义表情发送流程
     */
    private void doCustomFlow() {        
        if(tool.getDistinctFaceCount() > MAX_CUSTOM_FACES) {
            fail(text_too_more_faces);
            return;
        }
        // 建立初始连接
        if(port == null)
            agentAddress = selectOriginalAgent(); 
        createPort();
        
        // 发送请求包
        sendRequestAgent();
    }
    
    /**
     * 创建一个到中转服务器的连接
     */
    private void createPort() {
        // 如果这个连接已经建立了,直接返回
        if(port != null)
            return;
        // 首先查询是否存在这样的连接,有则复用,无则创建
        port = client.getConnection(agentAddress);
        if(port == null) {        
            try {
            	port = QQPort.CLUSTER_CUSTOM_FACE.create(client, agentAddress, null, true);
            } catch (Exception e) {
                // 失败,结束发送
                port = null;
                fail("Can't establish conection");
                return;
            }   
        } 
    }

    /**
     * 发送请求中转包,使用第一个自定义表情的相关信息
     */
    private void sendRequestAgent() {
        int id = tool.getId(currentIndex);
        FaceRegistry util = FaceRegistry.getInstance();
        Face face = util.getFace(id);
        byte[] md5 = Util.convertHexStringToByteNoSpace(face.getMd5());
        int imageLength = util.getFaceLength(face.getMd5());        
        expectedSequence = client.requestAgent(sender.getSenderId(), imageLength, md5, face.getFilename(), port.getId());
    }

    /**
     * 随机选择一个初始代理服务器
     * 
     * @return
     * 		初始代理服务器的地址
     */
    private InetSocketAddress selectOriginalAgent() {        
        String ip = QQ.QQ_SERVER_GROUP_FILE[Util.random().nextInt(QQ.QQ_SERVER_GROUP_FILE.length)];
        return new InetSocketAddress(ip, 443);
    }
    
    /**
     * 处理QQ事件
     * 
     * @param e
     */
    public void delegateQQEvent(QQEvent e) {
    	switch(e.type) {
    		case QQEvent.QQ_SEND_CLUSTER_IM_EX_SUCCESS:
    		case QQEvent.QQ_SEND_TEMP_CLUSTER_IM_SUCCESS:
    		    processSendIMSuccess(e);
    			break;
			case QQEvent.QQ_SEND_CLUSTER_IM_EX_FAIL:
			case QQEvent.QQ_SEND_TEMP_CLUSTER_IM_FAIL:
			    processSendIMFail(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_REDIRECT:
			    processRequestAgentRedirect(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_SUCCESS:
			    processRequestAgentOK(e);
				break;
			case QQEvent.QQ_REQUEST_AGENT_FAIL:
			    processRequestAgentFail(e);
				break;
			case QQEvent.QQ_REQUEST_BEGIN_SUCCESS:
			    processRequestBeginSuccess(e);
				break;
			case QQEvent.QQ_TRANSFER_FACE_SUCCESS:
			    processTransferFaceSuccess(e);
				break;
			case QQEvent.QQ_CONNECTION_BROKEN:
			    processConnectionBroken(e);
				break;
			case QQEvent.QQ_OPERATION_TIMEOUT:
				switch(e.operation) {
			        case QQ.QQ_CMD_CLUSTER_CMD:
					    processSendIMTimeOut(e);
			        	break;
				}
				break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -