Added ios open and write timeouts, changed js errors format

This commit is contained in:
kitolog 2018-02-28 11:35:33 +03:00
parent 64acef4ce9
commit 462dfdafc8
7 changed files with 295 additions and 216 deletions

View File

@ -156,3 +156,7 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## What's new
1.2.3 - fixed ios socket closing crashes
1.5.0 - added ios open and write timeouts, changed js errors format

View File

@ -1,9 +1,8 @@
{
"name": "SocketsForCordova",
"version": "1.2.0",
"name": "cordova-plugin-socket-tcp",
"version": "1.5.0",
"description": "This Cordova plugin provides JavaScript API, that allows you to communicate with server through TCP protocol. Currently we support these platforms: iOS, Android, WP8.",
"cordova": {
"id": "cz.blocshop.socketsforcordova",
"platforms": [
"ios",
"android",

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="cz.blocshop.socketsforcordova" version="1.2.0">
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="cordova-plugin-socket-tcp" version="1.5.0">
<name>SocketsForCordova</name>
<description>
This Cordova plugin provides JavaScript API, that allows you to communicate with server through TCP protocol.

View File

@ -1,4 +1,5 @@
/**
cordova.define("cordova-plugin-socket-tcp.Socket", function(require, exports, module) {
/**
* Copyright (c) 2015, Blocshop s.r.o.
* All rights reserved.
*
@ -16,26 +17,31 @@
*/
var exec = require('cordova/exec');
var exec = require('cordova/exec');
var SOCKET_EVENT = "SOCKET_EVENT";
var CORDOVA_SERVICE_NAME = "SocketsForCordova";
var SOCKET_EVENT = "SOCKET_EVENT";
var CORDOVA_SERVICE_NAME = "SocketsForCordova";
Socket.State = {};
Socket.State[Socket.State.CLOSED = 0] = "CLOSED";
Socket.State[Socket.State.OPENING = 1] = "OPENING";
Socket.State[Socket.State.OPENED = 2] = "OPENED";
Socket.State[Socket.State.CLOSING = 3] = "CLOSING";
Socket.State = {};
Socket.State[Socket.State.CLOSED = 0] = "CLOSED";
Socket.State[Socket.State.OPENING = 1] = "OPENING";
Socket.State[Socket.State.OPENED = 2] = "OPENED";
Socket.State[Socket.State.CLOSING = 3] = "CLOSING";
function Socket() {
Socket.ErrorType = {};
Socket.ErrorType[Socket.ErrorType.GENERAL = 0] = "general";
Socket.ErrorType[Socket.ErrorType.OPEN_TIMEOUT = 1] = "openTimeout";
Socket.ErrorType[Socket.ErrorType.WRITE_TIMEOUT = 2] = "writeTimeout";
function Socket() {
this._state = Socket.State.CLOSED;
this.onData = null;
this.onClose = null;
this.onError = null;
this.socketKey = guid();
}
}
Socket.prototype.open = function (host, port, success, error) {
Socket.prototype.open = function (host, port, success, error) {
success = success || function() { };
error = error || function() { };
@ -64,7 +70,7 @@ Socket.prototype.open = function (host, port, success, error) {
_that.onData(new Uint8Array(payload.data));
break;
case "Error":
_that.onError(payload.errorMessage);
_that.onError(payload);
break;
default:
console.error("SocketsForCordova: Unknown event type " + payload.type + ", socket key: " + payload.socketKey);
@ -87,9 +93,9 @@ Socket.prototype.open = function (host, port, success, error) {
CORDOVA_SERVICE_NAME,
"open",
[ this.socketKey, host, port ]);
};
};
Socket.prototype.write = function (data, success, error) {
Socket.prototype.write = function (data, success, error) {
success = success || function() { };
error = error || function() { };
@ -108,9 +114,9 @@ Socket.prototype.write = function (data, success, error) {
CORDOVA_SERVICE_NAME,
"write",
[ this.socketKey, dataToWrite ]);
};
};
Socket.prototype.shutdownWrite = function (success, error) {
Socket.prototype.shutdownWrite = function (success, error) {
success = success || function() { };
error = error || function() { };
@ -125,9 +131,9 @@ Socket.prototype.shutdownWrite = function (success, error) {
CORDOVA_SERVICE_NAME,
"shutdownWrite",
[ this.socketKey ]);
};
};
Socket.prototype.close = function (success, error) {
Socket.prototype.close = function (success, error) {
success = success || function() { };
error = error || function() { };
@ -144,17 +150,17 @@ Socket.prototype.close = function (success, error) {
CORDOVA_SERVICE_NAME,
"close",
[ this.socketKey ]);
};
};
Object.defineProperty(Socket.prototype, "state", {
Object.defineProperty(Socket.prototype, "state", {
get: function () {
return this._state;
},
enumerable: true,
configurable: true
});
});
Socket.prototype._ensureState = function(requiredState, errorCallback) {
Socket.prototype._ensureState = function(requiredState, errorCallback) {
var state = this._state;
if (state != requiredState) {
window.setTimeout(function() {
@ -165,25 +171,25 @@ Socket.prototype._ensureState = function(requiredState, errorCallback) {
else {
return true;
}
};
};
Socket.dispatchEvent = function (event) {
Socket.dispatchEvent = function (event) {
var eventReceive = document.createEvent('Events');
eventReceive.initEvent(SOCKET_EVENT, true, true);
eventReceive.payload = event;
document.dispatchEvent(eventReceive);
};
};
Socket._copyToArray = function (array) {
Socket._copyToArray = function (array) {
var outputArray = new Array(array.length);
for (var i = 0; i < array.length; i++) {
outputArray[i] = array[i];
}
return outputArray;
};
};
var guid = (function () {
var guid = (function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
@ -194,10 +200,10 @@ var guid = (function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
})();
})();
// Register event dispatcher for Windows Phone
if (navigator.userAgent.match(/iemobile/i)) {
if (navigator.userAgent.match(/iemobile/i)) {
window.document.addEventListener("deviceready", function () {
exec(
Socket.dispatchEvent,
@ -208,6 +214,8 @@ if (navigator.userAgent.match(/iemobile/i)) {
"registerWPEventDispatcher",
[ ]);
});
}
}
module.exports = Socket;
module.exports = Socket;
});

View File

@ -24,6 +24,9 @@
NSInputStream *inputStream1;
NSOutputStream *outputStream1;
NSTimer *openTimer;
NSTimer *writeTimer;
}
- (void)open:(NSString *)host port:(NSNumber*)port;
@ -36,6 +39,6 @@
@property (copy) void (^openErrorEventHandler)(NSString*);
@property (copy) void (^dataConsumer)(NSArray*);
@property (copy) void (^closeEventHandler)(BOOL);
@property (copy) void (^errorEventHandler)(NSString*);
@property (copy) void (^errorEventHandler)(NSString*, NSString *);
@end

View File

@ -27,10 +27,16 @@ CFWriteStreamRef writeStream;
NSInputStream *inputStream;
NSOutputStream *outputStream;
NSTimer *openTimer;
NSTimer *writeTimer;
BOOL wasOpenned = FALSE;
int const WRITE_BUFFER_SIZE = 10 * 1024;
int openTimeoutSeconds = 5.0;
int writeTimeoutSeconds = 5.0;
@implementation SocketAdapter
- (void)open:(NSString *)host port:(NSNumber*)port {
@ -38,8 +44,7 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
CFReadStreamRef readStream2;
CFWriteStreamRef writeStream2;
NSLog(@"Setting up connection to %@ : %@", host, [port stringValue]);
NSLog(@"[NATIVE] Setting up connection to %@ : %@", host, [port stringValue]);
if (![self isIp:host]) {
host = [self resolveIp:host];
@ -51,7 +56,7 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
CFWriteStreamSetProperty(writeStream2, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(writeStream2) || !CFReadStreamOpen(readStream2)) {
NSLog(@"Error, streams not open");
NSLog(@"[NATIVE] Error, streams not open");
@throw [NSException exceptionWithName:@"SocketException" reason:@"Cannot open streams." userInfo:nil];
}
@ -60,12 +65,28 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
[inputStream1 setDelegate:self];
[inputStream1 open];
NSTimer *timer = [NSTimer timerWithTimeInterval:openTimeoutSeconds target:self selector:@selector(onOpenTimeout:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
openTimer = timer;
outputStream1 = (__bridge NSOutputStream *)writeStream2;
[outputStream1 open];
[self performSelectorOnMainThread:@selector(runReadLoop) withObject:nil waitUntilDone:NO];
}
-(void)onOpenTimeout:(NSTimer *)timer {
NSLog(@"[NATIVE] Open timeout: %d", openTimeoutSeconds);
self.errorEventHandler(@"openTimeout", @"timeout");
openTimer = nil;
}
-(void)onWriteTimeout:(NSTimer *)timer {
NSLog(@"[NATIVE] Write timeout: %d", writeTimeoutSeconds);
self.errorEventHandler(@"writeTimeout", @"timeout");
writeTimer = nil;
}
-(BOOL)isIp:(NSString*) host {
const char *utf8 = [host UTF8String];
@ -82,7 +103,7 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
-(NSString*)resolveIp:(NSString*) host {
NSLog(@"Resolving host: %@", host);
NSLog(@"[NATIVE] Resolving host: %@", host);
const char *buff = [host cStringUsingEncoding:NSUTF8StringEncoding];
struct hostent *host_entry = gethostbyname(buff);
@ -94,7 +115,7 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
char *hostCstring = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
host = [NSString stringWithUTF8String:hostCstring];
NSLog(@"Resolved ip: %@", host);
NSLog(@"[NATIVE] Resolved ip: %@", host);
return host;
}
@ -104,7 +125,7 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
}
- (void)shutdownWrite {
NSLog(@"Shuting down write on socket.");
NSLog(@"[NATIVE] Shuting down write on socket.");
[self closeOutputStream];
@ -143,10 +164,21 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
case NSStreamEventOpenCompleted: {
self.openEventHandler();
wasOpenned = TRUE;
if(openTimer != nil){
NSLog(@"[NATIVE] openTimer invalidate on open event");
[openTimer invalidate];
openTimer = nil;
}
break;
}
case NSStreamEventHasBytesAvailable: {
if(stream == inputStream1) {
if(writeTimer != nil){
NSLog(@"[NATIVE] writeTimer invalidate on has bytes event");
[writeTimer invalidate];
writeTimer = nil;
}
uint8_t buf[65535];
long len = [inputStream1 read:buf maxLength:65535];
@ -172,14 +204,14 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
}
case NSStreamEventErrorOccurred:
{
NSLog(@"Stream event error: %@", [[stream streamError] localizedDescription]);
NSLog(@"[NATIVE] Stream event error: %@", [[stream streamError] localizedDescription]);
if (wasOpenned) {
self.errorEventHandler([[stream streamError] localizedDescription]);
self.errorEventHandler([[stream streamError] localizedDescription], @"general");
self.closeEventHandler(TRUE);
}
else {
self.errorEventHandler([[stream streamError] localizedDescription]);
self.errorEventHandler([[stream streamError] localizedDescription], @"general");
self.openErrorEventHandler([[stream streamError] localizedDescription]);
}
//[self closeStreams];
@ -198,6 +230,11 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
[self writeSubarray:dataArray offset:i * WRITE_BUFFER_SIZE length:WRITE_BUFFER_SIZE];
}
int lastBatchPosition = (numberOfBatches - 1) * WRITE_BUFFER_SIZE;
NSTimer *timer = [NSTimer timerWithTimeInterval:writeTimeoutSeconds target:self selector:@selector(onWriteTimeout:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
writeTimer = timer;
[self writeSubarray:dataArray offset:lastBatchPosition length:(dataArray.count - lastBatchPosition)];
}
@ -224,6 +261,18 @@ int const WRITE_BUFFER_SIZE = 10 * 1024;
- (void)closeStreams {
[self closeOutputStream];
[self closeInputStream];
if(writeTimer != nil){
[writeTimer invalidate];
writeTimer = nil;
NSLog(@"[NATIVE] writeTimer invalidate on close");
}
if(openTimer != nil){
[openTimer invalidate];
openTimer = nil;
NSLog(@"[NATIVE] openTimer invalidate on close");
}
}
@end

View File

@ -47,9 +47,10 @@
socketAdapter = nil;
};
socketAdapter.errorEventHandler = ^ void (NSString *error){
socketAdapter.errorEventHandler = ^ void (NSString *error, NSString *errorType){
NSMutableDictionary *errorDictionaryData = [[NSMutableDictionary alloc] init];
[errorDictionaryData setObject:@"Error" forKey:@"type"];
[errorDictionaryData setObject:errorType forKey:@"errorType"];
[errorDictionaryData setObject:error forKey:@"errorMessage"];
[errorDictionaryData setObject:socketKey forKey:@"socketKey"];
@ -97,7 +98,11 @@
[self.commandDelegate runInBackground:^{
@try {
if (socket != nil) {
[socket write:data];
}else{
NSLog(@"[NATIVE] Write: socket is nil. SocketKey: %@", socketKey);
}
[self.commandDelegate
sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK]
callbackId:command.callbackId];
@ -118,7 +123,12 @@
[self.commandDelegate runInBackground:^{
@try {
if (socket != nil) {
[socket shutdownWrite];
}else{
NSLog(@"[NATIVE] ShutdownWrite: socket is nil. SocketKey: %@", socketKey);
}
[self.commandDelegate
sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK]
callbackId:command.callbackId];
@ -139,7 +149,12 @@
[self.commandDelegate runInBackground:^{
@try {
if (socket != nil) {
[socket close];
}else{
NSLog(@"[NATIVE] Close: socket is nil. SocketKey: %@", socketKey);
}
[self.commandDelegate
sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK]
callbackId:command.callbackId];
@ -158,15 +173,16 @@
- (SocketAdapter*) getSocketAdapter: (NSString*) socketKey {
SocketAdapter* socketAdapter = [self->socketAdapters objectForKey:socketKey];
if (socketAdapter == nil) {
NSString *exceptionReason = [NSString stringWithFormat:@"Cannot find socketKey: %@. Connection is probably closed.", socketKey];
NSLog(@"[NATIVE] Cannot find socketKey: %@. Connection is probably closed.", socketKey);
//NSString *exceptionReason = [NSString stringWithFormat:@"Cannot find socketKey: %@. Connection is probably closed.", socketKey];
@throw [NSException exceptionWithName:@"IllegalArgumentException" reason:exceptionReason userInfo:nil];
//@throw [NSException exceptionWithName:@"IllegalArgumentException" reason:exceptionReason userInfo:nil];
}
return socketAdapter;
}
- (void) removeSocketAdapter: (NSString*) socketKey {
NSLog(@"Removing socket adapter from storage.");
NSLog(@"[NATIVE] Removing socket adapter from storage.");
[self->socketAdapters removeObjectForKey:socketKey];
}