The Battle for Wesnoth  1.15.2+dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
19 #include <cassert>
20 #include <stdexcept>
21 #include <string>
22 #include <vector>
23 
24 #include "log.hpp"
25 
26 static lg::log_domain log_plugins("plugins");
27 #define DBG_PLG LOG_STREAM(debug, log_plugins)
28 #define LOG_PLG LOG_STREAM(info, log_plugins)
29 #define WRN_PLG LOG_STREAM(warn, log_plugins)
30 #define ERR_PLG LOG_STREAM(err, log_plugins)
31 
32 
33 struct plugin {
34  std::string name;
35  std::string source;
36  bool is_file;
37  std::unique_ptr<application_lua_kernel::thread> thread;
38  std::vector<plugins_manager::event> queue;
39 };
40 
41 static plugins_manager * singleton = nullptr;
42 
44  : plugins_()
45  , playing_()
46  , kernel_(kernel)
47 {
48  assert(!singleton);
49  singleton = this;
50 
51  kernel_->load_core();
52  add_plugin("Null Plugin", "return function() end");
53  start_plugin(0);
54 }
55 
57 
59 {
60  return singleton;
61 }
62 
64 {
65  return kernel_.get();
66 }
67 
68 std::size_t plugins_manager::size() {
69  return plugins_.size();
70 }
71 
72 plugins_manager::STATUS plugins_manager::get_status(std::size_t idx) {
73  if (idx < plugins_.size()) {
74  if (!plugins_[idx].thread) {
76  } else {
77  return plugins_[idx].thread->is_running() ? plugins_manager::STATUS::RUNNING : plugins_manager::STATUS::STOPPED;
78  }
79  }
80  throw std::runtime_error("index out of bounds");
81 }
82 
83 std::string plugins_manager::get_detailed_status(std::size_t idx) {
84  if (idx < plugins_.size()) {
85  if (!plugins_[idx].thread) {
86  return "not loaded";
87  } else {
88  return plugins_[idx].thread->status();
89  }
90  }
91  throw std::runtime_error("index out of bounds");
92 }
93 
94 std::string plugins_manager::get_name(std::size_t idx) {
95  if (idx < plugins_.size()) {
96  return plugins_[idx].name;
97  }
98  throw std::runtime_error("index out of bounds");
99 }
100 
101 void plugins_manager::start_plugin(std::size_t idx)
102 {
103  DBG_PLG << "start_plugin[" << idx <<"]\n";
104  if (idx < plugins_.size()) {
105  if (!plugins_[idx].thread) {
106  DBG_PLG << "creating thread[" << idx << "]\n";
107  plugins_[idx].thread.reset(plugins_[idx].is_file ?
108  kernel_->load_script_from_file(plugins_[idx].source) : kernel_->load_script_from_string(plugins_[idx].source));
109  DBG_PLG << "finished [" << idx << "], status = '" << plugins_[idx].thread->status() << "'\n";
110  } else {
111  DBG_PLG << "thread already exists, skipping\n";
112  }
113  return ;
114  }
115  throw std::runtime_error("index out of bounds");
116 }
117 
118 std::size_t plugins_manager::add_plugin(const std::string & name, const std::string & prog)
119 {
120  std::size_t idx = plugins_.size();
121  plugins_.push_back(new plugin);
122 
123  plugin & p = plugins_[idx];
124  p.name = name;
125  p.source = prog;
126  p.is_file = false;
127 
128  return idx;
129 }
130 
131 std::size_t plugins_manager::load_plugin(const std::string & name, const std::string & filename)
132 {
133  std::size_t idx = plugins_.size();
134  plugins_.push_back(new plugin);
135 
136  plugin & p = plugins_[idx];
137  p.name = name;
138  p.source = filename;
139  p.is_file = true;
140 
141  return idx;
142 }
143 
144 void plugins_manager::notify_event(const std::string & name, const config & data)
145 {
146  event evt;
147  evt.name = name;
148  evt.data = data;
149 
150  for (std::size_t idx = 0; idx < size(); ++idx)
151  {
152  if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
153  plugins_[idx].queue.push_back(evt);
154  }
155  }
156 }
157 
159 {
160  if (playing_) {
161  *playing_ = false; //this is to ensure "reentrancy" -- any previous calls to this function that never returned
162  //and looped back into the plugins system, should be halted and their later requests discarded
163  //this is to ensure the semantics that if a plugins context is left, then any pending requests
164  //are discarded to prevent them from being executed at an improper time
165  }
166  playing_ = std::make_shared<bool> (true);
167  std::shared_ptr<bool> local = playing_; //make a local copy of the pointer on the stack
168 
169  for (std::size_t idx = 0; idx < size(); ++idx)
170  {
171  DBG_PLG << "play_slice[" << idx << "] ... \n";
172  if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
173  DBG_PLG << "is running...";
174  if (!*local) { //check playing_ before each call to be sure that we should still continue
175  DBG_PLG << "aborting\n";
176  return;
177  }
178 
179  std::vector<event> input = plugins_[idx].queue; //empty the queue to a temporary variable
180  plugins_[idx].queue = std::vector<event>();
181 
182  //application_lua_kernel::requests_list requests =
183  std::vector<std::function<bool(void)>> requests =
184  plugins_[idx].thread->run_script(ctxt, input);
185 
186  DBG_PLG << "thread returned " << requests.size() << " requests\n";
187 
188  for (std::size_t j = 0; j < requests.size(); ++j) {
189  if (!*local) return; //check playing_ before each call to be sure that we should still continue
190  if (!requests[j]()) {
191  *local = false;
192  return ; //call the function but if it returns false (error) then stop
193  }
194  }
195 
196  DBG_PLG << "play_slice[" << idx << "] finished.\n";
197  } else if (!plugins_[idx].thread) {
198  DBG_PLG << "thread ["<< idx << "] not created\n";
199  } else {
200  DBG_PLG << "thread ["<< idx << "] not running\n";
201  }
202  }
203  *local = false;
204 }
205 
207 {
208 
209  for (std::size_t i = 0; i < size(); ++i) {
210  if (STATUS::RUNNING == get_status(i)) {
211  return true;
212  }
213  }
214  return false;
215 }
std::string name
Definition: manager.cpp:34
#define DBG_PLG
Definition: manager.cpp:27
bool is_file
Definition: manager.cpp:36
std::unique_ptr< application_lua_kernel::thread > thread
Definition: manager.cpp:37
std::string source
Definition: manager.cpp:35
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
void start_plugin(std::size_t idx)
Definition: manager.cpp:101
std::string get_name(std::size_t idx)
Definition: manager.cpp:94
boost::ptr_vector< plugin > plugins_
Definition: manager.hpp:70
static plugins_manager * singleton
Definition: manager.cpp:41
std::size_t i
Definition: function.cpp:933
std::size_t add_plugin(const std::string &name, const std::string &prog)
Definition: manager.cpp:118
Default, unset return value.
Definition: retval.hpp:31
mock_party p
std::vector< plugins_manager::event > queue
Definition: manager.cpp:38
void play_slice(const plugins_context &)
Definition: manager.cpp:158
std::shared_ptr< bool > playing_
Definition: manager.hpp:71
bool any_running()
Definition: manager.cpp:206
std::string get_detailed_status(std::size_t idx)
Definition: manager.cpp:83
Standard logging facilities (interface).
std::size_t load_plugin(const std::string &name, const std::string &filename)
Definition: manager.cpp:131
lua_kernel_base * get_kernel_base()
Definition: manager.cpp:63
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:144
static lg::log_domain log_plugins("plugins")
std::unique_ptr< application_lua_kernel > kernel_
Definition: manager.hpp:72
static plugins_manager * get()
Definition: manager.cpp:58
plugins_manager(application_lua_kernel *)
Definition: manager.cpp:43