HTTP Chat sample (Cocoa)

This sample presents a small chat program allowing to send text messages over local network or Internet. The sample demonstrates how server callback events can be consumed by an application written in Xcode.

Server Requirements

This sample can work together with the HTTP Chat Sample (Delphi) server or with the HTTP Chat Sample (.NET) server.

Getting Started

To test the sample, you will need to start and activate the sample server for your preferred platform somewhere on the network. You can then start two or more client applications (you may also use Windows clients in addition to the Xcode one).
Set the server address in the client form and log in with different user names on different clients, then try to post text messages to the common chat and see how they appear. Then try to post private messages. To post a private message, you need to double-click the user name of the recipient in the users list. All chat events are initiated from the user session on the server. You can also try server-initiated events – there are two events of this kind supported. By clicking the corresponding button on the server form you can either warn all clients about an upcoming server shutdown or kick the user from the chat. From the client point of view there is no difference how events are initiated.

Examine the Code

All code parts that require attention are located in the HTTPChatAppDelegate files pair. The HTTPChatAppDelegate class implements two event protocols which describe the methods that will be called when an event occurs:

@interface HTTPChatAppDelegate : NSObject <NSApplicationDelegate, IHTTPChatEvents, IHTTPChatServerEvents> 

Look how the event receiver is set up:

-(id)init
{
    self = [super init];
    if (self) 
    {
        message = [[ROBinMessage alloc] init];
        message.clientID = [ROGuid guid];
        channel = [[ROHTTPClientChannel alloc] init];
        callbackChannel = [[ROHTTPClientChannel alloc] init];
        eventReceiver = [[ROEventReceiver alloc] initWithChannel:callbackChannel message:message];
        eventReceiver.serviceName = @"HTTPChatService";
        // ...
    }
    return self;
}

Notice that we have two client channels, the first for remote methods calls, the second will be used by the event receiver. Two channels are necessary to avoid possible collisions when the event receiver is polling for events in the background.
Notice how the client is being registered to receive particular events. After this, the event receiver can be activated:

-(IBAction)logIn:(id)sender
{
    // ...
    @try 
    {
        // ...
        [eventReceiver registerEventHandler:self forEvents:EID_HTTPChatEvents];
        [eventReceiver registerEventHandler:self forEvents:EID_HTTPChatServerEvents];
        eventReceiver.active = YES;
        // ...
    }
    @catch (NSException * e) 
    {
        NSBeginAlertSheet(@"Error", @"OK", nil, nil, window, nil, nil, nil, NULL, [e reason]);
    }
}

The reverse this action, unregister and stop:

-(IBAction)logOut:(id)sender
{
    // ...
    eventReceiver.active = NO;
    [eventReceiver unregisterAllEvents:self];
    // ...
}

And finally take a look at the event handling methods:

#pragma mark IHTTPChatEvents

-(void)OnLogin:(TUserInfo *)aUserInfo
{
    // ...
}

-(void)OnLogout:(NSString *)aUserID
{
    // ...
}

-(void)OnSendMessage:(NSString *)aSenderUserId :(NSString *)aMessage :(BOOL)aIsPrivateMessage
{
    // ...
}

#pragma mark IHTTPChatServerEvents

-(void)OnSystemShutdown:(int)aShutdownDelay :(NSString *)aReason
{
    // ...
}

-(void)OnMandatoryClose:(NSString *)aClientID :(NSString *)aReason
{
    // ...
}