Changeset 3703

Show
Ignore:
Timestamp:
07/08/07 02:32:00 (1 year ago)
Author:
timothy
Message:

Add long poll activity checking, so we ar not polling every 2 to 10 seconds. This should be better on EDGE and results in virturally instant updates to the web interface when messages come in.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Plug-Ins/Web Interface/JVWebInterfacePlugin.m

    r3701 r3703  
    2424static NSString *JVWebInterfaceOverrideStyle = @"overrideStyle"; 
    2525 
     26#define ActivityQueueFull 1 
     27#define ActivityQueueEmpty 2 
     28 
    2629static void processCommand( http_req_t *req, http_resp_t *resp, http_server_t *server ) { 
    2730        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
     
    225228 
    226229        [pool release]; 
     230} 
     231 
     232static int socketStatus( int sock, int timeoutSecs, int timeoutMsecs ) {  
     233        int selectResult = 0; 
     234        fd_set checkSet; 
     235        struct timeval timeout; 
     236 
     237        FD_ZERO( &checkSet ); 
     238        FD_SET( sock, &checkSet ); 
     239 
     240        timeout.tv_sec = timeoutSecs; 
     241        timeout.tv_usec = timeoutMsecs; 
     242 
     243        if( ( selectResult = select( sock + 1, &checkSet, 0, 0, &timeout ) ) < 0 ) 
     244                return -1; 
     245        if( ! selectResult ) 
     246                return 0; 
     247        return 1; 
    227248} 
    228249 
     
    481502                NSXMLDocument *doc = [NSXMLDocument documentWithRootElement:[NSXMLElement elementWithName:@"queue"]]; 
    482503                [info setObject:doc forKey:@"activityQueue"]; 
    483          
     504 
     505                NSConditionLock *activityLock = [[NSConditionLock alloc] initWithCondition:ActivityQueueEmpty]; 
     506                [info setObject:activityLock forKey:@"activityLock"]; 
     507                [activityLock release]; 
     508 
    484509                NSMutableDictionary *styles = [NSMutableDictionary dictionary]; 
    485510                [info setObject:styles forKey:@"styles"]; 
     
    654679        } 
    655680 
     681        BOOL wait = ( [arguments objectForKey:@"wait"] ? YES : NO ); 
     682 
     683        NSConditionLock *activityLock = nil; 
     684        NSXMLDocument *activityQueue = nil; 
     685 
    656686        @synchronized( _clients ) { 
    657687                NSDictionary *info = [_clients objectForKey:client]; 
     
    662692                } 
    663693 
    664                 NSXMLDocument *doc = [info objectForKey:@"activityQueue"]; 
    665                 if( ! doc ) return; 
    666  
    667                 if( [[doc rootElement] childCount] ) { 
    668                         NSData *xml = [doc XMLData]; 
     694                activityLock = [info objectForKey:@"activityLock"]; 
     695                activityQueue = [info objectForKey:@"activityQueue"]; 
     696 
     697                if( ! activityLock || ! activityQueue ) { 
     698                        resp -> status_code = 500; 
     699                        resp -> reason_phrase = "Internal Error"; 
     700                } 
     701        } 
     702 
     703        if( wait && ! [activityLock lockWhenCondition:ActivityQueueFull beforeDate:[NSDate dateWithTimeIntervalSinceNow:60.]] ) { 
     704                resp -> status_code = 204; 
     705                resp -> reason_phrase = "No Content"; 
     706                return; 
     707        } 
     708 
     709        BOOL success = NO; 
     710 
     711        @synchronized( activityQueue ) { 
     712                if( [[activityQueue rootElement] childCount] ) { 
     713                        NSData *xml = [activityQueue XMLData]; 
     714 
    669715                        resp -> content_type = "text/xml"; 
    670                         resp -> write( resp, (char *)[xml bytes], [xml length] ); 
    671                         [[doc rootElement] setChildren:nil]; // clear the queue 
    672                 } 
     716                        success = ( (unsigned) resp -> write( resp, (char *)[xml bytes], [xml length] ) == [xml length] ); 
     717 
     718                        if( success && socketStatus( resp -> sock, 0, 1) ) 
     719                                success = NO; 
     720 
     721                        if( success ) [[activityQueue rootElement] setChildren:nil]; // clear the queue 
     722                } else { 
     723                        resp -> status_code = 204; 
     724                        resp -> reason_phrase = "No Content"; 
     725                } 
     726        } 
     727 
     728        if( wait ) { 
     729                [activityLock unlockWithCondition:( success ? ActivityQueueEmpty : ActivityQueueFull )]; 
     730        } else { 
     731                if( success && [activityLock tryLockWhenCondition:ActivityQueueFull] ) 
     732                        [activityLock unlockWithCondition:ActivityQueueEmpty]; 
    673733        } 
    674734} 
     
    684744 
    685745                while( ( info = [enumerator nextObject] ) ) { 
    686                         NSXMLDocument *doc = [info objectForKey:@"activityQueue"]; 
    687                         if( ! doc ) continue; 
    688  
    689                         NSXMLElement *copy = [element copyWithZone:[self zone]]; 
    690                         [[doc rootElement] addChild:copy]; 
    691                         [copy release]; 
     746                        NSXMLDocument *activityQueue = [info objectForKey:@"activityQueue"]; 
     747                        NSConditionLock *activityLock = [info objectForKey:@"activityLock"]; 
     748                        if( ! activityQueue || ! activityLock ) continue; 
     749 
     750                        @synchronized( activityQueue ) { 
     751                                NSXMLElement *copy = [element copyWithZone:[self zone]]; 
     752                                [[activityQueue rootElement] addChild:copy]; 
     753                                [copy release]; 
     754                        } 
     755 
     756                        if( [activityLock tryLockWhenCondition:ActivityQueueEmpty] ) 
     757                                [activityLock unlockWithCondition:ActivityQueueFull]; 
    692758                } 
    693759        } 
     
    755821                        [body release]; 
    756822 
    757                         NSXMLDocument *doc = [info objectForKey:@"activityQueue"]; 
    758                         [[doc rootElement] addChild:element]; 
     823                        NSXMLDocument *activityQueue = [info objectForKey:@"activityQueue"]; 
     824                        NSConditionLock *activityLock = [info objectForKey:@"activityLock"]; 
     825                        if( ! activityQueue || ! activityLock ) continue; 
     826 
     827                        NSLog(@"append %d", [activityLock condition]); 
     828 
     829                        @synchronized( activityQueue ) { 
     830                                [[activityQueue rootElement] addChild:element]; 
     831                        } 
     832 
     833                        if( [activityLock tryLockWhenCondition:ActivityQueueEmpty] ) 
     834                                [activityLock unlockWithCondition:ActivityQueueFull]; 
    759835                } 
    760836 
     
    802878                        [body release]; 
    803879 
    804                         NSXMLDocument *doc = [info objectForKey:@"activityQueue"]; 
    805                         [[doc rootElement] addChild:element]; 
     880                        NSXMLDocument *activityQueue = [info objectForKey:@"activityQueue"]; 
     881                        NSConditionLock *activityLock = [info objectForKey:@"activityLock"]; 
     882                        if( ! activityQueue || ! activityLock ) continue; 
     883 
     884                        @synchronized( activityQueue ) { 
     885                                [[activityQueue rootElement] addChild:element]; 
     886                        } 
     887 
     888                        if( [activityLock tryLockWhenCondition:ActivityQueueEmpty] ) 
     889                                [activityLock unlockWithCondition:ActivityQueueFull]; 
    806890                } 
    807891 
  • trunk/Plug-Ins/Web Interface/Resources/iphone/iphone.js

    r3701 r3703  
    5959                ChatController.checkActivity(); 
    6060 
    61                 if(activityCheckInterval) clearInterval(activityCheckInterval); 
    62                 activityCheckInterval = setInterval(ChatController.checkActivity, currentActivityCheckInterval); 
     61                if( ! UserDefaults.longPollActivityChecking ) { 
     62                        if(activityCheckInterval) clearInterval(activityCheckInterval); 
     63                        activityCheckInterval = setInterval(ChatController.checkActivity, currentActivityCheckInterval); 
     64                } 
    6365        }; 
    6466 
     
    254256        maximumActivityCheckInterval: 10000, 
    255257        activityCheckIntervalIncrement: 200, 
    256         scrollBackMessageLimit: 200 
     258        scrollBackMessageLimit: 200, 
     259        longPollActivityChecking: true 
    257260}; 
    258261 
     
    292295 
    293296                if(request.status < 200 || request.status >= 300) { 
    294                         if(activityCheckInterval) clearInterval(activityCheckInterval); 
    295                         activityCheckInterval = setInterval(ChatController.checkActivity, UserDefaults.minimumActivityCheckInterval); 
     297                        if( UserDefaults.longPollActivityChecking ) { 
     298                                setTimeout(ChatController.checkActivity, 1000); // check in a bit, not right away 
     299                        } else { 
     300                                if(activityCheckInterval) clearInterval(activityCheckInterval); 
     301                                activityCheckInterval = setInterval(ChatController.checkActivity, UserDefaults.minimumActivityCheckInterval); 
     302                        } 
    296303                        return; 
    297304                } 
     305 
     306                if( UserDefaults.longPollActivityChecking ) 
     307                        setTimeout(ChatController.checkActivity, 0); // check again right away 
    298308 
    299309                var updateIntervalDelta = 0; 
     
    336346                } 
    337347 
    338                 if(! updateIntervalDelta) updateIntervalDelta = UserDefaults.activityCheckIntervalIncrement; 
    339  
    340                 var newActivityCheckInterval = Math.min((currentActivityCheckInterval + updateIntervalDelta), UserDefaults.maximumActivityCheckInterval); 
    341                 newActivityCheckInterval = Math.max(newActivityCheckInterval, UserDefaults.minimumActivityCheckInterval); 
    342  
    343                 if(newActivityCheckInterval != currentActivityCheckInterval) { 
    344                         currentActivityCheckInterval = newActivityCheckInterval; 
    345  
    346                         if(activityCheckInterval) clearInterval(activityCheckInterval); 
    347                         activityCheckInterval = setInterval(ChatController.checkActivity, currentActivityCheckInterval); 
     348                if( ! UserDefaults.longPollActivityChecking ) { 
     349                        if(! updateIntervalDelta) updateIntervalDelta = UserDefaults.activityCheckIntervalIncrement; 
     350 
     351                        var newActivityCheckInterval = Math.min((currentActivityCheckInterval + updateIntervalDelta), UserDefaults.maximumActivityCheckInterval); 
     352                        newActivityCheckInterval = Math.max(newActivityCheckInterval, UserDefaults.minimumActivityCheckInterval); 
     353 
     354                        if(newActivityCheckInterval != currentActivityCheckInterval) { 
     355                                currentActivityCheckInterval = newActivityCheckInterval; 
     356 
     357                                if(activityCheckInterval) clearInterval(activityCheckInterval); 
     358                                activityCheckInterval = setInterval(ChatController.checkActivity, currentActivityCheckInterval); 
     359                        } 
    348360                } 
    349361        }; 
    350362 
    351         request.open("get", "/command/checkActivity?order=" + Colloquy.nextOrderIdentifier++ + "&uinque=" + Math.round(Math.random() * 1000000), true); 
     363        request.open("get", "/command/checkActivity?order=" + Colloquy.nextOrderIdentifier++ + "&uinque=" + (Math.round(Math.random() * 1000000) + ( UserDefaults.longPollActivityChecking ? "&wait" : "" ) ), true); 
    352364        request.send(); 
    353365}; 
     
    550562                } 
    551563 
    552                 if(activityCheckInterval) clearInterval(activityCheckInterval); 
    553                 activityCheckInterval = setInterval(ChatController.checkActivity, 250); 
     564                if( ! UserDefaults.longPollActivityChecking ) { 
     565                        if(activityCheckInterval) clearInterval(activityCheckInterval); 
     566                        activityCheckInterval = setInterval(ChatController.checkActivity, 250); 
     567                } 
    554568        }; 
    555569