Added implementation for android and wp8 platforms
This commit is contained in:
parent
84b16cced7
commit
988ebdeb41
66
plugin.xml
Normal file
66
plugin.xml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="cz.blocshop.socketsforcordova" version="0.1.0">
|
||||||
|
<name>SocketsForCordova</name>
|
||||||
|
<description>Cordova plugin for socket communication</description>
|
||||||
|
<license>Apache 2.0</license>
|
||||||
|
<keywords>cordova,sockets,socket</keywords>
|
||||||
|
|
||||||
|
|
||||||
|
<js-module src="socket.js" name="Socket">
|
||||||
|
<clobbers target="window.Socket" />
|
||||||
|
</js-module>
|
||||||
|
|
||||||
|
<!-- android -->
|
||||||
|
<platform name="android">
|
||||||
|
<config-file target="res/xml/config.xml" parent="/*">
|
||||||
|
<feature name="SocketsForCordova">
|
||||||
|
<param name="android-package" value="cz.blocshop.socketsforcordova.SocketPlugin"/>
|
||||||
|
</feature>
|
||||||
|
</config-file>
|
||||||
|
<config-file target="AndroidManifest.xml" parent="/manifest">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</config-file>
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/Logging.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/Consumer.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/SocketAdapter.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/SocketAdapterImpl.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/SocketAdapterOptions.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
<source-file src="src/android/src/cz/blocshop/socketsforcordova/SocketPlugin.java" target-dir="src/cz/blocshop/socketsforcordova" />
|
||||||
|
|
||||||
|
</platform>
|
||||||
|
|
||||||
|
<!-- ios
|
||||||
|
<platform name="ios">
|
||||||
|
<config-file target="config.xml" parent="/*">
|
||||||
|
<feature name="InAppBrowser">
|
||||||
|
<param name="ios-package" value="CDVInAppBrowser" />
|
||||||
|
</feature>
|
||||||
|
</config-file>
|
||||||
|
|
||||||
|
<header-file src="src/ios/CDVInAppBrowser.h" />
|
||||||
|
<source-file src="src/ios/CDVInAppBrowser.m" />
|
||||||
|
|
||||||
|
<framework src="CoreGraphics.framework" />
|
||||||
|
</platform> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- wp8 -->
|
||||||
|
<platform name="wp8">
|
||||||
|
<config-file target="config.xml" parent="/*">
|
||||||
|
<feature name="SocketsForCordova">
|
||||||
|
<param name="wp-package" value="Blocshop.ScoketsForCordova.SocketPlugin"/>
|
||||||
|
</feature>
|
||||||
|
</config-file>
|
||||||
|
|
||||||
|
<source-file src="src/wp8/src/SocketAdapter.cs" target-dir="src" />
|
||||||
|
<source-file src="src/wp8/src/SocketAdapterOptions.cs" target-dir="src" />
|
||||||
|
<source-file src="src/wp8/src/SocketExtensions.cs" target-dir="src" />
|
||||||
|
<source-file src="src/wp8/src/SocketPlugin.cs" target-dir="src" />
|
||||||
|
<source-file src="src/wp8/src/SocketEvent.cs" target-dir="src" />
|
||||||
|
<source-file src="src/wp8/src/SocketStorage.cs" target-dir="src" />
|
||||||
|
</platform>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</plugin>
|
154
socket.js
Normal file
154
socket.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
var exec = require('cordova/exec');
|
||||||
|
|
||||||
|
var SOCKET_EVENT = "SOCKET_EVENT";
|
||||||
|
var CORDOVA_SERVICE_NAME = "SocketsForCordova";
|
||||||
|
|
||||||
|
function Socket() {
|
||||||
|
this.onData = null;
|
||||||
|
this.onClose = null;
|
||||||
|
this.onError = null;
|
||||||
|
this.socketKey = guid();
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket.create = function(callback) {
|
||||||
|
|
||||||
|
var socket = new Socket();
|
||||||
|
|
||||||
|
function socketEventHandler(event) {
|
||||||
|
|
||||||
|
var payload = event.payload;
|
||||||
|
|
||||||
|
if (payload.socketKey !== socket.socketKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(payload.type) {
|
||||||
|
case "Close":
|
||||||
|
console.debug("SocketsForCordova: Close event, socket key: " + payload.socketKey);
|
||||||
|
window.document.removeEventListener(SOCKET_EVENT, socketEventHandler);
|
||||||
|
socket.onClose();
|
||||||
|
break;
|
||||||
|
case "DataReceived":
|
||||||
|
console.debug("SocketsForCordova: DataReceived event, socket key: " + payload.socketKey);
|
||||||
|
socket.onData(new Int8Array(payload.data));
|
||||||
|
break;
|
||||||
|
case "Error":
|
||||||
|
console.debug("SocketsForCordova: Error event, socket key: " + payload.socketKey);
|
||||||
|
socket.onError(payload.errorMessage);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error("SocketsForCordova: Unknown event type " + payload.type + ", socket key: " + payload.socketKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.document.addEventListener(SOCKET_EVENT, socketEventHandler);
|
||||||
|
|
||||||
|
exec(
|
||||||
|
function() {
|
||||||
|
console.debug("SocketsForCordova: Socket object successfully constructed.");
|
||||||
|
callback(socket);
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
console.error("SocketsForCordova: Unexpected error during constructing Socket object. Error: " + error);
|
||||||
|
},
|
||||||
|
CORDOVA_SERVICE_NAME,
|
||||||
|
"create",
|
||||||
|
[ socket.socketKey ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.prototype.connect = function (host, port, success, error) {
|
||||||
|
exec(
|
||||||
|
function() {
|
||||||
|
console.debug("SocketsForCordova: Socket successfully connected.");
|
||||||
|
if (success)
|
||||||
|
success();
|
||||||
|
},
|
||||||
|
function(errorMessage) {
|
||||||
|
console.error("SocketsForCordova: Error during socket connecting. Error: " + errorMessage);
|
||||||
|
if (error)
|
||||||
|
error(errorMessage);
|
||||||
|
},
|
||||||
|
CORDOVA_SERVICE_NAME,
|
||||||
|
"connect",
|
||||||
|
[ this.socketKey, host, port ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.prototype.write = function (data, success, error) {
|
||||||
|
|
||||||
|
var dataToWrite = data instanceof Int8Array
|
||||||
|
? Socket._copyToArray(data)
|
||||||
|
: data;
|
||||||
|
|
||||||
|
exec(
|
||||||
|
function() {
|
||||||
|
console.debug("SocketsForCordova: Data successfully written to socket. Number of bytes: " + data.length);
|
||||||
|
if (success)
|
||||||
|
success();
|
||||||
|
},
|
||||||
|
function(errorMessage) {
|
||||||
|
console.error("SocketsForCordova: Error during writing data to socket. Error: " + errorMessage);
|
||||||
|
if (error)
|
||||||
|
error(errorMessage);
|
||||||
|
},
|
||||||
|
CORDOVA_SERVICE_NAME,
|
||||||
|
"write",
|
||||||
|
[ this.socketKey, dataToWrite ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket._copyToArray = function(array) {
|
||||||
|
var outputArray = new Array(array.length);
|
||||||
|
for (var i = 0; i < array.length; i++) {
|
||||||
|
outputArray[i] = array[i];
|
||||||
|
}
|
||||||
|
return outputArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.prototype.close = function () {
|
||||||
|
exec(
|
||||||
|
function() {
|
||||||
|
console.debug("SocketsForCordova: Close successfully closed.");
|
||||||
|
},
|
||||||
|
function(errorMessage) {
|
||||||
|
console.error("SocketsForCordova: Error when call close on socket. Error: " + errorMessage);
|
||||||
|
},
|
||||||
|
CORDOVA_SERVICE_NAME,
|
||||||
|
"close",
|
||||||
|
[ this.socketKey ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.dispatchEvent = function(event) {
|
||||||
|
var eventReceive = document.createEvent('Events');
|
||||||
|
eventReceive.initEvent(SOCKET_EVENT, true, true);
|
||||||
|
eventReceive.payload = event;
|
||||||
|
|
||||||
|
document.dispatchEvent(eventReceive);
|
||||||
|
};
|
||||||
|
|
||||||
|
var guid = (function() {
|
||||||
|
function s4() {
|
||||||
|
return Math.floor((1 + Math.random()) * 0x10000)
|
||||||
|
.toString(16)
|
||||||
|
.substring(1);
|
||||||
|
}
|
||||||
|
return function() {
|
||||||
|
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||||
|
s4() + '-' + s4() + s4() + s4();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Register event dispatcher for Windows Phone
|
||||||
|
if (navigator.userAgent.match(/iemobile/i)) {
|
||||||
|
window.document.addEventListener("deviceready", function() {
|
||||||
|
exec(
|
||||||
|
Socket.dispatchEvent,
|
||||||
|
function(errorMessage) {
|
||||||
|
console.error("SocketsForCordova: Cannot register WP event dispatcher, Error: " + errorMessage);
|
||||||
|
},
|
||||||
|
CORDOVA_SERVICE_NAME,
|
||||||
|
"registerWPEventDispatcher",
|
||||||
|
[ ]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Socket;
|
@ -0,0 +1,5 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
public interface Consumer<T> {
|
||||||
|
void accept(T t);
|
||||||
|
}
|
10
src/android/src/cz/blocshop/socketsforcordova/Logging.java
Normal file
10
src/android/src/cz/blocshop/socketsforcordova/Logging.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class Logging {
|
||||||
|
public static void Error(String klass, String message, Throwable t) {
|
||||||
|
Logger.getLogger(klass).log(Level.SEVERE, message, t);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SocketAdapter {
|
||||||
|
public void connect(String host, int port) throws IOException;
|
||||||
|
public void write(byte[] data) throws IOException;
|
||||||
|
public void close() throws IOException;
|
||||||
|
public void setOptions(SocketAdapterOptions options) throws SocketException;
|
||||||
|
public void setDataConsumer(Consumer<byte[]> dataConsumer);
|
||||||
|
public void setCloseEventHandler(Consumer<Boolean> closeEventHandler);
|
||||||
|
public void setErrorHandler(Consumer<IOException> errorHandler);
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
|
||||||
|
public class SocketAdapterImpl implements SocketAdapter {
|
||||||
|
|
||||||
|
private final int INPUT_STREAM_BUFFER_SIZE = 16 * 1024;
|
||||||
|
private final Socket socket;
|
||||||
|
|
||||||
|
private Consumer<byte[]> dataConsumer;
|
||||||
|
private Consumer<Boolean> closeEventHandler;
|
||||||
|
private Consumer<IOException> exceptionHandler;
|
||||||
|
|
||||||
|
public SocketAdapterImpl() {
|
||||||
|
this.socket = new Socket();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(String host, int port) throws IOException {
|
||||||
|
this.socket.connect(new InetSocketAddress(host, port));
|
||||||
|
this.submitReadTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] data) throws IOException {
|
||||||
|
this.socket.getOutputStream().write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (!this.socket.isClosed()) {
|
||||||
|
this.socket.shutdownOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOptions(SocketAdapterOptions options) throws SocketException {
|
||||||
|
if (options.getKeepAlive() != null) {
|
||||||
|
this.socket.setKeepAlive(options.getKeepAlive());
|
||||||
|
}
|
||||||
|
if (options.getOobInline() != null) {
|
||||||
|
this.socket.setOOBInline(options.getOobInline());
|
||||||
|
}
|
||||||
|
if (options.getSoLinger() != null) {
|
||||||
|
this.socket.setSoLinger(true, options.getSoLinger());
|
||||||
|
}
|
||||||
|
if (options.getSoTimeout() != null) {
|
||||||
|
this.socket.setSoTimeout(options.getSoTimeout());
|
||||||
|
}
|
||||||
|
if (options.getReceiveBufferSize() != null) {
|
||||||
|
this.socket.setReceiveBufferSize(options.getReceiveBufferSize());
|
||||||
|
}
|
||||||
|
if (options.getSendBufferSize() != null) {
|
||||||
|
this.socket.setSendBufferSize(options.getSendBufferSize());
|
||||||
|
}
|
||||||
|
if (options.getTrafficClass() != null) {
|
||||||
|
this.socket.setTrafficClass(options.getTrafficClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataConsumer(Consumer<byte[]> dataConsumer) {
|
||||||
|
this.dataConsumer = dataConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCloseEventHandler(Consumer<Boolean> closeEventHandler) {
|
||||||
|
this.closeEventHandler = closeEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setErrorHandler(Consumer<IOException> exceptionHandler) {
|
||||||
|
this.exceptionHandler = exceptionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submitReadTask() {
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
executor.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
runRead();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runRead() {
|
||||||
|
boolean hasError = false;
|
||||||
|
try {
|
||||||
|
runReadLoop();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logging.Error(SocketAdapterImpl.class.getName(), "Error during reading of socket input stream", e);
|
||||||
|
hasError = true;
|
||||||
|
invokeExceptionHandler(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logging.Error(SocketAdapterImpl.class.getName(), "Error during closing of socket", e);
|
||||||
|
} finally {
|
||||||
|
invokeCloseEventHandler(hasError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runReadLoop() throws IOException {
|
||||||
|
byte[] buffer = new byte[INPUT_STREAM_BUFFER_SIZE];
|
||||||
|
int bytesRead = 0;
|
||||||
|
|
||||||
|
while ((bytesRead = socket.getInputStream().read(buffer)) >= 0) {
|
||||||
|
byte[] data = buffer.length == bytesRead
|
||||||
|
? buffer
|
||||||
|
: Arrays.copyOfRange(buffer, 0, bytesRead);
|
||||||
|
|
||||||
|
this.invokeDataConsumer(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeDataConsumer(byte[] data) {
|
||||||
|
if (this.dataConsumer != null) {
|
||||||
|
this.dataConsumer.accept(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeCloseEventHandler(boolean hasError) {
|
||||||
|
if (this.closeEventHandler != null) {
|
||||||
|
this.closeEventHandler.accept(hasError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeExceptionHandler(IOException exception) {
|
||||||
|
if (this.exceptionHandler != null) {
|
||||||
|
this.exceptionHandler.accept(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
public class SocketAdapterOptions {
|
||||||
|
|
||||||
|
private Boolean keepAlive;
|
||||||
|
private Boolean oobInline;
|
||||||
|
private Integer soLinger;
|
||||||
|
private Integer soTimeout;
|
||||||
|
private Integer receiveBufferSize;
|
||||||
|
private Integer sendBufferSize;
|
||||||
|
private Integer trafficClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the keepAlive
|
||||||
|
*/
|
||||||
|
public Boolean getKeepAlive() {
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keepAlive the keepAlive to set
|
||||||
|
*/
|
||||||
|
public void setKeepAlive(Boolean keepAlive) {
|
||||||
|
this.keepAlive = keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the oobInline
|
||||||
|
*/
|
||||||
|
public Boolean getOobInline() {
|
||||||
|
return oobInline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param oobInline the oobInline to set
|
||||||
|
*/
|
||||||
|
public void setOobInline(Boolean oobInline) {
|
||||||
|
this.oobInline = oobInline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the soLinger
|
||||||
|
*/
|
||||||
|
public Integer getSoLinger() {
|
||||||
|
return soLinger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param soLinger the soLinger to set
|
||||||
|
*/
|
||||||
|
public void setSoLinger(Integer soLinger) {
|
||||||
|
this.soLinger = soLinger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the soTimeout
|
||||||
|
*/
|
||||||
|
public Integer getSoTimeout() {
|
||||||
|
return soTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param soTimeout the soTimeout to set
|
||||||
|
*/
|
||||||
|
public void setSoTimeout(Integer soTimeout) {
|
||||||
|
this.soTimeout = soTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the receiveBufferSize
|
||||||
|
*/
|
||||||
|
public Integer getReceiveBufferSize() {
|
||||||
|
return receiveBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param receiveBufferSize the receiveBufferSize to set
|
||||||
|
*/
|
||||||
|
public void setReceiveBufferSize(Integer receiveBufferSize) {
|
||||||
|
this.receiveBufferSize = receiveBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sendBufferSize
|
||||||
|
*/
|
||||||
|
public Integer getSendBufferSize() {
|
||||||
|
return sendBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sendBufferSize the sendBufferSize to set
|
||||||
|
*/
|
||||||
|
public void setSendBufferSize(Integer sendBufferSize) {
|
||||||
|
this.sendBufferSize = sendBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the trafficClass
|
||||||
|
*/
|
||||||
|
public Integer getTrafficClass() {
|
||||||
|
return trafficClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param trafficClass the trafficClass to set
|
||||||
|
*/
|
||||||
|
public void setTrafficClass(Integer trafficClass) {
|
||||||
|
this.trafficClass = trafficClass;
|
||||||
|
}
|
||||||
|
}
|
206
src/android/src/cz/blocshop/socketsforcordova/SocketPlugin.java
Normal file
206
src/android/src/cz/blocshop/socketsforcordova/SocketPlugin.java
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.cordova.CallbackContext;
|
||||||
|
import org.apache.cordova.CordovaArgs;
|
||||||
|
import org.apache.cordova.CordovaPlugin;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
|
||||||
|
public class SocketPlugin extends CordovaPlugin {
|
||||||
|
|
||||||
|
Map<String, SocketAdapter> socketAdapters = new HashMap<String, SocketAdapter>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
|
||||||
|
if(action.equals("create")) {
|
||||||
|
this.create(args, callbackContext);
|
||||||
|
} else if (action.equals("connect")) {
|
||||||
|
this.connect(args, callbackContext);
|
||||||
|
} else if (action.equals("write")) {
|
||||||
|
this.write(args, callbackContext);
|
||||||
|
} else if (action.equals("close")) {
|
||||||
|
this.close(args, callbackContext);
|
||||||
|
} else if (action.equals("setOptions")) {
|
||||||
|
this.setOptions(args, callbackContext);
|
||||||
|
} else {
|
||||||
|
callbackContext.error(String.format("SocketPlugin - invalid action:", action));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void create(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
|
||||||
|
final String socketKey = args.getString(0);
|
||||||
|
|
||||||
|
SocketAdapter socketAdapter = new SocketAdapterImpl();
|
||||||
|
socketAdapter.setCloseEventHandler(new CloseEventHandler(socketKey));
|
||||||
|
socketAdapter.setDataConsumer(new DataConsumer(socketKey));
|
||||||
|
socketAdapter.setErrorHandler(new ErrorHandler(socketKey));
|
||||||
|
|
||||||
|
this.socketAdapters.put(socketKey, socketAdapter);
|
||||||
|
|
||||||
|
callbackContext.success(socketKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
String socketKey = args.getString(0);
|
||||||
|
String host = args.getString(1);
|
||||||
|
int port = args.getInt(2);
|
||||||
|
|
||||||
|
SocketAdapter socket = this.getSocketAdapter(socketKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.connect(host, port);
|
||||||
|
callbackContext.success();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callbackContext.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
String socketKey = args.getString(0);
|
||||||
|
JSONArray data = args.getJSONArray(1);
|
||||||
|
|
||||||
|
byte[] dataBuffer = new byte[data.length()];
|
||||||
|
for(int i = 0; i < dataBuffer.length; i++) {
|
||||||
|
dataBuffer[i] = (byte) data.getInt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketAdapter socket = this.getSocketAdapter(socketKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.write(dataBuffer);
|
||||||
|
callbackContext.success();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callbackContext.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
String socketKey = args.getString(0);
|
||||||
|
|
||||||
|
SocketAdapter socket = this.getSocketAdapter(socketKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
callbackContext.success();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callbackContext.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOptions(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
|
||||||
|
String socketKey = args.getString(0);
|
||||||
|
JSONObject optionsJSON = args.getJSONObject(1);
|
||||||
|
|
||||||
|
SocketAdapter socket = this.getSocketAdapter(socketKey);
|
||||||
|
|
||||||
|
SocketAdapterOptions options = new SocketAdapterOptions();
|
||||||
|
options.setKeepAlive(getBooleanPropertyFromJSON(optionsJSON, "keepAlive"));
|
||||||
|
options.setOobInline(getBooleanPropertyFromJSON(optionsJSON, "oobInline"));
|
||||||
|
options.setReceiveBufferSize(getIntegerPropertyFromJSON(optionsJSON, "receiveBufferSize"));
|
||||||
|
options.setSendBufferSize(getIntegerPropertyFromJSON(optionsJSON, "sendBufferSize"));
|
||||||
|
options.setSoLinger(getIntegerPropertyFromJSON(optionsJSON, "soLinger"));
|
||||||
|
options.setSoTimeout(getIntegerPropertyFromJSON(optionsJSON, "soTimeout"));
|
||||||
|
options.setTrafficClass(getIntegerPropertyFromJSON(optionsJSON, "trafficClass"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
callbackContext.success();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callbackContext.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean getBooleanPropertyFromJSON(JSONObject jsonObject, String propertyName) throws JSONException {
|
||||||
|
return jsonObject.has(propertyName) ? jsonObject.getBoolean(propertyName) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getIntegerPropertyFromJSON(JSONObject jsonObject, String propertyName) throws JSONException {
|
||||||
|
return jsonObject.has(propertyName) ? jsonObject.getInt(propertyName) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SocketAdapter getSocketAdapter(String socketKey) {
|
||||||
|
if (!this.socketAdapters.containsKey(socketKey)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format("Cannot find socketKey: %s. Connection is probably closed.", socketKey));
|
||||||
|
}
|
||||||
|
return this.socketAdapters.get(socketKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatchEvent(JSONObject jsonEventObject) {
|
||||||
|
this.webView.sendJavascript(String.format("window.Socket.dispatchEvent(%s);", jsonEventObject.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CloseEventHandler implements Consumer<Boolean> {
|
||||||
|
private String socketKey;
|
||||||
|
public CloseEventHandler(String socketKey) {
|
||||||
|
this.socketKey = socketKey;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void accept(Boolean hasError) {
|
||||||
|
socketAdapters.remove(this.socketKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject event = new JSONObject();
|
||||||
|
event.put("type", "Close");
|
||||||
|
event.put("hasError", hasError.booleanValue());
|
||||||
|
event.put("socketKey", this.socketKey);
|
||||||
|
|
||||||
|
dispatchEvent(event);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DataConsumer implements Consumer<byte[]> {
|
||||||
|
private String socketKey;
|
||||||
|
public DataConsumer(String socketKey) {
|
||||||
|
this.socketKey = socketKey;
|
||||||
|
}
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
@Override
|
||||||
|
public void accept(byte[] data) {
|
||||||
|
try {
|
||||||
|
JSONObject event = new JSONObject();
|
||||||
|
event.put("type", "DataReceived");
|
||||||
|
event.put("data", new JSONArray(data));
|
||||||
|
event.put("socketKey", socketKey);
|
||||||
|
|
||||||
|
dispatchEvent(event);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ErrorHandler implements Consumer<IOException> {
|
||||||
|
private String socketKey;
|
||||||
|
public ErrorHandler(String socketKey) {
|
||||||
|
this.socketKey = socketKey;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void accept(IOException exception) {
|
||||||
|
try {
|
||||||
|
JSONObject event = new JSONObject();
|
||||||
|
event.put("type", "Error");
|
||||||
|
event.put("errorMessage", exception.toString());
|
||||||
|
event.put("socketKey", socketKey);
|
||||||
|
|
||||||
|
dispatchEvent(event);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you 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 cz.blocshop.socketsforcordova;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import org.apache.cordova.*;
|
||||||
|
|
||||||
|
public class SocketsForCordovaActivity extends CordovaActivity
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
super.init();
|
||||||
|
// Set by <content src="index.html" /> in config.xml
|
||||||
|
super.loadUrl(Config.getStartUrl());
|
||||||
|
//super.loadUrl("file:///android_asset/www/index.html");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
110
src/wp8/src/SocketAdapter.cs
Normal file
110
src/wp8/src/SocketAdapter.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
public interface ISocketAdapter
|
||||||
|
{
|
||||||
|
Task Connect(String host, int port);
|
||||||
|
Task Write(byte[] data);
|
||||||
|
void Close();
|
||||||
|
SocketAdapterOptions Options { set; }
|
||||||
|
Action<byte[]> DataConsumer { set; }
|
||||||
|
Action<bool> CloseEventHandler { set; }
|
||||||
|
Action<Exception> ErrorHandler { set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SocketAdapter : ISocketAdapter
|
||||||
|
{
|
||||||
|
private const int InputStreamBufferSize = 16 * 1024;
|
||||||
|
private readonly Socket socket;
|
||||||
|
|
||||||
|
public Action<byte[]> DataConsumer { get; set; }
|
||||||
|
public Action<bool> CloseEventHandler { get; set; }
|
||||||
|
public Action<Exception> ErrorHandler { get; set; }
|
||||||
|
public SocketAdapterOptions Options { get; set; }
|
||||||
|
|
||||||
|
public SocketAdapter()
|
||||||
|
{
|
||||||
|
this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Connect(string host, int port)
|
||||||
|
{
|
||||||
|
var connectSocketAsyncEventArgs = new SocketAsyncEventArgs
|
||||||
|
{
|
||||||
|
RemoteEndPoint = new DnsEndPoint(host, port)
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.socket.ConnectTaskAsync(connectSocketAsyncEventArgs);
|
||||||
|
|
||||||
|
this.StartReadTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Write(byte[] data)
|
||||||
|
{
|
||||||
|
var socketAsyncEventArgs = new SocketAsyncEventArgs();
|
||||||
|
socketAsyncEventArgs.SetBuffer(data, 0, data.Length);
|
||||||
|
|
||||||
|
await this.socket.SendTaskAsync(socketAsyncEventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
this.socket.Shutdown(SocketShutdown.Send);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartReadTask()
|
||||||
|
{
|
||||||
|
Task.Factory.StartNew(() => this.RunRead());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunRead()
|
||||||
|
{
|
||||||
|
bool hasError = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.RunReadLoop();
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
hasError = true;
|
||||||
|
this.ErrorHandler(ex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.socket.Close();
|
||||||
|
this.CloseEventHandler(hasError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunReadLoop()
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[InputStreamBufferSize];
|
||||||
|
int bytesRead = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var eventArgs = new SocketAsyncEventArgs();
|
||||||
|
eventArgs.SetBuffer(buffer, 0, InputStreamBufferSize);
|
||||||
|
|
||||||
|
await this.socket.ReceiveTaskAsync(eventArgs);
|
||||||
|
|
||||||
|
bytesRead = eventArgs.BytesTransferred;
|
||||||
|
|
||||||
|
byte[] data = new byte[bytesRead];
|
||||||
|
Array.Copy(buffer, data, data.Length);
|
||||||
|
this.DataConsumer(data);
|
||||||
|
}
|
||||||
|
while (bytesRead != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/wp8/src/SocketAdapterOptions.cs
Normal file
11
src/wp8/src/SocketAdapterOptions.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
public class SocketAdapterOptions
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
73
src/wp8/src/SocketEvent.cs
Normal file
73
src/wp8/src/SocketEvent.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public abstract class SocketEvent
|
||||||
|
{
|
||||||
|
[DataMember(Name = "type")]
|
||||||
|
public abstract string Type { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "socketKey")]
|
||||||
|
public string SocketKey { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class CloseSocketEvent : SocketEvent
|
||||||
|
{
|
||||||
|
public override string Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Close";
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(Name = "hasError")]
|
||||||
|
public bool HasError { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class DataReceivedSocketEvent : SocketEvent
|
||||||
|
{
|
||||||
|
public override string Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "DataReceived";
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(Name = "data")]
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class ErrorSocketEvent : SocketEvent
|
||||||
|
{
|
||||||
|
public override string Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(Name="errorMessage")]
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
62
src/wp8/src/SocketExtensions.cs
Normal file
62
src/wp8/src/SocketExtensions.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
public static class SocketExtensions
|
||||||
|
{
|
||||||
|
public static async Task ConnectTaskAsync(this Socket socket, SocketAsyncEventArgs socketAsyncEventArgs)
|
||||||
|
{
|
||||||
|
var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Connect);
|
||||||
|
|
||||||
|
socket.ConnectAsync(socketAsyncEventArgs);
|
||||||
|
|
||||||
|
await task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task SendTaskAsync(this Socket socket, SocketAsyncEventArgs socketAsyncEventArgs)
|
||||||
|
{
|
||||||
|
var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Send);
|
||||||
|
|
||||||
|
socket.SendAsync(socketAsyncEventArgs);
|
||||||
|
|
||||||
|
await task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<byte[]> ReceiveTaskAsync(this Socket socket, SocketAsyncEventArgs socketAsyncEventArgs)
|
||||||
|
{
|
||||||
|
var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Receive);
|
||||||
|
|
||||||
|
socket.ReceiveAsync(socketAsyncEventArgs);
|
||||||
|
|
||||||
|
await task;
|
||||||
|
|
||||||
|
return socketAsyncEventArgs.Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task CreateTaskFromCompletionHandler(SocketAsyncEventArgs socketAsyncEventArgs, SocketAsyncOperation socketAsyncOperation)
|
||||||
|
{
|
||||||
|
TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
|
||||||
|
socketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>((o, eventArgs) =>
|
||||||
|
{
|
||||||
|
if (eventArgs.LastOperation == socketAsyncOperation)
|
||||||
|
{
|
||||||
|
if (eventArgs.SocketError == SocketError.Success)
|
||||||
|
{
|
||||||
|
completionSource.SetResult("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completionSource.SetException(new SocketException((int)eventArgs.SocketError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return completionSource.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
152
src/wp8/src/SocketPlugin.cs
Normal file
152
src/wp8/src/SocketPlugin.cs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using WPCordovaClassLib.Cordova;
|
||||||
|
using WPCordovaClassLib.Cordova.Commands;
|
||||||
|
using WPCordovaClassLib.Cordova.JSON;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
public class SocketPlugin : BaseCommand
|
||||||
|
{
|
||||||
|
private readonly ISocketStorage socketStorage;
|
||||||
|
private string eventDispatcherCallbackId;
|
||||||
|
|
||||||
|
public SocketPlugin()
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("SocketPlugin constructor: " + DateTime.Now.Ticks);
|
||||||
|
this.socketStorage = SocketStorage.CreateSocketStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create(string parameters)
|
||||||
|
{
|
||||||
|
string socketKey = JsonHelper.Deserialize<string[]>(parameters)[0];
|
||||||
|
|
||||||
|
ISocketAdapter socketAdapter = new SocketAdapter();
|
||||||
|
socketAdapter.CloseEventHandler = (hasError) => this.CloseEventHandler(socketKey, hasError);
|
||||||
|
socketAdapter.DataConsumer = (data) => this.DataConsumer(socketKey, data);
|
||||||
|
socketAdapter.ErrorHandler = (ex) => this.ErrorHandler(socketKey, ex);
|
||||||
|
|
||||||
|
this.socketStorage.Add(socketKey, socketAdapter);
|
||||||
|
|
||||||
|
this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerWPEventDispatcher(string parameters)
|
||||||
|
{
|
||||||
|
this.eventDispatcherCallbackId = this.CurrentCommandCallbackId;
|
||||||
|
PluginResult result = new PluginResult(PluginResult.Status.OK);
|
||||||
|
result.KeepCallback = true;
|
||||||
|
DispatchCommandResult(result, this.eventDispatcherCallbackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(string parameters)
|
||||||
|
{
|
||||||
|
string socketKey = JsonHelper.Deserialize<string[]>(parameters)[0];
|
||||||
|
string host = JsonHelper.Deserialize<string[]>(parameters)[1];
|
||||||
|
int port = int.Parse(JsonHelper.Deserialize<string[]>(parameters)[2]);
|
||||||
|
|
||||||
|
ISocketAdapter socket = this.socketStorage.Get(socketKey);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.Connect(host, port).Wait();
|
||||||
|
|
||||||
|
this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
this.DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(string parameters/*, string socketKey, byte[] data*/)
|
||||||
|
{
|
||||||
|
string socketKey = JsonHelper.Deserialize<string[]>(parameters)[0];
|
||||||
|
string dataJsonArray = JsonHelper.Deserialize<string[]>(parameters)[1];
|
||||||
|
byte[] data = JsonHelper.Deserialize<byte[]>(dataJsonArray);
|
||||||
|
|
||||||
|
ISocketAdapter socket = this.socketStorage.Get(socketKey);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.Write(data).Wait();
|
||||||
|
|
||||||
|
this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
this.DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close(string parameters)
|
||||||
|
{
|
||||||
|
string socketKey = JsonHelper.Deserialize<string[]>(parameters)[0];
|
||||||
|
|
||||||
|
ISocketAdapter socket = this.socketStorage.Get(socketKey);
|
||||||
|
|
||||||
|
socket.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//private void setOptions(CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||||
|
|
||||||
|
// String socketKey = args.getString(0);
|
||||||
|
// JSONObject optionsJSON = args.getJSONObject(1);
|
||||||
|
|
||||||
|
// SocketAdapter socket = this.getSkocketAdapter(socketKey);
|
||||||
|
|
||||||
|
// SocketAdapterOptions options = new SocketAdapterOptions();
|
||||||
|
// options.setKeepAlive(getBooleanPropertyFromJSON(optionsJSON, "keepAlive"));
|
||||||
|
// options.setOobInline(getBooleanPropertyFromJSON(optionsJSON, "oobInline"));
|
||||||
|
// options.setReceiveBufferSize(getIntegerPropertyFromJSON(optionsJSON, "receiveBufferSize"));
|
||||||
|
// options.setSendBufferSize(getIntegerPropertyFromJSON(optionsJSON, "sendBufferSize"));
|
||||||
|
// options.setSoLinger(getIntegerPropertyFromJSON(optionsJSON, "soLinger"));
|
||||||
|
// options.setSoTimeout(getIntegerPropertyFromJSON(optionsJSON, "soTimeout"));
|
||||||
|
// options.setTrafficClass(getIntegerPropertyFromJSON(optionsJSON, "trafficClass"));
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// socket.close();
|
||||||
|
// callbackContext.success();
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// callbackContext.error(e.toString());
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
private void CloseEventHandler(string socketKey, bool hasError)
|
||||||
|
{
|
||||||
|
socketStorage.Remove(socketKey);
|
||||||
|
this.DispatchEvent(new CloseSocketEvent
|
||||||
|
{
|
||||||
|
HasError = hasError,
|
||||||
|
SocketKey = socketKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DataConsumer(string socketKey, byte[] data)
|
||||||
|
{
|
||||||
|
this.DispatchEvent(new DataReceivedSocketEvent
|
||||||
|
{
|
||||||
|
Data = data,
|
||||||
|
SocketKey = socketKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ErrorHandler(string socketKey, Exception exception)
|
||||||
|
{
|
||||||
|
this.DispatchEvent(new ErrorSocketEvent
|
||||||
|
{
|
||||||
|
ErrorMessage = exception.Message,
|
||||||
|
SocketKey = socketKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DispatchEvent(SocketEvent eventObject)
|
||||||
|
{
|
||||||
|
PluginResult result = new PluginResult(PluginResult.Status.OK, JsonHelper.Serialize(eventObject));
|
||||||
|
result.KeepCallback = true;
|
||||||
|
DispatchCommandResult(result, this.eventDispatcherCallbackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
src/wp8/src/SocketStorage.cs
Normal file
60
src/wp8/src/SocketStorage.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Blocshop.ScoketsForCordova
|
||||||
|
{
|
||||||
|
public interface ISocketStorage
|
||||||
|
{
|
||||||
|
void Add(string socketKey, ISocketAdapter socketAdapter);
|
||||||
|
ISocketAdapter Get(string socketKey);
|
||||||
|
void Remove(string socketKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocketStorage : ISocketStorage
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, ISocketAdapter> socketAdapters = new Dictionary<string, ISocketAdapter>();
|
||||||
|
|
||||||
|
private object syncRoot = new object();
|
||||||
|
|
||||||
|
public void Add(string socketKey, ISocketAdapter socketAdapter)
|
||||||
|
{
|
||||||
|
lock (syncRoot)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Add: " + DateTime.Now.Ticks);
|
||||||
|
this.socketAdapters.Add(socketKey, socketAdapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISocketAdapter Get(string socketKey)
|
||||||
|
{
|
||||||
|
lock (syncRoot)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Get: " + DateTime.Now.Ticks);
|
||||||
|
if (!this.socketAdapters.ContainsKey(socketKey))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format("Cannot find socketKey: {0}. Connection is probably closed.", socketKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.socketAdapters[socketKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(string socketKey)
|
||||||
|
{
|
||||||
|
lock (syncRoot)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("Remove: " + DateTime.Now.Ticks);
|
||||||
|
this.socketAdapters.Remove(socketKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ISocketStorage CreateSocketStorage()
|
||||||
|
{
|
||||||
|
return new SocketStorage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user