Commit a928818b authored by Colomban Wendling's avatar Colomban Wendling
Browse files

Start using asynchronous methods in LibOVCCClient

parent 809314ac
......@@ -8,28 +8,28 @@ public class Bot : OVCCClient.Client
private MainLoop loop = null;
private OVCC.SigQueue sigqueue = new OVCC.SigQueue ();
public bool join (OVCCClient.Server server)
public async bool join (OVCCClient.Server server)
throws Error
{
uint player_suffix = 7;
/* connect to the server */
bind_to (server);
yield bind_to (server);
/* login to the server, choosing an available nickname */
debug ("Trying to login...");
while (true) {
try {
login ("""Clever bot %03u""".printf (player_suffix));
yield login ("""Clever bot %03u""".printf (player_suffix));
break;
} catch (OVCCClient.ServerError.NICKNAME_IN_USE e) {
} catch (OVCCClient.ServerError.NICKNAME_IN_USE e1) {
player_suffix++;
} catch (OVCCClient.ServerError.MISSING_AUTHENTICATION e) {
} catch (OVCCClient.ServerError.MISSING_AUTHENTICATION e2) {
leave ();
throw e; /* avoid infinite loop */
} catch (Error e) {
throw e2; /* avoid infinite loop */
} catch (Error e3) {
leave ();
throw e;
throw e3;
}
}
debug ("Logged in with player_suffix = %u", player_suffix);
......@@ -38,9 +38,9 @@ public class Bot : OVCCClient.Client
debug ("Trying to join a table...");
try {
join_table (-1);
} catch (Error e) {
} catch (Error e4) {
leave ();
throw e;
throw e4;
}
debug ("Joined");
......@@ -177,7 +177,7 @@ public int main (string[] args)
#endif
try {
bot.join (server);
bot.join.begin (server);
/* wait to let others join */
Timeout.add_seconds (5, () => {
if (bot.game.state != OVCC.GameState.STARTED) {
......
......@@ -45,17 +45,16 @@ namespace OVCCClient
Object ();
}
public bool bind_to (Server s)
public async bool bind_to (Server s)
throws Error
{
if (server != null)
{
if (server != null) {
throw new ClientError.ALREADY_BOUND ("This client is already bound to a server");
}
server = s;
debug ("Trying to connect to server...");
server.connect_to (); /* may throw a rejection */
yield server.connect_to (); /* may throw a rejection */
debug ("Connected");
return true;
......@@ -75,17 +74,16 @@ namespace OVCCClient
return false;
}
public bool login (string nick)
public async bool login (string nick)
throws ServerError
{
server.login_to (nick, "patate");
yield server.login_to (nick, "patate");
player = new Player (nick);
return true;
}
public Game join_table (int index)
throws ServerError
{
......
......@@ -53,9 +53,11 @@ namespace OVCCClient
private SocketConnection connection = null;
private DataInputStream input;
private DataOutputStream output;
private SignalHandle signal_handle = null;
private Cancellable? listen_loop_cancel = null;
[Signal (detailed = true)]
public signal void message_received (Message msg);
public Server (string host,
uint16 port)
{
......@@ -66,54 +68,106 @@ namespace OVCCClient
/* instance unused, just to call the class_init() */
// Message msg = new DisconnectMessage();
}
~Server ()
{
}
public /*async*/ bool connect_to ()
throws ServerError
private void listen_loop ()
{
Message msg;
var running = true;
while (running && ! listen_loop_cancel.is_cancelled ()) {
Message? msg;
try {
msg = Message.receive (input, listen_loop_cancel);
} catch (IOError.CANCELLED e) {
break;
} catch (Error e) {
warning ("error receiving data: %s", e.message);
break;
}
if (msg == null) {
debug ("Invalid message received");
continue;
}
debug ("Message type %s received", msg.get_type ().name ());
/* make sure we emit the signal from the main loop */
Idle.add (() => {
message_received[msg.message_type.to_string ()] (msg);
return false;
});
if (msg.message_type == MessageType.DISCONNECT) {
running = false; break;
}
}
}
public async Message receive_type (MessageType mtype)
{
Message msg = null;
ulong id = 0;
id = this.message_received[mtype.to_string ()].connect ((m) => {
msg = m;
this.disconnect (id);
receive_type.callback ();
});
yield;
return msg;
}
public async bool connect_to ()
throws ServerError
requires (connection == null)
{
try {
SocketConnectable addr = NetworkAddress.parse (host, port);
connection = socket.connect (addr);
input = new DataInputStream (connection.input_stream);
output = new DataOutputStream (connection.output_stream);
listen_loop_cancel = new Cancellable ();
Thread.create<void> (listen_loop, false);
} catch (Error e) {
warning ("Trying to connect: %s", e.message);
throw new ServerError.FAILED ("Cannot connect to server");
}
try {
msg = Message.receive (input);
} catch (Error e) {
warning ("Failed getting welcome messsage: %s", e.message);
throw new ServerError.COMMUNICATION_FAILED ("Didn't receive welcome");
}
if (msg.message_type != MessageType.WELCOME) {
throw new ServerError.COMMUNICATION_FAILED ("Received invalid message type");
}
Message msg = yield receive_type (MessageType.WELCOME);
debug ("Got welcome from server: %s", (msg as WelcomeMessage).message);
return true;
}
public /*async*/ bool login_to (string login, string password)
public void disconnect_from ()
throws ServerError
requires (connection != null)
{
Message msg;
send_message (new LoginMessage (login, password));
if (listen_loop_cancel != null) {
listen_loop_cancel.cancel ();
listen_loop_cancel = null;
}
try {
msg = Message.receive (input);
send_message (new DisconnectMessage ());
connection.socket.close();
} catch (Error e) {
warning ("Failed getting login answer messsage: %s", e.message);
throw new ServerError.COMMUNICATION_FAILED ("Didn't receive login answer");
}
if (msg.message_type != MessageType.LOGIN) {
throw new ServerError.COMMUNICATION_FAILED ("Received invalid message type");
/* FIXME ? */
warning ("disconnection failed: %s", e.message);
}
connection = null;
input = null;
output = null;
}
public async bool login_to (string login, string password)
throws ServerError
requires (connection != null)
{
send_message (new LoginMessage (login, password));
Message msg = yield receive_type (MessageType.LOGIN);
if ((msg as LoginMessage).status == LoginMessage.State.ALREADY_EXISTS) {
throw new ServerError.NICKNAME_IN_USE ("");
}
......@@ -127,26 +181,6 @@ namespace OVCCClient
return true;
}
public void disconnect_from ()
throws ServerError
requires (connection != null)
{
if (listen_loop_cancel != null) {
listen_loop_cancel.cancel ();
}
try {
send_message (new DisconnectMessage ());
connection.socket.close();
} catch (Error e) {
/* FIXME ? */
warning ("disconnection failed: %s", e.message);
}
signal_handle = null;
connection = null;
input = null;
output = null;
}
public bool is_connected ()
{
return connection != null;
......@@ -184,57 +218,21 @@ namespace OVCCClient
Game game = new Game (tileset, null);
/* start communication NOW: we have the game and the player and must
* send the PLAYER_ADDED triggered by next instruction... */
start_communication (game, player);
/* start listening to game signals */
var signal_handle = new SignalHandle (game, player, input, output);
var sh_sigq = new SigQueue ();
sh_sigq.add (this, message_received[MessageType.SIGNAL.to_string ()].connect ((m) => {
signal_handle.emit_received (m as SignalMessage);
}));
sh_sigq.add (this, message_received[MessageType.DISCONNECT.to_string ()].connect ((m) => {
sh_sigq.remove_all ();
signal_handle = null;
}));
game.add_player (player);
return game;
}
private void listen_loop ()
{
var running = true;
while (running && ! listen_loop_cancel.is_cancelled ()) {
Message? msg;
try {
msg = Message.receive (input, listen_loop_cancel);
} catch (IOError.CANCELLED e) {
break;
} catch (Error e) {
warning ("error receiving data: %s", e.message);
break;
}
if (msg == null) {
debug ("Invalid message received");
continue;
}
debug ("Message type %s received", msg.get_type ().name ());
switch (msg.message_type) {
case MessageType.SIGNAL:
Idle.add (() => {
if (! listen_loop_cancel.is_cancelled ()) {
signal_handle.emit_received (msg as SignalMessage);
}
return false;
});
break;
case MessageType.DISCONNECT: running = false; break;
}
}
signal_handle = null;
}
public void start_communication (Game game, Player player)
{
listen_loop_cancel = new Cancellable ();
signal_handle = new SignalHandle (game, player, input, output);
Thread.create<void> (listen_loop, false);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment