1 // ONELAB - Copyright (C) 2010-2012 C. Geuzaine, F. Henrotte
2 //
3 // See the README.txt file for license information. Please report all
4 // issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #ifndef ONELAB_CLIENTS_H
7 #define ONELAB_CLIENTS_H
8 
9 #include <stdlib.h>
10 #include <fstream>
11 #include <iostream>
12 #include <sstream>
13 
14 #include "OS.h"
15 #include "onelab.h"
16 #include "OnelabMessage.h"
17 #include "StringUtils.h"
18 
19 // Onelab file extension
20 static std::string onelabExtension(".ol");
21 static std::string localFileTag("_");
22 
23 // Possible actions for clients
24 enum parseMode { REGISTER, ANALYZE, COMPUTE, EXIT };
25 
26 // TOOLS
27 
28 std::string itoa(const int i);
29 std::string ftoa(const double x);
30 bool checkIfPresent(std::string fileName);
31 bool chmod(std::string fileName);
32 int mySystem(std::string commandLine);
33 std::string getCurrentWorkdir();
34 std::string getUserHomedir();
35 std::string sanitize(const std::string &in);
36 std::string sanitizeString(const std::string &in, const std::string &forbidden);
37 std::string removeBlanks(const std::string &in);
38 std::vector<std::string> SplitOLFileName(const std::string &in);
39 std::vector<std::string> SplitOLHostName(const std::string &in);
40 std::string FixOLPath(const std::string &in);
41 std::string FixPathName(const std::string &in);
42 std::string FixWindowsQuotes(const std::string &in);
43 std::string QuoteExecPath(const std::string &in);
44 std::string unquote(const std::string &in);
45 
46 // Parser TOOLS
47 int enclosed(const std::string &in, std::vector<std::string> &arguments,
48              size_t &end);
49 int extract(const std::string &in, std::string &paramName, std::string &action,
50             std::vector<std::string> &arguments);
51 std::string extractExpandPattern(const std::string &str);
52 
53 typedef std::vector<std::vector<double> > array;
54 array read_array(std::string fileName, char sep);
55 double find_in_array(int i, int j,
56                      const std::vector<std::vector<double> > &data);
57 
getShortName(const std::string & name)58 static std::string getShortName(const std::string &name)
59 {
60   std::string s = name;
61   // remove path
62   std::string::size_type last = name.find_last_of('/');
63   if(last != std::string::npos) s = name.substr(last + 1);
64   // remove starting numbers
65   while(s.size() && s[0] >= '0' && s[0] <= '9') s = s.substr(1);
66   return s;
67 }
68 
69 class ShortNameLessThan {
70 public:
operator()71   bool operator()(const std::string p1, const std::string p2) const
72   {
73     return getShortName(p1) < getShortName(p2);
74   }
75 };
76 
77 void preProcess(const std::string &client, const std::string &fullName);
78 
79 /*
80 VIRTUAL and BASE CLASSES
81 
82 "localSolverClient" is the base class
83 for all onelab clients called from a metamodel.
84 It inherits from the "LocalClient" class of "onelab.h"
85 and has the additional metamodel specific functions:
86 analyze(), compute(), checkIfPresent(), checkCommandLine(),
87 inputFile(), outputFile()
88 
89 The subclass "localSolverNetworkClient" of "localSolverClient"
90 is for native clients (Gmsh and getDP so far)
91 that communicate with the server through sockets.
92 It has a GmshServer member,
93 uses localNetworkSolverClient::run instead of onelab::client::run().
94 
95 Both "localSolverNetworkClient" and "localSolverClient" are pure virtual.
96 
97 Encapsulated clients are interfaced clients called through a gmsh capsule
98 so that the GUI may remain active.
99 
100 The base class "remoteClient" is a base class
101 for clients running on a remote host.
102 It provides appropriate versions of checkIfPresent() and checkCommandLine().
103 
104 The combination of native/interfaced/encapsulated and local/remote
105 yields 6 clients:
106 NativeClient, RemoteINterfacedClient
107 InterfacedClient, RemoteInterfacesClient
108 Encapsulated, RemoteEncapsulated
109 */
110 class localSolverClient : public onelab::localClient {
111 private:
112   std::string _commandLine;
113   std::string _workingDir;
114   bool _remote;
115   int _active;
116   bool _onelabBlock;
117   std::set<std::string, ShortNameLessThan> _parameters;
118   std::string longName(const std::string name);
119 
120 public:
localSolverClient(const std::string & name,const std::string & cmdl,const std::string & wdir)121   localSolverClient(const std::string &name, const std::string &cmdl,
122                     const std::string &wdir)
123     : onelab::localClient(name), _commandLine(cmdl), _workingDir(wdir),
124       _remote(false), _active(0), _onelabBlock(false)
125   {
126   }
~localSolverClient()127   virtual ~localSolverClient() {}
getCommandLine()128   const std::string &getCommandLine() { return _commandLine; }
getWorkingDir()129   const std::string &getWorkingDir() { return _workingDir; }
setCommandLine(const std::string & s)130   virtual void setCommandLine(const std::string &s) { _commandLine = s; }
setWorkingDir(const std::string & s)131   virtual void setWorkingDir(const std::string &s) { _workingDir = s; }
132 
133   void setAction(const std::string action);
134   const std::string getString(const std::string what);
135   const bool getList(const std::string type, std::vector<std::string> &choices);
isRemote()136   const bool isRemote() { return _remote; }
setRemote(bool flag)137   const void setRemote(bool flag) { _remote = flag; }
isActive()138   const bool isActive() { return (bool)_active; }
setActive(int val)139   const void setActive(int val) { _active = val; }
getActive()140   int getActive() { return _active; }
141   virtual std::string toChar();
142 
143   // parser commands
144   void modify_tags(const std::string lab, const std::string com);
isOnelabBlock()145   const bool isOnelabBlock() { return _onelabBlock; }
openOnelabBlock()146   const void openOnelabBlock() { _onelabBlock = true; }
closeOnelabBlock()147   const void closeOnelabBlock() { _onelabBlock = false; }
148   std::string resolveString(const std::string &line);
149   std::string resolveGetVal(std::string line);
150   bool resolveLogicExpr(std::vector<std::string> arguments);
151   bool resolveRange(const std::string &in, std::vector<double> &arguments);
152   void parse_sentence(std::string line);
153   void parse_oneline(std::string line, std::ifstream &infile);
154   bool parse_block(std::ifstream &infile);
155   bool parse_ifstatement(std::ifstream &infile, bool condition);
156   bool parse_onefile(std::string ifileName, bool mandatory = true);
157   void convert_oneline(std::string line, std::ifstream &infile,
158                        std::ofstream &outfile);
159   bool convert_ifstatement(std::ifstream &infile, std::ofstream &outfile,
160                            bool condition);
161   void convert_onefile(std::string ifileName, std::ofstream &outfile);
162   virtual void client_sentence(const std::string &name,
163                                const std::string &action,
164                                const std::vector<std::string> &arguments);
165 
166   // execution
167   bool buildRmCommand(std::string &cmd);
isNative()168   virtual bool isNative() { return false; }
169   void FixExecPath(const std::string &in);
170   virtual bool checkCommandLine();
171   virtual void analyze() = 0;
172   virtual void compute() = 0;
173   void addNumberChoice(std::string name, double val, bool readOnly = false);
174   void PostArray(std::vector<std::string> choices);
175   void GmshMerge(std::vector<std::string> choices);
176 };
177 
178 class localNetworkSolverClient : public localSolverClient {
179 private:
180   // command line option to specify socket
181   std::string _socketSwitch;
182   // pid of the remote network client
183   int _pid;
184   // underlying GmshServer
185   GmshServer *_gmshServer;
186   // flag indicating whether socket communication should be monitored
187   bool _socketMsg;
188 
189 public:
localNetworkSolverClient(const std::string & name,const std::string & cmdl,const std::string & wdir)190   localNetworkSolverClient(const std::string &name, const std::string &cmdl,
191                            const std::string &wdir)
192     : localSolverClient(name, cmdl, wdir), _socketSwitch("-onelab"), _pid(-1),
193       _gmshServer(0), _socketMsg(false)
194   {
195   }
~localNetworkSolverClient()196   virtual ~localNetworkSolverClient() {}
isNetworkClient()197   virtual bool isNetworkClient() { return true; }
getSocketSwitch()198   const std::string &getSocketSwitch() { return _socketSwitch; }
setSocketSwitch(const std::string & s)199   void setSocketSwitch(const std::string &s) { _socketSwitch = s; }
getPid()200   int getPid() { return _pid; }
setPid(int pid)201   void setPid(int pid) { _pid = pid; }
getGmshServer()202   GmshServer *getGmshServer() { return _gmshServer; }
setGmshServer(GmshServer * server)203   void setGmshServer(GmshServer *server) { _gmshServer = server; }
204   bool receiveMessage();
205 
isNative()206   bool isNative() { return true; }
207   virtual std::string buildCommandLine();
208   std::string appendArguments();
209   virtual bool run();
210   virtual bool kill();
211 
212   virtual void analyze() = 0;
213   virtual void compute() = 0;
214 };
215 
216 class remoteClient {
217 private:
218   std::string _remoteHost;
219   std::string _remoteDir;
220 
221 public:
remoteClient(const std::string & host,const std::string & rdir)222   remoteClient(const std::string &host, const std::string &rdir)
223     : _remoteHost(host), _remoteDir(rdir)
224   {
225   }
~remoteClient()226   ~remoteClient() {}
227 
getRemoteHost()228   const std::string &getRemoteHost() const { return _remoteHost; }
getRemoteDir()229   const std::string &getRemoteDir() const { return _remoteDir; }
230 
231   bool checkCommandLine(const std::string &commandLine);
232   bool checkIfPresentRemote(const std::string &fileName);
233   bool syncInputFile(const std::string &wdir, const std::string &fileName);
234   bool syncOutputFile(const std::string &wdir, const std::string &fileName);
235 };
236 
237 // ONELAB CLIENTS
238 
239 class MetaModel : public localSolverClient {
240 private:
241   // clients in order of appearance in the metamodel
242   std::vector<localSolverClient *> _clients;
243   // action performed at this metamodel call
244   parseMode _todo;
245   // remains false as long as the successive clients need no recomputation
246   bool _started;
247 
248 public:
MetaModel(const std::string & cmdl,const std::string & wdir,const std::string & cname,const std::string & fname)249   MetaModel(const std::string &cmdl, const std::string &wdir,
250             const std::string &cname, const std::string &fname)
251     : localSolverClient(cname, cmdl, wdir)
252   {
253     clientName = cname;
254     genericNameFromArgs = fname.size() ? fname : cmdl;
255     setWorkingDir(wdir); // wdir from args
256     _todo = REGISTER;
257     _started = false;
258     construct();
259   }
~MetaModel()260   ~MetaModel() {}
261   typedef std::vector<localSolverClient *>::iterator citer;
setTodo(const parseMode x)262   void setTodo(const parseMode x) { _todo = x; }
getTodo()263   parseMode getTodo() { return _todo; }
isTodo(const parseMode x)264   bool isTodo(const parseMode x) { return (_todo == x); }
isStarted(bool x)265   bool isStarted(bool x)
266   {
267     _started = _started || x;
268     return _started;
269   }
firstClient()270   citer firstClient() { return _clients.begin(); }
lastClient()271   citer lastClient() { return _clients.end(); }
getNumClients()272   int getNumClients() { return _clients.size(); };
273 
274   void registerClient(const std::string &name, const std::string &type,
275                       const std::string &cmdl, const std::string &host,
276                       const std::string &rdir);
277   bool checkCommandLines();
278   void saveCommandLines();
279   bool findCommandLine(const std::string &client, const std::string &host);
findClientByName(std::string name)280   localSolverClient *findClientByName(std::string name)
281   {
282     for(unsigned int i = 0; i < _clients.size(); i++)
283       if(_clients[i]->getName() == name) return _clients[i];
284     return 0;
285   }
showClientStatus()286   void showClientStatus()
287   {
288     for(citer it = firstClient(); it < lastClient(); it++) {
289       bool changed = onelab::server::instance()->getChanged((*it)->getName());
290       std::cout << "(" << changed << ") " << (*it)->getName() << std::endl;
291     }
292   }
293 
294   std::string genericNameFromArgs, clientName;
295   void client_sentence(const std::string &name, const std::string &action,
296                        const std::vector<std::string> &arguments);
toChar()297   std::string toChar() { return ""; }
298   void PostArray(std::vector<std::string> choices);
299   void construct();
300   void analyze();
301   void compute();
302 };
303 
304 class InterfacedClient : public localSolverClient {
305   // n'utilise pas localNetworkSolverClient::run mais client::run()
306 public:
InterfacedClient(const std::string & name,const std::string & cmdl,const std::string & wdir)307   InterfacedClient(const std::string &name, const std::string &cmdl,
308                    const std::string &wdir)
309     : localSolverClient(name, cmdl, wdir)
310   {
311   }
~InterfacedClient()312   ~InterfacedClient() {}
313 
314   void analyze();
315   void convert();
316   virtual void compute();
317 };
318 
319 class NativeClient : public localNetworkSolverClient {
320 public:
NativeClient(const std::string & name,const std::string & cmdl,const std::string & wdir)321   NativeClient(const std::string &name, const std::string &cmdl,
322                const std::string &wdir)
323     : localNetworkSolverClient(name, cmdl, wdir)
324   {
325   }
~NativeClient()326   ~NativeClient() {}
327 
328   virtual void analyze();
329   virtual void compute();
330 };
331 
332 class EncapsulatedClient : public localNetworkSolverClient {
333 public:
EncapsulatedClient(const std::string & name,const std::string & cmdl,const std::string & wdir)334   EncapsulatedClient(const std::string &name, const std::string &cmdl,
335                      const std::string &wdir)
336     : localNetworkSolverClient(name, cmdl, wdir)
337   {
338     setSocketSwitch("-lol");
339   }
~EncapsulatedClient()340   ~EncapsulatedClient() {}
341 
342   std::string buildCommandLine();
343   void analyze();
344   void convert();
345   void compute();
346 };
347 
348 class RemoteInterfacedClient
349   : public InterfacedClient
350   , public remoteClient {
351 public:
RemoteInterfacedClient(const std::string & name,const std::string & cmdl,const std::string & wdir,const std::string & host,const std::string & rdir)352   RemoteInterfacedClient(const std::string &name, const std::string &cmdl,
353                          const std::string &wdir, const std::string &host,
354                          const std::string &rdir)
355     : InterfacedClient(name, cmdl, wdir), remoteClient(host, rdir)
356   {
357     setRemote(true);
358   }
~RemoteInterfacedClient()359   ~RemoteInterfacedClient() {}
360 
361   bool checkCommandLine();
362   // uses InterfacedClient::analyze()
363   void compute();
364 };
365 
366 class RemoteNativeClient
367   : public NativeClient
368   , public remoteClient {
369 public:
RemoteNativeClient(const std::string & name,const std::string & cmdl,const std::string & wdir,const std::string & host,const std::string & rdir)370   RemoteNativeClient(const std::string &name, const std::string &cmdl,
371                      const std::string &wdir, const std::string &host,
372                      const std::string &rdir)
373     : NativeClient(name, cmdl, wdir), remoteClient(host, rdir)
374   {
375     setRemote(true);
376   }
~RemoteNativeClient()377   ~RemoteNativeClient() {}
378 
379   std::string buildCommandLine();
380   bool checkCommandLine();
381   void analyze();
382   void compute();
383 };
384 
385 class RemoteEncapsulatedClient
386   : public EncapsulatedClient
387   , public remoteClient {
388 public:
RemoteEncapsulatedClient(const std::string & name,const std::string & cmdl,const std::string & wdir,const std::string & host,const std::string & rdir)389   RemoteEncapsulatedClient(const std::string &name, const std::string &cmdl,
390                            const std::string &wdir, const std::string &host,
391                            const std::string &rdir)
392     : EncapsulatedClient(name, cmdl, wdir), remoteClient(host, rdir)
393   {
394     setRemote(true);
395   }
~RemoteEncapsulatedClient()396   ~RemoteEncapsulatedClient() {}
397 
398   std::string buildCommandLine();
399   bool checkCommandLine();
400   void compute();
401 };
402 #endif
403