[Commit]
rrserver clients.5c,1.2,1.3 dispatch.5c,1.7,1.8 games.5c,1.6,1.7
protocol,1.15,1.16 readreq.5c,1.3,1.4 rr.5c,1.2,1.3 send.5c,1.2,1.3
server.5c,1.4,1.5
Keith Packard
commit at keithp.com
Fri May 30 14:26:10 PDT 2003
Committed by: keithp
Update of /local/src/CVS/rrserver
In directory home.keithp.com:/tmp/cvs-serv12112
Modified Files:
clients.5c dispatch.5c games.5c protocol readreq.5c rr.5c
send.5c server.5c
Log Message:
Move game_send from Clients to Games.
Rework client termination to place NOTICEs where the datastructures were
modified so that all paths will emit the right messages.
Use general 'error' exception to pass errors to clients.
Add WATCH support, change USERS to PLAYERS, add WATCHERS
Add REVOKE and PART.
Rework game state management to automate things when clients depart or
change bids.
Update protocol to reflect existing errors.
Index: clients.5c
===================================================================
RCS file: /local/src/CVS/rrserver/clients.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- clients.5c 30 May 2003 06:47:05 -0000 1.2
+++ clients.5c 30 May 2003 20:26:07 -0000 1.3
@@ -49,14 +49,6 @@
Clients::iterate (message_client);
}
- public void game_send (&Game g, string fmt, poly args...) {
- void message_client (&Client o) {
- if (o.game == (GameRef.game) (&g))
- client_send (&o, fmt, args...);
- }
- Clients::iterate (message_client);
- }
-
public &Client select (file f) {
exception found (&Client c);
try {
@@ -92,12 +84,18 @@
user = User.none,
game = GameRef.none,
score = 0,
+ bid = Bid.none,
+ playing = false
}));
return &clients[dim(clients)-1];
}
public void dispose (&Client c) {
+ printf ("Client closed %v\n", c.user);
+ if (c.user != User.none)
+ Clients::server_send ("NOTICE QUIT %s\n", c.user.username);
Array::remove (&clients, &c);
+ File::close (c.f);
}
public void print (&Client c) {
Index: dispatch.5c
===================================================================
RCS file: /local/src/CVS/rrserver/dispatch.5c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- dispatch.5c 30 May 2003 08:44:46 -0000 1.7
+++ dispatch.5c 30 May 2003 20:26:07 -0000 1.8
@@ -67,18 +67,18 @@
void assert_user ()
{
if (c.user == User.none)
- raise nonameset ();
+ raise error (Error.NONAMESET);
}
void assert_game ()
{
if (c.game == GameRef.none)
- raise notingame ();
+ raise error (Error.NOTINGAME);
}
void helo (string username) {
if (Clients::find (username) != ClientRef.none)
- raise invalidname ();
+ raise error (Error.INVALIDNAME);
c.user.username = username;
respond ("HELO %s\n", server_id);
Clients::server_send ("NOTICE USER %s\n", username);
@@ -100,14 +100,29 @@
respond ("\n");
}
- void users(string game) {
+ void players(string game) {
assert_user ();
&Game g = Games::find (game);
- respond ("USERS");
- Games::iterate_client (&g, print_client_score);
+ respond ("PLAYERS");
+ Games::iterate_client (&g, print_client_score, true, false);
+ respond ("\n");
+ }
+
+ void watchers(string game) {
+ assert_user ();
+ &Game g = Games::find (game);
+ respond ("WATCHERS");
+ Games::iterate_client (&g, print_client_score, false, true);
respond ("\n");
}
+ void new(string game) {
+ assert_user ();
+ &Game g = Games::new (game);
+ Games::add_client (&g, &c, true);
+ respond ("NEW %s\n", g.name);
+ }
+
void join (string game) {
assert_user ();
&Game g = Games::find (game);
@@ -115,14 +130,13 @@
respond ("JOIN\n");
}
- void new(string game) {
+ void watch (string game) {
assert_user ();
- &Game g =Games::new (game);
+ &Game g = Games::find (game);
Games::add_client (&g, &c, false);
- respond ("NEW %s\n", g.name);
- Clients::server_send ("NOTICE NEW %s\n", g.name);
+ respond ("WATCH\n");
}
-
+
void show () {
assert_user ();
assert_game ();
@@ -138,6 +152,13 @@
respond ("BID\n");
}
+ void revoke () {
+ assert_user ();
+ assert_game ();
+ Games::revoke (&c.game.game, &c);
+ respond ("REVOKE\n");
+ }
+
void move (Color color, Direction direction) {
assert_user ();
assert_game ();
@@ -180,6 +201,13 @@
Clients::server_send ("NOTICE MESSAGE %s %s\n", u, text);
}
+ void part () {
+ assert_user ();
+ assert_game ();
+ Games::remove_client (&c);
+ respond ("PART\n");
+ }
+
void quit () {
respond ("QUIT\n");
raise Readreq::request_closed();
@@ -202,8 +230,17 @@
case GAMES:
games ();
break;
- case USERS u:
- users (u.game);
+ case PLAYERS p:
+ players (p.game);
+ break;
+ case WATCHERS w:
+ watchers (w.game);
+ break;
+ case GAMEINFO g:
+# gameinfo (g.game);
+ break;
+ case USERINFO u:
+# userinfo (u.username);
break;
case NEW n:
new (n.game);
@@ -212,7 +249,7 @@
join (j.game);
break;
case WATCH w:
-# watch (w.game);
+ watch (w.game);
break;
case SHOW:
show ();
@@ -220,6 +257,9 @@
case BID b:
bid (b.number);
break;
+ case REVOKE:
+ revoke ();
+ break;
case MOVE m:
move (m.color, m.direction);
break;
@@ -238,62 +278,32 @@
case MESSAGE m:
message (m.text);
break;
+ case PART:
+ part ();
+ break;
case QUIT:
quit ();
break;
}
- } catch Readreq::invalid_request (string w) {
- respond ("ERROR COMMAND %s\n", w);
- } catch RR::Lex::syntax() {
- respond ("ERROR SYNTAX\n");
- } catch RR::Lex::invalid_color (string color) {
- respond ("ERROR NOTCOLOR %s\n", color);
- } catch RR::Lex::invalid_shape (string shape) {
- respond ("ERROR NOTSHAPE %s\n", shape);
- } catch RR::Lex::invalid_direction (string direction) {
- respond ("ERROR NOTDIRECTION %s\n", direction);
- } catch Games::notactive (&Game g, &Client c) {
- respond ("ERROR NOTACTIVE\n");
- } catch notingame () {
- respond ("ERROR NOTINGAME\n");
- } catch Games::no_such_game (string name) {
- respond ("ERROR NOGAME\n");
- } catch nonameset () {
- respond ("ERROR NONAMESET\n");
- } catch invalidname () {
- respond ("ERROR INVALIDNAME\n");
- } catch Games::notbidding (&Game g) {
- respond ("ERROR NOTBIDDING\n");
- } catch Games::toomanymoves (&Game g, &Client c) {
- respond ("ERROR TOOMANYMOVES\n");
- } catch Games::blocked (&Game g, &Client c) {
- respond ("ERROR BLOCKED\n");
- } catch Games::notlower (&Game g, &Client c, int bid) {
- respond ("ERROR NOTLOWER\n");
+ } catch error (Error e) {
+ respond ("ERROR %E\n", e);
} catch Readreq::request_closed () {
- User user = c.user;
- printf ("Client closed %v\n", c.user);
- Clients::dispose (&c);
- if (c.user != User.none)
- Clients::server_send ("NOTICE PART %s\n", c.user.username);
return;
}
}
}
void client_cleanup (&Client c) {
- if (c.game != GameRef.none)
- Games::remove_client (&c.game.game, &c);
+ Games::remove_client (&c);
Clients::dispose (&c);
}
public void client (file f)
{
- twixt (true; File::close (f))
- twixt (lock (); unlock ())
- twixt ((&Client c = Clients::new (f)), true;
- client_cleanup (&c))
- client_locked (f, &c);
+ twixt (lock (); unlock ())
+ twixt ((&Client c = Clients::new (f)), true;
+ client_cleanup (&c))
+ client_locked (f, &c);
}
}
}
Index: games.5c
===================================================================
RCS file: /local/src/CVS/rrserver/games.5c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- games.5c 30 May 2003 20:10:38 -0000 1.6
+++ games.5c 30 May 2003 20:26:07 -0000 1.7
@@ -40,17 +40,14 @@
Array::remove (&games, &g);
}
+ /* iterate over the available games */
public void iterate (void (&Game g) f) {
Array::iterate (&games, f);
}
public exception no_such_game (string name);
- public exception notactive (&Game g, &Client c);
- public exception notbidding (&Game g);
- public exception notlower (&Game g, &Client c, int bid);
- public exception toomanymoves (&Game g, &Client c);
- public exception blocked (&Game g, &Client c);
+ /* find a game by name */
public &Game find (string name) {
exception found (&Game g);
try {
@@ -77,28 +74,160 @@
return false;
}
- public void remove_client (&Game g, &Client c) {
- if (g.active == (ClientRef.client) (&c))
- g.active = ClientRef.none;
+ /* list clients associated with a game */
+ public void iterate_client (&Game g, void (&Client c) f,
+ bool playing, bool watching) {
+ void pick (&Client c) {
+ if ((playing && c.playing) || (watching && !c.playing))
+ f (&c);
+ }
+ Array::iterate (&g.clients, pick);
+ }
+
+ public void game_send (&Game g, string fmt, poly args...) {
+ void message_client (&Client o) {
+ Clients::client_send (&o, fmt, args...);
+ }
+ iterate_client (&g, message_client, true, true);
+ }
+
+ bool any_bids (&Game g) {
+ bool any = false;
+ void bid_set (&Client c) {
+ if (c.bid != Bid.none)
+ any = true;
+ }
+ iterate_client (&g, bid_set, true, false);
+ return any;
+ }
+
+ ClientRef lowest_bidder (&Game g) {
+ Bid min = Bid.none;
+ ClientRef min_client = ClientRef.none;
+ void lower_bid (&Client c) {
+ union switch (c.bid) {
+ case none:
+ break;
+ case number n:
+ if (min == Bid.none || min.number > n)
+ {
+ min = (Bid.number) n;
+ min_client = (ClientRef.client) (&c);
+ }
+ break;
+ }
+ }
+ iterate_client (&g, lower_bid, true, false);
+ return min_client;
+ }
+
+ void set_active (&Game g) {
+ ClientRef active = lowest_bidder (&g);
+
+ if (active != g.active) {
+ g.active = active;
+ union switch (active) {
+ case none:
+ break;
+ case client c:
+ game_send (&g, "NOTICE ACTIVE %s %d\n",
+ c.user.username, c.bid.number);
+ break;
+ }
+ }
+ }
+
+ void set_state (&Game g, GameState state) {
+ g.state = state;
+ game_send (&g, "NOTICE GAMESTATE %G\n", state);
+ switch (state) {
+ case GameState.Bidding:
+ int timer_serial = ++g.timer_serial;
+
+ bool validate () {
+ if (g.state != GameState.Bidding ||
+ g.timer_serial != timer_serial)
+ return false;
+ return true;
+ }
+
+ void notify (int remain) {
+ game_send (&g, "NOTICE TIMER %d\n", remain);
+ }
+
+ void expire () {
+ set_state (&g, GameState.Showing);
+ }
+
+ Timer::start (60, 10, lock, unlock, validate, notify, expire);
+ break;
+ case GameState.Showing:
+ set_active (&g);
+ break;
+ }
+ }
+
+ /* remove a client from any game */
+ public void remove_client (&Client c) {
+ if (c.game == GameRef.none)
+ return;
+ &Game g = &c.game.game;
Array::remove (&g.clients, &c);
+ game_send (&g, "NOTICE PART %s\n", c.user.username);
+ /* correct the state if necessary */
+ switch (g.state) {
+ case GameState.New:
+ break;
+ case GameState.Bidding:
+ if (!any_bids (&g))
+ set_state (&g, GameState.New);
+ break;
+ case GameState.Showing:
+ set_active (&g);
+ if (g.active == ClientRef.none)
+ set_state (&g, GameState.New);
+ break;
+ case GameState.Solved:
+ break;
+ }
}
+ /* add a client to a game */
public &Client add_client (&Game g, &Client c, bool playing) {
- if (c.game != GameRef.none)
- remove_client (&c.game.game, &c);
+ remove_client (&c);
c.game = (GameRef.game) (&g);
c.playing = playing;
c.score = 0;
c.bid = Bid.none;
Array::append (&g.clients, &c);
- Clients::game_send (&g, "NOTICE %s %s %s\n",
- playing ? "JOIN" : "WATCH",
- g.name, c.user.username);
+ game_send (&g, "NOTICE %s %s\n",
+ playing ? "JOIN" : "WATCH",
+ c.user.username);
return &c;
}
- public void iterate_client (&Game g, void (&Client c) f) {
- Array::iterate (&g.clients, f);
+ /* select the next target */
+ void next_target (&Game g) {
+ /* score */
+ if (g.active != ClientRef.none && Boards::solved (&g.board))
+ g.active.client.score++;
+
+ Target t = g.targets[0];
+ g.targets = (Target[dim(g.targets)-1]) { [i] = g.targets[i+1] };
+ g.history = (ObjectLoc[*]) {};
+ g.time = Time.none;
+ g.state = GameState.New;
+ Boards::set_target (&g.board, t.color, t.shape);
+
+ void reset_client (&Client c) {
+ c.bid = Bid.none;
+ }
+ iterate_client (&g, reset_client, true, false);
+ game_send (&g, "NOTICE TURN %C %S\n", t.color, t.shape);
+ }
+
+ public void next_turn (&Game g) {
+ next_target (&g);
}
Target[*] random_targets () {
@@ -123,25 +252,6 @@
return t;
}
- void next_target (&Game g) {
- Target t = g.targets[0];
- g.targets = (Target[dim(g.targets)-1]) { [i] = g.targets[i+1] };
- g.history = (ObjectLoc[*]) {};
- g.time = Time.none;
- g.state = GameState.New;
- Boards::set_target (&g.board, t.color, t.shape);
-
- void reset_client (&Client c) {
- c.bid = Bid.none;
- }
- iterate_client (&g, reset_client);
- Clients::game_send (&g, "NOTICE TURN %C %S\n", t.color, t.shape);
- }
-
- public void next_turn (&Game g) {
- next_target (&g);
- }
-
public &Game new (string suggestion) {
string name;
for (int n = 0;
@@ -157,6 +267,7 @@
g.active = ClientRef.none;
g.timer_serial = 0;
next_target (&g);
+ Clients::server_send ("NOTICE NEW %s\n", g.name);
return &g;
}
@@ -166,7 +277,7 @@
void assert_active (&Game g, &Client c) {
if (g.active != (ClientRef.client) (&c))
- raise notactive (&g, &c);
+ raise error (Error.NOTACTIVE);
}
void undo_move (&Game g)
@@ -181,7 +292,7 @@
if (dim (g.history) > 0)
{
undo_move (&g);
- Clients::game_send (&g, "NOTICE UNDO\n");
+ game_send (&g, "NOTICE UNDO\n");
}
}
@@ -189,71 +300,7 @@
assert_active (&g, &c);
while (dim (g.history) > 0)
undo (&g, &c);
- Clients::game_send (&g, "NOTICE RESET\n");
- }
-
- ClientRef lowest_bidder (&Game g) {
- Bid min = Bid.none;
- ClientRef min_client = ClientRef.none;
- void lower_bid (&Client c) {
- union switch (c.bid) {
- case none:
- break;
- case number n:
- if (min == Bid.none || min.number > n)
- {
- min = (Bid.number) n;
- min_client = (ClientRef.client) (&c);
- }
- break;
- }
- }
- iterate_client (&g, lower_bid);
- return min_client;
- }
-
- void set_active (&Game g) {
- g.active = lowest_bidder (&g);
-
- union switch (g.active) {
- case none:
- break;
- case client c:
- Clients::game_send (&g, "NOTICE ACTIVE %s %d\n",
- c.user.username, c.bid.number);
- break;
- }
- }
-
- void set_state (&Game g, GameState state) {
- g.state = state;
- Clients::game_send (&g, "NOTICE GAMESTATE %G\n", state);
- switch (state) {
- case GameState.Bidding:
- int timer_serial = ++g.timer_serial;
-
- bool validate () {
- if (g.state != GameState.Bidding ||
- g.timer_serial != timer_serial)
- return false;
- return true;
- }
-
- void notify (int remain) {
- Clients::game_send (&g, "NOTICE TIMER %d\n",
- remain);
- }
-
- void expire () {
- set_state (&g, GameState.Showing);
- }
-
- Timer::start (60, 10, lock, unlock, validate, notify, expire);
- break;
- case GameState.Showing:
- set_active (&g);
- break;
- }
+ game_send (&g, "NOTICE RESET\n");
}
public void bid (&Game g, &Client c, int number) {
@@ -264,15 +311,23 @@
break;
case GameState.Showing:
case GameState.Solved:
- raise notbidding (&g);
+ raise error (Error.NOTBIDDING);
break;
}
/*
if (c.bid != Bid.none && c.bid.number <= number)
- raise notlower (&g, &c, number);
+ raise error (Error.NOTLOWER);
*/
c.bid = (Bid.number) number;
- Clients::game_send (&g, "NOTICE BID %s %d\n", c.user.username, number);
+ game_send (&g, "NOTICE BID %s %d\n", c.user.username, number);
+ }
+
+ public void revoke (&Game g, &Client c) {
+ if (c.bid == Bid.none)
+ raise error (Error.NOBID);
+ c.bid = Bid.none;
+ if (!any_bids(&g))
+ set_state (&g, GameState.New);
}
public int count (&Game g) {
@@ -282,15 +337,14 @@
public void move (&Game g, &Client c, Color color, Direction dir) {
assert_active (&g, &c);
if (count (&g) >= c.bid.number)
- raise toomanymoves (&g, &c);
+ raise error (Error.TOOMANYMOVES);
ObjectLoc src = Boards::find_robot (&g.board, color);
ObjectLoc dst = Boards::move_robot (&g.board, color, dir);
if (src == dst)
- raise blocked (&g, &c);
+ raise error (Error.BLOCKED);
Array::push (&g.history, src);
Boards::position_robot (&g.board, color, dst.x, dst.y);
- Clients::game_send (&g, "NOTICE MOVE %d %C %D\n",
- Games::count (&g), color, dir);
+ game_send (&g, "NOTICE MOVE %d %C %D\n", count (&g), color, dir);
if (Boards::solved (&g.board))
set_state (&g, GameState.Solved);
}
Index: protocol
===================================================================
RCS file: /local/src/CVS/rrserver/protocol,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- protocol 30 May 2003 06:47:05 -0000 1.15
+++ protocol 30 May 2003 20:26:07 -0000 1.16
@@ -63,13 +63,21 @@
GAMES <game1> <game2> ...
-1.4. Listing users in a game
+1.4. Listing players in a game
- USERS <game>
+ PLAYERS <game>
->
- USERS <username1> <score1> <username2> <score2> ...
+ PLAYERS <username1> <score1> <username2> <score2> ...
+
+1.5. Listing watchers of a game
+
+ WATCHERS <game>
+
+ ->
+
+ WATCERS <username1> <username2> ...
1.5. Get game information
@@ -195,7 +203,17 @@
Possible errors: NOTINGAME, NOTBIDDING, NOTNUMBER, NOTLOWER
-1.12. Move
+1.12. Revoke
+
+ REVOKE
+
+ ->
+
+ REVOKE
+
+ Possible errors: NOTINGAME, NOTBIDDING, NOBID
+
+1.13. Move
MOVE <color> <dir>
@@ -208,7 +226,7 @@
Possible errors: NOTINGAME, NOTACTIVE, BLOCKED, TOOMANYMOVES
-1.13. Undo
+1.14. Undo
UNDO
@@ -222,7 +240,7 @@
XXX: Do we add another error code for no further undo?
-1.14. Reset
+1.15. Reset
RESET
@@ -234,7 +252,7 @@
Possible errors: NOTINGAME, NOTACTIVE
-1.14. Next turn
+1.16. Next turn
TURN
@@ -254,7 +272,7 @@
Possible errors: NOTINGAME
-1.15. Pass the bid to the next lowest bidder
+1.17. Pass the bid to the next lowest bidder
PASS
@@ -264,7 +282,7 @@
Possible errors: NOTINGAME
-1.16. Message
+1.18. Message
MESSAGE <text>
@@ -274,7 +292,7 @@
Possible errors: NOTINGAME
-1.17. Part
+1.19. Part
PART
@@ -284,7 +302,7 @@
Departs the current game
-1.17. Quit
+1.20. Quit
QUIT
@@ -329,39 +347,43 @@
NOTICE BID <username> <number>
-2.7. Timer (game)
+2.7. Revoke (game)
+
+ NOTICE REVOKE <username>
+
+2.8. Timer (game)
NOTICE TIME <seconds>
Timer ticks are sent every 10 seconds
-2.8. Select active player (game)
+2.9. Select active player (game)
NOTICE ACTIVE <username> <bid>
Only the active player may move the robots
-2.9. Game state change
+2.10. Game state change
NOTICE GAMESTATE <state>
-2.9. Undo (game)
+2.11. Undo (game)
NOTICE UNDO
-2.11. Reset (game)
+2.12. Reset (game)
NOTICE RESET
-2.12. Next turn (game)
+2.13. Next turn (game)
NOTICE TURN <color> <shape>
-2.13. Message (all)
+2.14. Message (all)
NOTICE MESSAGE <username> <text>
-2.14. Abandon request (game)
+2.15. Abandon request (game)
NOTICE ABANDON <username>
@@ -372,7 +394,15 @@
selected with the robots reset to their position before the
turn started.
-2.15. User departed game (game)
+2.16. Join game (game)
+
+ NOTICE JOIN <username>
+
+2.17. Watch game (game)
+
+ NOTICE WATCH <username>
+
+2.18. User departed game (game)
NOTICE PART <username>
@@ -412,7 +442,15 @@
Possibly returned by: BID
-3.4. Not active
+3.4. No bid
+
+ ERROR NOBID
+
+ A revoke was requested when no bid had been entered
+
+ Possibly returned by: REVOKE
+
+3.5. Not active
ERROR NOTACTIVE
@@ -421,19 +459,71 @@
Possibly returned by: MOVE, RESET, UNDO
-3.5. Not number
+3.6. Not number
ERROR NOTNUMBER
A non-numeric value was supplied where a number was required
-3.6. Blocked
+3.7. Blocked
ERROR BLOCKED
The robot cannot move the requested direction.
Possibly returned by: MOVE
+
+3.8. TOOMANYMOVES
+
+ ERROR TOOMANYMOVES
+
+ An attempt was made to make more moves than the users bid
+
+ Possibly returned by: MOVE
+
+3.8. Command
+
+ ERROR COMMAND
+
+ An invalid command was specified
+
+3.9. Syntax
+
+ ERROR SYNTAX
+
+ A syntax error was detected
+
+3.10. Not color
+
+ ERROR NOTCOLOR
+
+ The color name specified in the command was invalid
+
+3.11. Not shape
+
+ ERROR NOTSHAPE
+
+ The shape name specified in the command was invalid
+
+3.12. Not direction
+
+ ERROR NOTDIRECTION
+
+ The direction name specified in the command was invalid
+
+3.13. No name set
+
+ ERROR NONAMESET
+
+ 'helo' must be sent before any command other than 'quit'.
+
+3.14. Invalid name
+
+ ERROR INVALIDNAME
+
+ All names must be unique.
+
+
Some comments/questions
-----------------------
Index: readreq.5c
===================================================================
RCS file: /local/src/CVS/rrserver/readreq.5c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- readreq.5c 29 May 2003 17:46:29 -0000 1.3
+++ readreq.5c 30 May 2003 20:26:07 -0000 1.4
@@ -78,10 +78,25 @@
case "GAMES":
req = Request.GAMES;
break;
- case "USERS":
+ case "PLAYERS":
packet = (struct { string game; }) {};
game_ (&packet);
- req = (Request.USERS) packet;
+ req = (Request.PLAYERS) packet;
+ break;
+ case "WATCHERS":
+ packet = (struct { string game; }) {};
+ game_ (&packet);
+ req = (Request.WATCHERS) packet;
+ break;
+ case "GAMEINFO":
+ packet = (struct { string game; }) {};
+ game_ (&packet);
+ req = (Request.GAMEINFO) packet;
+ break;
+ case "USERINFO":
+ packet = (struct { string username; }) {};
+ username_ (&packet);
+ req = (Request.USERINFO) packet;
break;
case "NEW":
packet = (struct { string game; }) {};
@@ -106,6 +121,9 @@
number_ (&packet);
req = (Request.BID) packet;
break;
+ case "REVOKE":
+ req = Request.REVOKE;
+ break;
case "MOVE":
packet = (struct { Color color; Direction direction; }) {};
color_ (&packet);
@@ -129,23 +147,36 @@
text_ (&packet);
req = (Request.MESSAGE) packet;
break;
+ case "PART":
+ req = Request.PART;
+ break;
case "QUIT":
req = Request.QUIT;
break;
case "":
raise request_closed ();
default:
- raise invalid_request (w);
+ raise error (Error.COMMAND);
}
if (!eol (f))
- raise syntax ();
+ raise error (Error.SYNTAX);
return req;
}
public Request read (file f) {
- twixt (unlock (); lock ())
- twixt (true; skipline (f))
- return read_unlocked (f);
+ try {
+ twixt (unlock (); lock ())
+ twixt (true; skipline (f))
+ return read_unlocked (f);
+ } catch RR::Lex::syntax() {
+ raise error (Error.SYNTAX);
+ } catch RR::Lex::invalid_color (string color) {
+ raise error (Error.NOTCOLOR);
+ } catch RR::Lex::invalid_shape (string shape) {
+ raise error (Error.NOTSHAPE);
+ } catch RR::Lex::invalid_direction (string direction) {
+ raise error (Error.NOTDIRECTION);
+ }
raise notreached ();
}
}
Index: rr.5c
===================================================================
RCS file: /local/src/CVS/rrserver/rr.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- rr.5c 30 May 2003 06:47:05 -0000 1.2
+++ rr.5c 30 May 2003 20:26:07 -0000 1.3
@@ -74,36 +74,47 @@
public typedef union {
struct {
string username;
- } HELO;
+ } HELO;
void WHO;
void GAMES;
struct {
string game;
- } USERS;
+ } PLAYERS;
struct {
string game;
- } NEW;
+ } WATCHERS;
struct {
string game;
- } JOIN;
+ } GAMEINFO;
+ struct {
+ string username;
+ } USERINFO;
struct {
string game;
- } WATCH;
+ } NEW;
+ struct {
+ string game;
+ } JOIN;
+ struct {
+ string game;
+ } WATCH;
void SHOW;
struct {
int number;
- } BID;
+ } BID;
+ void REVOKE;
struct {
Color color;
Direction direction;
- } MOVE;
+ } MOVE;
void UNDO;
void RESET;
void TURN;
void PASS;
struct {
string text;
- } MESSAGE;
+ } MESSAGE;
+ void PART;
void QUIT;
} Request;
@@ -163,6 +174,9 @@
string username;
} BID;
struct {
+ string username;
+ } REVOKE;
+ struct {
int seconds;
} TIME;
struct {
@@ -183,10 +197,23 @@
} ABANDON;
} Notice;
- public typedef union {
- void NOGAME;
- void TIMEOUT;
- void NOTACTIVE;
+ public typedef enum {
+ NOGAME,
+ NOTINGAME,
+ NOTBIDDING,
+ NOTLOWER,
+ NOBID,
+ NOTACTIVE,
+ NOTNUMBER,
+ BLOCKED,
+ COMMAND,
+ SYNTAX,
+ NOTCOLOR,
+ NOTSHAPE,
+ NOTDIRECTION,
+ TOOMANYMOVES,
+ NONAMESET,
+ INVALIDNAME
} Error;
public typedef union {
Index: send.5c
===================================================================
RCS file: /local/src/CVS/rrserver/send.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- send.5c 30 May 2003 06:47:05 -0000 1.2
+++ send.5c 30 May 2003 20:26:07 -0000 1.3
@@ -98,6 +98,27 @@
}
}
+ void put_error (Error e) {
+ switch (e) {
+ case Error.NOGAME: File::fprintf (f, "NOGAME"); break;
+ case Error.NOTINGAME: File::fprintf (f, "NOTINGAME"); break;
+ case Error.NOTBIDDING: File::fprintf (f, "NOTBIDDING"); break;
+ case Error.NOTLOWER: File::fprintf (f, "NOTLOWER"); break;
+ case Error.NOBID: File::fprintf (f, "NOBID"); break;
+ case Error.NOTACTIVE: File::fprintf (f, "NOTACTIVE"); break;
+ case Error.NOTNUMBER: File::fprintf (f, "NOTNUMBER"); break;
+ case Error.BLOCKED: File::fprintf (f, "BLOCKED"); break;
+ case Error.COMMAND: File::fprintf (f, "COMMAND"); break;
+ case Error.SYNTAX: File::fprintf (f, "SYNTAX"); break;
+ case Error.NOTCOLOR: File::fprintf (f, "NOTCOLOR"); break;
+ case Error.NOTSHAPE: File::fprintf (f, "NOTSHAPE"); break;
+ case Error.NOTDIRECTION:File::fprintf (f, "NOTDIRECTION"); break;
+ case Error.TOOMANYMOVES:File::fprintf (f, "TOOMANYMOVES"); break;
+ case Error.NONAMESET: File::fprintf (f, "NONAMESET"); break;
+ case Error.INVALIDNAME: File::fprintf (f, "INVALIDNAME"); break;
+ }
+ }
+
void put_number (int n) {
File::fprintf (f, "%d", n);
}
@@ -185,6 +206,7 @@
case 'D': put_direction (a); break;
case 'S': put_shape (a); break;
case 'G': put_gamestate (a); break;
+ case 'E': put_error (a); break;
}
}
else
Index: server.5c
===================================================================
RCS file: /local/src/CVS/rrserver/server.5c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- server.5c 30 May 2003 06:47:05 -0000 1.4
+++ server.5c 30 May 2003 20:26:07 -0000 1.5
@@ -37,6 +37,8 @@
public void set_server_id (string id) { server_id = id; }
+ public exception error (Error e);
+
public bool lock () {
Mutex::acquire (server_mutex);
# printf ("lock %v\n", Thread::current());
More information about the Commit
mailing list