318 lines
11 KiB
Java
318 lines
11 KiB
Java
package net.xmeter.samplers;
|
|||
|
|
|
||
|
|
import java.text.MessageFormat;
|
||
|
|
import java.util.UUID;
|
||
|
|
import java.util.concurrent.CountDownLatch;
|
||
|
|
import java.util.concurrent.TimeUnit;
|
||
|
|
|
||
|
|
import javax.xml.bind.DatatypeConverter;
|
||
|
|
|
||
|
|
import cn.wildfirechat.proto.ProtoConstants;
|
||
|
|
import cn.wildfirechat.proto.WFCMessage;
|
||
|
|
import io.moquette.spi.impl.security.AES;
|
||
|
|
import org.fusesource.mqtt.client.MQTT;
|
||
|
|
import org.apache.jmeter.samplers.Entry;
|
||
|
|
import org.apache.jmeter.samplers.SampleResult;
|
||
|
|
import org.apache.jmeter.testelement.ThreadListener;
|
||
|
|
import org.apache.jorphan.logging.LoggingManager;
|
||
|
|
import org.apache.log.Logger;
|
||
|
|
import org.apache.log.Priority;
|
||
|
|
import org.fusesource.hawtbuf.Buffer;
|
||
|
|
import org.fusesource.hawtbuf.UTF8Buffer;
|
||
|
|
|
||
|
|
import net.xmeter.Util;
|
||
|
|
import org.fusesource.mqtt.client.Callback;
|
||
|
|
import org.fusesource.mqtt.client.CallbackConnection;
|
||
|
|
import org.fusesource.mqtt.client.Listener;
|
||
|
|
import org.fusesource.mqtt.client.QoS;
|
||
|
|
|
||
|
|
|
||
|
|
public class SendMessageSampler extends AbstractMQTTSampler implements ThreadListener {
|
||
|
|
/**
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
private static final long serialVersionUID = -4312341622759500786L;
|
||
|
|
private transient static Logger logger = LoggingManager.getLoggerForClass();
|
||
|
|
private transient MQTT mqtt = new MQTT();
|
||
|
|
private transient CallbackConnection connection = null;
|
||
|
|
private String payload = null;
|
||
|
|
private QoS qos_enum = QoS.AT_MOST_ONCE;
|
||
|
|
private String topicName = "";
|
||
|
|
private String connKey = "";
|
||
|
|
|
||
|
|
public String getQOS() {
|
||
|
|
return getPropertyAsString(QOS_LEVEL, String.valueOf(QOS_0));
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setQOS(String qos) {
|
||
|
|
setProperty(QOS_LEVEL, qos);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getTopic() {
|
||
|
|
return getPropertyAsString(TOPIC_NAME, DEFAULT_TOPIC_NAME);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setTopic(String topicName) {
|
||
|
|
setProperty(TOPIC_NAME, topicName);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setTarget(String target) {
|
||
|
|
setProperty(TARGET, target);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getTarget() {
|
||
|
|
return getPropertyAsString(TARGET, DEFAULT_TARGET);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setConvType(String type) {
|
||
|
|
setProperty(CONV_TYPE, type);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getConvType() {
|
||
|
|
return getPropertyAsString(CONV_TYPE, CONV_TYPE_SINGLE);
|
||
|
|
}
|
||
|
|
|
||
|
|
public boolean isAddTimestamp() {
|
||
|
|
return getPropertyAsBoolean(ADD_TIMESTAMP);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setAddTimestamp(boolean addTimestamp) {
|
||
|
|
setProperty(ADD_TIMESTAMP, addTimestamp);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getMessageType() {
|
||
|
|
return getPropertyAsString(MESSAGE_TYPE, MESSAGE_TYPE_RANDOM_STR_WITH_FIX_LEN);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setMessageType(String messageType) {
|
||
|
|
setProperty(MESSAGE_TYPE, messageType);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getMessageLength() {
|
||
|
|
return getPropertyAsString(MESSAGE_FIX_LENGTH, DEFAULT_MESSAGE_FIX_LENGTH);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setMessageLength(String length) {
|
||
|
|
setProperty(MESSAGE_FIX_LENGTH, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getMessage() {
|
||
|
|
return getPropertyAsString(MESSAGE_TO_BE_SENT, "hello");
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setMessage(String message) {
|
||
|
|
setProperty(MESSAGE_TO_BE_SENT, message);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getConnPrefix() {
|
||
|
|
return getPropertyAsString(CONN_CLIENT_ID_PREFIX, DEFAULT_CONN_PREFIX_FOR_PUB);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static byte[] hexToBinary(String hex) {
|
||
|
|
return DatatypeConverter.parseHexBinary(hex);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public boolean isConnectionShareShow() {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private String getKey() {
|
||
|
|
String key = getThreadName();
|
||
|
|
if(!isConnectionShare()) {
|
||
|
|
key = new String(getThreadName() + this.hashCode());
|
||
|
|
}
|
||
|
|
return key;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public SampleResult sample(Entry arg0) {
|
||
|
|
this.connKey = getKey();
|
||
|
|
if(connection == null) {
|
||
|
|
connection = ConnectionsManager.getInstance().getConnection(connKey);
|
||
|
|
if(connection != null) {
|
||
|
|
logger.info("Use the shared connection: " + connection);
|
||
|
|
ConnectionsManager.ConnectionInfo info = ConnectionsManager.getInstance().getConnectionInfo(connKey);
|
||
|
|
setUserName(info.userName);
|
||
|
|
token = info.token;
|
||
|
|
privateSecret = info.privateSecrect;
|
||
|
|
mqttServerIp = info.serverAddress;
|
||
|
|
mqttServerPort = info.serverPort;
|
||
|
|
} else {
|
||
|
|
try {
|
||
|
|
if (!getToken(getUserNameAuth())) {
|
||
|
|
throw new Exception("get token failure!!!");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!route(getUserNameAuth(), token)) {
|
||
|
|
throw new Exception("route failure!!!");
|
||
|
|
}
|
||
|
|
|
||
|
|
mqtt.setHost("tcp://" + mqttServerIp + ":" + mqttServerPort);
|
||
|
|
mqtt.setVersion(getMqttVersion());
|
||
|
|
mqtt.setKeepAlive((short) Integer.parseInt(getConnKeepAlive()));
|
||
|
|
|
||
|
|
mqtt.setClientId(getClientId());
|
||
|
|
mqtt.setConnectAttemptsMax(Integer.parseInt(getConnAttamptMax()));
|
||
|
|
mqtt.setReconnectAttemptsMax(Integer.parseInt(getConnReconnAttamptMax()));
|
||
|
|
|
||
|
|
mqtt.setUserName(getUserNameAuth());
|
||
|
|
|
||
|
|
byte[] password = AES.AESEncrypt(token, privateSecret);
|
||
|
|
mqtt.setPassword(new UTF8Buffer(password));
|
||
|
|
|
||
|
|
Object connLock = new Object();
|
||
|
|
connection = ConnectionsManager.getInstance().createConnection(connKey, mqtt, new ConnectionsManager.ConnectionInfo(getUserNameAuth(), token, privateSecret, mqttServerIp, mqttServerPort));
|
||
|
|
|
||
|
|
connection.listener(new Listener() {
|
||
|
|
@Override
|
||
|
|
public void onConnected() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onDisconnected() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onPublish(UTF8Buffer topic, Buffer body, Runnable ack) {
|
||
|
|
logger.log(Priority.DEBUG, "receive publish with topic:" + topic);
|
||
|
|
ack.run();
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onFailure(Throwable value) {
|
||
|
|
|
||
|
|
}
|
||
|
|
});
|
||
|
|
synchronized (connLock) {
|
||
|
|
ConnectionCallback callback = new ConnectionCallback(connection, connLock);
|
||
|
|
connection.connect(callback);
|
||
|
|
connLock.wait(TimeUnit.SECONDS.toMillis(Integer.parseInt(getConnTimeout())));
|
||
|
|
ConnectionsManager.getInstance().setConnectionStatus(connKey, callback.isConnectionSucc());
|
||
|
|
}
|
||
|
|
} catch (Exception e) {
|
||
|
|
logger.log(Priority.ERROR, e.getMessage(), e);
|
||
|
|
ConnectionsManager.getInstance().setConnectionStatus(connKey, false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
payload = getMessage();
|
||
|
|
if(payload == null) {
|
||
|
|
payload = Util.generatePayload(120);
|
||
|
|
}
|
||
|
|
|
||
|
|
SampleResult result = new SampleResult();
|
||
|
|
result.setSampleLabel(getName());
|
||
|
|
|
||
|
|
if(!ConnectionsManager.getInstance().getConnectionStatus(connKey)) {
|
||
|
|
result.sampleStart();
|
||
|
|
result.setSuccessful(false);
|
||
|
|
result.sampleEnd();
|
||
|
|
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
|
||
|
|
result.setResponseData("Publish failed becasue the connection has not been established.".getBytes());
|
||
|
|
result.setResponseCode("500");
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
byte[] toSend;
|
||
|
|
result.sampleStart();
|
||
|
|
|
||
|
|
final Object connLock = new Object();
|
||
|
|
SendMessageCallback pubCallback = new SendMessageCallback(connLock);
|
||
|
|
|
||
|
|
WFCMessage.Message message = WFCMessage.Message.newBuilder()
|
||
|
|
.setConversation(WFCMessage.Conversation.newBuilder().setType(getConvType().equals(CONV_TYPE_SINGLE) ? ProtoConstants.ConversationType.ConversationType_Private : ProtoConstants.ConversationType.ConversationType_Group).setTarget(getTarget()).setLine(0).build())
|
||
|
|
.setFromUser("")
|
||
|
|
.setContent(WFCMessage.MessageContent.newBuilder().setType(1).setSearchableContent(getMessage()).build())
|
||
|
|
.build();
|
||
|
|
toSend = message.toByteArray();
|
||
|
|
toSend = AES.AESEncrypt(toSend, privateSecret);
|
||
|
|
|
||
|
|
//wildfire send message use Qos1 and MS topic
|
||
|
|
topicName = "MS";
|
||
|
|
synchronized (connLock) {
|
||
|
|
connection.publish(topicName, toSend, QoS.AT_LEAST_ONCE, false, pubCallback);
|
||
|
|
connLock.wait();
|
||
|
|
}
|
||
|
|
|
||
|
|
String sendData = "Conversation(" + getConvType() + ":" + getTarget() + "), Message(" + getMessage() + ")";
|
||
|
|
result.sampleEnd();
|
||
|
|
result.setSamplerData(sendData);
|
||
|
|
result.setSentBytes(sendData.length());
|
||
|
|
result.setLatency(result.getEndTime() - result.getStartTime());
|
||
|
|
result.setSuccessful(pubCallback.isSuccessful());
|
||
|
|
|
||
|
|
if(pubCallback.isSuccessful()) {
|
||
|
|
result.setResponseData("Publish successfuly.".getBytes());
|
||
|
|
result.setResponseMessage(MessageFormat.format("publish successfully for Connection {0}.", connection));
|
||
|
|
result.setResponseCodeOK();
|
||
|
|
} else {
|
||
|
|
result.setSuccessful(false);
|
||
|
|
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
|
||
|
|
result.setResponseData(("Publish failed with error code " + pubCallback.getErrorCode()).getBytes());
|
||
|
|
result.setResponseCode("500");
|
||
|
|
}
|
||
|
|
} catch (Exception ex) {
|
||
|
|
logger.log(Priority.ERROR, ex.getMessage(), ex);
|
||
|
|
result.sampleEnd();
|
||
|
|
result.setLatency(result.getEndTime() - result.getStartTime());
|
||
|
|
result.setSuccessful(false);
|
||
|
|
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
|
||
|
|
result.setResponseData(ex.getMessage().getBytes());
|
||
|
|
result.setResponseCode("500");
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void threadStarted() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void threadFinished() {
|
||
|
|
if (!isConnectionShare()) {
|
||
|
|
if (this.connection != null) {
|
||
|
|
final CountDownLatch cdl = new CountDownLatch(1);
|
||
|
|
Callback<Void> cb = new Callback<Void>() {
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onSuccess(Void value) {
|
||
|
|
logger.info(MessageFormat.format("The connection {0} disconneted successfully.", connection));
|
||
|
|
cdl.countDown();
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onFailure(Throwable value) {
|
||
|
|
logger.log(Priority.ERROR, value.getMessage(), value);
|
||
|
|
cdl.countDown();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
logger.info("before disconnection");
|
||
|
|
this.connection.disconnect(cb);
|
||
|
|
logger.info("after disconnection");
|
||
|
|
try {
|
||
|
|
cdl.await();
|
||
|
|
} catch (InterruptedException e) {
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (ConnectionsManager.getInstance().containsConnection(connKey)) {
|
||
|
|
ConnectionsManager.getInstance().removeConnection(connKey);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
logger.info("share connection, not disconnect the connection");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public static String getUUID() {
|
||
|
|
UUID uuid = UUID.randomUUID();
|
||
|
|
String str = uuid.toString();
|
||
|
|
|
||
|
|
str = str.replace("-", "");
|
||
|
|
return str;
|
||
|
|
}
|
||
|
|
}
|