Merge commit 'refs/merge-requests/28' of git://gitorious.org/fg/flightgear into merge-requests/28
This commit is contained in:
parent
caf0138ab3
commit
9b4c2def75
2 changed files with 108 additions and 5 deletions
|
@ -33,6 +33,7 @@
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -43,8 +44,16 @@
|
||||||
|
|
||||||
#include <simgear/io/sg_netChat.hxx>
|
#include <simgear/io/sg_netChat.hxx>
|
||||||
|
|
||||||
|
#include <simgear/misc/strutils.hxx>
|
||||||
|
|
||||||
#include "props.hxx"
|
#include "props.hxx"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
using std::stringstream;
|
using std::stringstream;
|
||||||
using std::ends;
|
using std::ends;
|
||||||
|
|
||||||
|
@ -55,7 +64,7 @@ using std::endl;
|
||||||
* Props connection class.
|
* Props connection class.
|
||||||
* This class represents a connection to props client.
|
* This class represents a connection to props client.
|
||||||
*/
|
*/
|
||||||
class PropsChannel : public simgear::NetChat
|
class PropsChannel : public simgear::NetChat, public SGPropertyChangeListener
|
||||||
{
|
{
|
||||||
simgear::NetBuffer buffer;
|
simgear::NetBuffer buffer;
|
||||||
|
|
||||||
|
@ -75,6 +84,7 @@ public:
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
PropsChannel();
|
PropsChannel();
|
||||||
|
~PropsChannel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append incoming data to our request buffer.
|
* Append incoming data to our request buffer.
|
||||||
|
@ -89,10 +99,37 @@ public:
|
||||||
*/
|
*/
|
||||||
void foundTerminator();
|
void foundTerminator();
|
||||||
|
|
||||||
|
// callback for registered listeners (subscriptions)
|
||||||
|
void valueChanged(SGPropertyNode *node);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
typedef string_list ParameterList;
|
||||||
|
|
||||||
inline void node_not_found_error( const string& s ) const {
|
inline void node_not_found_error( const string& s ) const {
|
||||||
throw "node '" + s + "' not found";
|
throw "node '" + s + "' not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void error(std::string msg) { // wrapper: prints errors to STDERR and to the telnet client
|
||||||
|
push( msg.c_str() ); push( getTerminator() );
|
||||||
|
SG_LOG(SG_NETWORK, SG_ALERT, __FILE__<<"@" << __LINE__ <<" in " << __FUNCTION__ <<":"<< msg.c_str() << std::endl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool check_args(const ParameterList &tok, const unsigned int num, const char* func) {
|
||||||
|
if (tok.size()-1 < num) {
|
||||||
|
error(string("Error:Wrong argument count for:")+string(func) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SGPropertyNode_ptr> _listeners;
|
||||||
|
typedef void (PropsChannel::*TelnetCallback) (const ParameterList&);
|
||||||
|
std::map<std::string, TelnetCallback> callback_map;
|
||||||
|
|
||||||
|
// callback implementations:
|
||||||
|
void subscribe(const ParameterList &p);
|
||||||
|
void unsubscribe(const ParameterList &p);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,6 +141,62 @@ PropsChannel::PropsChannel()
|
||||||
mode(PROMPT)
|
mode(PROMPT)
|
||||||
{
|
{
|
||||||
setTerminator( "\r\n" );
|
setTerminator( "\r\n" );
|
||||||
|
callback_map["subscribe"] = &PropsChannel::subscribe;
|
||||||
|
callback_map["unsubscribe"] = &PropsChannel::unsubscribe;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropsChannel::~PropsChannel() {
|
||||||
|
// clean up all registered listeners
|
||||||
|
BOOST_FOREACH(SGPropertyNode_ptr l, _listeners) {
|
||||||
|
l->removeChangeListener( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropsChannel::subscribe(const ParameterList ¶m) {
|
||||||
|
if (! check_args(param,1,"subscribe")) return;
|
||||||
|
|
||||||
|
std::string command = param[0];
|
||||||
|
const char* p = param[1].c_str();
|
||||||
|
if (!p) return;
|
||||||
|
|
||||||
|
//SG_LOG(SG_GENERAL, SG_ALERT, p << std::endl);
|
||||||
|
push( command.c_str() ); push ( " " );
|
||||||
|
push( p );
|
||||||
|
push( getTerminator() );
|
||||||
|
|
||||||
|
SGPropertyNode *n = globals->get_props()->getNode( p,true );
|
||||||
|
if ( n->isTied() ) {
|
||||||
|
error("Error:Tied properties cannot register listeners");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
n->addChangeListener( this );
|
||||||
|
_listeners.push_back( n ); // housekeeping, save for deletion in dtor later on
|
||||||
|
} else {
|
||||||
|
error("listener could not be added");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropsChannel::unsubscribe(const ParameterList ¶m) {
|
||||||
|
if (!check_args(param,1,"unsubscribe")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
SGPropertyNode *n = globals->get_props()->getNode( param[1].c_str() );
|
||||||
|
if (n)
|
||||||
|
n->removeChangeListener( this );
|
||||||
|
} catch (sg_exception &e) {
|
||||||
|
error("Error:Listener could not be removed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: provide support for different types of subscriptions MODES ? (child added/removed, thesholds, min/max)
|
||||||
|
void PropsChannel::valueChanged(SGPropertyNode* ptr) {
|
||||||
|
//SG_LOG(SG_GENERAL, SG_ALERT, __FILE__<< "@"<<__LINE__ << ":" << __FUNCTION__ << std::endl);
|
||||||
|
std::stringstream response;
|
||||||
|
response << ptr->getPath(true) << "=" << ptr->getStringValue() << getTerminator(); //TODO: use hashes, echo several properties at once
|
||||||
|
push( response.str().c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,7 +253,7 @@ PropsChannel::foundTerminator()
|
||||||
const char* cmd = buffer.getData();
|
const char* cmd = buffer.getData();
|
||||||
SG_LOG( SG_IO, SG_INFO, "processing command = \"" << cmd << "\"" );
|
SG_LOG( SG_IO, SG_INFO, "processing command = \"" << cmd << "\"" );
|
||||||
|
|
||||||
vector<string> tokens = simgear::strutils::split( cmd );
|
ParameterList tokens = simgear::strutils::split( cmd );
|
||||||
|
|
||||||
SGPropertyNode* node = globals->get_props()->getNode( path.c_str() );
|
SGPropertyNode* node = globals->get_props()->getNode( path.c_str() );
|
||||||
|
|
||||||
|
@ -386,7 +479,14 @@ PropsChannel::foundTerminator()
|
||||||
mode = DATA;
|
mode = DATA;
|
||||||
} else if ( command == "prompt" ) {
|
} else if ( command == "prompt" ) {
|
||||||
mode = PROMPT;
|
mode = PROMPT;
|
||||||
} else {
|
} else if (callback_map.find(command) != callback_map.end() ) {
|
||||||
|
TelnetCallback t = callback_map[ command ];
|
||||||
|
if (t)
|
||||||
|
(this->*t) (tokens);
|
||||||
|
else
|
||||||
|
error("No matching callback found for command:"+command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
const char* msg = "\
|
const char* msg = "\
|
||||||
Valid commands are:\r\n\
|
Valid commands are:\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
|
@ -400,7 +500,9 @@ prompt switch to interactive mode (default)\r\n\
|
||||||
pwd display your current path\r\n\
|
pwd display your current path\r\n\
|
||||||
quit terminate connection\r\n\
|
quit terminate connection\r\n\
|
||||||
run <command> run built in command\r\n\
|
run <command> run built in command\r\n\
|
||||||
set <var> <val> set <var> to a new <val>\r\n";
|
set <var> <val> set <var> to a new <val>\r\n\
|
||||||
|
subscribe <var> subscribe to property changes \r\n\
|
||||||
|
unscubscribe <var> unscubscribe from property changes (var must be the property name/path used by subscribe)\r\n";
|
||||||
push( msg );
|
push( msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
* FlightGear properties.
|
* FlightGear properties.
|
||||||
*/
|
*/
|
||||||
class FGProps : public FGProtocol,
|
class FGProps : public FGProtocol,
|
||||||
public simgear::NetChannel
|
public simgear::NetChannel,
|
||||||
|
public SGPropertyChangeListener // for subscriptions
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue