MegaBits / SIOSocket

Realtime iOS application framework (client) http://socket.io
MIT License
494 stars 80 forks source link

Threading fixes #45

Closed jonathannorris closed 9 years ago

jonathannorris commented 9 years ago

Builds on @zulkis pull request #42 to fix threading issues #16, #36.

We store the thread created by the javascriptContext to use when calling evaluateScript, so that all calls to evaluateScript are on the same thread.

Also all callbacks are run against the main thread to ensure thread safety.

jonathannorris commented 9 years ago

@iliu I think this gets us all the way there.

zulkis commented 9 years ago

@jonathannorris, great job! Thank you.

iliu commented 9 years ago

@jonathannorris looks good from source inspection!

jonathannorris commented 9 years ago

Awesome.

The only question I had for you guys was waitUntilDone on performSelector:onThread:withObject:waitUntilDone:

I set it to NO right now as it probably doesn't make sense to have the calling thread wait because the calls to JS are async anyway.

@pcperini can you take a look at this pull request, it solves the threading issues many people have been seeing.

anuradhavasudeva commented 9 years ago

@jonathannorris my application(iOS8 on iPhone 5s) has become non-responsive after updating to the SIOSocket library with thread fixes. Neither the client is able to send (emit) messages to the server and nor is it able to receive(on) messages from server. Any idea why this could be happening? Do you suggest me to change anything sepcifically in my code?

zulkis commented 9 years ago

@anuradhavasudeva interesting, this thread fix was implemented exactly to solve this problem. Are you sure you don't JSON creation errors?

anuradhavasudeva commented 9 years ago

@zulkis I do not see any crashes or errors...in fact, the execution goes thru emit call...

jonathannorris commented 9 years ago

Odd I haven't seen any errors like this. If the emit's are still be sent to the JS, maybe its a connection issue or an issue in the JS thread?

zulkis commented 9 years ago

@jonathannorris I guess if the issue in JS thread - we will be informed about it in exception callback block. For me it works like a charm right after I found this issue with threading and @jonathannorris wrapped it in a big commit. @anuradhavasudeva are you sure, that your connection to server established?

iliu commented 9 years ago

@anuradhavasudeva, when you say non responsive is it the UI that's non-responsive, like a hang? Since all the callbacks are now dispatched to the main thread to be handled, you could be blocking the main thread in the callbacks, or something else could be blocking the main thread or deadlocking.

anuradhavasudeva commented 9 years ago

@jonathannorris @iliu @zulkis thanks for the response. Server runs on socket 1.3.3 and I was using SIOSocket earlier version and things were going smooth except for the connect/disconnect issue. Now, I updated the SIOSocket and what happens is - Client opens socket using a singleton class...server gets a connection request. Success. Now, Client prepares parameters for emit. Creates array of parameters and does emit BUT this time server doesn't receive emit!! Some code pasted here fyr

My singleton class looks like this :

jonathannorris commented 9 years ago

@anuradhavasudeva I think your issues is you are not initializing SIOSocket properly, take a look at SIOSocket.h you need to use one of the two generator functions.

Here is an example of how I initialize it:

    [SIOSocket socketWithHost:@"https://your.socket.path" response:^(SIOSocket *socket) {
        self.socket = socket;

        __weak typeof(self) weakSelf = self;
        self.socket.onConnect = ^() {
            NSLog(@"Socket Connected!");
            weakSelf.isConnected = YES;
            [weakSelf connectToSocketRoom];
        };

        self.socket.onConnectError = ^(NSDictionary* error) {
            NSLog(@"Socket Connection Error: %@", error);
            weakSelf.isConnected = NO;
            [weakSelf retrySocketConnection];
        };

        self.socket.onDisconnect = ^() {
            NSLog(@"Socket Disconnected");
            weakSelf.isConnected = NO;
            weakSelf.connectingSocketPath = nil;
            [weakSelf retrySocketConnection];
        };

        self.socket.onError = ^(NSDictionary* error) {
            NSLog(@"Socket Error: %@", error);
            [weakSelf retrySocketConnection];
        };

        [self.socket on:@"event" callback:^(id data) {
            NSLog(@"Got Socket event, data: %@", data);
        }];
    }];

