Annotation of Examples/DistributedObjects/RemoteVote/VoteTally.m, revision 1.1.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.