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 ¶mName, 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