cyphesis/client/ClientConnection.cpp
Al Riddoch 07a7543461 2002-07-14 Al Riddoch <alriddoch@zepler.org>
* ALL: Cleaned up headers into correct order.

	* common/log.h, common/log.cpp: Write some logging code which
	  handles message of different types using syslog or standard
	  error, depending on whether we are running as a daemon.

	* ALL: Switched to using log() for all output.
2002-07-14 21:04:50 +00:00

357 lines
8 KiB
C++

// This file may be redistributed and modified only under the terms of
// the GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2001 Alistair Riddoch
#include "ClientConnection.h"
#include "common/debug.h"
#include "common/globals.h"
#include <Atlas/Codecs/XML.h>
#include <Atlas/Net/Stream.h>
#include <Atlas/Objects/Encoder.h>
static bool debug_flag = false;
using Atlas::Message::Object;
ClientConnection::ClientConnection() :
client_fd(-1), encoder(NULL), serialNo(512)
{
}
ClientConnection::~ClientConnection()
{
if (encoder != NULL) {
delete encoder;
}
}
void ClientConnection::operation(const RootOperation & op)
{
#if 0
const std::string & from = op.GetFrom();
if (from.empty()) {
std::cerr << "ERROR: Operation with no destination" << std::endl << std::flush;
return;
}
dict_t::iterator I = objects.find(from);
if (I == objects.end()) {
std::cerr << "ERROR: Operation with invalid destination" << std::endl << std::flush;
return;
}
OpVector res = I->second->message(op);
OpVector::iterator J = res.begin();
for(J = res.begin(); J != res.end(); ++J) {
(*J)->SetFrom(I->first);
send(*(*J));
}
#endif
}
void ClientConnection::ObjectArrived(const Error&op)
{
debug(std::cout << "ERROR" << std::endl << std::flush;);
push(op);
error_flag = true;
}
void ClientConnection::ObjectArrived(const Info & op)
{
debug(std::cout << "INFO" << std::endl << std::flush;);
const std::string & from = op.GetFrom();
if (from.empty()) {
reply_flag = true;
error_flag = false;
try {
Object ac = op.GetArgs().front();
reply = ac.AsMap();
// const std::string & acid = reply["id"].AsString();
// objects[acid] = new ClientAccount(acid, *this);
}
catch (...) {
std::cerr << "WARNING: Malformed account from server" << std::endl << std::flush;
}
} else {
operation(op);
}
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Action& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Appearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Combine& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Communicate& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Create& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Delete& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Disappearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Divide& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Feel& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Get& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Imaginary& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Listen& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Login& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Logout& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Look& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Move& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perceive& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perception& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::RootOperation& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Set& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sight& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Smell& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sniff& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sound& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Talk& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Touch& op)
{
push(op);
}
int ClientConnection::read() {
if (ios.is_open()) {
codec->Poll();
return 0;
} else {
return -1;
}
}
bool ClientConnection::connect(const std::string & server)
{
debug(std::cout << "Connecting to " << server << std::endl << std::flush;);
ios.open(server, port_num);
if (!ios.is_open()) {
std::cerr << "ERROR: Could not connect to " << server << "."
<< std::endl << std::flush;
return false;
}
client_fd = ios.getSocket();
Atlas::Net::StreamConnect conn("cyphesis_aiclient", ios, this);
debug(std::cout << "Negotiating... " << std::flush;);
while (conn.GetState() == Atlas::Net::StreamConnect::IN_PROGRESS) {
conn.Poll();
}
debug(std::cout << "done" << std::endl;);
if (conn.GetState() == Atlas::Net::StreamConnect::FAILED) {
std::cerr << "Failed to negotiate" << std::endl;
return false;
}
codec = conn.GetCodec();
encoder = new Atlas::Objects::Encoder(codec);
codec->StreamBegin();
return true;
}
bool ClientConnection::login(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Login l = Atlas::Objects::Operation::Login::Instantiate();
Object::MapType acmap;
acmap["username"] = account;
acmap["password"] = password;
l.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(l);
return true;
}
bool ClientConnection::create(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Create c = Atlas::Objects::Operation::Create::Instantiate();
Object::MapType acmap;
acmap["id"] = account;
acmap["password"] = password;
c.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(c);
return true;
}
bool ClientConnection::wait()
// Waits for response from server. Used when we are expecting a login response
// Return whether or not an error occured
{
error_flag = false;
reply_flag = false;
while (!reply_flag) {
poll(1);
}
return error_flag;
}
void ClientConnection::send(Atlas::Objects::Operation::RootOperation & op)
{
debug(Atlas::Codecs::XML c((std::iostream&)std::cout, (Atlas::Bridge*)this);
Atlas::Objects::Encoder enc(&c);
enc.StreamMessage(&op);
std::cout << std::endl << std::flush;);
op.SetSerialno(++serialNo);
encoder->StreamMessage(&op);
ios << std::flush;
}
void ClientConnection::poll(int timeOut)
{
fd_set infds;
struct timeval tv;
FD_ZERO(&infds);
FD_SET(client_fd, &infds);
tv.tv_sec = timeOut;
tv.tv_usec = 0;
int retval = select(client_fd+1, &infds, NULL, NULL, &tv);
if (retval && (FD_ISSET(client_fd, &infds))) {
if (ios.peek() == -1) {
std::cerr << "Server disconnected" << std::endl << std::flush;
return;
}
codec->Poll();
return;
}
return;
}
RootOperation * ClientConnection::pop()
{
poll();
if (operationQueue.empty()) {
return NULL;
}
RootOperation * op = operationQueue.front();
operationQueue.pop_front();
return op;
}
bool ClientConnection::pending()
{
return !operationQueue.empty();
}
template<class O>
void ClientConnection::push(const O & op)
{
reply_flag = true;
RootOperation * new_op = new O(op);
operationQueue.push_back(new_op);
}