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.