mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-30 05:37:43 +00:00
Trying to simplify the sendPackage logic.
This commit is contained in:
parent
288ca01e44
commit
f0935ebb8a
@ -72,7 +72,7 @@ public abstract class BaseLink {
|
||||
}
|
||||
|
||||
//TO OVERRIDE, should be sync
|
||||
public abstract boolean sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback);
|
||||
public abstract boolean sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key);
|
||||
public abstract void sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback);
|
||||
public abstract void sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key);
|
||||
|
||||
}
|
||||
|
@ -30,12 +30,17 @@ import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class LanLink extends BaseLink {
|
||||
|
||||
@ -52,144 +57,100 @@ public class LanLink extends BaseLink {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private Thread sendPayload(NetworkPackage np, final Device.SendPackageStatusCallback callback) {
|
||||
|
||||
try {
|
||||
|
||||
final InputStream stream = np.getPayload();
|
||||
|
||||
ServerSocket candidateServer = null;
|
||||
boolean success = false;
|
||||
int tcpPort = 1739;
|
||||
while(!success) {
|
||||
try {
|
||||
candidateServer = new ServerSocket();
|
||||
candidateServer.bind(new InetSocketAddress(tcpPort));
|
||||
success = true;
|
||||
} catch(Exception e) {
|
||||
Log.e("LanLink", "Exception openning serversocket: "+e);
|
||||
tcpPort++;
|
||||
if (tcpPort >= 1764) {
|
||||
Log.e("LanLink", "No more ports available");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONObject payloadTransferInfo = new JSONObject();
|
||||
payloadTransferInfo.put("port", tcpPort);
|
||||
|
||||
final ServerSocket server = candidateServer;
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//TODO: Timeout when waiting for a connection and close the socket
|
||||
OutputStream socket = null;
|
||||
try {
|
||||
socket = server.accept().getOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
long progress = 0 ;
|
||||
Log.e("LanLink","Beginning to send payload");
|
||||
while ((bytesRead = stream.read(buffer)) != -1) {
|
||||
//Log.e("ok",""+bytesRead);
|
||||
progress += bytesRead;
|
||||
socket.write(buffer, 0, bytesRead);
|
||||
if (callback != null) callback.progressChanged(progress);
|
||||
}
|
||||
Log.e("LanLink","Finished sending payload");
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("LanLink", "Exception with payload upload socket");
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try { socket.close(); } catch(Exception e) { }
|
||||
}
|
||||
try { server.close(); } catch(Exception e) { }
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
|
||||
np.setPayloadTransferInfo(payloadTransferInfo);
|
||||
|
||||
return thread;
|
||||
|
||||
} catch(Exception e) {
|
||||
|
||||
e.printStackTrace();
|
||||
Log.e("LanLink", "Exception with payload upload socket");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Blocking, do not call from main thread
|
||||
@Override
|
||||
public boolean sendPackage(final NetworkPackage np,Device.SendPackageStatusCallback callback) {
|
||||
|
||||
private void sendPackageInternal(NetworkPackage np, final Device.SendPackageStatusCallback callback, PublicKey key) {
|
||||
if (session == null) {
|
||||
Log.e("LanLink", "sendPackage failed: not yet connected");
|
||||
return false;
|
||||
callback.sendFailure(new NotYetConnectedException());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread thread = null;
|
||||
|
||||
//Prepare socket for the payload
|
||||
final ServerSocket server;
|
||||
if (np.hasPayload()) {
|
||||
thread = sendPayload(np,callback);
|
||||
if (thread == null) return false;
|
||||
server = openTcpSocketOnFreePort();
|
||||
JSONObject payloadTransferInfo = new JSONObject();
|
||||
payloadTransferInfo.put("port", server.getLocalPort());
|
||||
np.setPayloadTransferInfo(payloadTransferInfo);
|
||||
} else {
|
||||
server = null;
|
||||
}
|
||||
|
||||
//Encrypt if key provided
|
||||
if (key != null) {
|
||||
np = np.encrypt(key);
|
||||
}
|
||||
|
||||
//Send body of the network package
|
||||
WriteFuture future = session.write(np.serialize());
|
||||
future.awaitUninterruptibly();
|
||||
if (!future.isWritten()) return false;
|
||||
|
||||
if (thread != null) {
|
||||
thread.join(); //Wait for thread to finish
|
||||
if (!future.isWritten()) {
|
||||
callback.sendFailure(future.getException());
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
//Send payload
|
||||
if (server != null) {
|
||||
OutputStream socket = null;
|
||||
try {
|
||||
//Wait a maximum of 10 seconds for the other end to establish a connection with our socket, close it afterwards
|
||||
Timer timeout = new Timer();
|
||||
timeout.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try { server.close(); } catch (Exception e) { }
|
||||
callback.sendFailure(new TimeoutException("Timed out waiting for other end to establish a connection to receive the payload."));
|
||||
}
|
||||
},10*1000);
|
||||
socket = server.accept().getOutputStream();
|
||||
timeout.cancel();
|
||||
|
||||
Log.i("LanLink", "Beginning to send payload");
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
long progress = 0;
|
||||
InputStream stream = np.getPayload();
|
||||
while ((bytesRead = stream.read(buffer)) != -1) {
|
||||
//Log.e("ok",""+bytesRead);
|
||||
progress += bytesRead;
|
||||
socket.write(buffer, 0, bytesRead);
|
||||
if (np.getPayloadSize() > 0) {
|
||||
callback.sendProgress((int)(progress / np.getPayloadSize()));
|
||||
}
|
||||
}
|
||||
Log.i("LanLink", "Finished sending payload");
|
||||
} catch (Exception e) {
|
||||
callback.sendFailure(e);
|
||||
return;
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try { socket.close(); } catch (Exception e) { }
|
||||
}
|
||||
try { server.close(); } catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
|
||||
callback.sendSuccess();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("LanLink", "sendPackage exception");
|
||||
return false;
|
||||
callback.sendFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Blocking, do not call from main thread
|
||||
@Override
|
||||
public void sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback) {
|
||||
sendPackageInternal(np, callback, null);
|
||||
|
||||
}
|
||||
|
||||
//Blocking, do not call from main thread
|
||||
@Override
|
||||
public boolean sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key) {
|
||||
|
||||
if (session == null) {
|
||||
Log.e("LanLink", "sendPackage failed: not yet connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Thread thread = null;
|
||||
if (np.hasPayload()) {
|
||||
thread = sendPayload(np,callback);
|
||||
if (thread == null) return false;
|
||||
}
|
||||
|
||||
np = np.encrypt(key);
|
||||
WriteFuture future = session.write(np.serialize());
|
||||
if (!future.await().isWritten()) return false;
|
||||
|
||||
if (thread != null) {
|
||||
thread.join(); //Wait for thread to finish
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("LanLink", "sendPackageEncrypted exception");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendPackageEncrypted(NetworkPackage np, Device.SendPackageStatusCallback callback, PublicKey key) {
|
||||
sendPackageInternal(np, callback, key);
|
||||
}
|
||||
|
||||
public void injectNetworkPackage(NetworkPackage np) {
|
||||
@ -222,4 +183,28 @@ public class LanLink extends BaseLink {
|
||||
|
||||
packageReceived(np);
|
||||
}
|
||||
|
||||
|
||||
static ServerSocket openTcpSocketOnFreePort() throws IOException {
|
||||
boolean success = false;
|
||||
int tcpPort = 1739;
|
||||
ServerSocket candidateServer = null;
|
||||
while(!success) {
|
||||
try {
|
||||
candidateServer = new ServerSocket();
|
||||
candidateServer.bind(new InetSocketAddress(tcpPort));
|
||||
success = true;
|
||||
Log.i("LanLink", "Using port "+tcpPort);
|
||||
} catch(IOException e) {
|
||||
//Log.e("LanLink", "Exception openning serversocket: "+e);
|
||||
tcpPort++;
|
||||
if (tcpPort >= 1764) {
|
||||
Log.e("LanLink", "No more ports available");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidateServer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,29 +36,30 @@ public class LoopbackLink extends BaseLink {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendPackage(NetworkPackage in,Device.SendPackageStatusCallback callback) {
|
||||
String s = in.serialize();
|
||||
NetworkPackage out= NetworkPackage.unserialize(s);
|
||||
if (in.hasPayload()) out.setPayload(in.getPayload(), in.getPayloadSize());
|
||||
packageReceived(out);
|
||||
return true;
|
||||
public void sendPackage(NetworkPackage in, Device.SendPackageStatusCallback callback) {
|
||||
sendPackageEncrypted(in, callback, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendPackageEncrypted(NetworkPackage in,Device.SendPackageStatusCallback callback, PublicKey key) {
|
||||
public void sendPackageEncrypted(NetworkPackage in, Device.SendPackageStatusCallback callback, PublicKey key) {
|
||||
try {
|
||||
in = in.encrypt(key);
|
||||
if (key != null) {
|
||||
in = in.encrypt(key);
|
||||
}
|
||||
String s = in.serialize();
|
||||
NetworkPackage out= NetworkPackage.unserialize(s);
|
||||
out.decrypt(privateKey);
|
||||
if (key != null) {
|
||||
out.decrypt(privateKey);
|
||||
}
|
||||
packageReceived(out);
|
||||
if (in.hasPayload()) out.setPayload(in.getPayload(), in.getPayloadSize());
|
||||
return true;
|
||||
if (in.hasPayload()) {
|
||||
callback.sendProgress(0);
|
||||
out.setPayload(in.getPayload(), in.getPayloadSize());
|
||||
callback.sendProgress(100);
|
||||
}
|
||||
callback.sendSuccess();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("LoopbackLink", "Encryption exception");
|
||||
return false;
|
||||
callback.sendFailure(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,6 @@ import java.security.PublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
@ -192,14 +190,8 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
//Send our own public key
|
||||
NetworkPackage np = NetworkPackage.createPublicKeyPackage(context);
|
||||
sendPackage(np, new SendPackageStatusCallback(){
|
||||
|
||||
@Override
|
||||
public void progressChanged(long progress) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSuccessful() {
|
||||
public void onSuccess() {
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
pairingTimer = new Timer();
|
||||
pairingTimer.schedule(new TimerTask() {
|
||||
@ -216,7 +208,7 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFailed() {
|
||||
public void onFailure(Throwable e) {
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_could_not_send_package));
|
||||
}
|
||||
@ -285,16 +277,11 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
NetworkPackage np = NetworkPackage.createPublicKeyPackage(context);
|
||||
sendPackage(np, new SendPackageStatusCallback() {
|
||||
@Override
|
||||
public void progressChanged(long progress) {
|
||||
// Do nothng
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSuccessful() {
|
||||
protected void onSuccess() {
|
||||
pairingDone();
|
||||
}
|
||||
@Override
|
||||
public void sendFailed() {
|
||||
protected void onFailure(Throwable e) {
|
||||
Log.e("Device","Unpairing (sendFailed B)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
@ -500,59 +487,59 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
}
|
||||
|
||||
public interface SendPackageStatusCallback {
|
||||
void progressChanged(long progress);
|
||||
void sendSuccessful();
|
||||
void sendFailed();
|
||||
public static abstract class SendPackageStatusCallback {
|
||||
protected abstract void onSuccess();
|
||||
protected abstract void onFailure(Throwable e);
|
||||
protected void onProgressChanged(int percent) { }
|
||||
|
||||
private boolean success = false;
|
||||
public void sendSuccess() {
|
||||
success = true;
|
||||
onSuccess();
|
||||
}
|
||||
public void sendFailure(Throwable e) {
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
Log.e("sendPackage", "Exception: " + e.getMessage());
|
||||
} else {
|
||||
Log.e("sendPackage", "Unknown (null) exception");
|
||||
}
|
||||
onFailure(e);
|
||||
}
|
||||
public void sendProgress(int percent) { onProgressChanged(percent); }
|
||||
}
|
||||
|
||||
|
||||
public void sendPackage(NetworkPackage np) {
|
||||
sendPackage(np,null);
|
||||
sendPackage(np,new SendPackageStatusCallback() {
|
||||
@Override
|
||||
protected void onSuccess() { }
|
||||
@Override
|
||||
protected void onFailure(Throwable e) { }
|
||||
});
|
||||
}
|
||||
|
||||
//Async
|
||||
public void sendPackage(final NetworkPackage np, final SendPackageStatusCallback callback) {
|
||||
|
||||
//Log.e("sendPackage", "Sending package...");
|
||||
//Log.e("sendPackage", np.serialize());
|
||||
|
||||
final Exception backtrace = new Exception();
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
//Log.e("sendPackage", "Sending package...");
|
||||
//Log.e("sendPackage", np.serialize());
|
||||
|
||||
boolean useEncryption = (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired());
|
||||
|
||||
//We need a copy to avoid concurrent modification exception if the original list changes
|
||||
//Make a copy to avoid concurrent modification exception if the original list changes
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
for (BaseLink link : mLinks) {
|
||||
if (useEncryption) {
|
||||
success = link.sendPackageEncrypted(np,callback, publicKey);
|
||||
} else {
|
||||
success = link.sendPackage(np,callback);
|
||||
}
|
||||
if (success) break;
|
||||
for (final BaseLink link : mLinks) {
|
||||
if (useEncryption) {
|
||||
link.sendPackageEncrypted(np, callback, publicKey);
|
||||
} else {
|
||||
link.sendPackage(np, callback);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("sendPackage","Error while sending package");
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// Log.e("sendPackage","Package sent");
|
||||
} else {
|
||||
backtrace.printStackTrace();
|
||||
Log.e("sendPackage","Error: Package could not be sent ("+mLinks.size()+" links available)");
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
if (success) callback.sendSuccessful();
|
||||
else callback.sendFailed();
|
||||
if (callback.success) break; //If the link didn't call sendSuccess(), try the next one
|
||||
}
|
||||
|
||||
}
|
||||
@ -560,10 +547,6 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Plugin-related functions
|
||||
//
|
||||
|
@ -144,7 +144,7 @@ public class SharePlugin extends Plugin {
|
||||
try {
|
||||
OutputStream output = new FileOutputStream(destinationFullPath.getPath());
|
||||
byte data[] = new byte[1024];
|
||||
long progress = 0,prevProgressPercentage = 0;
|
||||
long progress = 0, prevProgressPercentage = 0;
|
||||
int count;
|
||||
while ((count = input.read(data)) >= 0) {
|
||||
progress += count;
|
||||
@ -152,7 +152,7 @@ public class SharePlugin extends Plugin {
|
||||
if (fileLength > 0) {
|
||||
if (progress >= fileLength) break;
|
||||
long progressPercentage = (progress * 100 / fileLength);
|
||||
if ((progressPercentage - prevProgressPercentage) > 0) {
|
||||
if (progressPercentage != prevProgressPercentage) {
|
||||
prevProgressPercentage = progressPercentage;
|
||||
builder.setProgress(100, (int) progressPercentage, false);
|
||||
notificationManager.notify(notificationId, builder.build());
|
||||
|
@ -292,28 +292,24 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
|
||||
device.sendPackage(np, new Device.SendPackageStatusCallback() {
|
||||
|
||||
int prevProgressPercentage = 0,progressPercentage;
|
||||
int prevProgress = 0;
|
||||
|
||||
@Override
|
||||
public void progressChanged(final long progress) {
|
||||
// update notification progress
|
||||
progressPercentage = (int)((progress * 100) / filesize);
|
||||
if (filesize > 0 && (progressPercentage - prevProgressPercentage) > 0) {
|
||||
prevProgressPercentage = progressPercentage;
|
||||
public void onProgressChanged(final int progress) {
|
||||
if (progress != prevProgress) {
|
||||
prevProgress = progress;
|
||||
progressBarHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
builder.setProgress(100, progressPercentage, false);
|
||||
builder.setProgress(100, progress, false);
|
||||
notificationManager.notify(notificationId, builder.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSuccessful() {
|
||||
|
||||
public void onSuccess() {
|
||||
progressBarHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -339,8 +335,7 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFailed() {
|
||||
|
||||
public void onFailure(Throwable e) {
|
||||
progressBarHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user