Skip to content

Commit

Permalink
Ping relay when no data received in five minutes
Browse files Browse the repository at this point in the history
If no data is received after an additional 30 seconds, disconnect.
  • Loading branch information
mhoran committed Feb 16, 2015
1 parent 5061e71 commit d869e41
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 23 deletions.
7 changes: 6 additions & 1 deletion weechat-android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ubergeek42.WeechatAndroid" >

<permission
android:name="com.ubergeek42.WeechatAndroid.PING_ACTION"
android:protectionLevel="signature" />

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.ubergeek42.WeechatAndroid.PING_ACTION"/>

<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:theme="@style/Weechat"
android:windowSoftInputMode="adjustResize">
<service android:name=".service.RelayService" />
<activity
<activity
android:name=".WeechatActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateHidden"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright 2014 Matthew Horan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.ubergeek42.WeechatAndroid.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PingActionReceiver extends BroadcastReceiver {
private static Logger logger = LoggerFactory.getLogger("PingActionReceiver");
private RelayService relayService;
public static final String PING_ACTION = "com.ubergeek42.WeechatAndroid.PING_ACTION";

public PingActionReceiver(RelayService relayService) {
super();
this.relayService = relayService;
}

@Override
public void onReceive(Context context, Intent intent) {
logger.debug("onReceive intent: {}, sentPing: {}", intent, intent.getBooleanExtra("sentPing", false));

if (!relayService.isConnection(RelayService.CONNECTED))
return;

long triggerAt;
Bundle extras = new Bundle();

if (SystemClock.elapsedRealtime() - relayService.lastMessageReceivedAt > 60 * 5 * 1000) {
if (!intent.getBooleanExtra("sentPing", false)) {
logger.debug("last message too old, sending ping");
relayService.connection.sendMsg("ping");
triggerAt = SystemClock.elapsedRealtime() + 30 * 1000;
extras.putBoolean("sentPing", true);
} else {
logger.debug("no message received, disconnecting");
relayService.startThreadedDisconnect(false);
return;
}
} else {
triggerAt = relayService.lastMessageReceivedAt + 60 * 5 * 1000;
}

relayService.schedulePing(triggerAt, extras);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Paint;
import android.graphics.Typeface;
Expand Down Expand Up @@ -53,11 +54,21 @@ public class RelayService extends RelayServiceBackbone {
public static final String PREFS_ENCLOSE_NICK = "enclose_nick";
public static final String PREFS_TEXT_SIZE = "text_size";

private PingActionReceiver pingActionReceiver;

/** super method sets 'prefs' */
@Override
public void onCreate() {
super.onCreate();

pingActionReceiver = new PingActionReceiver(this);
registerReceiver(
pingActionReceiver,
new IntentFilter(PingActionReceiver.PING_ACTION),
PingActionReceiver.PING_ACTION,
null
);

// buffer list preferences
BufferList.SORT_BUFFERS = prefs.getBoolean(PREFS_SORT_BUFFERS, false);
BufferList.SHOW_TITLE = prefs.getBoolean(PREFS_SHOW_BUFFER_TITLES, false);
Expand Down Expand Up @@ -123,6 +134,7 @@ void startHandlingBoneEvents() {
@Override
public void onDestroy() {
eraseStoredStuff();
unregisterReceiver(pingActionReceiver);
super.onDestroy();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,8 @@
******************************************************************************/
package com.ubergeek42.WeechatAndroid.service;

import java.io.File;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
Expand All @@ -40,6 +32,7 @@
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
Expand All @@ -65,6 +58,15 @@
import com.ubergeek42.weechat.relay.messagehandler.UpgradeObserver;
import com.ubergeek42.weechat.relay.protocol.RelayObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public abstract class RelayServiceBackbone extends Service implements RelayConnectionHandler,
OnSharedPreferenceChangeListener, UpgradeObserver {

Expand Down Expand Up @@ -116,8 +118,10 @@ public abstract class RelayServiceBackbone extends Service implements RelayConne
SharedPreferences prefs;
SSLHandler certmanager;
X509Certificate untrustedCert;
private AlarmManager alarmMgr;

int hot_count = 0;
volatile long lastMessageReceivedAt = 0;

/** mainly used to tell the user if we are REconnected */
private volatile boolean disconnected;
Expand Down Expand Up @@ -183,6 +187,8 @@ public void onCreate() {
connectivityActionReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
);

alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
}

@Override
Expand Down Expand Up @@ -397,12 +403,12 @@ public void run() {
});
}

// do the actual shutdown on its own thread (to avoid an error on Android 3.0+) (why?)
// do the actual shutdown on a separate thread (to avoid NetworkOnMainThreadException on Android 3.0+)
// remember that we are down lest we are reconnected when application
// kills the service and restores it back later
public void startThreadedDisconnect() {
public void startThreadedDisconnect(boolean mustStayDisconnected) {
if (DEBUG_CONNECTION) logger.debug("startThreadedDisconnect()");
prefs.edit().putBoolean(PREF_MUST_STAY_DISCONNECTED, true).commit();
prefs.edit().putBoolean(PREF_MUST_STAY_DISCONNECTED, mustStayDisconnected).commit();
thandler.removeCallbacksAndMessages(null);
thandler.post(new Runnable() {
@Override
Expand All @@ -412,6 +418,32 @@ public void run() {
});
}

public void startThreadedDisconnect() {
startThreadedDisconnect(true);
}

@TargetApi(19)
void schedulePing(long triggerAt, Bundle extras) {
Intent intent = new Intent(PingActionReceiver.PING_ACTION);
intent.putExtras(extras);

PendingIntent alarmIntent = PendingIntent.getBroadcast(
this, 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT
);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt, alarmIntent);
} else {
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt, alarmIntent);
}
}

void schedulePing(long triggerAt) {
schedulePing(triggerAt, new Bundle());
}

////////////////////////////////////////////////////////////////////////////////////////////////

/** try connect once
Expand Down Expand Up @@ -508,6 +540,12 @@ public void onConnecting() {
public void onConnect() {
if (DEBUG) logger.debug("onConnect()");
connection_status = CONNECTED;

long triggerAt = SystemClock.elapsedRealtime() + 30 * 1000;
schedulePing(triggerAt);

connection.addHandler("*", lastMessageHandler);

for (RelayConnectionHandler rch : connectionHandlers) rch.onConnect();
}

Expand Down Expand Up @@ -559,6 +597,10 @@ public void onDisconnect() {
if (disconnected) return;
disconnected = true;

Intent intent = new Intent(PingActionReceiver.PING_ACTION);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_NO_CREATE);
alarmMgr.cancel(alarmIntent);

// automatically attempt reconnection if enabled (and if we aren't shutting down)
if (mustAutoConnect()) {
startThreadedConnectLoop(true);
Expand Down Expand Up @@ -611,4 +653,11 @@ public void run() {
});
upgrading.start();
}

private RelayMessageHandler lastMessageHandler = new RelayMessageHandler() {
@Override
public void handleMessage(RelayObject obj, String id) {
lastMessageReceivedAt = SystemClock.elapsedRealtime();
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,20 +244,26 @@ public void addHandler(String id, RelayMessageHandler wmh) {
private void handleMessage(RelayMessage msg) {
String id = msg.getID();
if (DEBUG) logger.debug("handling message {}", id);
HashSet<RelayMessageHandler> handlers = new HashSet<RelayMessageHandler>();

if (messageHandlers.containsKey(id)) {
HashSet<RelayMessageHandler> handlers = messageHandlers.get(id);
for (RelayMessageHandler rmh : handlers) {
if (msg.getObjects().length == 0) {
rmh.handleMessage(null, id);
} else {
for (RelayObject obj : msg.getObjects()) {
rmh.handleMessage(obj, id);
}
}
}
handlers.addAll(messageHandlers.get(id));
} else {
if (DEBUG) logger.debug("Unhandled message: {}", id);
}

if (messageHandlers.containsKey("*"))
handlers.addAll(messageHandlers.get("*"));

for (RelayMessageHandler rmh : handlers) {
if (msg.getObjects().length == 0) {
rmh.handleMessage(null, id);
} else {
for (RelayObject obj : msg.getObjects()) {
rmh.handleMessage(obj, id);
}
}
}
}


Expand Down

0 comments on commit d869e41

Please sign in to comment.