diff options
| author | Avi Levkovich <avi@twine-s.com> | 2017-12-28 15:16:27 +0200 |
|---|---|---|
| committer | Avi Levkovich <avi@twine-s.com> | 2017-12-28 15:16:27 +0200 |
| commit | c056f991c0168f6449fac16c3b0cb165518c5e01 (patch) | |
| tree | e5c69bb1f3e03029991efe15e930af80ff6712db /Software/Android_Studio/Tango.Integration/src/main/java | |
| parent | 15799210aab388996f86808e000940093306ca41 (diff) | |
| parent | 2d3f4bfd4b265888933ad8a7e21e4dd80aa1eda2 (diff) | |
| download | Tango-c056f991c0168f6449fac16c3b0cb165518c5e01.tar.gz Tango-c056f991c0168f6449fac16c3b0cb165518c5e01.zip | |
MERGE.
Diffstat (limited to 'Software/Android_Studio/Tango.Integration/src/main/java')
9 files changed, 584 insertions, 16 deletions
diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/MachineIdentityProvider.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/MachineIdentityProvider.java deleted file mode 100644 index 29cb0c30c..000000000 --- a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/MachineIdentityProvider.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.twine.tango.integration; - - -/** - * Represents the default machine identity provider implementation. - */ -public class MachineIdentityProvider implements IMachineIdentityProvider -{ - - @Override - public String getSerialNumber() - { - return "1234"; - } -} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/IMachineOperator.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/IMachineOperator.java new file mode 100644 index 000000000..9963f295b --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/IMachineOperator.java @@ -0,0 +1,12 @@ +package com.twine.tango.integration.operators; + +import com.twine.tango.transport.ITransporter; + +/** + * Created by Roy on 12/23/2017. + */ + +public interface IMachineOperator extends ITransporter +{ + +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/MachineOperator.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/MachineOperator.java new file mode 100644 index 000000000..f23c8c705 --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/operators/MachineOperator.java @@ -0,0 +1,20 @@ +package com.twine.tango.integration.operators; + +import com.twine.tango.transport.ITransportAdapter; +import com.twine.tango.transport.transporters.ProtoTransporter; + +/** + * Created by Roy on 12/23/2017. + */ + +public class MachineOperator extends ProtoTransporter implements IMachineOperator +{ + public MachineOperator() + { + } + + public MachineOperator(ITransportAdapter adapter) + { + super(adapter); + } +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/IMachineIdentityProvider.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/providers/IMachineIdentityProvider.java index 3e35be9d0..547a17e50 100644 --- a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/IMachineIdentityProvider.java +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/providers/IMachineIdentityProvider.java @@ -1,4 +1,4 @@ -package com.twine.tango.integration; +package com.twine.tango.integration.providers; /** diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/providers/MachineIdentityProvider.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/providers/MachineIdentityProvider.java new file mode 100644 index 000000000..c72b9cea4 --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/providers/MachineIdentityProvider.java @@ -0,0 +1,19 @@ +package com.twine.tango.integration.providers; +import com.twine.tango.dal.dao.TangoDAO; +import com.twine.tango.dal.entities.Machine; + +import static br.com.zbra.androidlinq.Linq.stream; + + +/** + * Represents the default machine identity provider implementation. + */ +public class MachineIdentityProvider implements IMachineIdentityProvider +{ + @Override + public String getSerialNumber() + { + Machine machine = stream(TangoDAO.getAllMachines()).firstOrNull(); + return machine != null ? machine.getSerialNumber() : "0000"; + } +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ExternalBridgeService.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ExternalBridgeService.java new file mode 100644 index 000000000..24ae72eba --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ExternalBridgeService.java @@ -0,0 +1,281 @@ +package com.twine.tango.integration.services; + +import android.content.Context; +import android.net.DhcpInfo; +import android.net.wifi.WifiManager; +import android.os.StrictMode; +import android.os.SystemClock; +import android.provider.SyncStateContract.Constants; +import android.util.Log; + +import com.elvishew.xlog.XLog; +import com.google.protobuf.GeneratedMessageV3; +import com.twine.tango.core.ContextHelper; +import com.twine.tango.core.IEventHandler; +import com.twine.tango.integration.operators.IMachineOperator; +import com.twine.tango.integration.providers.IMachineIdentityProvider; +import com.twine.tango.pmr.MessageFactory; +import com.twine.tango.pmr.TangoMessage; +import com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer; +import com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType; +import com.twine.tango.pmr.integration.ExternalBridgeUdpDiscoveryPacketOuterClass.ExternalBridgeUdpDiscoveryPacket; +import com.twine.tango.pmr.integration.ExternalClientLoginRequestOuterClass.ExternalClientLoginRequest; +import com.twine.tango.pmr.integration.ExternalClientLoginResponseOuterClass.ExternalClientLoginResponse; +import com.twine.tango.transport.ITransportAdapter; +import com.twine.tango.transport.ResponseErrorException; +import com.twine.tango.transport.adapters.TcpTransportAdapter; +import com.twine.tango.transport.transporters.ProtoTransporter; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import static br.com.zbra.androidlinq.Linq.stream; + +/** + * Created by Roy on 12/22/2017. + */ + +public class ExternalBridgeService extends ProtoTransporter implements IExternalBridgeService +{ + private ServerSocket listener; + private boolean isStarted; + private List<HandlerAndType> handlers; + private IMachineIdentityProvider identityProvider; + private IMachineOperator machineOperator; + + @Inject + public ExternalBridgeService(IMachineIdentityProvider identityProvider, IMachineOperator machineOperator) + { + this.identityProvider = identityProvider; + this.machineOperator = machineOperator; + handlers = new ArrayList<>(); + } + + @Override + public boolean isStarted() + { + return isStarted; + } + + @Override + public void start() throws IOException + { + listener = new ServerSocket(1984); + isStarted = true; + Thread listenerThread = new Thread(this::listenerThreadMethod); + Thread discoveryThread = new Thread(this::discoveryThreadMethod); + listenerThread.start(); + discoveryThread.start(); + } + + private void discoveryThreadMethod() + { + // Hack Prevent crash (sending should be done using an async task) + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); + + byte[] packet = ExternalBridgeUdpDiscoveryPacket.newBuilder().setSerialNumber(identityProvider.getSerialNumber()).build().toByteArray(); + + while (isStarted) + { + try + { + DatagramSocket socket = new DatagramSocket(); + socket.setBroadcast(true); + + //First try to send to emulator host... + DatagramPacket sendPacket = new DatagramPacket(packet, packet.length, InetAddress.getByName("10.0.2.2"), 8888); + socket.send(sendPacket); + + //This will not work on the emulator as far as I know. + //TODO: This needs to be tested on a real device! + sendPacket = new DatagramPacket(packet, packet.length, InetAddress.getByName("255.255.255.255"), 8888); + socket.send(sendPacket); + + } catch (IOException e) + { + XLog.e(e); + } + + SystemClock.sleep(5000); + } + } + + private InetAddress getBroadcastAddress() throws IOException + { + WifiManager wifi = (WifiManager) ContextHelper.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + assert wifi != null; + DhcpInfo dhcp = wifi.getDhcpInfo(); + + if (dhcp != null) + { + int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask; + byte[] quads = new byte[4]; + for (int k = 0; k < 4; k++) + quads[k] = (byte) ((broadcast >> k * 8) & 0xFF); + return InetAddress.getByAddress(quads); + } else + { + return null; + } + } + + @Override + public void stop() + { + isStarted = false; + try + { + listener.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + + @Override + public <T> void registerMessageHandler(IEventHandler<MessageReceivedArgs<T>> handler, MessageType messageType) + { + handlers.add(new HandlerAndType(handler, messageType)); + } + + @Override + public <T> void unRegisterMessageHandler(IEventHandler<MessageReceivedArgs<T>> handler) + { + HandlerAndType h = stream(handlers).singleOrNull(x -> x.handler == handler); + if (h != null) + { + handlers.remove(h); + } + } + + private void listenerThreadMethod() + { + while (isStarted) + { + try + { + Socket newSocket = listener.accept(); + + if (newSocket != null) + { + for (ITransportAdapter adapter : getAdapters()) + { + adapter.disconnect().blockingAwait(); + } + getAdapters().clear(); + TcpTransportAdapter adapter = new TcpTransportAdapter(newSocket); + adapter.setAuthenticated(false); + getAdapters().add(adapter); + connect().blockingAwait(); + } + + } catch (IOException e) + { + XLog.e(e); + } + + SystemClock.sleep(100); + } + + disconnect().blockingAwait(); + } + + @Override + protected void onRequestReceived(MessageContainer container) + { + super.onRequestReceived(container); + + try + { + if (container.getType() == MessageType.ExternalClientLoginRequest) + { + ExternalClientLoginRequest request = MessageFactory.parseMessageFromContainer(container); + if (request.getPassword().equals("Aa123456")) //TODO: Compare with global machine settings password... + { + getAdapters().get(0).setAuthenticated(true); + sendResponse(MessageFactory.createTangoMessage( + ExternalClientLoginResponse.class, + ExternalClientLoginResponse.newBuilder().setAuthenticated(true).build(), + container.getToken())); + } else + { + getAdapters().get(0).setAuthenticated(false); + sendResponse(MessageFactory.createTangoMessage( + ExternalClientLoginResponse.class, + ExternalClientLoginResponse.newBuilder().setAuthenticated(false).build(), + container.getToken())); + } + + return; + } + + if (getAdapters().get(0).isAuthenticated()) + { + GeneratedMessageV3 message = MessageFactory.parseMessageFromContainerAgnostic(container); + + List<HandlerAndType> receivers = stream(handlers).where((x) -> x.messageType == container.getType()).toList(); + + if (receivers.size() > 0) + { + for (HandlerAndType receiver : receivers) + { + //noinspection unchecked + receiver.handler.invoke(this, new MessageReceivedArgs(container, message)); + } + } else + { + //Route to machine... + if (container.getContinuous()) + { + //noinspection unchecked + machineOperator.sendContinuousRequest(MessageFactory.createTangoMessage(container, message)).subscribe((response) -> + { + sendResponse((TangoMessage<? extends GeneratedMessageV3>) response); + }, (ex) -> + { + sendResponse((TangoMessage<? extends GeneratedMessageV3>) ((ResponseErrorException)ex).getResponse()); + }); + } else + { + //noinspection unchecked + machineOperator.sendRequest(MessageFactory.createTangoMessage(container, message)).subscribe((response) -> + { + sendResponse((TangoMessage<? extends GeneratedMessageV3>) response); + }, (ex) -> + { + sendResponse((TangoMessage<? extends GeneratedMessageV3>) ((ResponseErrorException)ex).getResponse()); + }); + } + } + } else + { + XLog.w("Message received from an unauthorized adapter!"); + } + + } catch (Exception e) + { + XLog.e(e); + } + } + + private class HandlerAndType + { + IEventHandler handler; + MessageType messageType; + + public HandlerAndType(IEventHandler handler, MessageType messageType) + { + this.handler = handler; + this.messageType = messageType; + } + } +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/IExternalBridgeService.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/IExternalBridgeService.java new file mode 100644 index 000000000..5a2aed9aa --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/IExternalBridgeService.java @@ -0,0 +1,53 @@ +package com.twine.tango.integration.services; + +import com.twine.tango.core.IEventHandler; +import com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer; +import com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType; +import com.twine.tango.transport.ITransporter; + +import java.io.IOException; + +/** + * Created by Roy on 12/22/2017. + */ + +public interface IExternalBridgeService extends ITransporter +{ + boolean isStarted(); + void start() throws IOException; + void stop(); + <T> void registerMessageHandler(IEventHandler<MessageReceivedArgs<T>> handler, MessageType messageType); + <T> void unRegisterMessageHandler(IEventHandler<MessageReceivedArgs<T>> handler); + + public class MessageReceivedArgs<T> + { + private MessageContainer container; + private T message; + + public MessageReceivedArgs(MessageContainer container, T message) + { + this.container = container; + this.message = message; + } + + public MessageContainer getContainer() + { + return container; + } + + public void setContainer(MessageContainer container) + { + this.container = container; + } + + public T getMessage() + { + return message; + } + + public void setMessage(T message) + { + this.message = message; + } + } +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ISynchronizationService.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ISynchronizationService.java new file mode 100644 index 000000000..631522fd0 --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/ISynchronizationService.java @@ -0,0 +1,19 @@ +package com.twine.tango.integration.services; + +import java.io.IOException; + +import io.reactivex.Completable; + + +/** + * Represents the Tango application local to remote synchronization engine. + */ +public interface ISynchronizationService +{ + /** + * Synchronizes the local database with the remote database through the remote machine service. + * + * @return the completable. + */ + Completable synchronizeDB(); +} diff --git a/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/SynchronizationService.java b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/SynchronizationService.java new file mode 100644 index 000000000..53b4c8194 --- /dev/null +++ b/Software/Android_Studio/Tango.Integration/src/main/java/com/twine/tango/integration/services/SynchronizationService.java @@ -0,0 +1,179 @@ +package com.twine.tango.integration.services; + +import android.os.AsyncTask; + +import com.elvishew.xlog.XLog; +import com.google.protobuf.ByteString; +import com.snatik.storage.Storage; +import com.twine.tango.core.ContextHelper; +import com.twine.tango.dal.TangoDB; +import com.twine.tango.integration.providers.IMachineIdentityProvider; +import com.twine.tango.integration.services.IExternalBridgeService.MessageReceivedArgs; +import com.twine.tango.pmr.MessageFactory; +import com.twine.tango.pmr.TangoMessage; +import com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType; +import com.twine.tango.pmr.integration.DirectSynchronizationRequestOuterClass.DirectSynchronizationRequest; +import com.twine.tango.pmr.integration.DirectSynchronizationResponseOuterClass.DirectSynchronizationResponse; +import com.twine.tango.pmr.integration.OverrideDataBaseRequestOuterClass.OverrideDataBaseRequest; +import com.twine.tango.pmr.integration.OverrideDataBaseResponseOuterClass.OverrideDataBaseResponse; +import com.twine.tango.pmr.stubs.CalculateRequestOuterClass.CalculateRequest; +import com.twine.tango.pmr.stubs.CalculateResponseOuterClass.CalculateResponse; +import com.twine.tango.pmr.synchronization.SynchronizeDBRequestOuterClass.SynchronizeDBRequest; +import com.twine.tango.web.WebApiFactory; +import com.twine.tango.web.ISynchronizationAPI; + +import java.io.IOException; + +import javax.inject.Inject; + +import io.reactivex.Completable; + + +/** + * Represents the Tango application local to remote synchronization engine. + */ +public class SynchronizationService implements ISynchronizationService +{ + private IMachineIdentityProvider machineIdentityProvider; + private IExternalBridgeService bridgeService; + + /** + * Instantiates a new Tango synchronizer. + * + * @param machineIdentityProvider the machine identity provider + */ + @Inject + public SynchronizationService(IMachineIdentityProvider machineIdentityProvider, IExternalBridgeService bridgeService) + { + this.machineIdentityProvider = machineIdentityProvider; + this.bridgeService = bridgeService; + this.bridgeService.registerMessageHandler(this::handleDirectSynchronizationRequest, MessageType.DirectSynchronizationRequest); + this.bridgeService.<OverrideDataBaseRequest>registerMessageHandler(this::handleOverrideDataBaseRequest, MessageType.OverrideDataBaseRequest); + + } + + private void handleOverrideDataBaseRequest(Object o, MessageReceivedArgs<OverrideDataBaseRequest> request) + { + AsyncTask.execute(() -> + { + try + { + //Backup DataBase. + TangoDB.backup(); + + //Replace Database. + TangoDB.replace(request.getMessage().getRemoteDB().toByteArray()); + + //Create response. + OverrideDataBaseResponse response = OverrideDataBaseResponse.newBuilder() + .setSuccessful(true) + .build(); + + TangoMessage<OverrideDataBaseResponse> message = MessageFactory.createTangoMessage( + OverrideDataBaseResponse.class, + response); + + bridgeService.sendResponse(message, request.getContainer().getToken()).subscribe(() -> + { + + },(ex) -> + { + XLog.e(ex); + }); + + } catch (Exception e) + { + XLog.e(e); + //Create response. + OverrideDataBaseResponse response = OverrideDataBaseResponse.newBuilder() + .setSuccessful(false) + .build(); + + TangoMessage<OverrideDataBaseResponse> message = MessageFactory.createTangoMessage( + OverrideDataBaseResponse.class, + response); + + bridgeService.sendResponse(message, request.getContainer().getToken()).subscribe(() -> + { + + },(ex) -> + { + XLog.e(ex); + }); + } + }); + } + + private void handleDirectSynchronizationRequest(Object o, MessageReceivedArgs<DirectSynchronizationRequest> request) + { + AsyncTask.execute(() -> + { + try + { + Storage storage = new Storage(ContextHelper.getApplicationContext()); + + //Read current DB file bytes. + byte[] data = storage.readFile(TangoDB.getDataBasePath()); + + //Create synchronization response. + DirectSynchronizationResponse response = DirectSynchronizationResponse.newBuilder() + .setLocalDB(ByteString.copyFrom(data)) + .build(); + + TangoMessage<DirectSynchronizationResponse> message = MessageFactory.createTangoMessage( + DirectSynchronizationResponse.class, + response); + + bridgeService.sendResponse(message, request.getContainer().getToken()).subscribe(() -> + { + + },(ex) -> + { + XLog.e(ex); + }); + + } catch (Exception e) + { + XLog.e(e); + } + }); + } + + @Override + public Completable synchronizeDB() + { + return Completable.create((emitter) -> + { + + //Backup DataBase. + TangoDB.backup(); + + Storage storage = new Storage(ContextHelper.getApplicationContext()); + + //Read current DB file bytes. + byte[] data = storage.readFile(TangoDB.getDataBasePath()); + + //Create synchronization web api. + ISynchronizationAPI synchAPI = WebApiFactory.getSynchronizationAPI(); + + //Create synchronization response. + SynchronizeDBRequest request = SynchronizeDBRequest.newBuilder() + .setSerialNumber(machineIdentityProvider.getSerialNumber()) + .setLocalDB(ByteString.copyFrom(data)) + .build(); + + synchAPI.synchronize(request).singleOrError().subscribe((response) -> + { + + TangoDB.replace(response.getRemoteDB().toByteArray()); + emitter.onComplete(); + + }, (ex) -> + { + XLog.e(ex); + emitter.onError(ex); + }); + + }); + } +} |
