I have a working Telegram bot that replies to my private messages. However, when I add it to my test chat and run the app, I get this error: 'Unexpected action from user'. I guess, it's a wrong way to create a bot for group chat, and maybe I shouldn't use TelegramLongPollingBot. Can you please help me to understand, how to create a group chat bot?
The Bot's class:
public class MessageCalculator extends TelegramLongPollingBot {
private PropertiesFileReader propertiesFileReader = new PropertiesFileReader();
private Properties prop;
{
try {
prop = propertiesFileReader.readPropertiesFile("src/main/resources/config.properties");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
private static final Logger log = LoggerFactory.getLogger(Main.class);
private int messageCount = 0;
#Override
public String getBotUsername() {
return prop.getProperty("telegram.bot.username");
}
#Override
public String getBotToken() {
return prop.getProperty("telegram.bot.token");
}
#Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String textFromUser = update.getMessage().getText();
Long userId = update.getMessage().getChatId();
String userFirstName = update.getMessage().getFrom().getFirstName();
log.info("[{}, {}] : {}", userId, userFirstName, textFromUser);
messageCount++;
SendMessage sendMessage = SendMessage.builder()
.chatId(userId.toString())
.text("Hello, " + userFirstName + "! Thank you for the message #" + messageCount ": " + textFromUser)
.build();
try {
this.sendApiMethod(sendMessage);
} catch (TelegramApiException e) {
log.error("Sending message error:\t", e);
}
} else {
//And I get this error message:
log.warn("Unexpected action from user");
}
}
}
I expect to create a chat bot that can count messages from each user later.
Related
Fully Updated Code
I am using Twilio to implement a text reminder to be send 3 days before an appointment. I have implemented it in my back-end (java). I have added a few visits into the database that should trigger a job to be scheduled but I am unsure how to check if the job has been scheduled to send a message?
I know the visit is being added to the database since I can check that, so scheduleJob(visit); should be scheduling a text to send, but I am not sure.
VisitController.java
#PostMapping()
public ResponseEntity<Object> addVisit(#RequestBody Visit visit){
Result<Visit> result = service.add(visit);
if(result.isSuccess()){
scheduleJob(visit);
return new ResponseEntity<>(result.getPayload(), HttpStatus.CREATED);
}
return ErrorResponse.build(result);
}
private void scheduleJob(Visit visit) {
String visitId = String.valueOf(visit.getVisitId());
ZoneId defaultZoneId = ZoneId.systemDefault();
LocalDate date = visit.getVisitDate().minusDays(3);
Date finalDate = Date.from(date.atStartOfDay(defaultZoneId).plusHours(16).toInstant());
JobDetail job =
newJob(VisitScheduler.class).withIdentity("Appointment_J_" + visitId)
.usingJobData("visitId", visitId).build();
Trigger trigger =
newTrigger().withIdentity("Appointment_T_" + visitId).startAt(finalDate).build();
try {
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
System.out.println("Unable to schedule the Job");
}
}
VisitScheduler.java
public class VisitScheduler implements Job {
private static Logger logger = LoggerFactory.getLogger(VisitScheduler.class);
public static final String ACCOUNT_SID = "account sid";
public static final String AUTH_TOKEN = "auth token";
public static final String TWILIO_NUMBER = "twilio number";
public static final String TO_NUMBER= "number to send messages to";
private final VisitRepository repository;
public VisitScheduler(VisitRepository repository) {
this.repository = repository;
}
#Override
public void execute(JobExecutionContext context) {
VisitService service = new VisitService(repository);
Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int visitId = Integer.parseInt(dataMap.getString("visitId"));
Visit visit = service.findByVisitId(visitId);
if (visit != null) {
String date = String.valueOf(visit.getVisitDate());
String time = String.valueOf(visit.getVisitTime());
String messageBody = "This is a reminder about your visit at " + time + " on " + date + " See you then!";
try {
Message message = Message
.creator(new PhoneNumber(TO_NUMBER), new PhoneNumber(TWILIO_NUMBER), messageBody)
.create();
System.out.println("Message sent! Message SID: " + message.getSid());
} catch(TwilioException ex) {
logger.error("An exception occurred trying to send the message \"{}\" to {}." +
" \nTwilio returned: {} \n", messageBody, TO_NUMBER, ex.getMessage());
}
}
}
}
Twilio developer evangelist here.
In this line you store the job data:
JobDetail job = newJob(VisitScheduler.class).withIdentity("Appointment_J_" + visitId)
.usingJobData("appointmentId", visitId).build();
You set the "appointmentId" to visitId.
In VisitScheduler you then try to get the visitId with:
int visitId = Integer.parseInt(dataMap.getString("visitId"));
Should this be "appointmentId" to match the field you set earlier?
I have been trying for several days to connect Amazon S3 to my Android project. I downloaded the example "https://github.com/awslabs/aws-sdk-android-samples" "S3TransferUtilitySample" and everything works fine on it, I see the files through the aws admin panel.
I copied into my project "Constants.java" with the working settings, also copied "Util.java" without changes.
The purpose of my project is to record the file from the microphone and transfer it to the cloud.
Here is the singleton that should implement this operations :
public class RecorderHelper {
private static final String TAG = "UploadActivity";
private static TransferUtility sTransferUtility;
static private Util util;
static RecorderHelper singleton;
static Boolean RecordStateRecording;
private static MediaRecorder recorder;
private final String RECORD = Environment.getExternalStorageDirectory() + "/record.aac";
String fileName;
private RecorderHelper() {
}
public static RecorderHelper getSingleton(Context context) {
if (singleton == null) {
RecordStateRecording = false;
singleton = new RecorderHelper();
util = new Util();
AmazonS3Client s3Client = util.getS3Client(context);
sTransferUtility = util.getTransferUtility(context);
}
;
return singleton;
}
public void StopRecording() {
try {
if (RecordStateRecording) {
recorder.stop();
recorder.reset();
recorder.release();
AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl(RECORD));
if (aacTrack.getSamples().size() > 1000) {
CroppedTrack aacTrackShort = new CroppedTrack(aacTrack, aacTrack.getSamples().size() - 1000, aacTrack.getSamples().size());
Movie movie = new Movie();
movie.addTrack(aacTrackShort);
Container mp4file = new DefaultMp4Builder().build(movie);
FileChannel fc = new FileOutputStream(new File(fileName)).getChannel();
mp4file.writeContainer(fc);
fc.close();
aacTrackShort.close();
aacTrack.close();
} else {
aacTrack.close();
}
}
File file = new File(RECORD);
TransferObserver observer = sTransferUtility.upload(Constants.BUCKET_NAME, file.getName(),
file);
observer.setTransferListener(new UploadListener());
} catch (Exception e) {
Log.e("RECORD", e.getMessage());
}
RecordStateRecording = false;
}
public void StartNewRecording(String UUID) {
StopRecording();
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
fileName = Environment.getExternalStorageDirectory() + "/" + UUID + ".aac";
recorder.setOutputFile(RECORD);
try {
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start(); // Recording is now started
RecordStateRecording = true;
}
private class UploadListener implements TransferListener {
// Simply updates the UI list when notified.
#Override
public void onError(int id, Exception e) {
Log.e(TAG, "Error during upload: " + id, e);
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
Log.d(TAG, String.format("onProgressChanged: %d, total: %d, current: %d",
id, bytesTotal, bytesCurrent));
}
#Override
public void onStateChanged(int id, TransferState newState) {
Log.d(TAG, "onStateChanged: " + id + ", " + newState);
}
}
}
However, the file does not appear in the cloud and the listener tells me about the 405 error. Here is the full text.
Can anyone tell me what I'm doing wrong?
Unable to unmarshall error response (Attempt to invoke virtual method
'boolean java.lang.String.equals(java.lang.Object)' on a null object
reference). Response Code: 405, Response Text:
I'm ussing the latest SDK :
compile 'com.amazonaws:aws-android-sdk-s3:2.6.+'
Not sure about stacktrace because because i just get a callback to my listener about the transfer fails.
API 22
I am new in MQTT world. I have written a code to subscribe a topic and get message from topic and store it in database. Now my problem is how to put this code on server so that it will keep receiving message infinitely. I am trying to create a scheduler but in that case i am Getting Persistence Already in Use error from MQTT. I cannot change the clientId every time it connect. It is a fixed one in my case. Is there any way to get the persistence object which is already connected for a particular clientId?
Please help. Thanks and advance.
Please Find the code subscribe topic and messageArrived method of mqqt to get message from topic
public class AppTest {
private MqttHandler handler;
public void doApp() {
// Read properties from the conf file
Properties props = MqttUtil.readProperties("MyData/app.conf");
String org = props.getProperty("org");
String id = props.getProperty("appid");
String authmethod = props.getProperty("key");
String authtoken = props.getProperty("token");
// isSSL property
String sslStr = props.getProperty("isSSL");
boolean isSSL = false;
if (sslStr.equals("T")) {
isSSL = true;
}
// Format: a:<orgid>:<app-id>
String clientId = "a:" + org + ":" + id;
String serverHost = org + MqttUtil.SERVER_SUFFIX;
handler = new AppMqttHandler();
handler.connect(serverHost, clientId, authmethod, authtoken, isSSL);
// Subscribe Device Events
// iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>
handler.subscribe("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
+ "/id/+/evt/" + MqttUtil.DEFAULT_EVENT_ID + "/fmt/json", 0);
}
/**
* This class implements as the application MqttHandler
*
*/
private class AppMqttHandler extends MqttHandler {
// Pattern to check whether the events comes from a device for an event
Pattern pattern = Pattern.compile("iot-2/type/"
+ MqttUtil.DEFAULT_DEVICE_TYPE + "/id/(.+)/evt/"
+ MqttUtil.DEFAULT_EVENT_ID + "/fmt/json");
DatabaseHelper dbHelper = new DatabaseHelper();
/**
* Once a subscribed message is received
*/
#Override
public void messageArrived(String topic, MqttMessage mqttMessage)
throws Exception {
super.messageArrived(topic, mqttMessage);
Matcher matcher = pattern.matcher(topic);
if (matcher.matches()) {
String payload = new String(mqttMessage.getPayload());
// Parse the payload in Json Format
JSONObject contObj = new JSONObject(payload);
System.out
.println("jsonObject arrived in AppTest : " + contObj);
// Call method to insert data in database
dbHelper.insertIntoDB(contObj);
}
}
}
Code to connect to client
public void connect(String serverHost, String clientId, String authmethod,
String authtoken, boolean isSSL) {
// check if client is already connected
if (!isMqttConnected()) {
String connectionUri = null;
//tcp://<org-id>.messaging.internetofthings.ibmcloud.com:1883
//ssl://<org-id>.messaging.internetofthings.ibmcloud.com:8883
if (isSSL) {
connectionUri = "ssl://" + serverHost + ":" + DEFAULT_SSL_PORT;
} else {
connectionUri = "tcp://" + serverHost + ":" + DEFAULT_TCP_PORT;
}
if (client != null) {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
client = null;
}
try {
client = new MqttClient(connectionUri, clientId);
} catch (MqttException e) {
e.printStackTrace();
}
client.setCallback(this);
// create MqttConnectOptions and set the clean session flag
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setUserName(authmethod);
options.setPassword(authtoken.toCharArray());
//If SSL is used, do not forget to use TLSv1.2
if (isSSL) {
java.util.Properties sslClientProps = new java.util.Properties();
sslClientProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
options.setSSLProperties(sslClientProps);
}
try {
// connect
client.connect(options);
System.out.println("Connected to " + connectionUri);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
I am testing nv-websocket-client on Android using Android Studio 2.2.3/JRE1.8.0_76.
My code is basically the same as the echo sample application in the README.md file. The class runs fine under Java 8 Update 111, but fails under Android Studio. I walked the code in debug mode and it failed at:
Source:com/neovisionaries/ws/client/Address.java:36
InetSocketAddress toInetSocketAddress()
{
return new InetSocketAddress(mHost, mPort);// mHost = "echo.websocket.org", mPort = 80.
}
Error message in Android Studio:
Method threw 'java.lang.NullPointerException' exception. Cannot evaluate java.net.InetSocketAddress.toString()
Any idea what I did wrong here?
My Test Class:
public class TestWS {
private String m_msg;
private String m_uriStr; // = "ws://echo.websocket.org";
private static final int TIMEOUT = 5000;
public TestWS(String uriStr) {
m_uriStr = uriStr;
m_msg = "";
}
public void RunTest() {
try {
// Connect to the echo server.
WebSocket ws = connect();
ws.sendText("This is a test");
Thread.sleep(1000); // Make sure m_msg is updated before function return.
ws.disconnect();
}
catch(Exception ex)
{
m_msg += "Exception: " + ex.getMessage(); // getMessage() returns null.
}
}
private WebSocket connect() throws IOException, WebSocketException
{
return new WebSocketFactory()
.setConnectionTimeout(TIMEOUT)
.createSocket(m_uriStr)
.addListener(new WebSocketAdapter() {
// A text message arrived from the server.
#Override
public void onTextMessage(WebSocket websocket, String message) {
m_msg += "Echo: " + message;
}
})
.addExtension(WebSocketExtension.PERMESSAGE_DEFLATE)
.connect(); // <= failed in this function.
}
public String GetMsg(){
return m_msg;
}
}
My program is laid out so that the main app can send commands to any node connected to it. When a node receives a request, it returns a response and continues to wait for more requests.
When the app is run the node successfully replies to one request, and when a second request is sent the node sees it as a null or does not see it at all. Why does this keep happening?
P.S. I want the connection to the node to stay open, so that it can receive more requests.
Request sending code:
public java.lang.String getTime(server.Node node){
protocol.Message ms = new protocol.Message("<time>","");
node.sendRequestToClient(ms);
node.dos.flush();
java.lang.System.out.println("Sent time request to " + node.ip);
java.lang.String time = null;
try {
time = node.dis.readLine();
} catch (java.io.IOException ex) {
System.out.println("Could not read response.");
}
protocol.Message response = protocol.Message.parseDataToMessage(time);
java.lang.String systime = response.getActionData();
return systime;
}
Response sending code:
public class Client {
public Client(NetworkConnection connection){
this.connectionToServer = connection;
try{
connectionToServer.connect();
responseOutStream = connectionToServer.getPrintWriter();
requestInStream = connectionToServer.getBufferedReader();
}catch(IOException ex){
System.out.println("Could not connect to server." + ex.getMessage() + ex.toString());
}
}
public void beginRequestListener(){
String request;
try {
while((request = requestInStream.readLine())!=""){
System.out.println("Recieved request: " + request + request.length());
Message response = Message.parseDataToMessage(request);
sendResponseToServer(response);
}
} catch (java.io.IOException ex) {
System.out.println("Could not read request stream.");
} catch(NullPointerException e){
e.printStackTrace();
e.getClass();
}
}
public void sendResponseToServer(Message ms){
protocol.Message response = MessageParser.compileResponse(ms);
java.lang.System.out.println("Response to send: "+response);
response.send(responseOutStream);
}
public BufferedReader requestInStream;
public PrintWriter responseOutStream;
public NetworkConnection connectionToServer;
}
MessageParser class:
public class MessageParser {
static public Message compileResponse(Message ms){
Message response = null;
switch(ms.getAction()){
case "<time>":
response = new Message("<time>", String.valueOf(System.currentTimeMillis()));
break;
case "<date>":
SimpleDateFormat sd = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
Date date = new Date();
sd.setTimeZone(TimeZone.getTimeZone("IST"));
response = new Message("<date>", date.toString());
break;
default:
break;
}
return response;
}
}
The stack trace and output:
Recieved request: <action><time><action><actionData><actionData>
Response to send: <action><time><action><actionData>1370380854566<actionData>
Recieved request:
java.lang.NullPointerException
at protocol.MessageParser.compileResponse(MessageParser.java:23)
at client.Client.sendResponseToServer(Client.java:67)
at client.Client.beginRequestListener(Client.java:52)
at client.ClientInterface.main(ClientInterface.java:107)
Message class:
public class Message {
public Message(String data){
}
public Message(String action, String actionData){
this.action = action;
this.actionData = actionData;
}
public void send(PrintWriter connection){
try{
connection.println(this.toString());
connection.flush();
//System.out.println(this.toString());
}catch(Exception ex){
System.out.println("Could not send Message.");
}
}
#java.lang.Override
public String toString(){
return
action_marker + action + action_marker +
actionData_marker + actionData + actionData_marker +
eof_marker;
}
public static Message parseDataToMessage(String data){
Message ms = null;
if(data.isEmpty() == false){
int begin_action_marker = data.indexOf("<action>")+8;
int end_action_marker = data.lastIndexOf("<action>");
String action = data.substring(begin_action_marker, end_action_marker);
int begin_actionData_marker = data.indexOf("<actionData>")+12;
int end_actionData_marker = data.lastIndexOf("<actionData>");
String actionData = data.substring(begin_actionData_marker, end_actionData_marker);
ms = new Message(action, actionData);
}
return ms;
}
public void setAction(String action){
this.action = action;
}
public String getActionData(){
return actionData;
}
public String getAction(){
return action;
}
public void setActionData(String action){
this.actionData = action;
}
public String eof_marker = "\r\n";
public String action;
public String action_marker = "<action>";
public String actionData;
public String actionData_marker = "<actionData>";
}
My guess:
you receive an empty request in (request = requestInStream.readLine())
this goes to Message.parseDataToMessage(request); which returns null for empty requests
that generates a NullPointerException in compileResponse
The (likely) solution: change this
while((request = requestInStream.readLine())!=""){
into this:
while(!(request = requestInStream.readLine()).isEmpty())
Why your code does not work: How do I compare strings in Java?
while((request = requestInStream.readLine())!=""){
What's this test for? Are you expecting empty requests? You shouldn't be. If you get one it's a bug at the sender.
However you must test the result of readLine() for null before doing anything else with it. The line should read:
while((request = requestInStream.readLine())!= null){