The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Chris Beck <[email protected]>
3  Part of the Battle for Wesnoth Project http://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 <assert.h>
20 #include <boost/ptr_container/ptr_vector.hpp>
21 #include <boost/make_shared.hpp>
22 #include <boost/scoped_ptr.hpp>
23 #include <boost/shared_ptr.hpp>
24 #include <stdexcept>
25 #include <string>
26 #include <vector>
27 
28 #include "log.hpp"
29 
30 static lg::log_domain log_plugins("plugins");
31 #define DBG_PLG LOG_STREAM(debug, log_plugins)
32 #define LOG_PLG LOG_STREAM(info, log_plugins)
33 #define WRN_PLG LOG_STREAM(warn, log_plugins)
34 #define ERR_PLG LOG_STREAM(err, log_plugins)
35 
36 
37 struct plugin {
40  bool is_file;
41  boost::scoped_ptr<application_lua_kernel::thread> thread;
42  std::vector<plugins_manager::event> queue;
43 };
44 
45 static plugins_manager * singleton = nullptr;
46 
48  : plugins_()
49  , playing_()
50  , kernel_(kernel)
51 {
52  assert(!singleton);
53  singleton = this;
54 
55  add_plugin("Null Plugin", "return function() end");
56  start_plugin(0);
57 }
58 
60 
62 {
63  return singleton;
64 }
65 
67 {
68  return kernel_.get();
69 }
70 
71 size_t plugins_manager::size() {
72  return plugins_.size();
73 }
74 
75 plugins_manager::STATUS plugins_manager::get_status(size_t idx) {
76  if (idx < plugins_.size()) {
77  if (!plugins_[idx].thread) {
79  } else {
80  return plugins_[idx].thread->is_running() ? plugins_manager::STATUS::RUNNING : plugins_manager::STATUS::STOPPED;
81  }
82  }
83  throw std::runtime_error("index out of bounds");
84 }
85 
87  if (idx < plugins_.size()) {
88  if (!plugins_[idx].thread) {
89  return "not loaded";
90  } else {
91  return plugins_[idx].thread->status();
92  }
93  }
94  throw std::runtime_error("index out of bounds");
95 }
96 
98  if (idx < plugins_.size()) {
99  return plugins_[idx].name;
100  }
101  throw std::runtime_error("index out of bounds");
102 }
103 
105 {
106  DBG_PLG << "start_plugin[" << idx <<"]\n";
107  if (idx < plugins_.size()) {
108  if (!plugins_[idx].thread) {
109  DBG_PLG << "creating thread[" << idx << "]\n";
110  plugins_[idx].thread.reset(plugins_[idx].is_file ?
111  kernel_->load_script_from_file(plugins_[idx].source) : kernel_->load_script_from_string(plugins_[idx].source));
112  DBG_PLG << "finished [" << idx << "], status = '" << plugins_[idx].thread->status() << "'\n";
113  } else {
114  DBG_PLG << "thread already exists, skipping\n";
115  }
116  return ;
117  }
118  throw std::runtime_error("index out of bounds");
119 }
120 
122 {
123  size_t idx = plugins_.size();
124  plugins_.push_back(new plugin);
125 
126  plugin & p = plugins_[idx];
127  p.name = name;
128  p.source = prog;
129  p.is_file = false;
130 
131  return idx;
132 }
133 
134 size_t plugins_manager::load_plugin(const std::string & name, const std::string & filename)
135 {
136  size_t idx = plugins_.size();
137  plugins_.push_back(new plugin);
138 
139  plugin & p = plugins_[idx];
140  p.name = name;
141  p.source = filename;
142  p.is_file = true;
143 
144  return idx;
145 }
146 
148 {
149  event evt;
150  evt.name = name;
151  evt.data = data;
152 
153  for (size_t idx = 0; idx < size(); ++idx)
154  {
155  if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
156  plugins_[idx].queue.push_back(evt);
157  }
158  }
159 }
160 
162 {
163  if (playing_) {
164  *playing_ = false; //this is to ensure "reentrancy" -- any previous calls to this function that never returned
165  //and looped back into the plugins system, should be halted and their later requests discarded
166  //this is to ensure the semantics that if a plugins context is left, then any pending requests
167  //are discarded to prevent them from being executed at an improper time
168  }
169  playing_ = boost::make_shared<bool> (true);
170  boost::shared_ptr<bool> local = playing_; //make a local copy of the pointer on the stack
171 
172  for (size_t idx = 0; idx < size(); ++idx)
173  {
174  DBG_PLG << "play_slice[" << idx << "] ... \n";
175  if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
176  DBG_PLG << "is running...";
177  if (!*local) { //check playing_ before each call to be sure that we should still continue
178  DBG_PLG << "aborting\n";
179  return;
180  }
181 
182  std::vector<event> input = plugins_[idx].queue; //empty the queue to a temporary variable
183  plugins_[idx].queue = std::vector<event>();
184 
185  //application_lua_kernel::requests_list requests =
186  std::vector<std::function<bool(void)> > requests =
187  plugins_[idx].thread->run_script(ctxt, input);
188 
189  DBG_PLG << "thread returned " << requests.size() << " requests\n";
190 
191  for (size_t j = 0; j < requests.size(); ++j) {
192  if (!*local) return; //check playing_ before each call to be sure that we should still continue
193  if (!requests[j]()) {
194  *local = false;
195  return ; //call the function but if it returns false (error) then stop
196  }
197  }
198 
199  DBG_PLG << "play_slice[" << idx << "] finished.\n";
200  } else if (!plugins_[idx].thread) {
201  DBG_PLG << "thread ["<< idx << "] not created\n";
202  } else {
203  DBG_PLG << "thread ["<< idx << "] not running\n";
204  }
205  }
206  *local = false;
207 }
208 
210 {
211 
212  for (size_t i = 0; i < size(); ++i) {
213  if (STATUS::RUNNING == get_status(i)) {
214  return true;
215  }
216  }
217  return false;
218 }
std::string name
Definition: manager.cpp:38
#define DBG_PLG
Definition: manager.cpp:31
size_t add_plugin(const std::string &name, const std::string &prog)
Definition: manager.cpp:121
bool is_file
Definition: manager.cpp:40
GLenum GLenum GLenum input
Definition: glew.h:10668
boost::scoped_ptr< application_lua_kernel::thread > thread
Definition: manager.cpp:41
STATUS get_status(size_t idx)
Definition: manager.cpp:75
std::string source
Definition: manager.cpp:39
size_t load_plugin(const std::string &name, const std::string &filename)
Definition: manager.cpp:134
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
boost::scoped_ptr< application_lua_kernel > kernel_
Definition: manager.hpp:75
boost::shared_ptr< bool > playing_
Definition: manager.hpp:74
GLfloat GLfloat p
Definition: glew.h:12766
boost::ptr_vector< plugin > plugins_
Definition: manager.hpp:73
std::string get_detailed_status(size_t idx)
Definition: manager.cpp:86
static plugins_manager * singleton
Definition: manager.cpp:45
size_t i
Definition: function.cpp:1057
std::vector< plugins_manager::event > queue
Definition: manager.cpp:42
void play_slice(const plugins_context &)
Definition: manager.cpp:161
std::string get_name(size_t idx)
Definition: manager.cpp:97
GLuint const GLchar * name
Definition: glew.h:1782
GLsizeiptr size
Definition: glew.h:1649
bool any_running()
Definition: manager.cpp:209
void start_plugin(size_t idx)
Definition: manager.cpp:104
Standard logging facilities (interface).
lua_kernel_base * get_kernel_base()
Definition: manager.cpp:66
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:147
static lg::log_domain log_plugins("plugins")
GLsizei const GLcharARB ** string
Definition: glew.h:4503
GLsizei GLsizei GLchar * source
Definition: glew.h:1800
static plugins_manager * get()
Definition: manager.cpp:61
plugins_manager(application_lua_kernel *)
Definition: manager.cpp:47