Minsky: 3.17.0
addon.cc
Go to the documentation of this file.
1 /*
2  @copyright Steve Keen 2021
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
21 #include <napi.h>
22 #include "RESTMinsky.h"
23 #include "minsky_epilogue.h"
24 
25 #include <exception>
26 #include <atomic>
27 #include <future>
28 #include <filesystem>
29 
30 #ifdef _WIN32
31 #include <time.h>
32 #else
33 #include <sys/times.h>
34 #endif
35 
36 using namespace Napi;
37 using namespace std;
38 using namespace classdesc;
39 using namespace boost::posix_time;
40 
41 namespace
42 {
43 
44  // all NAPI calls involving an Env must be called on Javascript's
45  // thread. In order to pass something back to Javascript's thread,
46  // we need to use a ThreadSafeFunction
48  {
49  Promise::Deferred promise;
50  bool success;
51  string result;
52 
53  void doResolve();
54  void resolve(const std::string& result) {
55  success=true;
56  this->result=result;
57  doResolve();
58  }
59  void reject(const std::string& error) {
60  success=false;
61  result=error;
62  doResolve();
63  }
64 
65  PromiseResolver(const Napi::Env& env):
66  promise(env)
67  {}
68  };
69 
70  // function called back from Javascript eventually
71  void resolvePromise(Napi::Env env, Napi::Function, void*, PromiseResolver* promiseResolver)
72  {
73  if (!promiseResolver) return;
74  // Javascript needs the result returned as UTF-16.
75  auto result=String::New(env, utf_to_utf<char16_t>(promiseResolver->result));
76  if (promiseResolver->success)
77  promiseResolver->promise.Resolve(result);
78  else
79  promiseResolver->promise.Reject(result);
80  delete promiseResolver; // cleans up object allocated in Command::Command() below
81  }
82 
83  TypedThreadSafeFunction<void,PromiseResolver,resolvePromise> tsPromiseResolver;
84 
85  void PromiseResolver::doResolve() {
86  tsPromiseResolver.BlockingCall(this);
87  }
88 
89  struct Command
90  {
92  string command;
93  json_pack_t arguments;
94  Command(const Napi::Env& env, const string& command, const json_pack_t& arguments):
95  promiseResolver(new PromiseResolver(env)), // ownership passed to JS interpreter
96  command(command),
97  arguments(arguments) {}
98  };
99 
100  struct Times
101  {
102  unsigned long counts;
103  double elapsed, user, system;
104  clock_t start_e, start_u, start_s;
105  bool started;
106  Times(): counts(0), elapsed(0), user(0), system(0), started(false) {}
107 
108  void start()
109  {
110  if (started) return;
111  started = true;
112  counts++;
113 
114 #ifdef _WIN32
115  start_e=clock();
116 #else
117  struct tms tbuf;
118  start_e = times(&tbuf);
119  start_u = tbuf.tms_utime;
120  start_s = tbuf.tms_stime;
121 #endif
122  }
123 
124  void stop()
125  {
126  if (!started) return;
127  started = false;
128 
129 #ifdef _WIN32
130  static const double seconds=1.0/CLOCKS_PER_SEC;
131  elapsed+=(clock()-start_e)*seconds;
132 #else
133 #ifdef __linux__
134  static const double seconds=1.0/sysconf(_SC_CLK_TCK);
135 #else
136  static const double seconds=1.0/CLK_TCK;
137 #endif
138  struct tms tbuf;
139  elapsed += (times(&tbuf)-start_e)*seconds;
140  user += (tbuf.tms_utime-start_u)*seconds;
141  system += (tbuf.tms_stime-start_s)*seconds;
142 #endif
143  }
144  };
145 
146 #ifdef TIMERS
147  class Timer
148  {
149  Times& timer;
150  public:
151  Timer(Times& timer): timer(timer) {timer.start();}
152  ~Timer() {timer.stop();}
153  };
154 
155  class Timers: public map<string, Times>
156  {
157  Times overall;
158  public:
159  Timers() {overall.start();}
160  ~Timers() {
161  overall.stop();
162  vector<pair<string,Times>> times(begin(),end());
163  sort(times.begin(),times.end(),[](auto& i, auto& j){return i.second.elapsed>j.second.elapsed;});
164  cout<<setw(40)<<"Times"<<setw(10)<<"Elapsed"<<setw(10)<<"User"<<setw(10)<<"System"<<endl;
165  cout<<setw(40)<<"Overall"<<setw(10)<<overall.elapsed<<setw(10)<<overall.user<<setw(10)<<overall.system<<endl;
166  for (auto& [command,timer]: times)
167  cout<<setw(40)<<command<<setw(10)<<timer.elapsed<<setw(10)<<timer.user<<setw(10)<<timer.system<<endl;
168  }
169  };
170 #else // dummiable
171  struct Timer
172  {
173  Timer(int) {}
174  };
175  struct Timers
176  {
177  int operator[](const string&) {return 0;}
178  };
179 #endif
180 
181 }
182 
183 namespace minsky
184 {
185  namespace
186  {
187  // ensure access to only one global Minsky object at a time,
188  // particular needed for jest tests, which run in parallel
190 
191  struct AddOnMinsky: public RESTMinsky
192  {
193  Timers timers;
194  deque<unique_ptr<Command>> minskyCommands;
195  mutex cmdMutex;
196  atomic<bool> running{true};
197  std::thread thread;
198  bool inputBufferExceeded=false;
199 
200  AddOnMinsky(): thread([this](){run();}) {
201  flags=0;
202  }
203 
205  running=false;
206  if (thread.joinable()) thread.join();
207  }
208 
209  Value queueCommand(Env env, string command, const json_pack_t& arguments)
210  {
211  static const std::string sync=".$sync";
212  if (command.ends_with(sync))
213  {
214  command.erase(command.size()-sync.length());
215  // Javascript needs the result returned as UTF-16.
216  return String::New(env, utf_to_utf<char16_t>(doCommand(command, arguments)));
217  }
218 #if defined(_WIN32) || defined(MAC_OSX_TK)
219  // renderFrame needs to be called synchronously, otherwise inexplicable hangs occur on Windows.
220  if (command.ends_with(".renderFrame"))
221  return String::New(env, utf_to_utf<char16_t>(doCommand(command, arguments)));
222 #endif
223  if (minskyCommands.size()>20)
224  {
225  if (!inputBufferExceeded) setBusyCursor();
226  inputBufferExceeded=true;
227  return env.Null();
228  }
229  if (inputBufferExceeded) clearBusyCursor(); // single shot clear of busy curser
230  inputBufferExceeded=false;
231  const lock_guard<mutex> lock(cmdMutex);
232  minskyCommands.emplace_back(new Command{env,command,arguments});
233  return minskyCommands.back()->promiseResolver->promise.Promise();
234  }
235 
236  string doCommand(const string& command, const json_pack_t& arguments)
237  {
238  const lock_guard<mutex> lock(minskyCmdMutex);
239  const Timer timer(timers[command]);
240 
241  // if reset requested, postpone it
242  if (reset_flag()) requestReset();
243 
244  civita::ITensor::cancel(false);
245  // disable quoting wide characters in UTF-8 strings
246  auto result=write(registry.process(command, arguments)->asBuffer(),json5_parser::raw_utf8);
247  commandHook(command,arguments);
248  return result;
249  }
250 
252  {
253  const lock_guard<mutex> lock(minskyCmdMutex);
254  const Timer timer(timers["draw"]);
255  for (auto i: nativeWindowsToRedraw)
256  try
257  {
258  i->draw();
259  }
260  catch (const std::exception& ex)
261  {
262  /* absorb and log any exceptions, cannot do anything anyway */
263  cerr << ex.what() << endl;
264  break;
265  }
266  catch (...) {break;}
267  nativeWindowsToRedraw.clear();
268  }
269 
270  // arrange for native window drawing to happen on node's main thread, required for MacOSX.
271  atomic<bool> drawLaunched{false};
272  static void tsDrawNativeWindows(Napi::Env env, Napi::Function, AddOnMinsky* minsky, void*)
273  {minsky->macOSXDrawNativeWindows();}
274 
275  TypedThreadSafeFunction<AddOnMinsky,void,tsDrawNativeWindows> tsDrawNativeWindows_;
276 
278  {
279  // share the lock with all window redraw routines - when all windows redrawn, lock is released
280  auto lock=make_shared<lock_guard<mutex>>(minskyCmdMutex);
281  const Timer timer(timers["draw"]);
282  for (auto i: nativeWindowsToRedraw)
283  macOSXRedraw(*i,lock);
284  nativeWindowsToRedraw.clear();
285  drawLaunched=false;
286  }
287 
289  {
290  drawLaunched=true;
291  tsDrawNativeWindows_.BlockingCall(this);
292  }
293 
294  void run()
295  {
296 #if defined(_PTHREAD_H) && defined(__USE_GNU) && !defined(NDEBUG)
297  pthread_setname_np(pthread_self(),"minsky thread");
298 #endif
299  while (running)
300  {
301  unique_ptr<Command> command;
302  {
303  const lock_guard<mutex> lock(cmdMutex);
304  if (!minskyCommands.empty())
305  {
306  command=std::move(minskyCommands.front());
307  minskyCommands.pop_front();
308  }
309  }
310 
311  if (!command) // perform housekeeping
312  {
313  if (reset_flag() && resetDuration<resetPostponedThreshold && resetAt<std::chrono::system_clock::now())
314  try
315  {
316  const lock_guard<mutex> lock(minskyCmdMutex);
317  if (reset_flag()) // check again, in case another thread got there first
318  {
319  const Timer timer(timers["minsky.reset"]);
320  reset();
321  }
322  }
323  catch (...)
324  {flags&=~reset_needed;}
325 #ifdef MAC_OSX_TK
326  if (!drawLaunched && nativeWindowsToRedraw.size())
327  macOSXLaunchDrawNativeWindows();
328 #else
329  drawNativeWindows();
330 #endif
331  if (inputBufferExceeded && minskyCommands.empty())
332  {
333  // clears busy cursor when no commands are being received or processed
334  clearBusyCursor();
335  inputBufferExceeded=false;
336  }
337  this_thread::sleep_for(chrono::milliseconds(10));
338  continue;
339  }
340 
341  if (!running) return;
342  try
343  {
344  auto result=doCommand(command->command, command->arguments);
345  if (!running) return; // prevent crashes on shutdown
346  command->promiseResolver->resolve(result);
347  }
348  catch (const std::exception& ex)
349  {
350  if (!running) return; // prevent crashes on shutdown
351  command->promiseResolver->reject(ex.what());
352  }
353  catch (...)
354  {
355  if (!running) return; // prevent crashes on shutdown
356  command->promiseResolver->reject("Unknown exception");
357  }
358  }
359  }
360 
361  mutable string theMessage;
362  mutable vector<string> messageButtons;
363  mutable promise<unsigned> userResponse;
364  static void messageCallback(Napi::Env env, Napi::Function fn, void*, AddOnMinsky* addonMinsky)
365  {
366  auto buttons=Array::New(env);
367  for (unsigned i=0; i< addonMinsky->messageButtons.size(); ++i)
368  buttons[i]=String::New(env,addonMinsky->messageButtons[i]);
369  try {
370  addonMinsky->userResponse.set_value(fn({String::New(env,addonMinsky->theMessage), buttons}).As<Number>().Int32Value());
371  } catch (...) {/* may fail if multiple messages posted in rapid succession */}
372  }
373 
374  bool messageCallbackSet=false;
375  TypedThreadSafeFunction<void,AddOnMinsky,messageCallback> tsMessageCallback;
376  Value setMessageCallback(const Napi::CallbackInfo& info)
377  {
378  const Env env = info.Env();
379  if (info.Length()<1 || !info[0].IsFunction())
380  {
381  Napi::Error::New(env, "Callback not provided").ThrowAsJavaScriptException();
382  }
383  messageCallbackSet=true;
384  tsMessageCallback=TypedThreadSafeFunction<void,AddOnMinsky,messageCallback>::New
385  (env,info[0].As<Function>(), "message",0,2,nullptr);
386 
387  return env.Null();
388  }
389 
390 
391  void message(const std::string& msg) override
392  {
393  if (!messageCallbackSet) return;
394  theMessage=msg;
395  messageButtons.clear(); // empty buttons imply a single OK button
396  userResponse={}; //reset the promise
397  tsMessageCallback.BlockingCall(const_cast<AddOnMinsky*>(this));
398  }
399 
400  MemCheckResult checkMemAllocation(std::size_t bytes) const override {
401  // Electron restricts heap size to 4GiB, regardless of how much physical memory is present
402  if (messageCallbackSet && bytes>/*physicalMem()*/4ULL*1024*1024*1024)
403  {
404  theMessage="Allocation will use more than 50% of available memory. Do you want to proceed?";
405  messageButtons={"No","Yes"};
406  userResponse={}; //reset the promise
407  tsMessageCallback.BlockingCall(const_cast<AddOnMinsky*>(this));
408  return userResponse.get_future().get()? proceed: abort;
409  }
410  return OK;
411  }
412 
413  // signature of last param must be non-const
414  static void busyCursorCallback(Napi::Env env, Napi::Function fn, void*, bool* busy) // NOLINT
415  {
416  fn({Boolean::New(env,*busy)});
417  }
418 
419  bool busyCursorCallbackSet=false;
420  TypedThreadSafeFunction<void,bool,busyCursorCallback> tsBusyCursorCallback;
421  Value setBusyCursorCallback(const Napi::CallbackInfo& info)
422  {
423  const Env env = info.Env();
424  if (info.Length()<1 || !info[0].IsFunction())
425  {
426  Napi::Error::New(env, "Callback not provided").ThrowAsJavaScriptException();
427  }
428  busyCursorCallbackSet=true;
429  tsBusyCursorCallback=TypedThreadSafeFunction<void,bool,busyCursorCallback>::New
430  (env,info[0].As<Function>(), "setBusyCursor",0,2,nullptr);
431  return env.Null();
432  }
433 
434  bool busyCursor=false;
435  void doBusyCursor(bool bc)
436  {
437  if (!busyCursorCallbackSet) return;
438  busyCursor=bc;
439  tsBusyCursorCallback.BlockingCall(&busyCursor);
440  }
441  void setBusyCursor() override
442  {doBusyCursor(true);}
443  void clearBusyCursor() override
444  {doBusyCursor(false);}
445 
446  static void progressCallback(Napi::Env env, Napi::Function fn, void*, AddOnMinsky* addon)
447  {
448  fn({String::New(env,addon->progressTitle), Number::New(env,addon->progressValue)});
449  }
450 
451  int progressValue=0;
453  void progress(const string& title, int x) override
454  {
455  if (!progressCallbackSet) return;
456  progressValue=x;
457  progressTitle=title;
458  tsProgressCallback.BlockingCall(this);
459  }
460  bool progressCallbackSet=false;
461  TypedThreadSafeFunction<void,AddOnMinsky,progressCallback> tsProgressCallback;
462  Value setProgressCallback(const Napi::CallbackInfo& info)
463  {
464  const Env env = info.Env();
465  if (info.Length()<1 || !info[0].IsFunction())
466  {
467  Napi::Error::New(env, "Callback not provided").ThrowAsJavaScriptException();
468  }
469  progressCallbackSet=true;
470  tsProgressCallback=TypedThreadSafeFunction<void,AddOnMinsky,progressCallback>::New
471  (env,info[0].As<Function>(), "progress",0,2,nullptr);
472  return env.Null();
473  }
474 
475  static void bookmarkRefreshCallback(Napi::Env env, Napi::Function fn, void*, AddOnMinsky* addon)
476  {
477  fn({});
478  }
479 
480  void bookmarkRefresh() override
481  {
482  if (!bookmarkRefreshSet) return;
483  tsBookmarkRefreshCallback.BlockingCall(this);
484  }
485  bool bookmarkRefreshSet=false;
486  TypedThreadSafeFunction<void,AddOnMinsky,bookmarkRefreshCallback> tsBookmarkRefreshCallback;
487  Value setBookmarkRefreshCallback(const Napi::CallbackInfo& info)
488  {
489  const Env env = info.Env();
490  if (info.Length()<1 || !info[0].IsFunction())
491  {
492  Napi::Error::New(env, "Callback not provided").ThrowAsJavaScriptException();
493  }
494  bookmarkRefreshSet=true;
495  tsBookmarkRefreshCallback=TypedThreadSafeFunction<void,AddOnMinsky,bookmarkRefreshCallback>::New
496  (env,info[0].As<Function>(), "refreshBookmark",0,2,nullptr);
497  return env.Null();
498  }
499 
500  static void resetScrollCallback(Napi::Env env, Napi::Function fn, void*, AddOnMinsky* addon)
501  {
502  fn({});
503  }
504 
505  void resetScroll() override
506  {
507  if (!resetScrollSet) return;
508  tsResetScrollCallback.BlockingCall(this);
509  }
510  bool resetScrollSet=false;
511  TypedThreadSafeFunction<void,AddOnMinsky,resetScrollCallback> tsResetScrollCallback;
512  Value setResetScrollCallback(const Napi::CallbackInfo& info)
513  {
514  const Env env = info.Env();
515  if (info.Length()<1 || !info[0].IsFunction())
516  {
517  Napi::Error::New(env, "Callback not provided").ThrowAsJavaScriptException();
518  }
519  resetScrollSet=true;
520  tsResetScrollCallback=TypedThreadSafeFunction<void,AddOnMinsky,resetScrollCallback>::New
521  (env,info[0].As<Function>(), "resetScroll",0,2,nullptr);
522  return env.Null();
523  }
525  {
526  string file=(std::filesystem::current_path()/"savedRavelSession.rvl").string();
527  if (autoSaver) {
528  autoSaver->killThread();
529  file=autoSaver->fileName;
530  }
531  save(file);
532 
533  theMessage="Out of memory, saving to autosave file: "+file;
534  messageButtons={"OK"};
535  userResponse={}; //reset the promise
536  tsMessageCallback.BlockingCall(const_cast<AddOnMinsky*>(this));
537  userResponse.get_future().get();
538  }
539  };
540 
541  Minsky s_minsky; //This object is not really used, needed to avoid a null dereference in minsky()
542  Minsky* l_minsky=&s_minsky; //weak reference to global Minsky object
543  }
544 
545  Minsky& minsky() {return *l_minsky;}
546 
547  // Needed only to solve linkage problems
548  LocalMinsky::LocalMinsky(Minsky& minsky) {}
549  LocalMinsky::~LocalMinsky() {}
550  void doOneEvent(bool idleTasksOnly) {}
551 
552 }
553 
554 void handleSignal(int)
555 {
556  static_cast<minsky::AddOnMinsky&>(minsky::minsky()).outOfMemoryHandler();
557  exit(1); // NOLINT
558 }
559 
560 struct MinskyAddon: public Addon<MinskyAddon>
561 {
562  // Actual global minsky object needs to be declared here, to ensure
563  // threads are started and torn down at the right point in time.
564  minsky::AddOnMinsky addOnMinsky;
565 
566  MinskyAddon(Env env, Napi::Object exports)
567  {
568  minsky::l_minsky=&addOnMinsky; // set the global minsky object
569  tsPromiseResolver=TypedThreadSafeFunction<void,PromiseResolver,resolvePromise>::
570  New(env,"TSResolver", 0, 2, nullptr);
571  addOnMinsky.tsDrawNativeWindows_=
572  TypedThreadSafeFunction<minsky::AddOnMinsky,void,minsky::AddOnMinsky::tsDrawNativeWindows>::
573  New(env,"TSDrawNativeWindows",0, 2,&addOnMinsky);
574 
575  DefineAddon(exports, {
576  InstanceMethod("call", &MinskyAddon::call),
577  InstanceMethod("setMessageCallback", &MinskyAddon::setMessageCallback),
578  InstanceMethod("setBusyCursorCallback", &MinskyAddon::setBusyCursorCallback),
579  InstanceMethod("setProgressCallback", &MinskyAddon::setProgressCallback),
580  InstanceMethod("setBookmarkRefreshCallback", &MinskyAddon::setBookmarkRefreshCallback),
581  InstanceMethod("setResetScrollCallback", &MinskyAddon::setResetScrollCallback),
582  InstanceMethod("cancelProgress", &MinskyAddon::cancelProgress)
583  });
584 #ifndef _WIN32
585  signal(SIGTRAP,handleSignal);
586 #endif
587  }
588 
589  Value setMessageCallback(const Napi::CallbackInfo& info) {return addOnMinsky.setMessageCallback(info);}
590  Value setBusyCursorCallback(const Napi::CallbackInfo& info) {return addOnMinsky.setBusyCursorCallback(info);}
591  Value setProgressCallback(const Napi::CallbackInfo& info) {return addOnMinsky.setProgressCallback(info);}
592  Value setBookmarkRefreshCallback(const Napi::CallbackInfo& info) {return addOnMinsky.setBookmarkRefreshCallback(info);}
593  Value setResetScrollCallback(const Napi::CallbackInfo& info) {return addOnMinsky.setResetScrollCallback(info);}
594  Value cancelProgress(const Napi::CallbackInfo& info) {
595  *addOnMinsky.progressState.cancel=true;
596  civita::ITensor::cancel(true);
597  return info.Env().Null();
598  }
599 
600 
601  Value call(const Napi::CallbackInfo& info)
602  {
603  const Env env = info.Env();
604  if (info.Length() < 1)
605  {
606  Napi::TypeError::New(env, "Needs to be call(endpoint[, arguments])").ThrowAsJavaScriptException();
607  return env.Null();
608  }
609 
610 #if defined(_PTHREAD_H) && defined(__USE_GNU) && !defined(NDEBUG)
611  pthread_setname_np(pthread_self(),"addon thread");
612 #endif
613 
614  try
615  {
616  json_pack_t arguments(json5_parser::mValue::null);
617  if (info.Length()>1)
618  {
619  const string jsonArguments=info[1].ToString();
620  if (!jsonArguments.empty())
621  read(jsonArguments, arguments);
622  }
623  return addOnMinsky.queueCommand(env,info[0].ToString(),arguments);
624  }
625  catch (const std::exception& ex)
626  {
627  // throw C++ exception as Javascript exception
628  Napi::Error::New(env, ex.what()).ThrowAsJavaScriptException();
629  return env.Null();
630  }
631  catch (...)
632  {
633  Napi::Error::New(env, "unknown exception caught").ThrowAsJavaScriptException();
634  return env.Null();
635  }
636  }
637 };
638 
Command(const Napi::Env &env, const string &command, const json_pack_t &arguments)
Definition: addon.cc:94
Value setBusyCursorCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:590
Value setBookmarkRefreshCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:487
void doOneEvent(bool idleTasksOnly)
checks if any GUI events are waiting, and proces an event if so
Definition: addon.cc:550
void message(const std::string &msg) override
display a message in a popup box on the GUI
Definition: addon.cc:391
void reject(const std::string &error)
Definition: addon.cc:59
static void resetScrollCallback(Napi::Env env, Napi::Function fn, void *, AddOnMinsky *addon)
Definition: addon.cc:500
TypedThreadSafeFunction< void, AddOnMinsky, messageCallback > tsMessageCallback
Definition: addon.cc:375
minsky::Minsky minsky
Definition: pyminsky.cc:28
MemCheckResult
check whether to proceed or abort, given a request to allocate bytes of memory. Implemented in Minsky...
Definition: minsky.h:449
STL namespace.
TypedThreadSafeFunction< void, AddOnMinsky, bookmarkRefreshCallback > tsBookmarkRefreshCallback
Definition: addon.cc:486
static void tsDrawNativeWindows(Napi::Env env, Napi::Function, AddOnMinsky *minsky, void *)
Definition: addon.cc:272
minsky::AddOnMinsky addOnMinsky
Definition: addon.cc:564
static void messageCallback(Napi::Env env, Napi::Function fn, void *, AddOnMinsky *addonMinsky)
Definition: addon.cc:364
void resetScroll() override
reset main window scroll bars after model has been panned
Definition: addon.cc:505
PromiseResolver * promiseResolver
Definition: addon.cc:91
TypedThreadSafeFunction< AddOnMinsky, void, tsDrawNativeWindows > tsDrawNativeWindows_
Definition: addon.cc:275
string doCommand(const string &command, const json_pack_t &arguments)
Definition: addon.cc:236
Value setMessageCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:589
void macOSXRedraw(RenderNativeWindow &window, const std::shared_ptr< std::lock_guard< std::mutex >> &lock)
TypedThreadSafeFunction< void, bool, busyCursorCallback > tsBusyCursorCallback
Definition: addon.cc:420
MinskyAddon(Env env, Napi::Object exports)
Definition: addon.cc:566
void bookmarkRefresh() override
refresh the bookmark menu after changes
Definition: addon.cc:480
static void progressCallback(Napi::Env env, Napi::Function fn, void *, AddOnMinsky *addon)
Definition: addon.cc:446
void progress(const string &title, int x) override
set progress bar, out of 100, labelling the progress bar with title
Definition: addon.cc:453
void resolve(const std::string &result)
Definition: addon.cc:54
Value setProgressCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:462
deque< unique_ptr< Command > > minskyCommands
Definition: addon.cc:194
Value setResetScrollCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:593
static void busyCursorCallback(Napi::Env env, Napi::Function fn, void *, bool *busy)
Definition: addon.cc:414
Value setBusyCursorCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:421
TypedThreadSafeFunction< void, AddOnMinsky, progressCallback > tsProgressCallback
Definition: addon.cc:461
void setBusyCursor() override
set/clear busy cursor in GUI
Definition: addon.cc:441
TypedThreadSafeFunction< void, AddOnMinsky, resetScrollCallback > tsResetScrollCallback
Definition: addon.cc:511
Value queueCommand(Env env, string command, const json_pack_t &arguments)
Definition: addon.cc:209
Value cancelProgress(const Napi::CallbackInfo &info)
Definition: addon.cc:594
Value setMessageCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:376
Value setBookmarkRefreshCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:592
Value setResetScrollCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:512
Value setProgressCallback(const Napi::CallbackInfo &info)
Definition: addon.cc:591
MemCheckResult checkMemAllocation(std::size_t bytes) const override
Definition: addon.cc:400
Minsky & minsky()
global minsky object
Definition: addon.cc:545
Value call(const Napi::CallbackInfo &info)
Definition: addon.cc:601
NODE_API_ADDON(MinskyAddon)
int operator[](const string &)
Definition: addon.cc:177
TypedThreadSafeFunction< void, PromiseResolver, resolvePromise > tsPromiseResolver
Definition: addon.cc:83
void resolvePromise(Napi::Env env, Napi::Function, void *, PromiseResolver *promiseResolver)
Definition: addon.cc:71
static void bookmarkRefreshCallback(Napi::Env env, Napi::Function fn, void *, AddOnMinsky *addon)
Definition: addon.cc:475
void handleSignal(int)
Definition: addon.cc:554