home *** CD-ROM | disk | FTP | other *** search
- //
- // $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
-