diff --git a/utils/solvers/c++/onelab.h b/utils/solvers/c++/onelab.h new file mode 100644 index 0000000000000000000000000000000000000000..32ed1533606dcb71cbd144f5a5a22a87849fcb4f --- /dev/null +++ b/utils/solvers/c++/onelab.h @@ -0,0 +1,817 @@ +// OneLab - Copyright (C) 2011 ULg-UCL +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished +// to do so, provided that the above copyright notice(s) and this +// permission notice appear in all copies of the Software and that +// both the above copyright notice(s) and this permission notice +// appear in supporting documentation. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE +// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR +// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY +// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +// OF THIS SOFTWARE. +// +// Please report all bugs and problems to <gmsh@geuz.org>. + +#ifndef _ONELAB_H_ +#define _ONELAB_H_ + +#include <string> +#include <vector> +#include <set> +#include <map> +#include <iostream> +#include <sstream> +#include "GmshSocket.h" + +namespace onelab{ + + // The base parameter class. + class parameter{ + private: + // the name of the parameter, including its '/'-separated path in + // the parameter hierarchy. Parameters or subpaths can start with + // numbers to force their relative ordering (such numbers are + // automatically hidden in the interface). + std::string _name; + // help strings (if provided, the short help serves as a better + // way to display the parameter in the interface). Richer encoding + // (UTF? HTML?) might be used in the future. + std::string _shortHelp, _help; + // clients that use this parameter + std::set<std::string> _clients; + // flag to check if the parameter has been changed since the last + // run() + bool _changed; + // should the parameter be visible in the interface? + bool _visible; + protected: + // optional additional attributes + std::map<std::string, std::string> _attributes; + public: + parameter(const std::string &name="", const std::string &shortHelp="", + const std::string &help="") + : _name(name), _shortHelp(shortHelp), _help(help), _changed(true), + _visible(true) {} + void setName(const std::string &name){ _name = name; } + void setShortHelp(const std::string &shortHelp){ _shortHelp = shortHelp; } + void setHelp(const std::string &help){ _help = help; } + void setChanged(bool changed){ _changed = changed; } + void setVisible(bool visible){ _visible = visible; } + void setAttribute(const std::string &key, const std::string &value) + { + _attributes[key] = value; + } + void setAttributes(const std::map<std::string, std::string> &attributes) + { + _attributes = attributes; + } + void setClients(const std::set<std::string> &clients){ _clients = clients; } + void addClient(const std::string &client){ _clients.insert(client); } + void addClients(const std::set<std::string> &clients) + { + _clients.insert(clients.begin(), clients.end()); + } + bool hasClient(const std::string &client) + { + return (_clients.find(client) != _clients.end()); + } + virtual std::string getType() const = 0; + const std::string &getName() const { return _name; } + const std::string &getShortHelp() const { return _shortHelp; } + const std::string &getHelp() const { return _help; } + bool getChanged() const { return _changed; } + bool getVisible() const { return _visible; } + std::string getAttribute(const std::string &key) const + { + std::map<std::string, std::string>::const_iterator it = _attributes.find(key); + if(it != _attributes.end()) return it->second; + return ""; + } + const std::map<std::string, std::string> &getAttributes() const + { + return _attributes; + } + const std::set<std::string> &getClients() const { return _clients; } + static char charSep() { return '\0'; } + static double maxNumber() { return 1e200; } + static std::string version() { return "1.0"; } + static std::string getNextToken(const std::string &msg, + std::string::size_type &first) + { + std::string::size_type last = msg.find_first_of(charSep(), first); + std::string next = msg.substr(first, last - first); + first = (last == std::string::npos) ? last : last + 1; + return next; + } + std::string sanitize(const std::string &in) const + { + std::string out(in); + for(unsigned int i = 0; i < in.size(); i++) + if(out[i] == charSep()) out[i] = ' '; + return out; + } + virtual std::string toChar() const + { + std::ostringstream sstream; + sstream << version() << charSep() << getType() << charSep() + << sanitize(getName()) << charSep() + << sanitize(getShortHelp()) << charSep() + << sanitize(getHelp()) << charSep() + << (getVisible() ? 1 : 0) << charSep() + << _attributes.size() << charSep(); + for(std::map<std::string, std::string>::const_iterator it = _attributes.begin(); + it != _attributes.end(); it++) + sstream << sanitize(it->first) << charSep() + << sanitize(it->second) << charSep(); + sstream << getClients().size() << charSep(); + for(std::set<std::string>::const_iterator it = getClients().begin(); + it != getClients().end(); it++) + sstream << sanitize(*it) << charSep(); + return sstream.str(); + } + virtual std::string::size_type fromChar(const std::string &msg) + { + std::string::size_type pos = 0; + if(getNextToken(msg, pos) != version()) return 0; + if(getNextToken(msg, pos) != getType()) return 0; + setName(getNextToken(msg, pos)); + setShortHelp(getNextToken(msg, pos)); + setHelp(getNextToken(msg, pos)); + setVisible(atoi(getNextToken(msg, pos).c_str())); + int numAttributes = atoi(getNextToken(msg, pos).c_str()); + for(int i = 0; i < numAttributes; i++){ + std::string key(getNextToken(msg, pos)); + setAttribute(key, getNextToken(msg, pos)); + } + int numClients = atoi(getNextToken(msg, pos).c_str()); + for(int i = 0; i < numClients; i++){ + std::string client(getNextToken(msg, pos)); + addClient(client); + } + return pos; + } + static void getInfoFromChar(const std::string &msg, std::string &version, + std::string &type, std::string &name) + { + std::string::size_type first = 0; + version = getNextToken(msg, first); + type = getNextToken(msg, first); + name = getNextToken(msg, first); + } + }; + + class parameterLessThan{ + public: + bool operator()(const parameter *p1, const parameter *p2) const + { + return p1->getName() < p2->getName(); + } + }; + + // The number class. Numbers are stored internally as double + // precision real numbers. Currently all more complicated types + // (complex numbers, vectors, etc.) are supposed to be encapsulated + // in functions. We might add more base types in the future to make + // the interface more expressive. + class number : public parameter{ + private: + double _value, _min, _max, _step; + std::vector<double> _choices; + public: + number(const std::string &name="", double value=0., + const std::string &shortHelp="", const std::string &help="") + : parameter(name, shortHelp, help), _value(value), + _min(-maxNumber()), _max(maxNumber()), _step(0.) {} + void setValue(double value){ _value = value; } + void setMin(double min){ _min = min; } + void setMax(double max){ _max = max; } + void setStep(double step){ _step = step; } + void setChoices(const std::vector<double> &choices){ _choices = choices; } + std::string getType() const { return "number"; } + double getValue() const { return _value; } + double getMin() const { return _min; } + double getMax() const { return _max; } + double getStep() const { return _step; } + const std::vector<double> &getChoices() const { return _choices; } + void update(const number &p) + { + addClients(p.getClients()); // complete the list + setShortHelp(p.getShortHelp()); + setHelp(p.getHelp()); + setAttributes(p.getAttributes()); + if(p.getValue() != getValue()){ + setValue(p.getValue()); + setChanged(true); + } + setMin(p.getMin()); + setMax(p.getMax()); + setStep(p.getStep()); + setChoices(p.getChoices()); + } + std::string toChar() const + { + std::ostringstream sstream; + sstream << parameter::toChar() << _value << charSep() + << _min << charSep() << _max << charSep() << _step << charSep() + << _choices.size() << charSep(); + for(unsigned int i = 0; i < _choices.size(); i++) + sstream << _choices[i] << charSep(); + return sstream.str(); + } + std::string::size_type fromChar(const std::string &msg) + { + std::string::size_type pos = parameter::fromChar(msg); + if(!pos) return 0; + setValue(atof(getNextToken(msg, pos).c_str())); + setMin(atof(getNextToken(msg, pos).c_str())); + setMax(atof(getNextToken(msg, pos).c_str())); + setStep(atof(getNextToken(msg, pos).c_str())); + _choices.resize(atoi(getNextToken(msg, pos).c_str())); + for(unsigned int i = 0; i < _choices.size(); i++) + _choices[i] = atof(getNextToken(msg, pos).c_str()); + return pos; + } + }; + + // The string class. A string has a mutable "kind": we do not derive + // specialized classes, because the kind should be changeable at + // runtime (e.g. from a client-dependent mathematical expression to + // a table of values). Possible kinds: generic, filename, hostname, + // client-dependent mathematical expression, comma-separated list of + // values, matlab matrix, onelab mathematical expression (through + // mathex?), ... + class string : public parameter{ + private: + std::string _value, _kind; + std::vector<std::string> _choices; + public: + string(const std::string &name="", const std::string &value="", + const std::string &shortHelp="", const std::string &help="") + : parameter(name, shortHelp, help), _value(value), _kind("generic") {} + void setValue(const std::string &value){ _value = value; } + void setKind(const std::string &kind){ _kind = kind; } + void setChoices(const std::vector<std::string> &choices){ _choices = choices; } + std::string getType() const { return "string"; } + const std::string &getValue() const { return _value; } + const std::string &getKind() const { return _kind; } + const std::vector<std::string> &getChoices() const { return _choices; } + void update(const string &p) + { + addClients(p.getClients()); + setShortHelp(p.getShortHelp()); + setHelp(p.getHelp()); + setAttributes(p.getAttributes()); + if(p.getValue() != getValue()){ + setValue(p.getValue()); + setChanged(true); + } + if(p.getKind() != getKind()){ + setKind(p.getKind()); + setChanged(true); + } + setChoices(p.getChoices()); + } + std::string toChar() const + { + std::ostringstream sstream; + sstream << parameter::toChar() << sanitize(_value) << charSep() + << sanitize(_kind) << charSep() + << _choices.size() << charSep(); + for(unsigned int i = 0; i < _choices.size(); i++) + sstream << sanitize(_choices[i]) << charSep(); + return sstream.str(); + } + std::string::size_type fromChar(const std::string &msg) + { + std::string::size_type pos = parameter::fromChar(msg); + if(!pos) return 0; + setValue(getNextToken(msg, pos)); + setKind(getNextToken(msg, pos)); + _choices.resize(atoi(getNextToken(msg, pos).c_str())); + for(unsigned int i = 0; i < _choices.size(); i++) + _choices[i] = getNextToken(msg, pos); + return pos; + } + }; + + // The region class. A region can be any kind of geometrical entity, + // represented as identifiers of physical regions. Operations on + // regions will include union, intersection, etc. + class region : public parameter{ + private: + std::string _value; // TODO: change this into std::set<std::string> + std::vector<std::string> _choices; + public: + region(const std::string &name="", const std::string &value="", + const std::string &shortHelp="", const std::string &help="") + : parameter(name, shortHelp, help), _value(value) {} + void setValue(const std::string &value){ _value = value; } + std::string getType() const { return "region"; } + const std::string &getValue() const { return _value; } + void update(const region &p) + { + addClients(p.getClients()); + setShortHelp(p.getShortHelp()); + setHelp(p.getHelp()); + setAttributes(p.getAttributes()); + if(p.getValue() != getValue()){ + setValue(p.getValue()); + setChanged(true); + } + } + std::string toChar() const + { + std::ostringstream sstream; + sstream << parameter::toChar() << _value << charSep() + << _choices.size() << charSep(); + for(unsigned int i = 0; i < _choices.size(); i++) + sstream << sanitize(_choices[i]) << charSep(); + return sstream.str(); + } + }; + + // The (possibly piece-wise defined on regions) function + // class. Functions are entirely client-dependent: they are just + // represented internally as onelab strings, defined on onelab + // regions. + class function : public parameter{ + private: + std::string _value; + std::map<std::string, std::string> _pieceWiseValues; + std::vector<std::string> _choices; + public: + function(const std::string &name="", const std::string &value="", + const std::string &shortHelp="", const std::string &help="") + : parameter(name, shortHelp, help), _value(value) {} + void setValue(const std::string &value, const std::string ®ion="") + { + if(region.empty()) + _value = value; + else + _pieceWiseValues[region] = value; + } + std::string getType() const { return "function"; } + const std::string getValue(const std::string ®ion="") const + { + if(region.size()){ + std::map<std::string, std::string>::const_iterator it = + _pieceWiseValues.find(region); + if(it != _pieceWiseValues.end()) return it->second; + return ""; + } + else return _value; + } + const std::map<std::string, std::string> &getPieceWiseValues() const + { + return _pieceWiseValues; + } + void update(const function &p) + { + addClients(p.getClients()); + setShortHelp(p.getShortHelp()); + setHelp(p.getHelp()); + setAttributes(p.getAttributes()); + if(p.getValue() != getValue()){ + setValue(p.getValue()); + setChanged(true); + } + } + std::string toChar() const + { + std::ostringstream sstream; + sstream << parameter::toChar() << sanitize(_value) << charSep() + << _pieceWiseValues.size() << charSep(); + for(std::map<std::string, std::string>::const_iterator it = + _pieceWiseValues.begin(); it != _pieceWiseValues.end(); it++) + sstream << sanitize(it->first) << charSep() + << sanitize(it->second) << charSep(); + sstream << _choices.size() << charSep(); + for(unsigned int i = 0; i < _choices.size(); i++) + sstream << sanitize(_choices[i]) << charSep(); + return sstream.str(); + } + }; + + // The parameter space, i.e., the set of parameters stored and + // handled by the onelab server. + class parameterSpace{ + private: + std::set<number*, parameterLessThan> _numbers; + std::set<string*, parameterLessThan> _strings; + std::set<region*, parameterLessThan> _regions; + std::set<function*, parameterLessThan> _functions; + // set a parameter in the parameter space; if it already exists, + // update it (adding new clients if necessary). This needs to be + // locked to avoid race conditions when several clients try to set + // a parameter at the same time. + template <class T> bool _set(const T &p, const std::string &client, + std::set<T*, parameterLessThan> &ps) + { + typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p); + if(it != ps.end()){ + (*it)->update(p); + if(client.size()) (*it)->addClient(client); + } + else{ + T* newp = new T(p); + if(client.size()) newp->addClient(client); + ps.insert(newp); + } + return true; + } + // get the parameter matching the given name, or all the + // parameters in the category if no name is given. If we find a + // given parameter by name, we add the client requesting the + // parameter to the list of clients for this parameter. This also + // needs to be locked. + template <class T> bool _get(std::vector<T> &p, const std::string &name, + const std::string &client, + std::set<T*, parameterLessThan> &ps) + { + p.clear(); + if(name.empty()){ + for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++) + p.push_back(**it); + } + else{ + T tmp(name); + typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp); + if(it != ps.end()){ + if(client.size()) (*it)->addClient(client); + p.push_back(**it); + } + } + return true; + } + void _getAllParameters(std::set<parameter*> &ps) const + { + ps.insert(_numbers.begin(), _numbers.end()); + ps.insert(_strings.begin(), _strings.end()); + ps.insert(_regions.begin(), _regions.end()); + ps.insert(_functions.begin(), _functions.end()); + } + public: + parameterSpace(){} + ~parameterSpace(){ clear(); } + void clear() + { + std::set<parameter*> ps; + _getAllParameters(ps); + for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) + delete *it; + _numbers.clear(); + _strings.clear(); + _regions.clear(); + _functions.clear(); + } + bool set(const number &p, + const std::string &client=""){ return _set(p, client, _numbers); } + bool set(const string &p, + const std::string &client=""){ return _set(p, client, _strings); } + bool set(const region &p, + const std::string &client=""){ return _set(p, client, _regions); } + bool set(const function &p, + const std::string &client=""){ return _set(p, client, _functions); } + bool get(std::vector<number> &ps, const std::string &name="", + const std::string &client=""){ return _get(ps, name, client, _numbers); } + bool get(std::vector<string> &ps, const std::string &name="", + const std::string &client=""){ return _get(ps, name, client, _strings); } + bool get(std::vector<region> &ps, const std::string &name="", + const std::string &client=""){ return _get(ps, name, client, _regions); } + bool get(std::vector<function> &ps, const std::string &name="", + const std::string &client=""){ return _get(ps, name, client, _functions); } + // check if at least one parameter depends on the given client + bool hasClient(const std::string &client) const + { + std::set<parameter*> ps; + _getAllParameters(ps); + for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) + if((*it)->hasClient(client)) return true; + return false; + } + // check if some parameters have changed (optionnally only check + // the parameters that depend on a given client) + bool getChanged(const std::string &client="") const + { + std::set<parameter*> ps; + _getAllParameters(ps); + for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++){ + if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged()) + return true; + } + return false; + } + // set the changed flag for all parameters (optionnally only affect those + // parameters that depend on a given client) + bool setChanged(bool changed, const std::string &client="") + { + std::set<parameter*> ps; + _getAllParameters(ps); + for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) + if(client.empty() || (*it)->hasClient(client)) + (*it)->setChanged(changed); + } + // serialize the parameter space (optinally only serialize those + // parameters that depend on the given client) + std::string toChar(const std::string &client="") const + { + std::string s; + std::set<parameter*> ps; + _getAllParameters(ps); + for(std::set<parameter*>::const_iterator it = ps.begin(); it != ps.end(); it++) + if(client.empty() || (*it)->hasClient(client)) s += (*it)->toChar() + "\n"; + return s; + } + }; + + // The onelab client: a class that communicates with the onelab + // server. Each client should be derived from this one. A client can + // be understood as "one simulation step in a complex computation". + class client{ + protected: + // the name of the client + std::string _name; + // the id of the client, used to create a unique socket for this client + int _id; + // the index of the client in an external client list (if any) + int _index; + public: + client(const std::string &name) : _name(name), _id(0), _index(-1){} + virtual ~client(){} + std::string getName(){ return _name; } + void setId(int id){ _id = id; } + int getId(){ return _id; } + void setIndex(int index){ _index = index; } + int getIndex(){ return _index; } + virtual bool run(const std::string &what){ return false; } + virtual bool isNetworkClient(){ return false; } + virtual bool kill(){ return false; } + virtual void sendInfo(const std::string &msg){ std::cout << msg << std::endl; } + virtual void sendWarning(const std::string &msg){ std::cerr << msg << std::endl; } + virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; } + virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; } + virtual void sendMergeFileRequest(const std::string &msg){} + virtual void sendParseStringRequest(const std::string &msg){} + virtual void sendVertexArray(const std::string &msg){} + virtual bool set(const number &p) = 0; + virtual bool set(const string &p) = 0; + virtual bool set(const region &p) = 0; + virtual bool set(const function &p) = 0; + virtual bool get(std::vector<number> &ps, const std::string &name="") = 0; + virtual bool get(std::vector<string> &ps, const std::string &name="") = 0; + virtual bool get(std::vector<region> &ps, const std::string &name="") = 0; + virtual bool get(std::vector<function> &ps, const std::string &name="") = 0; + }; + + // The onelab server: a singleton that stores the parameter space + // and interacts with onelab clients. + class server{ + private: + // the unique server + static server *_server; + // the address of the server + std::string _address; + // the connected clients, indexed by name + std::map<std::string, client*> _clients; + // the parameter space + parameterSpace _parameterSpace; + public: + server(const std::string &address="") : _address(address) {} + ~server(){} + static server *instance(const std::string &address="") + { + if(!_server) _server = new server(address); + return _server; + } + void clear(){ _parameterSpace.clear(); } + template <class T> bool set(const T &p, const std::string &client="") + { + return _parameterSpace.set(p, client); + } + template <class T> bool get(std::vector<T> &ps, const std::string &name="", + const std::string &client="") + { + return _parameterSpace.get(ps, name, client); + } + typedef std::map<std::string, client*>::iterator citer; + citer firstClient(){ return _clients.begin(); } + citer lastClient(){ return _clients.end(); } + citer findClient(const std::string &name){ return _clients.find(name); } + void registerClient(client *c) + { + _clients[c->getName()] = c; + c->setId(_clients.size()); + } + void unregisterClient(client *c){ _clients.erase(c->getName()); } + void setChanged(bool changed, const std::string &client="") + { + _parameterSpace.setChanged(changed, client); + } + bool getChanged(const std::string &client="") + { + return _parameterSpace.getChanged(client); + } + std::string toChar(const std::string &client="") + { + return _parameterSpace.toChar(client); + } + }; + + class localClient : public client{ + private: + template <class T> bool _set(const T &p) + { + server::instance()->set(p, _name); + return true; + } + template <class T> bool _get(std::vector<T> &ps, + const std::string &name="") + { + server::instance()->get(ps, name, _name); + return true; + } + public: + localClient(const std::string &name) : client(name) + { + server::instance()->registerClient(this); + } + virtual ~localClient(){} + virtual bool set(const number &p){ return _set(p); } + virtual bool set(const string &p){ return _set(p); } + virtual bool set(const function &p){ return _set(p); } + virtual bool set(const region &p){ return _set(p); } + virtual bool get(std::vector<number> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<string> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<function> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<region> &ps, + const std::string &name=""){ return _get(ps, name); } + }; + + class localNetworkClient : public localClient{ + private: + // command line to launch the remote network client + std::string _commandLine; + // command line option to specify socket + std::string _socketSwitch; + // pid of the remote network client + int _pid; + // underlying GmshServer + GmshServer *_gmshServer; + public: + localNetworkClient(const std::string &name, const std::string &commandLine) + : localClient(name), _commandLine(commandLine), _socketSwitch("-onelab"), + _pid(-1), _gmshServer(0) {} + virtual ~localNetworkClient(){} + virtual bool isNetworkClient(){ return true; } + const std::string &getCommandLine(){ return _commandLine; } + void setCommandLine(const std::string &s){ _commandLine = s; } + const std::string &getSocketSwitch(){ return _socketSwitch; } + void setSocketSwitch(const std::string &s){ _socketSwitch = s; } + int getPid(){ return _pid; } + void setPid(int pid){ _pid = pid; } + GmshServer *getGmshServer(){ return _gmshServer; } + void setGmshServer(GmshServer *server){ _gmshServer = server; } + virtual bool run(const std::string &what); + virtual bool kill(); + }; + + class remoteNetworkClient : public client{ + private: + // address (inet:port or unix socket) of the server + std::string _serverAddress; + // underlying GmshClient + GmshClient *_gmshClient; + template <class T> bool _set(const T &p) + { + if(!_gmshClient) return false; + std::string msg = p.toChar(); + _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER, msg.size(), &msg[0]); + return true; + } + template <class T> bool _get(std::vector<T> &ps, + const std::string &name="") + { + ps.clear(); + if(!_gmshClient) return false; + T p(name); + std::string msg = p.toChar(); + _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY, msg.size(), &msg[0]); + while(1){ + // stop if we have no communications for 10 secs + int ret = _gmshClient->Select(10, 0); + if(!ret){ + _gmshClient->Info("Timout: aborting remote get"); + return false; + } + else if(ret < 0){ + _gmshClient->Error("Error on select: aborting remote get"); + return false; + } + int type, length, swap; + if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){ + _gmshClient->Error("Did not receive message header: aborting remote get"); + return false; + } + std::string msg(length, ' '); + if(!_gmshClient->ReceiveMessage(length, &msg[0])){ + _gmshClient->Error("Did not receive message body: aborting remote get"); + return false; + } + if(type == GmshSocket::GMSH_PARAMETER){ + T p; + p.fromChar(msg); + ps.push_back(p); + return true; + } + else if(type == GmshSocket::GMSH_INFO){ + // parameter not found + return true; + } + else{ + _gmshClient->Error("Unknown message type: aborting remote get"); + return false; + } + } + return true; + } + public: + remoteNetworkClient(const std::string &name, const std::string &serverAddress) + : client(name), _serverAddress(serverAddress) + { + _gmshClient = new GmshClient(); + if(_gmshClient->Connect(_serverAddress.c_str()) < 0){ + delete _gmshClient; + _gmshClient = 0; + } + else{ + _gmshClient->Start(); + } + } + virtual ~remoteNetworkClient() + { + if(_gmshClient){ + _gmshClient->Stop(); + _gmshClient->Disconnect(); + delete _gmshClient; + _gmshClient = 0; + } + } + GmshClient *getGmshClient(){ return _gmshClient; } + virtual bool isNetworkClient(){ return true; } + virtual bool set(const number &p){ return _set(p); } + virtual bool set(const string &p){ return _set(p); } + virtual bool set(const function &p){ return _set(p); } + virtual bool set(const region &p){ return _set(p); } + virtual bool get(std::vector<number> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<string> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<function> &ps, + const std::string &name=""){ return _get(ps, name); } + virtual bool get(std::vector<region> &ps, + const std::string &name=""){ return _get(ps, name); } + void sendInfo(const std::string &msg) + { + if(_gmshClient) _gmshClient->Info(msg.c_str()); + } + void sendWarning(const std::string &msg) + { + if(_gmshClient) _gmshClient->Warning(msg.c_str()); + } + void sendError(const std::string &msg) + { + if(_gmshClient) _gmshClient->Error(msg.c_str()); + } + void sendProgress(const std::string &msg) + { + if(_gmshClient) _gmshClient->Progress(msg.c_str()); + } + void sendMergeFileRequest(const std::string &msg) + { + if(_gmshClient) _gmshClient->MergeFile(msg.c_str()); + } + void sendParseStringRequest(const std::string &msg) + { + if(_gmshClient) _gmshClient->ParseString(msg.c_str()); + } + }; + +} + +#endif diff --git a/utils/solvers/c++/solver.cpp b/utils/solvers/c++/solver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dec6b3d8ffe2afbf6c32ee50fd3d93d780be8bec --- /dev/null +++ b/utils/solvers/c++/solver.cpp @@ -0,0 +1,36 @@ +#include <iostream> +#include <vector> +#include <string> +#include "onelab.h" + +int main(int argc, char **argv) +{ + onelab::remoteNetworkClient *client = 0; + + for(int i = 0; i < argc; i++){ + if(std::string(argv[i]) == "-onelab" && i < argc - 1) + client = new onelab::remoteNetworkClient("My solver", argv[i + 1]); + } + + if(!client){ + printf("usage: %s -onelab socket\n", argv[0]); + exit(1); + } + + std::vector<onelab::string> strings; + + // try to get the string variable "My solver/My string" from the server + client->get(strings, "My solver/My string"); + if(strings.size()){ + std::cout << "Got string from server: '" << strings[0].getValue() << "'\n"; + } + else{ + // send a value to the server + onelab::string s("My solver/My string", "Hello!"); + client->set(s); + } + + delete client; + + return 0; +}