Annotation of Examples/DistributedObjects/RemoteVote/VoteTally.m, revision 1.1

1.1     ! root        1: 
        !             2: /* 
        !             3:  *     VoteTally.m     Written by Joe Freeman 5/27/92
        !             4:  *
        !             5:  * Note: 
        !             6:  *     You can talk back to a remote object, if it gives you
        !             7:  *     its id.  But, you cannot, while responding to a message that came 
        !             8:  *     remote, send a message to a remote server in the same process.  That  
        !             9:  *     be blocked out by the conversation that you are responding to.
        !            10:  *
        !            11:  *     You can talk to the NXConnection object in the client, that
        !            12:  *     was created when connecting to the server, if the client has
        !            13:  *     done a runFromAppkit using that connection object
        !            14:  *
        !            15:  * Also,
        !            16:  *     clientList = nil if we are not the server
        !            17:  *
        !            18:  */
        !            19: #import "VoteTally.h"
        !            20: 
        !            21: @implementation VoteTally
        !            22: 
        !            23: #define numAttendees   ([clientList count] )
        !            24: - appDidInit:sender
        !            25: {
        !            26: 
        !            27:     /* You should really give it the name of the machine you want it to
        !            28:      * connect to. The "*" will cause the server to look at every machine
        !            29:      * on the subnet.  That could take a LONG time.
        !            30:      */
        !            31:     remoteHub = [NXConnection connectToName:"VoteTally" onHost:"*"];
        !            32:     if (remoteHub){
        !            33:        [clearAllMenu setEnabled:NO];
        !            34:        
        !            35:        /* if someone is already the hub, then we will be the client
        !            36:         * we find the NXConnection object that is handling the Proxy
        !            37:         * that represents the vote server.  We then register this object
        !            38:         * to handle errors for that server 
        !            39:         *
        !            40:         * the client understands more than this protocol 
        !            41:         * but these are used most so lets tell it about the them.
        !            42:         */
        !            43:        [[scrollers window] setTitle: "Voting Client"];
        !            44:         ourServer = [remoteHub connectionForProxy];
        !            45:        [remoteHub setProtocolForProxy:@protocol(VoteTallyServerMethods)];
        !            46: 
        !            47:     } else {
        !            48:        /* The fact that no one is registered, means that we are going to
        !            49:         * be the server.  So, we register our connection 
        !            50:         * 
        !            51:         * The server understands the client protocol also 
        !            52:         * but these are the most common messages
        !            53:         */
        !            54:        clientList = [[List alloc] init];
        !            55:        [[scrollers window] setTitle: "Voting Server"];
        !            56:        ourServer = [NXConnection registerRoot: self withName:"VoteTally"];
        !            57:        
        !            58:        /* add ourselves as a psuedo client */
        !            59:        remoteHub = self;
        !            60:     }
        !            61: 
        !            62:     /* 
        !            63:      * we take ourServer, which represets the NXConnection objec that
        !            64:      *  will handle all our proxys (?) and make ourselves the handler for
        !            65:      *  errors for that object.  Then we run from appkit.
        !            66:      *
        !            67:      * The case for the voting server makes sense.  We need to run from
        !            68:      * appkit so that we can server all the clients.  
        !            69:      *
        !            70:      * The case for the clients is not as clear.   We register the 
        !            71:      * NXConnection that is behind our connection to the vote server
        !            72:      * so that the server, which will have our ID will be able to talk
        !            73:      * back without the client having initiated the connection.  This is
        !            74:      * NOT OBVIOUS from the PR1 docs
        !            75:      */
        !            76:     [ourServer registerForInvalidationNotification:self];
        !            77:     [ourServer runFromAppKit];
        !            78:     [remoteHub addClient:self];
        !            79: 
        !            80:     return self;
        !            81: }
        !            82: 
        !            83: - appWillTerminate:sender
        !            84: {
        !            85:     [remoteHub removeClient:self];
        !            86:     return self;
        !            87: }
        !            88: 
        !            89: - free
        !            90: {
        !            91:     [super free];
        !            92:     [ourServer free];
        !            93:     return self;
        !            94: }
        !            95:  
        !            96: /* ============================================================
        !            97:  *     who is part of this conference anyway?
        !            98:  *
        !            99:  *     All three of these messages may cause traffic to ALL the
        !           100:  *     clients which means the NXConnection objects on those 
        !           101:  *     need to be free.  So, we declare these oneway to release
        !           102:  *
        !           103:  * ============================================================ */
        !           104: 
        !           105: - addClient:sender
        !           106: {
        !           107:     id connectionToClient;
        !           108:     
        !           109:     if (sender != self){
        !           110:        /* do some error trapping and optimizaitons */
        !           111:        
        !           112:        /* figure out who is behind this new client and get their errors */
        !           113:        connectionToClient = [sender connectionForProxy];
        !           114:        [connectionToClient registerForInvalidationNotification:self];
        !           115:          
        !           116:        /* make sure this new object is smart about the client messages */
        !           117:        [sender setProtocolForProxy:@protocol(VoteTallyClientMethods)];
        !           118:     }
        !           119:     
        !           120:     /* do some bookeeping */
        !           121:     [clientList addObjectIfAbsent:sender];
        !           122:     [self updateStats];
        !           123:     return self;
        !           124: }
        !           125: 
        !           126: - removeClient:anObject
        !           127: {
        !           128:     [clientList removeObject:anObject];
        !           129:     if ( anObject != self ){
        !           130:        /* the server should rebuild the stats */
        !           131:        [self updateStats];
        !           132:     }
        !           133:     return self;
        !           134: }
        !           135: 
        !           136: /* an updateStats:message means two different things, depending on server
        !           137:  * Server      rebuilds the stats and then tells all clients to get stats
        !           138:  * Client      gets all the stats from the server
        !           139:  */
        !           140: #define NUMSLIDERS 6
        !           141: 
        !           142: -  (void) updateStats
        !           143: {
        !           144:     int last = numAttendees;
        !           145:     int i,s;
        !           146:     float sliders[NUMSLIDERS];
        !           147:     float tmp;
        !           148:     int   iTmp;
        !           149: 
        !           150: ///    fprintf(stderr,"%d updateStats with remote hub = %d\n", self, remoteHub);
        !           151: 
        !           152:     [remoteHub getNumAttend:&i];
        !           153:     [numVoting setIntValue: i];
        !           154:     
        !           155:     if (remoteHub != self){
        !           156:        for ( s = 0 ; s < NUMSLIDERS; s++){
        !           157:                [remoteHub getMean:&tmp at:s];
        !           158:                [[means findCellWithTag:s] setFloatValue:tmp];
        !           159:        }
        !           160:        
        !           161:     } else {
        !           162:        /* build new stats */
        !           163:        for ( s = 0 ; s < NUMSLIDERS; s++){
        !           164:                sliders[s] = 0.0;
        !           165:                for ( i = 0 ; i < last; i++){
        !           166:                        [[clientList objectAt:i] getValue:&iTmp at:s];
        !           167:                        sliders[s]+= iTmp;
        !           168:                }
        !           169:                sliders[s] = sliders[s]/numAttendees;
        !           170:                [[means findCellWithTag:s] setFloatValue:sliders[s]];
        !           171:        }
        !           172: 
        !           173: ///    fprintf(stderr,"%d stats rebuilt \n", self);
        !           174:        /* tell all the clients to update their displays from us */
        !           175:        for ( i = 0 ; i < last ; i++){
        !           176:                if ([clientList objectAt:i] != self)
        !           177:                        [[clientList objectAt:i] updateStats];
        !           178:        }
        !           179:     }
        !           180: }
        !           181:  
        !           182: 
        !           183: /* ============================================================
        !           184:  *
        !           185:  * ============================================================ */
        !           186: 
        !           187: /* 
        !           188:  * only the hub is allowed to restore everyone's score
        !           189:  */
        !           190: - resetAll:sender
        !           191: {
        !           192:     [clientList makeObjectsPerform:@selector(resetLocal:) with:self];
        !           193:     [self updateStats];
        !           194:     return self;
        !           195: }
        !           196: 
        !           197: /* reset is the same as moving all sliders.  So, we should notify hub 
        !           198:  * if the hub sent us this message, then it already knows 
        !           199:  */
        !           200: - resetLocal:sender
        !           201: {
        !           202:     int i,numRows,numCols;
        !           203:     [scrollers getNumRows:&numRows numCols:&numCols];
        !           204:     for ( i = 0 ; i < numCols; i++){
        !           205:        [[scrollers findCellWithTag:i] setIntValue:50]; 
        !           206:     }
        !           207:     if (sender != remoteHub)
        !           208:        [remoteHub updateStats];
        !           209:     return self;
        !           210: }
        !           211: 
        !           212: /* a slider has moved... have the hub query everyone for new stats */
        !           213: - takeVoteFrom:sender
        !           214: {
        !           215:    [remoteHub updateStats];
        !           216:    return self;
        !           217: }
        !           218: 
        !           219: /* ============================================================
        !           220:  *
        !           221:  * ============================================================ */
        !           222: 
        !           223: - getNumAttend:(int *)anInt
        !           224: {
        !           225:     *anInt = numAttendees;
        !           226:     return self;
        !           227: }
        !           228: 
        !           229: - getValue:(int *)aVal at:(int)index
        !           230: {
        !           231:     *aVal = [[scrollers findCellWithTag:index] intValue];
        !           232:     return self;
        !           233: }
        !           234: 
        !           235: - getMean:(float *)aFloat at:(int)index
        !           236: {
        !           237:     *aFloat = [[means findCellWithTag:index] floatValue];
        !           238:     return self;
        !           239: }
        !           240: 
        !           241: /* ============================================================
        !           242:  *
        !           243:  *     part of the registerForInvalidationNotification stuff
        !           244:  *
        !           245:  *
        !           246:  * ============================================================ */
        !           247: 
        !           248: - senderIsInvalid:sender
        !           249: {
        !           250:     if (self != remoteHub){
        !           251:        /* server is dead, so lets kill ourselves */
        !           252:        remoteHub = nil;
        !           253:        [NXApp terminate:self];
        !           254:     } else {
        !           255:        /* the server ran into a dead client */
        !           256:        [self removeClient:sender];
        !           257:     }
        !           258:     return self;
        !           259: }
        !           260: 
        !           261: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.