2009-11-27 13:16:40 +00:00
|
|
|
// Cyphesis Online RPG Server and AI Engine
|
|
|
|
|
// Copyright (C) 2001 Alistair Riddoch
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "Interactive.h"
|
|
|
|
|
|
|
|
|
|
#include "Flusher.h"
|
|
|
|
|
#include "OperationMonitor.h"
|
2013-11-14 23:59:31 +01:00
|
|
|
#include "EntityExporter.h"
|
|
|
|
|
#include "EntityImporter.h"
|
2009-11-27 13:16:40 +00:00
|
|
|
|
2012-05-31 00:50:52 +01:00
|
|
|
#include "tools/AccountContext.h"
|
2012-06-06 19:01:43 +01:00
|
|
|
#include "tools/ConnectionContext.h"
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
#include "common/Tick.h"
|
|
|
|
|
|
|
|
|
|
#include <Atlas/Objects/Encoder.h>
|
|
|
|
|
#include <Atlas/Net/Stream.h>
|
|
|
|
|
#include <Atlas/Objects/Entity.h>
|
|
|
|
|
|
|
|
|
|
#include "common/Monitor.h"
|
|
|
|
|
#include "common/Connect.h"
|
|
|
|
|
#include "common/compose.hpp"
|
2010-11-24 16:38:45 +00:00
|
|
|
#include "common/utils.h"
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
#include <sigc++/connection.h>
|
|
|
|
|
|
|
|
|
|
#ifndef READLINE_CXX_SANE // defined in config.h
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
#define USE_VARARGS
|
|
|
|
|
#define PREFER_STDARG
|
|
|
|
|
#include <readline/readline.h>
|
|
|
|
|
#include <readline/history.h>
|
|
|
|
|
#ifndef READLINE_CXX_SANE
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
using Atlas::Message::Element;
|
|
|
|
|
using Atlas::Message::MapType;
|
|
|
|
|
using Atlas::Message::ListType;
|
|
|
|
|
|
|
|
|
|
using Atlas::Objects::Root;
|
|
|
|
|
|
|
|
|
|
using Atlas::Objects::Operation::Appearance;
|
|
|
|
|
using Atlas::Objects::Operation::Create;
|
|
|
|
|
using Atlas::Objects::Operation::Delete;
|
|
|
|
|
using Atlas::Objects::Operation::Disappearance;
|
|
|
|
|
using Atlas::Objects::Operation::Get;
|
|
|
|
|
using Atlas::Objects::Operation::Set;
|
|
|
|
|
using Atlas::Objects::Operation::Look;
|
|
|
|
|
using Atlas::Objects::Operation::Login;
|
|
|
|
|
using Atlas::Objects::Operation::Logout;
|
|
|
|
|
using Atlas::Objects::Operation::Talk;
|
|
|
|
|
using Atlas::Objects::Operation::Tick;
|
|
|
|
|
using Atlas::Objects::Entity::RootEntity;
|
|
|
|
|
using Atlas::Objects::Entity::Anonymous;
|
|
|
|
|
|
|
|
|
|
using Atlas::Objects::smart_dynamic_cast;
|
|
|
|
|
|
|
|
|
|
using Atlas::Objects::Operation::Monitor;
|
|
|
|
|
using Atlas::Objects::Operation::Connect;
|
|
|
|
|
|
2014-10-01 21:38:20 +02:00
|
|
|
using std::shared_ptr;
|
2012-05-31 21:22:17 +01:00
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
/// \brief Entry in the global command table for cycmd
|
|
|
|
|
struct command {
|
|
|
|
|
const char * cmd_string;
|
|
|
|
|
const char * cmd_description;
|
2012-05-30 23:21:25 +01:00
|
|
|
int (Interactive::*cmd_method)(struct command *, const std::string &);
|
2012-05-30 23:27:36 +01:00
|
|
|
int cmd_flags;
|
2012-05-30 23:06:58 +01:00
|
|
|
const char * cmd_longhelp;
|
2009-11-27 13:16:40 +00:00
|
|
|
};
|
|
|
|
|
|
2012-05-30 23:27:36 +01:00
|
|
|
static const int CMD_DEFAULT = 0;
|
|
|
|
|
static const int CMD_CONTEXT = 1 << 1;
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
struct command commands[] = {
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "add_agent", "Create an in-game agent",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "cancel", "Cancel the current admin task",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "connect", "Connect server to a peer",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "create", "Use account to create server objects",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "delete", "Delete an entity from the server",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "dump", "Write a copy of the world to an Atlas file",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "get", "Examine any object on the server",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "find_by_name", "Find an entity with the given name",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "find_by_type", "Find an entity with the given type",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "flush", "Flush entities from the server",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "help", "Display this help",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "install", "Install a new type",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "login", "Log into a peer server",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "restore", "Read world data from file and add it to the world",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "look", "Return the current server lobby",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "logout", "Log user out of server",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "monitor", "Enable in-game op monitoring",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "query", "Synonym for \"get\" (deprecated)",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "reload", "Reload the script for a type",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "stat", "Return current server status",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2012-05-30 23:06:58 +01:00
|
|
|
{ "unmonitor", "Disable in-game op monitoring",
|
2012-05-30 23:27:36 +01:00
|
|
|
&Interactive::commandUnknown, CMD_DEFAULT, 0, },
|
2018-01-30 16:54:49 +01:00
|
|
|
{ nullptr, "Guard", 0, 0, }
|
2009-11-27 13:16:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void help()
|
|
|
|
|
{
|
|
|
|
|
size_t max_length = 0;
|
|
|
|
|
|
2018-01-30 16:54:49 +01:00
|
|
|
for (struct command * I = &commands[0]; I->cmd_string != nullptr; ++I) {
|
2009-11-27 13:16:40 +00:00
|
|
|
max_length = std::max(max_length, strlen(I->cmd_string));
|
|
|
|
|
}
|
|
|
|
|
max_length += 2;
|
|
|
|
|
|
|
|
|
|
std::cout << "Cyphesis commands:" << std::endl << std::endl;
|
|
|
|
|
|
2018-01-30 16:54:49 +01:00
|
|
|
for (struct command * I = &commands[0]; I->cmd_string != nullptr; ++I) {
|
2012-05-30 23:06:58 +01:00
|
|
|
std::cout << " " << I->cmd_string
|
2009-11-27 13:16:40 +00:00
|
|
|
<< std::string(max_length - strlen(I->cmd_string), ' ')
|
|
|
|
|
<< I->cmd_description << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::endl << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-12 23:46:24 -07:00
|
|
|
Interactive::Interactive() : m_server_flag(false),
|
2012-07-27 10:04:57 +01:00
|
|
|
m_serverName("cyphesis"), m_prompt("cyphesis> ")
|
2009-11-27 13:16:40 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Interactive::~Interactive()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-30 09:56:30 +01:00
|
|
|
void Interactive::operation(const Operation & op)
|
|
|
|
|
{
|
|
|
|
|
ContextMap::const_iterator J = m_contexts.begin();
|
|
|
|
|
ContextMap::const_iterator Jend = m_contexts.end();
|
|
|
|
|
for (; J != Jend; ++J) {
|
2012-05-31 21:22:17 +01:00
|
|
|
ObjectContext & c = **J;
|
2012-05-30 09:56:30 +01:00
|
|
|
if (c.accept(op)) {
|
2012-07-28 18:08:37 +01:00
|
|
|
if (c.dispatch(op) == 0) {
|
|
|
|
|
// It is not safe to carry on iterating, as the
|
|
|
|
|
// dispatch may have modified the context map.
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-05-30 09:56:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AdminClient::operation(op);
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
void Interactive::appearanceArrived(const Operation & op)
|
|
|
|
|
{
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId != op->getTo()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
// This is an IG op we are monitoring
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (op->getArgs().empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RootEntity ent = smart_dynamic_cast<RootEntity>(op->getArgs().front());
|
|
|
|
|
if (!ent.isValid()) {
|
|
|
|
|
std::cerr << "Got Appearance of non-entity" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!ent->hasAttrFlag(Atlas::Objects::ID_FLAG)) {
|
|
|
|
|
std::cerr << "Got Appearance of non-string ID" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const std::string & id = ent->getId();
|
|
|
|
|
std::cout << "Appearance(id: " << id << ")";
|
|
|
|
|
if (!ent->hasAttrFlag(Atlas::Objects::Entity::LOC_FLAG)) {
|
|
|
|
|
std::cout << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const std::string & loc = ent->getLoc();
|
|
|
|
|
std::cout << " in " << loc << std::endl;
|
|
|
|
|
if (loc == "lobby") {
|
|
|
|
|
std::cout << id << " has logged in." << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::disappearanceArrived(const Operation & op)
|
|
|
|
|
{
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId != op->getTo()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
// This is an IG op we are monitoring
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (op->getArgs().empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RootEntity ent = smart_dynamic_cast<RootEntity>(op->getArgs().front());
|
|
|
|
|
if (!ent.isValid()) {
|
|
|
|
|
std::cerr << "Got Disappearance of non-entity" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!ent->hasAttrFlag(Atlas::Objects::ID_FLAG)) {
|
|
|
|
|
std::cerr << "Got Disappearance of non-string ID" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const std::string & id = ent->getId();
|
|
|
|
|
std::cout << "Disappearance(id: " << id << ")";
|
|
|
|
|
if (!ent->hasAttrFlag(Atlas::Objects::Entity::LOC_FLAG)) {
|
|
|
|
|
std::cout << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const std::string & loc = ent->getLoc();
|
|
|
|
|
std::cout << " in " << loc << std::endl;
|
|
|
|
|
if (loc == "lobby") {
|
|
|
|
|
std::cout << id << " has logged out." << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::infoArrived(const Operation & op)
|
|
|
|
|
{
|
|
|
|
|
reply_flag = true;
|
|
|
|
|
if (op->getArgs().empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const Root & ent = op->getArgs().front();
|
2012-06-12 23:46:24 -07:00
|
|
|
if (m_server_flag) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Server query success" << std::endl << std::flush;
|
|
|
|
|
if (!ent->isDefaultName()) {
|
2010-08-28 18:10:36 +01:00
|
|
|
m_serverName = ent->getName();
|
|
|
|
|
std::string::size_type p = m_serverName.find(".");
|
2009-11-27 13:16:40 +00:00
|
|
|
if (p != std::string::npos) {
|
2010-08-28 18:10:36 +01:00
|
|
|
m_serverName = m_serverName.substr(0, p);
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
updatePrompt();
|
|
|
|
|
}
|
|
|
|
|
Element raw_attr;
|
|
|
|
|
if (ent->copyAttr("server", raw_attr) == 0) {
|
|
|
|
|
if (raw_attr.isString()) {
|
2010-08-28 18:10:36 +01:00
|
|
|
m_systemType = raw_attr.String();
|
2009-11-27 13:16:40 +00:00
|
|
|
updatePrompt();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-28 18:13:35 +01:00
|
|
|
m_server_flag = false;
|
2012-06-12 23:46:24 -07:00
|
|
|
} else if (m_currentTask == 0 && op->isDefaultRefno()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Info(" << std::endl;
|
2012-06-09 15:51:58 -07:00
|
|
|
output(ent);
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << ")" << std::endl << std::flush;
|
|
|
|
|
// Display results of command
|
|
|
|
|
}
|
2012-06-12 23:46:24 -07:00
|
|
|
AtlasStreamClient::infoArrived(op);
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::errorArrived(const Operation & op)
|
|
|
|
|
{
|
|
|
|
|
reply_flag = true;
|
|
|
|
|
error_flag = true;
|
2009-12-27 00:10:51 +00:00
|
|
|
|
|
|
|
|
if (m_currentTask != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Error(";
|
|
|
|
|
const std::vector<Root> & args = op->getArgs();
|
|
|
|
|
const Root & arg = args.front();
|
|
|
|
|
Element message_attr;
|
|
|
|
|
if (arg->copyAttr("message", message_attr) == 0 && message_attr.isString()) {
|
|
|
|
|
std::cout << message_attr.asString();
|
|
|
|
|
}
|
|
|
|
|
std::cout << ")" << std::endl << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::soundArrived(const Operation & op)
|
|
|
|
|
{
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountId != op->getTo()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
// This is an IG op we are monitoring
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
reply_flag = true;
|
2009-11-30 02:24:31 +00:00
|
|
|
if (op->getArgs().empty()) {
|
|
|
|
|
std::cout << "Sound op has no args" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Operation sub_op = smart_dynamic_cast<Operation>(op->getArgs().front());
|
|
|
|
|
if (!sub_op.isValid()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (sub_op->isDefaultFrom()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Sound arg has no from" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-30 02:24:31 +00:00
|
|
|
const std::string & from = sub_op->getFrom();
|
|
|
|
|
if (sub_op->getArgs().empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Sound arg has no args" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-30 02:24:31 +00:00
|
|
|
const Root & arg = sub_op->getArgs().front();
|
|
|
|
|
Element say;
|
|
|
|
|
if (arg->copyAttr("say", say) != 0 || !say.isString()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Sound arg arg has no say" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-30 02:24:31 +00:00
|
|
|
std::cout << "[" << from << "] " << say.String()
|
2009-11-27 13:16:40 +00:00
|
|
|
<< std::endl << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-30 09:49:15 +01:00
|
|
|
void Interactive::loginSuccess(const Atlas::Objects::Root & arg)
|
|
|
|
|
{
|
2012-06-04 03:13:47 +01:00
|
|
|
// Create a new account context, store it in our context set,
|
|
|
|
|
// and assign it as the current context
|
2012-06-07 07:46:29 -07:00
|
|
|
ObjectContext * ac = new AccountContext(*this, m_accountId, m_username);
|
2012-06-04 03:13:47 +01:00
|
|
|
// This is slightly unwieldy, but it ensures we get a weak pointer to
|
|
|
|
|
// the context object with a minimum of weak copies.
|
2012-06-07 10:44:26 -07:00
|
|
|
addCurrentContext(shared_ptr<ObjectContext>(ac));
|
2012-05-30 09:49:15 +01:00
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
sigc::signal<void, char *> CmdLine;
|
2012-05-23 22:32:05 +01:00
|
|
|
sigc::signal<void, int, int> ContextSwitch;
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
void Interactive::gotCommand(char * cmd)
|
|
|
|
|
{
|
|
|
|
|
CmdLine.emit(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::runCommand(char * cmd)
|
|
|
|
|
{
|
2018-01-30 16:54:49 +01:00
|
|
|
if (cmd == nullptr) {
|
2012-07-27 09:59:56 +01:00
|
|
|
cleanDisconnect();
|
2009-11-27 13:16:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*cmd == 0) {
|
|
|
|
|
free(cmd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_history(cmd);
|
|
|
|
|
|
|
|
|
|
char * arg = strchr(cmd, ' ');
|
2018-01-30 16:54:49 +01:00
|
|
|
if (arg != nullptr) {
|
2009-11-27 13:16:40 +00:00
|
|
|
*arg++ = 0;
|
|
|
|
|
int len = strlen(arg);
|
|
|
|
|
while (len > 0 && arg[--len] == ' ') { arg[len] = 0; }
|
|
|
|
|
} else {
|
|
|
|
|
arg = (char *)"";
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-30 16:54:49 +01:00
|
|
|
for (struct command * I = &commands[0]; I->cmd_string != nullptr; ++I) {
|
2012-05-30 23:21:25 +01:00
|
|
|
if (strcmp(cmd, I->cmd_string) == 0) {
|
|
|
|
|
(this->*(I->cmd_method))(I, arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
exec(cmd, arg);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-23 22:32:05 +01:00
|
|
|
void Interactive::switchContext(int, int)
|
|
|
|
|
{
|
2012-06-06 08:50:20 +01:00
|
|
|
ContextMap::const_iterator I = m_contexts.begin();
|
|
|
|
|
ContextMap::const_iterator Iend = m_contexts.end();
|
|
|
|
|
for (; I != Iend; ++I) {
|
2014-10-01 21:38:20 +02:00
|
|
|
const std::shared_ptr<ObjectContext> & i = *I;
|
2012-06-06 08:50:20 +01:00
|
|
|
if (m_currentContext.lock() == i) {
|
|
|
|
|
if (++I == Iend) {
|
|
|
|
|
I = m_contexts.begin();
|
|
|
|
|
}
|
|
|
|
|
m_currentContext = *I;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-23 22:32:05 +01:00
|
|
|
updatePrompt();
|
2012-06-06 09:30:47 +01:00
|
|
|
rl_redisplay();
|
2012-05-23 22:32:05 +01:00
|
|
|
}
|
|
|
|
|
|
2012-06-07 10:44:26 -07:00
|
|
|
const shared_ptr<ObjectContext> & Interactive::addContext(
|
|
|
|
|
const shared_ptr<ObjectContext> & c)
|
|
|
|
|
{
|
|
|
|
|
return *m_contexts.insert(c).first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::addCurrentContext(const shared_ptr<ObjectContext> & c)
|
|
|
|
|
{
|
|
|
|
|
m_currentContext = *m_contexts.insert(c).first;
|
2012-06-07 11:53:42 -07:00
|
|
|
updatePrompt();
|
|
|
|
|
rl_redisplay();
|
2012-06-07 10:44:26 -07:00
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
int completion_iterator = 0;
|
|
|
|
|
|
|
|
|
|
char * completion_generator(const char * text, int state)
|
|
|
|
|
{
|
|
|
|
|
if (state == 0) {
|
|
|
|
|
completion_iterator = 0;
|
|
|
|
|
}
|
|
|
|
|
for (int i = completion_iterator; commands[i].cmd_string != 0; ++i) {
|
|
|
|
|
if (strncmp(text, commands[i].cmd_string, strlen(text)) == 0) {
|
|
|
|
|
completion_iterator = i + 1;
|
|
|
|
|
return strdup(commands[i].cmd_string);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-23 22:32:05 +01:00
|
|
|
static int context_switch(int a, int b)
|
|
|
|
|
{
|
|
|
|
|
ContextSwitch.emit(a, b);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
void Interactive::loop()
|
|
|
|
|
{
|
2012-05-23 22:32:05 +01:00
|
|
|
if (rl_bind_keyseq("`", &context_switch) != 0) {
|
2014-02-02 01:01:53 +01:00
|
|
|
std::cout << "BINDING FAILED" << std::endl;
|
2012-05-23 22:32:05 +01:00
|
|
|
}
|
2010-08-28 18:10:36 +01:00
|
|
|
rl_callback_handler_install(m_prompt.c_str(),
|
2009-11-27 13:16:40 +00:00
|
|
|
&Interactive::gotCommand);
|
|
|
|
|
rl_completion_entry_function = &completion_generator;
|
|
|
|
|
CmdLine.connect(sigc::mem_fun(this, &Interactive::runCommand));
|
2012-05-23 22:32:05 +01:00
|
|
|
ContextSwitch.connect(sigc::mem_fun(this, &Interactive::switchContext));
|
2012-07-27 10:04:57 +01:00
|
|
|
while (select() == 0);
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << std::endl << std::flush;
|
|
|
|
|
rl_callback_handler_remove();
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-27 10:04:57 +01:00
|
|
|
int Interactive::select(bool rewrite_prompt)
|
2009-11-27 13:16:40 +00:00
|
|
|
{
|
2014-02-02 01:01:53 +01:00
|
|
|
fd_set rfds;
|
2009-11-27 13:16:40 +00:00
|
|
|
struct timeval tv;
|
|
|
|
|
int retval;
|
2014-02-02 01:01:53 +01:00
|
|
|
FD_ZERO(&rfds);
|
|
|
|
|
FD_SET(0, &rfds);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
2014-02-02 01:01:53 +01:00
|
|
|
tv.tv_sec = 0;
|
|
|
|
|
tv.tv_usec = 0;
|
2009-11-27 13:16:40 +00:00
|
|
|
|
2018-01-30 16:54:49 +01:00
|
|
|
retval = ::select(1, &rfds, nullptr, nullptr, &tv);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
2014-02-02 01:01:53 +01:00
|
|
|
if (retval){
|
|
|
|
|
rl_callback_read_char();
|
|
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
|
2014-02-02 01:01:53 +01:00
|
|
|
|
2014-10-01 22:48:22 +02:00
|
|
|
int result = poll(0, 10000);
|
2014-02-02 01:01:53 +01:00
|
|
|
if (result >= 0) {
|
|
|
|
|
return 0;
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
2014-02-02 01:01:53 +01:00
|
|
|
std::cout << "Server disconnected" << std::endl << std::flush;
|
|
|
|
|
return -1;
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::updatePrompt()
|
|
|
|
|
{
|
|
|
|
|
std::string designation(">");
|
2012-05-31 15:25:54 +01:00
|
|
|
if (m_accountType == "admin" || m_accountType == "sys") {
|
2009-12-27 11:21:43 +00:00
|
|
|
designation = "#";
|
2009-11-27 13:16:40 +00:00
|
|
|
} else {
|
2009-12-27 11:21:43 +00:00
|
|
|
designation = "$";
|
|
|
|
|
}
|
|
|
|
|
std::string status = "idle";
|
|
|
|
|
if (m_currentTask != 0) {
|
|
|
|
|
status = m_currentTask->description();
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
2012-06-06 08:50:20 +01:00
|
|
|
std::string context = "";
|
2014-10-01 21:38:20 +02:00
|
|
|
std::shared_ptr<ObjectContext> c = m_currentContext.lock();
|
2012-06-06 08:50:20 +01:00
|
|
|
if (c) {
|
|
|
|
|
context = c->repr();
|
|
|
|
|
}
|
|
|
|
|
m_prompt = String::compose("[%1@%2 %3{%4}]%5 ", context, m_serverName,
|
|
|
|
|
m_systemType, status, designation);
|
2010-08-28 18:10:36 +01:00
|
|
|
rl_set_prompt(m_prompt.c_str());
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Interactive::setup()
|
|
|
|
|
{
|
2012-06-07 07:46:29 -07:00
|
|
|
ObjectContext * cc = new ConnectionContext(*this);
|
2012-06-07 10:44:26 -07:00
|
|
|
addContext(shared_ptr<ObjectContext>(cc));
|
2012-06-06 19:01:43 +01:00
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
Get get;
|
|
|
|
|
|
|
|
|
|
send(get);
|
|
|
|
|
|
2010-08-28 18:13:35 +01:00
|
|
|
m_server_flag = true;
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
reply_flag = true;
|
2010-08-28 18:13:35 +01:00
|
|
|
while (m_server_flag && !error_flag) {
|
2014-02-02 01:01:53 +01:00
|
|
|
poll(10, 0);
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-28 18:13:35 +01:00
|
|
|
m_server_flag = false;
|
2009-11-27 13:16:40 +00:00
|
|
|
if (!error_flag) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Interactive::exec(const std::string & cmd, const std::string & arg)
|
|
|
|
|
{
|
|
|
|
|
bool reply_expected = true;
|
|
|
|
|
reply_flag = false;
|
|
|
|
|
error_flag = false;
|
|
|
|
|
|
2014-10-01 21:38:20 +02:00
|
|
|
std::shared_ptr<ObjectContext> command_context = m_currentContext.lock();
|
2012-06-06 15:48:05 -07:00
|
|
|
if (!command_context) {
|
|
|
|
|
std::cout << "ERROR: Context free" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-27 13:16:40 +00:00
|
|
|
if (cmd == "stat") {
|
|
|
|
|
Get g;
|
|
|
|
|
send(g);
|
|
|
|
|
} else if (cmd == "install") {
|
|
|
|
|
size_t space = arg.find(' ');
|
|
|
|
|
if (space == std::string::npos || space >= (arg.size() - 1)) {
|
|
|
|
|
std::cout << "usage: install <type id> <parent id>"
|
|
|
|
|
<< std::endl << std::flush;
|
|
|
|
|
} else {
|
|
|
|
|
Create c;
|
2012-05-31 15:25:54 +01:00
|
|
|
c->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
Anonymous ent;
|
|
|
|
|
ent->setId(std::string(arg, 0, space));
|
|
|
|
|
ent->setObjtype("class");
|
2017-07-24 13:39:22 +02:00
|
|
|
ent->setParent(std::string(arg, space + 1));
|
2009-11-27 13:16:40 +00:00
|
|
|
c->setArgs1(ent);
|
|
|
|
|
send(c);
|
|
|
|
|
}
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else if (cmd == "look") {
|
|
|
|
|
Look l;
|
|
|
|
|
if (!arg.empty()) {
|
|
|
|
|
Anonymous cmap;
|
|
|
|
|
cmap->setId(arg);
|
|
|
|
|
l->setArgs1(cmap);
|
|
|
|
|
}
|
2012-06-09 18:06:03 -07:00
|
|
|
l->setSerialno(newSerialNo());
|
2012-06-06 16:45:21 -07:00
|
|
|
command_context->setFromContext(l);
|
2009-11-27 13:16:40 +00:00
|
|
|
send(l);
|
2012-06-09 18:03:35 -07:00
|
|
|
reply_expected = false;
|
2009-11-27 13:16:40 +00:00
|
|
|
} else if (cmd == "logout") {
|
|
|
|
|
Logout l;
|
2012-05-31 15:25:54 +01:00
|
|
|
l->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
if (!arg.empty()) {
|
|
|
|
|
Anonymous lmap;
|
|
|
|
|
lmap->setId(arg);
|
|
|
|
|
l->setArgs1(lmap);
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
|
|
|
|
send(l);
|
|
|
|
|
} else if (cmd == "say") {
|
|
|
|
|
Talk t;
|
|
|
|
|
Anonymous ent;
|
|
|
|
|
ent->setAttr("say", arg);
|
|
|
|
|
t->setArgs1(ent);
|
2012-05-31 15:25:54 +01:00
|
|
|
t->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
send(t);
|
|
|
|
|
} else if (cmd == "help" || cmd == "?") {
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
help();
|
|
|
|
|
} else if (cmd == "query") {
|
|
|
|
|
Get g;
|
|
|
|
|
|
|
|
|
|
if (!arg.empty()) {
|
|
|
|
|
Anonymous cmap;
|
|
|
|
|
if (::isdigit(arg[0])) {
|
|
|
|
|
cmap->setObjtype("obj");
|
|
|
|
|
} else {
|
|
|
|
|
cmap->setObjtype("meta");
|
|
|
|
|
}
|
|
|
|
|
cmap->setId(arg);
|
|
|
|
|
g->setArgs1(cmap);
|
|
|
|
|
}
|
2012-05-31 15:25:54 +01:00
|
|
|
g->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(g);
|
|
|
|
|
} else if (cmd == "reload") {
|
|
|
|
|
if (arg.empty()) {
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
std::cout << "reload: Argument required" << std::endl << std::flush;
|
|
|
|
|
} else {
|
|
|
|
|
Set s;
|
|
|
|
|
|
|
|
|
|
Anonymous tmap;
|
|
|
|
|
tmap->setObjtype("class");
|
|
|
|
|
tmap->setId(arg);
|
|
|
|
|
s->setArgs1(tmap);
|
2012-05-31 15:25:54 +01:00
|
|
|
s->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(s);
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "get") {
|
|
|
|
|
Get g;
|
|
|
|
|
|
|
|
|
|
if (!arg.empty()) {
|
|
|
|
|
Anonymous cmap;
|
|
|
|
|
if (::isdigit(arg[0])) {
|
|
|
|
|
cmap->setObjtype("obj");
|
|
|
|
|
} else {
|
|
|
|
|
cmap->setObjtype("meta");
|
|
|
|
|
}
|
|
|
|
|
cmap->setId(arg);
|
|
|
|
|
g->setArgs1(cmap);
|
|
|
|
|
}
|
2012-05-31 15:25:54 +01:00
|
|
|
g->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(g);
|
|
|
|
|
} else if (cmd == "monitor") {
|
2009-11-28 18:10:09 +00:00
|
|
|
ClientTask * task = new OperationMonitor;
|
2009-11-27 13:16:40 +00:00
|
|
|
if (runTask(task, arg) == 0) {
|
|
|
|
|
Monitor m;
|
|
|
|
|
|
|
|
|
|
m->setArgs1(Anonymous());
|
2012-05-31 15:25:54 +01:00
|
|
|
m->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(m);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else if (cmd == "unmonitor") {
|
2009-11-28 18:31:28 +00:00
|
|
|
OperationMonitor * om = dynamic_cast<OperationMonitor *>(m_currentTask);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
if (om != 0) {
|
|
|
|
|
Monitor m;
|
|
|
|
|
|
2012-05-31 15:25:54 +01:00
|
|
|
m->setFrom(m_accountId);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(m);
|
|
|
|
|
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
|
2011-10-31 19:52:12 +00:00
|
|
|
SystemTime now;
|
|
|
|
|
now.update();
|
|
|
|
|
|
2011-10-31 23:33:16 +00:00
|
|
|
time_t monitor_time = now.seconds() - om->startTime();
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
std::cout << om->count() << " operations monitored in "
|
|
|
|
|
<< monitor_time << " seconds = "
|
|
|
|
|
<< om->count() / monitor_time
|
|
|
|
|
<< " operations per second"
|
|
|
|
|
<< std::endl << std::flush;
|
|
|
|
|
|
|
|
|
|
endTask();
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "connect") {
|
2012-06-07 15:46:03 -07:00
|
|
|
std::vector<std::string> args;
|
|
|
|
|
tokenize(arg, args);
|
|
|
|
|
|
|
|
|
|
if (args.size() != 2) {
|
|
|
|
|
std::cout << "usage: connect <hostname> <port>"
|
2010-11-24 16:38:45 +00:00
|
|
|
<< std::endl << std::flush;
|
|
|
|
|
|
2012-06-07 15:46:03 -07:00
|
|
|
reply_expected = false;
|
|
|
|
|
} else {
|
|
|
|
|
Anonymous cmap;
|
|
|
|
|
cmap->setAttr("hostname", args[0]);
|
|
|
|
|
cmap->setAttr("port", strtol(args[1].c_str(), 0, 10));
|
2010-12-06 22:27:07 +00:00
|
|
|
|
2012-06-07 15:46:03 -07:00
|
|
|
Connect m;
|
|
|
|
|
m->setArgs1(cmap);
|
|
|
|
|
// No serialno yet
|
|
|
|
|
// FIXME add serialno once Juncture context can handle this
|
2010-12-06 22:27:07 +00:00
|
|
|
|
2012-06-07 15:46:03 -07:00
|
|
|
command_context->setFromContext(m);
|
2010-12-06 22:27:07 +00:00
|
|
|
|
2012-06-07 15:46:03 -07:00
|
|
|
send(m);
|
2010-11-24 16:38:45 +00:00
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
} else if (cmd == "add_agent") {
|
|
|
|
|
std::string agent_type("creator");
|
|
|
|
|
|
|
|
|
|
if (!arg.empty()) {
|
|
|
|
|
agent_type = arg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Create c;
|
|
|
|
|
|
|
|
|
|
Anonymous cmap;
|
2017-07-24 13:39:22 +02:00
|
|
|
cmap->setParent(agent_type);
|
2009-11-27 13:16:40 +00:00
|
|
|
cmap->setName("cycmd agent");
|
|
|
|
|
cmap->setObjtype("obj");
|
|
|
|
|
c->setArgs1(cmap);
|
2012-06-09 12:30:29 -07:00
|
|
|
c->setSerialno(newSerialNo());
|
|
|
|
|
|
|
|
|
|
command_context->setFromContext(c);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(c);
|
|
|
|
|
} else if (cmd == "delete") {
|
2012-06-09 12:16:22 -07:00
|
|
|
if (arg.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Please specify the entity to delete" << std::endl << std::flush;
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else {
|
|
|
|
|
Delete del;
|
|
|
|
|
|
|
|
|
|
Anonymous del_arg;
|
|
|
|
|
del_arg->setId(arg);
|
|
|
|
|
del->setArgs1(del_arg);
|
2012-06-09 12:16:22 -07:00
|
|
|
|
|
|
|
|
command_context->setFromContext(del);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(del);
|
|
|
|
|
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "find_by_name") {
|
2012-06-09 12:16:22 -07:00
|
|
|
if (arg.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Please specify the name to search for" << std::endl << std::flush;
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else {
|
|
|
|
|
Look l;
|
|
|
|
|
|
|
|
|
|
Anonymous lmap;
|
|
|
|
|
lmap->setName(arg);
|
|
|
|
|
l->setArgs1(lmap);
|
2012-06-09 18:40:00 -07:00
|
|
|
l->setSerialno(newSerialNo());
|
2012-06-09 12:16:22 -07:00
|
|
|
|
|
|
|
|
command_context->setFromContext(l);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(l);
|
|
|
|
|
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "find_by_type") {
|
2012-06-09 12:16:22 -07:00
|
|
|
if (arg.empty()) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Please specify the type to search for" << std::endl << std::flush;
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else {
|
|
|
|
|
Look l;
|
|
|
|
|
|
|
|
|
|
Anonymous lmap;
|
2017-07-24 13:39:22 +02:00
|
|
|
lmap->setParent(arg);
|
2009-11-27 13:16:40 +00:00
|
|
|
l->setArgs1(lmap);
|
2012-06-09 18:40:00 -07:00
|
|
|
l->setSerialno(newSerialNo());
|
2012-06-09 12:16:22 -07:00
|
|
|
|
|
|
|
|
command_context->setFromContext(l);
|
2009-11-27 13:16:40 +00:00
|
|
|
|
|
|
|
|
send(l);
|
|
|
|
|
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "flush") {
|
2012-06-11 14:07:07 -07:00
|
|
|
if (arg.empty()) {
|
|
|
|
|
// FIXME usage
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << "Please specify the type to flush" << std::endl << std::flush;
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
} else {
|
2012-06-11 14:07:07 -07:00
|
|
|
ClientTask * task = new Flusher(command_context);
|
2009-11-27 13:16:40 +00:00
|
|
|
runTask(task, arg);
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmd == "cancel") {
|
|
|
|
|
if (endTask() != 0) {
|
|
|
|
|
std::cout << "No task currently running" << std::endl << std::flush;
|
|
|
|
|
}
|
2009-12-14 03:19:11 +00:00
|
|
|
} else if (cmd == "dump") {
|
2013-11-14 23:59:31 +01:00
|
|
|
if (command_context->repr() != "avatar") {
|
|
|
|
|
std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
|
|
|
|
|
} else {
|
|
|
|
|
//Extract the avatar id by "misusing" the setFromContext method
|
|
|
|
|
Operation op;
|
|
|
|
|
command_context->setFromContext(op);
|
|
|
|
|
ClientTask * task = new EntityExporter(m_accountId, op->getFrom());
|
|
|
|
|
runTask(task, "world.xml");
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
2009-12-21 22:08:00 +00:00
|
|
|
} else if (cmd == "restore") {
|
2013-11-14 23:59:31 +01:00
|
|
|
if (command_context->repr() != "avatar") {
|
|
|
|
|
std::cout << "You must have an agent in the world in order to dump the world." << std::endl << std::flush;
|
|
|
|
|
} else {
|
|
|
|
|
//Extract the avatar id by "misusing" the setFromContext method
|
|
|
|
|
Operation op;
|
|
|
|
|
command_context->setFromContext(op);
|
|
|
|
|
ClientTask * task = new EntityImporter(m_accountId, op->getFrom());
|
|
|
|
|
runTask(task, "world.xml");
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
}
|
2010-12-06 22:27:07 +00:00
|
|
|
} else if (cmd == "create") {
|
|
|
|
|
std::vector<std::string> args;
|
|
|
|
|
tokenize(arg, args);
|
|
|
|
|
|
|
|
|
|
if (args.size() < 1) {
|
|
|
|
|
std::cout << "usage: create <type> <params> ... "
|
|
|
|
|
<< std::endl << std::flush;
|
|
|
|
|
} else {
|
|
|
|
|
Anonymous cmap;
|
2017-07-24 13:39:22 +02:00
|
|
|
cmap->setParent(args[0]);
|
2010-12-06 22:27:07 +00:00
|
|
|
cmap->setObjtype("obj");
|
|
|
|
|
|
|
|
|
|
Create c;
|
|
|
|
|
c->setArgs1(cmap);
|
2012-06-06 19:39:18 -07:00
|
|
|
c->setSerialno(newSerialNo());
|
|
|
|
|
command_context->setFromContext(c);
|
2010-12-06 22:27:07 +00:00
|
|
|
|
|
|
|
|
send(c);
|
|
|
|
|
}
|
2012-06-09 18:34:06 -07:00
|
|
|
reply_expected = false;
|
2010-12-06 22:27:07 +00:00
|
|
|
} else if (cmd == "login") {
|
2012-06-06 13:48:14 -07:00
|
|
|
std::vector<std::string> args;
|
|
|
|
|
tokenize(arg, args);
|
|
|
|
|
|
|
|
|
|
if (args.size() != 2) {
|
|
|
|
|
std::cout << "usage: login <username> <password>"
|
2010-12-06 22:27:07 +00:00
|
|
|
<< std::endl << std::flush;
|
2012-06-06 16:45:02 -07:00
|
|
|
reply_expected = false;
|
2010-12-06 22:27:07 +00:00
|
|
|
} else {
|
2012-06-06 13:48:14 -07:00
|
|
|
Anonymous cmap;
|
|
|
|
|
cmap->setAttr("username", args[0]);
|
|
|
|
|
cmap->setAttr("password", args[1]);
|
2010-12-06 22:27:07 +00:00
|
|
|
|
2012-06-06 13:48:14 -07:00
|
|
|
Login m;
|
|
|
|
|
m->setArgs1(cmap);
|
|
|
|
|
m->setSerialno(newSerialNo());
|
2010-12-06 22:27:07 +00:00
|
|
|
|
2012-06-06 15:48:05 -07:00
|
|
|
command_context->setFromContext(m);
|
2012-06-06 13:48:14 -07:00
|
|
|
|
|
|
|
|
send(m);
|
2010-12-06 22:27:07 +00:00
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
} else {
|
|
|
|
|
reply_expected = false;
|
|
|
|
|
std::cout << cmd << ": Command not known" << std::endl << std::flush;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-27 11:21:43 +00:00
|
|
|
if (!reply_expected) {
|
|
|
|
|
updatePrompt();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
// Wait for reply
|
2018-01-30 16:54:49 +01:00
|
|
|
time_t wait_start_time = time(nullptr);
|
2009-11-27 13:16:40 +00:00
|
|
|
while (!reply_flag) {
|
2018-01-30 16:54:49 +01:00
|
|
|
if (time(nullptr) - wait_start_time > 5) {
|
2009-11-27 13:16:40 +00:00
|
|
|
std::cout << cmd << ": No reply from server" << std::endl << std::flush;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-07-27 10:07:20 +01:00
|
|
|
if (select(false) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-27 13:16:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-30 23:06:58 +01:00
|
|
|
|
2012-05-30 23:21:25 +01:00
|
|
|
int Interactive::commandUnknown(struct command * cmd,
|
2012-05-30 23:06:58 +01:00
|
|
|
const std::string & arg)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|