This is ServerController.m in view mode; [Download] [Up]
//
// $Id: ServerController.m,v 1.10 1997/10/31 04:52:07 nygard Exp $
//
//
// This file is a part of Empire, a game of exploration and conquest.
// Copyright (C) 1996 Steve Nygard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// You may contact the author by:
// e-mail: nygard@telusplanet.net
//
#import "Empire.h"
RCSID ("$Id: ServerController.m,v 1.10 1997/10/31 04:52:07 nygard Exp $");
#import "ServerController.h"
#import "Client.h"
#import <Foundation/NSProtocolChecker.h>
#import <Foundation/NSDistantObject.h>
//======================================================================
// The ServerController provides a window for interactively establishing
// and disconnecting the named port of the server. It also lists the
// clients that are currently connected, and provides a textview for
// reporting status messages.
//
// A client can be "pinged" by double clicking its row in the table.
//
// This also provides notification to observers when clients are added
// and removed. This is used, for example, by the NewGameController to
// provide popup lists of the available remote hosts.
//======================================================================
#define ServerController_VERSION 1
@implementation ServerController
+ (void) initialize
{
if (self == [ServerController class])
{
[self setVersion:ServerController_VERSION];
}
}
//----------------------------------------------------------------------
- (void) awakeFromNib
{
[serverWindow setTitle:[NSString stringWithFormat:@"Server %c %@", 208, [[NSHost currentHost] name]]];
// There doesn't appear to be a way of setting this in InterfaceBuilder.
[clientTable setDoubleAction:@selector (doubleAction:)];
[clientTable setTarget:self];
}
//----------------------------------------------------------------------
- init
{
NSString *nibFile;
BOOL loaded;
[super init];
nibFile = @"ServerWindow.nib";
loaded = [NSBundle loadNibNamed:nibFile owner:self];
if (loaded == NO)
{
NSLog (@"Could not load %@.", nibFile);
[super dealloc];
return nil;
}
serverConnection = nil;
clientList = [[NSMutableArray array] retain];
observers = [[NSMutableArray array] retain];
return self;
}
//----------------------------------------------------------------------
- (void) dealloc
{
SNRelease (clientList);
// If this were really deallocated, we might want to notify the
// remaining observers that we are going away, so that they don't
// try detaching.
SNRelease (observers);
SNRelease (serverConnection);
[super dealloc];
}
//----------------------------------------------------------------------
- (void) showPanel
{
[serverWindow makeKeyAndOrderFront:self];
}
//----------------------------------------------------------------------
- (void) establishServer:sender
{
NSProtocolChecker *protocolChecker;
BOOL success;
NSAssert (serverConnection == nil, @"Server already running");
if (serverConnection != nil )
{
[self showText:@"The server is already running."];
return;
}
protocolChecker = [NSProtocolChecker protocolCheckerWithTarget:self
protocol:@protocol (EmpireServerConnectionProtocol)];
NSAssert (protocolChecker != nil, @"A protocol checker could not be allocated.");
serverConnection = [[NSConnection alloc] init];
NSAssert (serverConnection != nil, @"Could not allocate server connection.");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector (connectionDidDie:)
name:NSConnectionDidDieNotification
object:serverConnection];
[serverConnection setRootObject:protocolChecker];
success = [serverConnection registerName:SERVER_PORT_NAME];
NSAssert (success == YES, @"Could not name server connection.");
[statusTextfield setStringValue:@"Running..."];
[serverConnection setDelegate:self];
}
//----------------------------------------------------------------------
- (void) stopServer:sender
{
NSAssert (serverConnection != nil, @"Server not running.");
[serverConnection registerName:nil];
[serverConnection invalidate];
SNRelease (serverConnection);
[statusTextfield setStringValue:@"Stopped."];
}
//----------------------------------------------------------------------
- (void) doubleAction:sender
{
int row = [sender selectedRow];
if (row >= 0 && row < [clientList count])
{
NS_DURING
{
[[[clientList objectAtIndex:row] client] ping];
}
NS_HANDLER
{
EHAND;
}
NS_ENDHANDLER;
}
}
//----------------------------------------------------------------------
- (void) showText:(NSString *)format, ...
{
NSMutableString *message;
NSRange selected;
va_list ap;
va_start(ap, format);
message = [[[NSMutableString alloc] initWithFormat:format arguments:ap] autorelease];
[message appendString:@"\n"];
va_end(ap);
[messageText selectAll:nil];
selected = [messageText selectedRange];
selected.location = selected.length;
selected.length = 0;
[messageText setSelectedRange:selected];
[messageText replaceCharactersInRange:selected withString:message];
[messageText scrollRangeToVisible:selected];
}
//----------------------------------------------------------------------
- (void) connectionDidDie:(NSNotification *)notification
{
id object;
Client *client;
NSEnumerator *clientEnumerator;
int l = 0;
object = [notification object];
clientEnumerator = [clientList objectEnumerator];
while (client = [clientEnumerator nextObject])
{
if ([client clientConnection] == object)
{
[clientList removeObjectAtIndex:l];
[self removedClientHostNumber:l];
[clientTable reloadData];
break;
}
l++;
}
[[NSNotificationCenter defaultCenter] removeObserver:self
name:nil
object:object];
}
//----------------------------------------------------------------------
- (BOOL) connection:(NSConnection *)parentConnection shouldMakeNewConnection:(NSConnection *)newConnection
{
return YES;
}
//----------------------------------------------------------------------
- (Client *) clientAtIndex:(int)index
{
return [clientList objectAtIndex:index];
}
//======================================================================
// EmpireServerConnectionProtocol
//======================================================================
- (void) ping
{
[self showText:@"We were pinged."];
}
//----------------------------------------------------------------------
// I can't seem to get it to accept (id <EmpireClientConnectionProtocol>) as the type,
// since it will complain that -connectionForProxy isn't part of the protocol!
//----------------------------------------------------------------------
- (void) client:clientController onHost:(NSString *)hostname
{
Client *client;
[self showText:@"Client hostname is %@", hostname];
[clientController setProtocolForProxy:@protocol (EmpireClientConnectionProtocol)];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector (connectionDidDie:)
name:NSConnectionDidDieNotification
object:[clientController connectionForProxy]];
client = [[[Client alloc] initWithClient:clientController fromHost:hostname] autorelease];
[clientList addObject:client];
[self newClientHost:[client numberedHostname]];
[clientTable reloadData];
}
//----------------------------------------------------------------------
- (void) aboutToDisconnect:sender
{
[[sender connectionForProxy] invalidate];
}
//======================================================================
// NSTableDataSource
//======================================================================
- (int) numberOfRowsInTableView:(NSTableView *)aTableView
{
return [clientList count];
}
//----------------------------------------------------------------------
- tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
NSString *identifier;
id value;
value = nil;
identifier = [aTableColumn identifier];
if ([identifier isEqualToString:@"Client"] == YES)
{
value = [[clientList objectAtIndex:rowIndex] hostname];
}
else if ([identifier isEqualToString:@"Index"] == YES)
{
value = [NSNumber numberWithInt:rowIndex + 1];
}
else if ([identifier isEqualToString:@"Identifier"] == YES)
{
value = [NSNumber numberWithUnsignedLong:(unsigned long)[clientList objectAtIndex:rowIndex]];
}
return value;
}
//======================================================================
// ObserverPattern
//======================================================================
- (void) attach:observer
{
[observers addObject:observer];
if ([observer respondsToSelector:@selector (newClientHost:)] == YES)
{
NSEnumerator *enumerator;
id object;
enumerator = [clientList objectEnumerator];
while (object = [enumerator nextObject])
{
[observer newClientHost:[object numberedHostname]];
}
}
}
//----------------------------------------------------------------------
- (void) detach:observer
{
int l, count;
[observers removeObject:observer];
if ([observer respondsToSelector:@selector (removedClientHostNumber:)] == YES)
{
count = [observers count];
for (l = count - 1; l >= 0; l--)
[observer removedClientHostNumber:l];
}
}
//----------------------------------------------------------------------
- (void) newClientHost:(NSString *)hostname
{
NSEnumerator *enumerator;
id observer;
enumerator = [observers objectEnumerator];
while (observer = [enumerator nextObject])
{
if ([observer respondsToSelector:@selector (newClientHost:)] == YES)
[observer newClientHost:hostname];
}
}
//----------------------------------------------------------------------
- (void) removedClientHostNumber:(int)index
{
NSEnumerator *enumerator;
id observer;
enumerator = [observers objectEnumerator];
while (observer = [enumerator nextObject])
{
if ([observer respondsToSelector:@selector (removedClientHostNumber:)] == YES)
[observer removedClientHostNumber:index];
}
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.