(also take a look at github markdown to format your code: https://guides.github.com/features/mastering-markdown/)

anuradhavasudeva commented 9 years ago

@jonathannorris - Oops! sorry for not including the initialisation code. Here is what I'm doing for initialisation: (Please note, the code was working before replacing the library)

[MySocket socketWithHost: @"http://bubble.trafficmanager.net:80"  response: ^(SIOSocket *socket)
{
     self.socket = socket;

     self.socket.onConnect = ^ () {
         NSLog(@"connected");
     };

     self.socket.onDisconnect = ^ () {
         NSLog(@"disconnected");
     };

     self.socket.onError = ^(NSDictionary* error) {
         NSLog(@"%@", error);
     };

     if(!loggedin)
     {
         NSArray * dataPieces = [[NSArray alloc] initWithObjects:
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"NickName"]  ],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"PhoneNumber"] ],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"Gender"] ],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"CLatitude"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"CLongitude"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"country"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"postalCode"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"administrativeArea"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"subAdministrativeArea"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"locality"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"subLocality"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"thoroughfare"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"subThoroughfare"]],
                                 [NSString stringWithFormat: @"regionTBD", [defaults objectForKey:@"region"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"PhoneId"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"UserMood"]],
                                 [NSString stringWithFormat: @"V1", [defaults objectForKey:@"ClientVersion"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"deviceToken"]],
                                 [NSString stringWithFormat: @"iPhone", [defaults objectForKey:@"Device"]],
                                 [NSString stringWithFormat: @"%@", [defaults objectForKey:@"age"]],

                                 nil
                                 ];

         [ MySocket emit:@"join"
                    args: dataPieces];
    }];
I printed the string before emit and it shows : 
objc_socket.emit('join', 'juggling', '96666', 'Male', '48.4052', '2.68482', 'France', '77300', 'Île-de-France', 'Seine-et-Marne', 'Fontainebleau', '(null)', 'Route de l'Ermitage', '(null)', 'regionTBD', 'E1C3FED7-FE4A-413D-AD53-87FBEC2361FD', 'what's happening now?', 'V1', '<5f83df2d d5c6a5c3 b4cc35f6 96c94199 c85392b8 516ec850 d9c989d6 4311e39b>', 'iPhone', '16');

Server connect, disconnect is successful. Is this library tested with 1.3.3 socket IO on the server?

anuradhavasudeva commented 9 years ago

Anyone here knows how to fix the issue I'm facing? I'm unable to make progress on my Project..

zulkis commented 9 years ago

@anuradhavasudeva, how you could emit:args: on a class? I see that you socketWithHost:response: on MySocket, which is class, then you do emit:args: on MySocket again.

Another issue: Try emit after you get onConnect callback. So:

self.socket.onConnect = ^ () {
    NSLog(@"connected");
    self.socket.emit('join', 'juggling', '96666', 'Male', '48.4052', '2.68482', 'France', '77300', 'Île-de-France', 'Seine-et-Marne', 'Fontainebleau', '(null)', 'Route de l'Ermitage', '(null)', 'regionTBD', 'E1C3FED7-FE4A-413D-AD53-87FBEC2361FD', 'what's happening now?', 'V1', '<5f83df2d d5c6a5c3 b4cc35f6 96c94199 c85392b8 516ec850 d9c989d6 4311e39b>', 'iPhone', '16');
};
anuradhavasudeva commented 9 years ago

@zulkis thanks for the comments. I'm using a singleton class and Mysocket is defined as follows: SIOSocket *MySocket = [SingletonSocket SIOsocket]; I get a singleton socket here. I tried to put this code inside onConnect block and also used socket object instead of singleton socket still it doesn't work!

zulkis commented 9 years ago

@anuradhavasudeva did you try to debug emit call? Did it successfully JSON it? What about jsException handler in SIOSocket? Did it show anything?

anuradhavasudeva commented 9 years ago

@zulkis I've written NSLog statements in error and exception handlers...They are not executed. It means emit is OK.

I have enabled log after emit as shown below:

   NSString* script = [NSString stringWithFormat: @"objc_socket.emit(%@);", [arguments componentsJoinedByString: @", "]];
    [self performSelector:@selector(evaluateScript:) onThread:_thread withObject:[script copy] waitUntilDone:NO];
    NSLog(@"emit script is : %@", script);

It prints the following:

emit script is : objc_socket.emit('join', 'zombies ', '999999993', 'Male', '37.3327', '-122.061', 'United States', '95014', 'CA', 'Santa Clara', 'Cupertino', 'Homestead', 'I-280 N', '(null)', 'regionTBD', 'BA440682-A758-4CA6-ABA8-1DA1416C71E1', 'what's happening now?', 'V1', '(null)', 'iPhone', '19');

anuradhavasudeva commented 9 years ago

@zulkis @jonathannorris @iliu - interesting update is: I sent an event to the server that requires no parameters and it worked. Do you see any obvious issue with the param list(mentioned above) i'm sending?

anuradhavasudeva commented 9 years ago

@zulkis @jonathannorris @iliu The issue was with - apostrophe!! If any parameter includes apostrophe in the text then the emit fails! I have solved it. Now I'm not getting call back from the server (on function) any thoughts?

anuradhavasudeva commented 9 years ago

Old code base with earlier SIOSocket library has the following on function

- (void)on:(NSString *)event callback:(void (^)(id))function  -- V1

this used to work and still works with the old SIOSocket library... but the moment i change to the new library on function with the following signature -

- (void)on:(NSString *)event callback:(void (^)(SIOParameterArray *args))function {  -- V2

call back doesn't work and strangely putting back the old function(V1) is not helping ...